diff options
Diffstat (limited to 'packages/linux/linux-rp-2.6.22/tmio-ohci-r6.patch')
-rw-r--r-- | packages/linux/linux-rp-2.6.22/tmio-ohci-r6.patch | 929 |
1 files changed, 0 insertions, 929 deletions
diff --git a/packages/linux/linux-rp-2.6.22/tmio-ohci-r6.patch b/packages/linux/linux-rp-2.6.22/tmio-ohci-r6.patch deleted file mode 100644 index 9fdd2962c9..0000000000 --- a/packages/linux/linux-rp-2.6.22/tmio-ohci-r6.patch +++ /dev/null @@ -1,929 +0,0 @@ - - drivers/usb/host/Kconfig | 1 - drivers/usb/host/ohci-hcd.c | 1 - drivers/usb/host/ohci-tmio.c | 894 +++++++++++++++++++++++++++++++++++++++++++ - 3 files changed, 896 insertions(+) - -Index: git/drivers/usb/host/ohci-tmio.c -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ git/drivers/usb/host/ohci-tmio.c 2006-11-07 21:48:33.000000000 +0000 -@@ -0,0 +1,894 @@ -+/* -+ * OHCI HCD (Host Controller Driver) for USB. -+ * -+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at> -+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net> -+ * (C) Copyright 2002 Hewlett-Packard Company -+ * -+ * Bus glue for Toshiba Mobile IO (TMIO) Controller's OHCI core -+ * (C) Copyright 2005 Chris Humbert <mahadri-usb@drigon.com> -+ * -+ * This is known to work with the following variants: -+ * TC6393XB revision 3 (32kB SRAM) -+ * -+ * The TMIO's OHCI core DMAs through a small internal buffer that -+ * is directly addressable by the CPU. dma_declare_coherent_memory -+ * and DMA bounce buffers allow the higher-level OHCI host driver to -+ * work. However, the dma API doesn't handle dma mapping failures -+ * well (dma_sg_map() is a prime example), so it is unusable. -+ * -+ * This HC pretends be a PIO-ish controller and uses the kernel's -+ * generic allocator for the entire SRAM. Using the USB core's -+ * usb_operations, we provide hcd_buffer_alloc/free. Using the OHCI's -+ * ohci_ops, we provide memory management for OHCI's TDs and EDs. We -+ * internally queue a URB's TDs until enough dma memory is available -+ * to enqueue them with the HC. -+ * -+ * Written from sparse documentation from Toshiba and Sharp's driver -+ * for the 2.4 kernel, -+ * usb-ohci-tc6393.c (C) Copyright 2004 Lineo Solutions, Inc. -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include <linux/fs.h> -+#include <linux/mount.h> -+#include <linux/pagemap.h> -+#include <linux/init.h> -+#include <linux/namei.h> -+#include <linux/sched.h> -+ -+#include <linux/genalloc.h> -+#include <asm/dma-mapping.h> /* for consistent_sync() */ -+#include <asm/hardware/tmio.h> -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * USB Host Controller Configuration Register -+ */ -+struct tmio_uhccr { -+ u8 x00[8]; -+ u8 revid; /* 0x08 Revision ID */ -+ u8 x01[7]; -+ u16 basel; /* 0x10 USB Control Register Base Address Low */ -+ u16 baseh; /* 0x12 USB Control Register Base Address High */ -+ u8 x02[0x2c]; -+ u8 ilme; /* 0x40 Internal Local Memory Enable */ -+ u8 x03[0x0b]; -+ u16 pm; /* 0x4c Power Management */ -+ u8 x04[2]; -+ u8 intc; /* 0x50 INT Control */ -+ u8 x05[3]; -+ u16 lmw1l; /* 0x54 Local Memory Window 1 LMADRS Low */ -+ u16 lmw1h; /* 0x56 Local Memory Window 1 LMADRS High */ -+ u16 lmw1bl; /* 0x58 Local Memory Window 1 Base Address Low */ -+ u16 lmw1bh; /* 0x5A Local Memory Window 1 Base Address High */ -+ u16 lmw2l; /* 0x5C Local Memory Window 2 LMADRS Low */ -+ u16 lmw2h; /* 0x5E Local Memory Window 2 LMADRS High */ -+ u16 lmw2bl; /* 0x60 Local Memory Window 2 Base Address Low */ -+ u16 lmw2bh; /* 0x62 Local Memory Window 2 Base Address High */ -+ u8 x06[0x98]; -+ u8 misc; /* 0xFC MISC */ -+ u8 x07[3]; -+} __attribute__ ((packed)); -+ -+union tmio_uhccr_pm { -+ u16 raw; -+struct { -+ unsigned gcken:1; /* D0 */ -+ unsigned ckrnen:1; /* D1 */ -+ unsigned uspw1:1; /* D2 USB Port 1 Power Disable */ -+ unsigned uspw2:1; /* D3 USB Port 2 Power Disable */ -+ unsigned x00:4; -+ unsigned pmee:1; /* D8 */ -+ unsigned x01:6; -+ unsigned pmes:1; /* D15 */ -+} __attribute__ ((packed)); -+} __attribute__ ((packed)); -+ -+/*-------------------------------------------------------------------------*/ -+ -+struct tmio_dma_pool { -+ struct device* dev; -+ unsigned int size; -+}; -+ -+struct tmio_hcd { -+ struct gen_pool* poolp; -+ struct usb_operations ops; -+ struct tmio_dma_pool td_pool; -+ struct tmio_dma_pool ed_pool; -+ -+ struct tmio_uhccr __iomem *ccr; -+ void __iomem * sram; -+ size_t sram_len; -+}; -+ -+#define hcd_to_tmio(hcd) ((struct tmio_hcd*)(hcd_to_ohci (hcd) + 1)) -+ -+struct tmio_td { -+ void* data; /* td's data buffer */ -+ void __iomem * bounce; /* dma bounce buffer */ -+ dma_addr_t dma; /* bounce buffer dma address */ -+ size_t len; /* bounce buffer length */ -+ u32 info; /* parameter for td_fill */ -+}; -+ -+struct tmio_urb { -+ int td_add; /* next index to be added */ -+ int td_queue; /* next index to be HC enqueued */ -+ -+ struct tmio_td td [0]; /* private td data */ -+}; -+ -+static inline struct tmio_urb *urb_to_turb (struct urb *urb) -+{ -+ urb_priv_t* urb_priv = urb->hcpriv; -+ return (struct tmio_urb*)(urb_priv->td + urb_priv->length); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* gen_pool_alloc page allocator callback */ -+static unsigned long tmio_pool_callback(struct gen_pool *poolp) -+{ -+ return 0; -+} -+ -+static inline void tmio_pool_destroy(struct tmio_hcd *tmio) -+{ -+ struct gen_pool *poolp = tmio->poolp; -+ -+ if (!poolp) -+ return; -+ if (poolp->h) -+ kfree(poolp->h); -+ kfree(poolp); -+ tmio->poolp = NULL; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+#define BOUNDED_XYL(x,y,ylen) (((y) <= (x)) && ((x) < ((y)+(ylen)))) -+#define BOUNDED_XYY(x,y1,y2) (((y1) <= (x)) && ((x) < (y2))) -+ -+static inline dma_addr_t tmio_virt_to_dma (struct usb_hcd *hcd, void *vaddr) -+{ -+ struct resource* sram = tmio_resource_mem (hcd->self.controller); -+ struct tmio_hcd* tmio = hcd_to_tmio (hcd); -+ -+ return BOUNDED_XYL (vaddr, tmio->sram, tmio->sram_len) -+ ? sram->start + (vaddr - tmio->sram) -+ : ~0; -+} -+ -+static inline void* tmio_dma_to_virt (struct usb_hcd *hcd, dma_addr_t handle) -+{ -+ struct resource* sram = tmio_resource_mem (hcd->self.controller); -+ struct tmio_hcd* tmio = hcd_to_tmio (hcd); -+ -+ return BOUNDED_XYY (handle, sram->start, sram->end + 1) -+ ? tmio->sram + handle - sram->start -+ : NULL; -+} -+ -+/* -+ * allocate dma-able memory in the device's internal sram -+ * -+ * The generic pool allocator's minimum chunk size is 32 bytes, -+ * which is the cache line size on the PXA255, so we don't need -+ * to do anything special for smaller requests. -+ */ -+static inline void *tmio_dma_alloc (struct device *dev, size_t size, -+ dma_addr_t *handle, gfp_t mem_flags) -+{ -+ struct usb_hcd* hcd = dev_get_drvdata (dev); -+ struct tmio_hcd* tmio = hcd_to_tmio (hcd); -+ void* virt = (void*) gen_pool_alloc (tmio->poolp, size); -+ -+ return (*handle = tmio_virt_to_dma (hcd, virt)) == ~0 ? NULL : virt; -+} -+ -+static inline void tmio_dma_free (struct device *dev, size_t size, -+ void *cpu_addr, dma_addr_t handle) -+{ -+ struct usb_hcd* hcd = dev_get_drvdata (dev); -+ struct tmio_hcd* tmio = hcd_to_tmio (hcd); -+ dma_addr_t dma = tmio_virt_to_dma (hcd, cpu_addr); -+ -+ if (unlikely (dma == ~0)) { -+ dev_err (dev, "trying to free bad address 0x%p\n", cpu_addr); -+ return; -+ } -+ -+ if (unlikely (handle != dma)) -+ dev_err (dev, "dma address mismatch for 0x%p: %08x != %08x\n", -+ cpu_addr, handle, dma); -+ -+ gen_pool_free (tmio->poolp, (unsigned long) cpu_addr, size); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void *tmio_dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, -+ dma_addr_t *handle) -+{ -+ struct tmio_dma_pool *tdp = (struct tmio_dma_pool*) pool; -+ return tmio_dma_alloc (tdp->dev, tdp->size, handle, mem_flags); -+} -+ -+static void -+tmio_dma_pool_free (struct dma_pool *pool, void *vaddr, dma_addr_t addr) -+{ -+ struct tmio_dma_pool *tdp = (struct tmio_dma_pool*) pool; -+ return tmio_dma_free (tdp->dev, tdp->size, vaddr, addr); -+} -+ -+static void *tmio_buffer_alloc (struct usb_bus *bus, size_t size, -+ gfp_t mem_flags, dma_addr_t *dma) -+{ -+ return tmio_dma_alloc (bus->controller, size, dma, mem_flags); -+} -+ -+static void tmio_buffer_free (struct usb_bus *bus, size_t size, -+ void *addr, dma_addr_t dma) -+{ -+ tmio_dma_free (bus->controller, size, addr, dma); -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void tmio_hc_stop (struct usb_hcd *hcd) -+{ -+ struct device* dev = hcd->self.controller; -+ struct tmio_device* tdev = dev_to_tdev (dev); -+ struct tmio_hcd* tmio = hcd_to_tmio (hcd); -+ struct tmio_uhccr __iomem* ccr = tmio->ccr; -+ union tmio_uhccr_pm pm = {0}; -+ -+ pm.gcken = 1; -+ pm.ckrnen = 1; -+ pm.uspw1 = 1; -+ pm.uspw2 = 1; -+ -+ iowrite8 (0, &ccr->intc); -+ iowrite8 (0, &ccr->ilme); -+ iowrite16(0, &ccr->basel); -+ iowrite16(0, &ccr->baseh); -+ iowrite16(pm.raw, &ccr->pm); -+ -+ tdev->ops->function (dev, 0); -+ tdev->ops->clock (dev, 0); -+} -+ -+static void tmio_hc_start (struct usb_hcd *hcd) -+{ -+ struct device* dev = hcd->self.controller; -+ struct tmio_device* tdev = dev_to_tdev (dev); -+ struct tmio_hcd* tmio = hcd_to_tmio (hcd); -+ struct tmio_uhccr __iomem* ccr = tmio->ccr; -+ union tmio_uhccr_pm pm = {0}; -+ -+ pm.pmes = 1; -+ pm.pmee = 1; -+ pm.ckrnen = 1; -+ pm.gcken = 1; -+ -+ tdev->ops->clock (dev, 1); -+ tdev->ops->function (dev, 1); -+ -+ iowrite16(pm.raw, &ccr->pm); -+ iowrite16(hcd->rsrc_start, &ccr->basel); -+ iowrite16(hcd->rsrc_start >> 16, &ccr->baseh); -+ iowrite8 (1, &ccr->ilme); -+ iowrite8 (2, &ccr->intc); -+ -+ consistent_sync (tmio->sram, tmio->sram_len, DMA_BIDIRECTIONAL); -+ -+ dev_info (dev, "revision %d @ 0x%08llx, irq %d\n", -+ ioread8 (&ccr->revid), hcd->rsrc_start, hcd->irq); -+} -+ -+static void tmio_stop (struct usb_hcd *hcd) -+{ -+ struct ohci_hcd* ohci = hcd_to_ohci (hcd); -+ -+ /* NULL these so ohci_stop() doesn't try to free them */ -+ ohci->hcca = NULL; -+ ohci->td_cache = NULL; -+ ohci->ed_cache = NULL; -+ -+ ohci_stop (hcd); -+ tmio_hc_stop (hcd); -+ tmio_pool_destroy (hcd_to_tmio (hcd)); -+ -+ /* We don't free the hcca because tmio_hc_stop() turns off -+ * the sram and the memory allocation data is destroyed. */ -+} -+ -+static int tmio_start (struct usb_hcd *hcd) -+{ -+ struct device* dev = hcd->self.controller; -+ struct ohci_hcd* ohci = hcd_to_ohci (hcd); -+ struct tmio_hcd* tmio = hcd_to_tmio (hcd); -+ int retval; -+ -+ tmio_hc_start (hcd); -+ -+ tmio->poolp = gen_pool_create(0, fls(tmio->sram_len) - 1, -+ tmio_pool_callback, 0); -+ if (!tmio->poolp) { -+ retval = -ENOMEM; -+ goto err_gen_pool_create; -+ } -+ -+ gen_pool_free (tmio->poolp, (unsigned long)(tmio->sram), -+ tmio->sram_len); -+ -+ ohci->hcca = tmio_dma_alloc (dev, sizeof *ohci->hcca, -+ &ohci->hcca_dma, GFP_KERNEL); -+ if (!ohci->hcca) { -+ retval = -ENOMEM; -+ goto err_hcca_alloc; -+ } -+ -+ /* for our dma_pool_alloc/free hooks */ -+ ohci->td_cache = (struct dma_pool*) &tmio->td_pool; -+ ohci->ed_cache = (struct dma_pool*) &tmio->ed_pool; -+ -+ if ((retval = ohci_init (ohci)) < 0) -+ goto err_ohci_init; -+ -+ if ((retval = ohci_run (ohci)) < 0) -+ goto err_ohci_run; -+ -+ return 0; -+ -+err_ohci_run: -+ err ("can't start %s", hcd->self.bus_name); -+err_ohci_init: -+err_hcca_alloc: -+err_gen_pool_create: -+ tmio_stop (hcd); -+ return retval; -+} -+ -+/*-------------------------------------------------------------------------*/ -+ -+static inline void *tmio_urb_dma_to_virt(struct urb *urb, dma_addr_t dma) -+{ -+ if (BOUNDED_XYL(dma, urb->transfer_dma, urb->transfer_buffer_length)) -+ return urb->transfer_buffer + dma - urb->transfer_dma; -+ -+ if (BOUNDED_XYL(dma, urb->setup_dma, sizeof (struct usb_ctrlrequest))) -+ return urb->setup_packet + dma - urb->setup_dma; -+ -+ return NULL; -+} -+ -+static struct tmio_td* tmio_td_find (struct td *td, int *index) -+{ -+ struct urb* urb = td->urb; -+ urb_priv_t* urb_priv = urb->hcpriv; -+ struct tmio_urb* turb = urb_to_turb (urb); -+ int i; -+ -+ for (i=0; i < urb_priv->length; i++) -+ if (urb_priv->td[i] == td) { -+ *index = i; -+ return turb->td + i; -+ } -+ -+ return NULL; -+} -+ -+/* -+ * map the td's data to dma-able memory -+ * -+ * if this td transfers data, -+ * sets tmtd->data to the urb's data buffer -+ * sets tmtd->dma to dma-able memory -+ * sets tmtd->bounce to non-NULL if a bounce buffer is allocated -+ * copies the urb's data buffer to the bounce buffer if necessary -+ */ -+static int tmio_td_dma_map (struct ohci_hcd *ohci, struct urb *urb, -+ struct tmio_td *tmtd, int idx) -+{ -+ struct usb_hcd* hcd = ohci_to_hcd (ohci); -+ struct device* dev = hcd->self.controller; -+ dma_addr_t dma; -+ -+ if (!tmtd->len) -+ return 0; -+ -+ if (tmio_dma_to_virt (hcd, tmtd->dma)) -+ return 0; -+ -+ tmtd->data = tmio_urb_dma_to_virt (urb, tmtd->dma); -+ if (unlikely (!tmtd->data)) { -+ dev_err (dev, "TD has bad dma address 0x%08x\n", tmtd->dma); -+ return 0; -+ } -+ -+ tmtd->bounce = tmio_dma_alloc (dev, tmtd->len, &dma, GFP_ATOMIC); -+ if (!tmtd->bounce) -+ return -ENOMEM; -+ -+ if ((usb_pipecontrol (urb->pipe) && !idx) || usb_pipeout (urb->pipe)) { -+ consistent_sync (tmtd->bounce, tmtd->len, DMA_TO_DEVICE); -+ memcpy (tmtd->bounce, tmtd->data, tmtd->len); -+ } else -+ consistent_sync (tmtd->bounce, tmtd->len, DMA_FROM_DEVICE); -+ -+ tmtd->dma = dma; -+ return 0; -+} -+ -+/* -+ * unmaps the td's data from dma-able memory -+ * -+ * if a bounce buffer has been allocated, -+ * copy the bounce buffer to the urb's data buffer if necessary -+ * free the bounce buffer -+ */ -+static void tmio_td_dma_unmap (struct ohci_hcd *ohci, struct td *td) -+{ -+ struct device* dev = (ohci_to_hcd (ohci))->self.controller; -+ struct urb* urb = td->urb; -+ int idx; -+ struct tmio_td* tmtd = tmio_td_find (td, &idx); -+ -+ if (!tmtd->bounce) -+ return; -+ -+ if (usb_pipein (urb->pipe) && (usb_pipecontrol (urb->pipe) ? idx : 1)) { -+ memcpy (tmtd->data, tmtd->bounce, tmtd->len); -+ consistent_sync (tmtd->data, tmtd->len, DMA_TO_DEVICE); -+ } -+ -+ tmio_dma_free (dev, tmtd->len, tmtd->bounce, tmtd->dma); -+} -+ -+static int tmio_urb_runqueue (struct ohci_hcd *ohci, struct urb *urb) -+{ -+ struct tmio_urb* turb = urb_to_turb (urb); -+ urb_priv_t* urb_priv= urb->hcpriv; -+ int start = turb->td_queue; -+ int retval = 0; -+ int i; -+ -+ for (i = start; i < turb->td_add; i = ++turb->td_queue) { -+ struct tmio_td *tmtd = turb->td + i; -+ -+ if ((retval = tmio_td_dma_map (ohci, urb, tmtd, i))) -+ break; -+ -+ td_fill (ohci, tmtd->info, tmtd->dma, tmtd->len, urb, i); -+ } -+ -+ if (i <= start) -+ return retval; -+ -+ /* kickstart the appropriate list */ -+ wmb (); -+ switch (urb_priv->ed->type) { -+ case PIPE_BULK: -+ ohci_writel (ohci, OHCI_BLF, &ohci->regs->cmdstatus); -+ break; -+ case PIPE_CONTROL: -+ ohci_writel (ohci, OHCI_CLF, &ohci->regs->cmdstatus); -+ break; -+ } -+ -+ return retval; -+} -+ -+/* -+ * This needs to be called with ohci->lock held so the pending urb list -+ * isn't modified. -+ */ -+static int tmio_ohci_runqueue (struct ohci_hcd *ohci) -+{ -+ urb_priv_t* priv; -+ int retval = 0; -+ -+ list_for_each_entry_reverse (priv, &ohci->pending, pending) -+ if ((retval = tmio_urb_runqueue (ohci, priv->td[0]->urb))) -+ return retval; -+ -+ return retval; -+} -+ -+static void tmio_td_fill (struct ohci_hcd *ohci, u32 info, -+ dma_addr_t data, int len, struct urb *urb, int index) -+{ -+ struct tmio_urb* turb = urb_to_turb (urb); -+ struct tmio_td* tmtd = turb->td + index; -+ -+ tmtd->data = NULL; -+ tmtd->bounce = NULL; -+ tmtd->dma = data; -+ tmtd->len = len; -+ tmtd->info = info; -+ turb->td_add = index + 1; -+} -+ -+static void -+tmio_td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td) -+{ -+ tmio_td_dma_unmap (ohci, td); -+ td_done (ohci, urb, td); -+} -+ -+const static struct ohci_ops tmio_ops = { -+ .dma_pool_alloc = tmio_dma_pool_alloc, -+ .dma_pool_free = tmio_dma_pool_free, -+ .td_fill = tmio_td_fill, -+ .td_done = tmio_td_done, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+static irqreturn_t tmio_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) -+{ -+ irqreturn_t retval = ohci_irq (hcd, ptregs); -+ -+ if (retval == IRQ_HANDLED) { -+ struct ohci_hcd *ohci = hcd_to_ohci (hcd); -+ unsigned long flags; -+ -+ spin_lock_irqsave(&ohci->lock, flags); -+ tmio_ohci_runqueue (ohci); -+ spin_unlock_irqrestore (&ohci->lock, flags); -+ } -+ -+ return retval; -+} -+ -+/* -+ * This is ohci_urb_enqueue with: -+ * dma address sanitization for tmio_urb_dma_to_virt() -+ * allocate extra space in urb_priv for our private data -+ * initialize urb_priv->td[0]->urb for tmio_ohci_runqueue() -+ * call tmio_ohci_runqueue() after submitting TDs -+ */ -+static int tmio_urb_enqueue ( -+ struct usb_hcd *hcd, -+ struct usb_host_endpoint *ep, -+ struct urb *urb, -+ gfp_t mem_flags -+) { -+ struct ohci_hcd *ohci = hcd_to_ohci (hcd); -+ struct ed *ed; -+ urb_priv_t *urb_priv; -+ unsigned int pipe = urb->pipe; -+ int i, size = 0; -+ unsigned long flags; -+ int retval = 0; -+ -+#ifdef OHCI_VERBOSE_DEBUG -+ urb_print (urb, "SUB", usb_pipein (pipe)); -+#endif -+ -+ /* make sure we can convert dma offsets back to virtual addresses */ -+ if (!tmio_dma_to_virt (hcd, urb->setup_dma)) -+ urb->setup_dma = 0; -+ -+ if (!tmio_dma_to_virt (hcd, urb->transfer_dma)) -+ urb->transfer_dma = sizeof (struct usb_ctrlrequest); -+ -+ /* every endpoint has a ed, locate and maybe (re)initialize it */ -+ if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval))) -+ return -ENOMEM; -+ -+ /* for the private part of the URB we need the number of TDs (size) */ -+ switch (ed->type) { -+ case PIPE_CONTROL: -+ /* td_submit_urb() doesn't yet handle these */ -+ if (urb->transfer_buffer_length > 4096) -+ return -EMSGSIZE; -+ -+ /* 1 TD for setup, 1 for ACK, plus ... */ -+ size = 2; -+ /* FALLTHROUGH */ -+ // case PIPE_INTERRUPT: -+ // case PIPE_BULK: -+ default: -+ /* one TD for every 4096 Bytes (can be upto 8K) */ -+ size += urb->transfer_buffer_length / 4096; -+ /* ... and for any remaining bytes ... */ -+ if ((urb->transfer_buffer_length % 4096) != 0) -+ size++; -+ /* ... and maybe a zero length packet to wrap it up */ -+ if (size == 0) -+ size++; -+ else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0 -+ && (urb->transfer_buffer_length -+ % usb_maxpacket (urb->dev, pipe, -+ usb_pipeout (pipe))) == 0) -+ size++; -+ break; -+ case PIPE_ISOCHRONOUS: /* number of packets from URB */ -+ size = urb->number_of_packets; -+ break; -+ } -+ -+ /* allocate the private part of the URB */ -+ urb_priv = kzalloc (sizeof (urb_priv_t) -+ + size * sizeof (struct td*) -+ + sizeof (struct tmio_urb) -+ + size * sizeof (struct tmio_td), -+ mem_flags); -+ if (!urb_priv) -+ return -ENOMEM; -+ INIT_LIST_HEAD (&urb_priv->pending); -+ urb_priv->length = size; -+ urb_priv->ed = ed; -+ -+ /* allocate the TDs (deferring hash chain updates) */ -+ for (i = 0; i < size; i++) { -+ urb_priv->td [i] = td_alloc (ohci, mem_flags); -+ if (!urb_priv->td [i]) { -+ urb_priv->length = i; -+ urb_free_priv (ohci, urb_priv); -+ return -ENOMEM; -+ } -+ urb_priv->td [i]->urb = urb; -+ } -+ -+ spin_lock_irqsave (&ohci->lock, flags); -+ -+ /* don't submit to a dead HC */ -+ if (!HC_IS_RUNNING(hcd->state)) { -+ retval = -ENODEV; -+ goto fail; -+ } -+ -+ /* in case of unlink-during-submit */ -+ spin_lock (&urb->lock); -+ if (urb->status != -EINPROGRESS) { -+ spin_unlock (&urb->lock); -+ urb->hcpriv = urb_priv; -+ finish_urb (ohci, urb, NULL); -+ retval = 0; -+ goto fail; -+ } -+ -+ /* schedule the ed if needed */ -+ if (ed->state == ED_IDLE) { -+ retval = ed_schedule (ohci, ed); -+ if (retval < 0) -+ goto fail0; -+ if (ed->type == PIPE_ISOCHRONOUS) { -+ u16 frame = ohci_frame_no(ohci); -+ -+ /* delay a few frames before the first TD */ -+ frame += max_t (u16, 8, ed->interval); -+ frame &= ~(ed->interval - 1); -+ frame |= ed->branch; -+ urb->start_frame = frame; -+ -+ /* yes, only URB_ISO_ASAP is supported, and -+ * urb->start_frame is never used as input. -+ */ -+ } -+ } else if (ed->type == PIPE_ISOCHRONOUS) -+ urb->start_frame = ed->last_iso + ed->interval; -+ -+ /* fill the TDs and link them to the ed; and -+ * enable that part of the schedule, if needed -+ * and update count of queued periodic urbs -+ */ -+ urb->hcpriv = urb_priv; -+ td_submit_urb (ohci, urb); -+ tmio_ohci_runqueue (ohci); -+ -+fail0: -+ spin_unlock (&urb->lock); -+fail: -+ if (retval) -+ urb_free_priv (ohci, urb_priv); -+ spin_unlock_irqrestore (&ohci->lock, flags); -+ return retval; -+} -+ -+static const struct hc_driver tmio_hc_driver = { -+ .description = hcd_name, -+ .product_desc = "TMIO OHCI USB Host Controller", -+ .hcd_priv_size = sizeof (struct ohci_hcd) -+ + sizeof (struct tmio_hcd), -+ -+ /* generic hardware linkage */ -+ .irq = tmio_irq, -+ .flags = HCD_USB11 | HCD_MEMORY, -+ -+ /* basic lifecycle operations */ -+ .start = tmio_start, -+ .stop = tmio_stop, -+ -+ /* managing i/o requests and associated device resources */ -+ .urb_enqueue = tmio_urb_enqueue, -+ .urb_dequeue = ohci_urb_dequeue, -+ .endpoint_disable = ohci_endpoint_disable, -+ -+ /* scheduling support */ -+ .get_frame_number = ohci_get_frame, -+ -+ /* root hub support */ -+ .hub_status_data = ohci_hub_status_data, -+ .hub_control = ohci_hub_control, -+#ifdef CONFIG_PM -+ .bus_suspend = ohci_bus_suspend, -+ .bus_resume = ohci_bus_resume, -+#endif -+ .start_port_reset = ohci_start_port_reset, -+}; -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* configure so an HC device and id are always provided */ -+/* always called with process context; sleeping is OK */ -+ -+/** -+ * tmio_probe - initialize TMIO-based HCDs -+ * Context: !in_interrupt() -+ * -+ * Allocates basic resources for this USB host controller, and -+ * then invokes the start() method for the HCD associated with it -+ * through the hotplug entry's driver_data. -+ */ -+static int tmio_probe (struct device *dev) -+{ -+ struct tmio_device* tdev = dev_to_tdev (dev); -+ struct resource* config = tmio_resource_config (dev); -+ struct resource* regs = tmio_resource_control (dev); -+ struct resource* sram = tmio_resource_mem (dev); -+ struct resource* irq = tmio_resource_irq (dev); -+ struct usb_operations* ops; -+ struct tmio_hcd* tmio; -+ struct ohci_hcd* ohci; -+ struct usb_hcd* hcd; -+ int retval; -+ -+ if (usb_disabled ()) -+ return -ENODEV; -+ -+ if (dev->dma_mask || dev->coherent_dma_mask) { -+ dev_err (dev, "DMA not supported\n"); -+ return -ENODEV; -+ } -+ -+ hcd = usb_create_hcd (&tmio_hc_driver, dev, dev->bus_id); -+ if (!hcd) { -+ retval = -ENOMEM; -+ goto err_create_hcd; -+ } -+ -+ tmio = hcd_to_tmio (hcd); -+ tmio->td_pool.dev = dev; -+ tmio->ed_pool.dev = dev; -+ tmio->td_pool.size = sizeof (struct td); -+ tmio->ed_pool.size = sizeof (struct ed); -+ ohci = hcd_to_ohci (hcd); -+ ohci_hcd_init (ohci); -+ ohci->ops = &tmio_ops; -+ -+ retval = request_resource (tdev->iomem, config); -+ if (retval) -+ goto err_request_config_resource; -+ -+ retval = request_resource (tdev->iomem, regs); -+ if (retval) -+ goto err_request_regs_resource; -+ -+ retval = request_resource (tdev->iomem, sram); -+ if (retval) -+ goto err_request_sram_resource; -+ -+ hcd->rsrc_start = regs->start; -+ hcd->rsrc_len = regs->end - regs->start + 1; -+ tmio->sram_len = sram->end - sram->start + 1; -+ -+ tmio->ccr = ioremap (config->start, config->end - config->start + 1); -+ if (!tmio->ccr) { -+ retval = -ENOMEM; -+ goto err_ioremap_ccr; -+ } -+ -+ hcd->regs = ioremap (hcd->rsrc_start, hcd->rsrc_len); -+ if (!hcd->regs) { -+ retval = -ENOMEM; -+ goto err_ioremap_regs; -+ } -+ -+ tmio->sram = ioremap (sram->start, tmio->sram_len); -+ if (!tmio->sram) { -+ retval = -ENOMEM; -+ goto err_ioremap_sram; -+ } -+ -+ /* drivers should use our coherent buffer allocator */ -+ ops = &tmio->ops; -+ memcpy (ops, hcd->self.op, sizeof *ops); -+ ops->buffer_alloc = tmio_buffer_alloc; -+ ops->buffer_free = tmio_buffer_free; -+ hcd->self.op = ops; -+ -+ retval = usb_add_hcd (hcd, irq->start, SA_INTERRUPT); -+ if (retval) -+ goto err_usb_add_hcd; -+ -+ return 0; -+ -+err_usb_add_hcd: -+ iounmap (tmio->sram); -+err_ioremap_sram: -+ iounmap (hcd->regs); -+err_ioremap_regs: -+ iounmap (tmio->ccr); -+err_ioremap_ccr: -+ release_resource (sram); -+err_request_sram_resource: -+ release_resource (regs); -+err_request_regs_resource: -+ release_resource (config); -+err_request_config_resource: -+ usb_put_hcd (hcd); -+err_create_hcd: -+ return retval; -+} -+ -+/* may be called without controller electrically present */ -+/* may be called with controller, bus, and devices active */ -+ -+/** -+ * tmio_remove - shutdown processing for TMIO-based HCDs -+ * @dev: USB Host Controller being removed -+ * Context: !in_interrupt() -+ * -+ * Reverses the effect of tmio_probe(), first invoking -+ * the HCD's stop() method. It is always called from a thread -+ * context, normally "rmmod", "apmd", or something similar. -+ */ -+static int tmio_remove (struct device *dev) -+{ -+ struct usb_hcd* hcd = dev_get_drvdata (dev); -+ struct tmio_hcd* tmio = hcd_to_tmio (hcd); -+ -+ usb_remove_hcd (hcd); -+ iounmap (tmio->sram); -+ iounmap (hcd->regs); -+ iounmap (tmio->ccr); -+ release_resource (tmio_resource_mem (dev)); -+ release_resource (tmio_resource_control (dev)); -+ release_resource (tmio_resource_config (dev)); -+ usb_put_hcd (hcd); -+ return 0; -+} -+ -+static struct device_driver tmio_ohci = { -+ .name = TMIO_NAME_OHCI, -+ .bus = &tmio_bus_type, -+ .probe = tmio_probe, -+ .remove = tmio_remove, -+}; -+ -+static int __init tmio_init (void) -+{ -+ dbg (DRIVER_INFO " (%s)", TMIO_SOC_NAME); -+ dbg ("block sizes: ed %d td %d", -+ sizeof (struct ed), sizeof (struct td)); -+ -+ return driver_register (&tmio_ohci); -+} -+ -+static void __exit tmio_exit (void) -+{ -+ driver_unregister (&tmio_ohci); -+} -+ -+module_init (tmio_init); -+module_exit (tmio_exit); -Index: git/drivers/usb/host/Kconfig -=================================================================== ---- git.orig/drivers/usb/host/Kconfig 2006-11-07 21:46:32.000000000 +0000 -+++ git/drivers/usb/host/Kconfig 2006-11-07 21:48:38.000000000 +0000 -@@ -84,6 +84,7 @@ config USB_OHCI_HCD - depends on USB && USB_ARCH_HAS_OHCI - select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 - select I2C if ARCH_PNX4008 -+ select GENERIC_ALLOCATOR if TOSHIBA_TC6393XB - ---help--- - The Open Host Controller Interface (OHCI) is a standard for accessing - USB 1.1 host controller hardware. It does more in hardware than Intel's -Index: git/drivers/usb/host/ohci-hcd.c -=================================================================== ---- git.orig/drivers/usb/host/ohci-hcd.c 2006-11-07 21:46:32.000000000 +0000 -+++ git/drivers/usb/host/ohci-hcd.c 2006-11-07 21:48:33.000000000 +0000 -@@ -944,6 +944,7 @@ MODULE_LICENSE ("GPL"); - || defined(CONFIG_ARCH_OMAP) \ - || defined (CONFIG_ARCH_LH7A404) \ - || defined (CONFIG_PXA27x) \ -+ || defined (CONFIG_TOSHIBA_TC6393XB) \ - || defined (CONFIG_ARCH_EP93XX) \ - || defined (CONFIG_SOC_AU1X00) \ - || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \ |