summaryrefslogtreecommitdiff
path: root/packages/linux/linux-rp-2.6.18/tmio-ohci-r5.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/linux-rp-2.6.18/tmio-ohci-r5.patch')
-rw-r--r--packages/linux/linux-rp-2.6.18/tmio-ohci-r5.patch923
1 files changed, 0 insertions, 923 deletions
diff --git a/packages/linux/linux-rp-2.6.18/tmio-ohci-r5.patch b/packages/linux/linux-rp-2.6.18/tmio-ohci-r5.patch
deleted file mode 100644
index a87469afb3..0000000000
--- a/packages/linux/linux-rp-2.6.18/tmio-ohci-r5.patch
+++ /dev/null
@@ -1,923 +0,0 @@
-Index: linux-2.6.18/drivers/usb/host/ohci-tmio.c
-===================================================================
---- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.18/drivers/usb/host/ohci-tmio.c 2006-09-20 16:18:08.000000000 +0200
-@@ -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: linux-2.6.18/drivers/usb/host/Kconfig
-===================================================================
---- linux-2.6.18.orig/drivers/usb/host/Kconfig 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18/drivers/usb/host/Kconfig 2006-09-20 16:18:08.000000000 +0200
-@@ -83,6 +83,7 @@
- tristate "OHCI HCD support"
- depends on USB && USB_ARCH_HAS_OHCI
- select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
-+ 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: linux-2.6.18/drivers/usb/host/ohci-hcd.c
-===================================================================
---- linux-2.6.18.orig/drivers/usb/host/ohci-hcd.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18/drivers/usb/host/ohci-hcd.c 2006-09-20 16:18:54.000000000 +0200
-@@ -923,6 +923,7 @@
- || 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) \