Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/521/?format=api
{ "id": 521, "url": "http://patchwork.ozlabs.org/api/patches/521/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/20080918151746.GC31187@oksana.dev.rtsoft.ru/", "project": { "id": 2, "url": "http://patchwork.ozlabs.org/api/projects/2/?format=api", "name": "Linux PPC development", "link_name": "linuxppc-dev", "list_id": "linuxppc-dev.lists.ozlabs.org", "list_email": "linuxppc-dev@lists.ozlabs.org", "web_url": "https://github.com/linuxppc/wiki/wiki", "scm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git", "webscm_url": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/", "list_archive_url": "https://lore.kernel.org/linuxppc-dev/", "list_archive_url_format": "https://lore.kernel.org/linuxppc-dev/{}/", "commit_url_format": "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/commit/?id={}" }, "msgid": "<20080918151746.GC31187@oksana.dev.rtsoft.ru>", "list_archive_url": "https://lore.kernel.org/linuxppc-dev/20080918151746.GC31187@oksana.dev.rtsoft.ru/", "date": "2008-09-18T15:17:46", "name": "[3/3] USB: driver for Freescale QUICC Engine USB Host Controller", "commit_ref": null, "pull_url": null, "state": "superseded", "archived": true, "hash": "7ab92bda55abceaf5d1e40d89d80faa9b844d4f4", "submitter": { "id": 45, "url": "http://patchwork.ozlabs.org/api/people/45/?format=api", "name": "Anton Vorontsov", "email": "avorontsov@ru.mvista.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linuxppc-dev/patch/20080918151746.GC31187@oksana.dev.rtsoft.ru/mbox/", "series": [], "comments": "http://patchwork.ozlabs.org/api/patches/521/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/521/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org>", "X-Original-To": [ "patchwork-incoming@ozlabs.org", "linuxppc-dev@ozlabs.org" ], "Delivered-To": [ "patchwork-incoming@ozlabs.org", "linuxppc-dev@ozlabs.org" ], "Received": [ "from ozlabs.org (localhost [127.0.0.1])\n\tby ozlabs.org (Postfix) with ESMTP id BB92ADE708\n\tfor <patchwork-incoming@ozlabs.org>;\n\tFri, 19 Sep 2008 01:18:23 +1000 (EST)", "from buildserver.ru.mvista.com (unknown [85.21.88.6])\n\tby ozlabs.org (Postfix) with ESMTP id 5F94CDE1BA\n\tfor <linuxppc-dev@ozlabs.org>; Fri, 19 Sep 2008 01:17:48 +1000 (EST)", "from localhost (unknown [10.150.0.9])\n\tby buildserver.ru.mvista.com (Postfix) with ESMTP\n\tid D43C3881D; Thu, 18 Sep 2008 20:17:46 +0500 (SAMST)" ], "Date": "Thu, 18 Sep 2008 19:17:46 +0400", "From": "Anton Vorontsov <avorontsov@ru.mvista.com>", "To": "Andrew Morton <akpm@linux-foundation.org>", "Subject": "[PATCH 3/3] USB: driver for Freescale QUICC Engine USB Host\n\tController", "Message-ID": "<20080918151746.GC31187@oksana.dev.rtsoft.ru>", "References": "<20080918151659.GA20140@oksana.dev.rtsoft.ru>", "MIME-Version": "1.0", "Content-Disposition": "inline", "In-Reply-To": "<20080918151659.GA20140@oksana.dev.rtsoft.ru>", "User-Agent": "Mutt/1.5.18 (2008-05-17)", "Cc": "David Brownell <dbrownell@users.sourceforge.net>,\n\tGreg Kroah-Hartman <greg@kroah.com>, linux-usb@vger.kernel.org,\n\tlinux-kernel@vger.kernel.org, linuxppc-dev@ozlabs.org,\n\tLi Yang <leoli@freescale.com>, Timur Tabi <timur@freescale.com>", "X-BeenThere": "linuxppc-dev@ozlabs.org", "X-Mailman-Version": "2.1.11", "Precedence": "list", "List-Id": "Linux on PowerPC Developers Mail List <linuxppc-dev.ozlabs.org>", "List-Unsubscribe": "<https://ozlabs.org/mailman/options/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@ozlabs.org?subject=unsubscribe>", "List-Archive": "<http://ozlabs.org/pipermail/linuxppc-dev>", "List-Post": "<mailto:linuxppc-dev@ozlabs.org>", "List-Help": "<mailto:linuxppc-dev-request@ozlabs.org?subject=help>", "List-Subscribe": "<https://ozlabs.org/mailman/listinfo/linuxppc-dev>,\n\t<mailto:linuxppc-dev-request@ozlabs.org?subject=subscribe>", "Content-Type": "text/plain; charset=\"us-ascii\"", "Content-Transfer-Encoding": "7bit", "Sender": "linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org", "Errors-To": "linuxppc-dev-bounces+patchwork-incoming=ozlabs.org@ozlabs.org" }, "content": "This patch adds support for the FHCI USB controller, as found\nin the Freescale MPC836x and MPC832x processors. It can support\nFull or Low speed modes.\n\nQuite a lot the hardware is doing by itself (SOF generation, CRC\ngeneration and checking), though scheduling and retransmission is on\nsoftware's shoulders.\n\nThis controller does not integrate the root hub, so this driver also\nfakes one-port hub. External hub is required to support more than\none device.\n\nSigned-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>", "diff": "diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile\nindex a419c42..7b14564 100644\n--- a/drivers/usb/Makefile\n+++ b/drivers/usb/Makefile\n@@ -16,6 +16,7 @@ obj-$(CONFIG_USB_UHCI_HCD)\t+= host/\n obj-$(CONFIG_USB_SL811_HCD)\t+= host/\n obj-$(CONFIG_USB_U132_HCD)\t+= host/\n obj-$(CONFIG_USB_R8A66597_HCD)\t+= host/\n+obj-$(CONFIG_USB_FHCI_HCD)\t+= host/\n \n obj-$(CONFIG_USB_C67X00_HCD)\t+= c67x00/\n \ndiff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig\nindex 228797e..594c263 100644\n--- a/drivers/usb/host/Kconfig\n+++ b/drivers/usb/host/Kconfig\n@@ -305,3 +305,20 @@ config SUPERH_ON_CHIP_R8A66597\n \thelp\n \t This driver enables support for the on-chip R8A66597 in the\n \t SH7366 and SH7723 processors.\n+\n+config USB_FHCI_HCD\n+\ttristate \"Freescale QE USB Host Controller support\"\n+\tdepends on USB && OF_GPIO && QUICC_ENGINE\n+\tselect FSL_GTM\n+\tselect QE_USB\n+\thelp\n+\t This driver enables support for Freescale QE USB Host Controller\n+\t (as found on MPC8360 and MPC8323 processors), the driver supports\n+\t Full and Low Speed USB.\n+\n+config FHCI_DEBUG\n+\tbool \"Freescale QE USB Host Controller debug support\"\n+\tdepends on USB_FHCI_HCD && DEBUG_FS\n+\thelp\n+\t Say \"y\" to see some FHCI debug information and statistics\n+\t throught debugfs.\ndiff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile\nindex f1edda2..b71dfed 100644\n--- a/drivers/usb/host/Makefile\n+++ b/drivers/usb/host/Makefile\n@@ -19,3 +19,4 @@ obj-$(CONFIG_USB_SL811_CS)\t+= sl811_cs.o\n obj-$(CONFIG_USB_U132_HCD)\t+= u132-hcd.o\n obj-$(CONFIG_USB_R8A66597_HCD)\t+= r8a66597-hcd.o\n obj-$(CONFIG_USB_ISP1760_HCD)\t+= isp1760.o\n+obj-$(CONFIG_USB_FHCI_HCD)\t+= fhci-hcd.o\ndiff --git a/drivers/usb/host/fhci-cq.c b/drivers/usb/host/fhci-cq.c\nnew file mode 100644\nindex 0000000..23716fa\n--- /dev/null\n+++ b/drivers/usb/host/fhci-cq.c\n@@ -0,0 +1,105 @@\n+/*\n+ * Freescale QUICC Engine USB Host Controller Driver\n+ *\n+ * Copyright (c) Freescale Semicondutor, Inc. 2006.\n+ * Shlomi Gridish <gridish@freescale.com>\n+ * Jerry Huang <Chang-Ming.Huang@freescale.com>\n+ * Copyright (c) Logic Product Development, Inc. 2007\n+ * Peter Barada <peterb@logicpd.com>\n+ * Copyright (c) MontaVista Software, Inc. 2008.\n+ * Anton Vorontsov <avorontsov@ru.mvista.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License as published by the\n+ * Free Software Foundation; either version 2 of the License, or (at your\n+ * option) any later version.\n+ */\n+\n+/* circular queue structure */\n+struct cir_q {\n+ int max;\t\t/* size of queue */\n+ int max_in;\t/* max items in queue */\n+ int first;\t/* index of first in queue */\n+ int last;\t/* index after last in queue */\n+ int read;\t/* current reading position */\n+ void *table[1];\t/* fake size */\n+};\n+\n+/* circular queue handle */\n+static int cq_howmany(struct cir_q *cq)\n+{\n+\tint l = cq->last;\n+\tint f = cq->first;\n+\n+\treturn l >= f ? l - f : l + cq->max - f;\n+}\n+\n+static struct cir_q *cq_new(int size)\n+{\n+\tstruct cir_q *cq;\n+\n+\tcq = kzalloc((sizeof(*cq) + size * sizeof(void *)), GFP_KERNEL);\n+\tif (cq) {\n+\t\tcq->max = size;\n+\t\tcq->first = 0;\n+\t\tcq->last = 0;\n+\t\tcq->read = 0;\n+\t\tcq->max_in = 0;\n+\t}\n+\n+\treturn cq;\n+}\n+\n+static void cq_delete(struct cir_q *cq)\n+{\n+\tkfree(cq);\n+}\n+\n+static int cq_put(struct cir_q *cq, void *p)\n+{\n+\tint n;\n+\tint k;\n+\n+\t/* see if we can freely advance the last pointer */\n+\tn = cq->last;\n+\tk = cq_howmany(cq);\n+\tif ((k + 1) >= cq->max)\n+\t\treturn -1;\n+\n+\tif (++n >= cq->max)\n+\t\tn = 0;\n+\n+\t/* add element to queue */\n+\tcq->table[cq->last] = p;\n+\tcq->last = n;\n+\tif ((k + 1) > cq->max_in)\n+\t\tcq->max_in = k + 1;\n+\n+\treturn k;\n+}\n+\n+static void *cq_get(struct cir_q *cq)\n+{\n+\tint n;\n+\tint k;\n+\tvoid *p;\n+\n+\tn = cq->first;\n+\t/* see if the queue is not empty */\n+\tif (n == cq->last)\n+\t\treturn NULL;\n+\n+\tp = cq->table[n];\n+\tif (++n >= cq->max)\n+\t\tn = 0;\n+\tif (cq->read == cq->first)\n+\t\tcq->read = n;\n+\tcq->first = n;\n+\n+\t/* see if we've passed our previous maximum */\n+\tk = cq_howmany(cq);\n+\tif (k > cq->max_in)\n+\t\tcq->max_in = k;\n+\n+\treturn p;\n+}\ndiff --git a/drivers/usb/host/fhci-dbg.c b/drivers/usb/host/fhci-dbg.c\nnew file mode 100644\nindex 0000000..8127935\n--- /dev/null\n+++ b/drivers/usb/host/fhci-dbg.c\n@@ -0,0 +1,144 @@\n+/*\n+ * Freescale QUICC Engine USB Host Controller Driver\n+ *\n+ * Copyright (c) Freescale Semicondutor, Inc. 2006.\n+ * Shlomi Gridish <gridish@freescale.com>\n+ * Jerry Huang <Chang-Ming.Huang@freescale.com>\n+ * Copyright (c) Logic Product Development, Inc. 2007\n+ * Peter Barada <peterb@logicpd.com>\n+ * Copyright (c) MontaVista Software, Inc. 2008.\n+ * Anton Vorontsov <avorontsov@ru.mvista.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License as published by the\n+ * Free Software Foundation; either version 2 of the License, or (at your\n+ * option) any later version.\n+ */\n+\n+#ifdef CONFIG_FHCI_DEBUG\n+\n+#include <linux/debugfs.h>\n+#include <linux/seq_file.h>\n+\n+static void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er)\n+{\n+\tint i;\n+\n+\tif (usb_er == -1) {\n+\t\tfhci->usb_irq_stat[12]++;\n+\t\treturn;\n+\t}\n+\n+\tfor (i = 0; i < 12; ++i) {\n+\t\tif (usb_er & (1 << i))\n+\t\t\tfhci->usb_irq_stat[i]++;\n+\t}\n+}\n+\n+static int fhci_dfs_regs_show(struct seq_file *s, void *v)\n+{\n+\tstruct fhci_hcd *fhci = s->private;\n+\tstruct fhci_regs __iomem *regs = fhci->regs;\n+\n+\tseq_printf(s,\n+\t\t\"mode: 0x%x\\n\" \"addr: 0x%x\\n\"\n+\t\t\"command: 0x%x\\n\" \"ep0: 0x%x\\n\"\n+\t\t\"event: 0x%x\\n\" \"mask: 0x%x\\n\"\n+\t\t\"status: 0x%x\\n\" \"SOF timer: %d\\n\"\n+\t\t\"frame number: %d\\n\"\n+\t\t\"lines status: 0x%x\\n\",\n+\t\tin_8(®s->usb_mod), in_8(®s->usb_addr),\n+\t\tin_8(®s->usb_comm), in_be16(®s->usb_ep[0]),\n+\t\tin_be16(®s->usb_event), in_be16(®s->usb_mask),\n+\t\tin_8(®s->usb_status), in_be16(®s->usb_sof_tmr),\n+\t\tin_be16(®s->usb_frame_num),\n+\t\tfhci_ioports_check_bus_state(fhci));\n+\n+\treturn 0;\n+}\n+\n+static int fhci_dfs_irq_stat_show(struct seq_file *s, void *v)\n+{\n+\tstruct fhci_hcd *fhci = s->private;\n+\tint *usb_irq_stat = fhci->usb_irq_stat;\n+\n+\tseq_printf(s,\n+\t\t\"RXB: %d\\n\" \"TXB: %d\\n\" \"BSY: %d\\n\"\n+\t\t\"SOF: %d\\n\" \"TXE0: %d\\n\" \"TXE1: %d\\n\"\n+\t\t\"TXE2: %d\\n\" \"TXE3: %d\\n\" \"IDLE: %d\\n\"\n+\t\t\"RESET: %d\\n\" \"SFT: %d\\n\" \"MSF: %d\\n\"\n+\t\t\"IDLE_ONLY: %d\\n\",\n+\t\tusb_irq_stat[0], usb_irq_stat[1], usb_irq_stat[2],\n+\t\tusb_irq_stat[3], usb_irq_stat[4], usb_irq_stat[5],\n+\t\tusb_irq_stat[6], usb_irq_stat[7], usb_irq_stat[8],\n+\t\tusb_irq_stat[9], usb_irq_stat[10], usb_irq_stat[11],\n+\t\tusb_irq_stat[12]);\n+\n+\treturn 0;\n+}\n+\n+static int fhci_dfs_regs_open(struct inode *inode, struct file *file)\n+{\n+\treturn single_open(file, fhci_dfs_regs_show, inode->i_private);\n+}\n+\n+static int fhci_dfs_irq_stat_open(struct inode *inode, struct file *file)\n+{\n+\treturn single_open(file, fhci_dfs_irq_stat_show, inode->i_private);\n+}\n+\n+static const struct file_operations fhci_dfs_regs_fops = {\n+\t.open = fhci_dfs_regs_open,\n+\t.read = seq_read,\n+\t.llseek = seq_lseek,\n+\t.release = single_release,\n+};\n+\n+static const struct file_operations fhci_dfs_irq_stat_fops = {\n+\t.open = fhci_dfs_irq_stat_open,\n+\t.read = seq_read,\n+\t.llseek = seq_lseek,\n+\t.release = single_release,\n+};\n+\n+static void fhci_dfs_create(struct fhci_hcd *fhci)\n+{\n+\tstruct device *dev = fhci_to_hcd(fhci)->self.controller;\n+\n+\tfhci->dfs_root = debugfs_create_dir(dev->bus_id, NULL);\n+\tif (!fhci->dfs_root) {\n+\t\tWARN_ON(1);\n+\t\treturn;\n+\t}\n+\n+\tfhci->dfs_regs = debugfs_create_file(\"regs\", S_IFREG | S_IRUGO,\n+\t\tfhci->dfs_root, fhci, &fhci_dfs_regs_fops);\n+\n+\tfhci->dfs_irq_stat = debugfs_create_file(\"irq_stat\",\n+\t\tS_IFREG | S_IRUGO, fhci->dfs_root, fhci,\n+\t\t&fhci_dfs_irq_stat_fops);\n+\n+\tWARN_ON(!fhci->dfs_regs || !fhci->dfs_irq_stat);\n+}\n+\n+static void fhci_dfs_destroy(struct fhci_hcd *fhci)\n+{\n+\tif (!fhci->dfs_root)\n+\t\treturn;\n+\n+\tif (fhci->dfs_irq_stat)\n+\t\tdebugfs_remove(fhci->dfs_irq_stat);\n+\n+\tif (fhci->dfs_regs)\n+\t\tdebugfs_remove(fhci->dfs_regs);\n+\n+\tdebugfs_remove(fhci->dfs_root);\n+}\n+\n+#else\n+\n+static void fhci_dbg_isr(struct fhci_hcd *fhci, int usb_er) {}\n+static void fhci_dfs_destroy(struct fhci_hcd *fhci) {}\n+static void fhci_dfs_create(struct fhci_hcd *fhci) {}\n+\n+#endif /* CONFIG_FHCI_DEBUG */\ndiff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c\nnew file mode 100644\nindex 0000000..588dfbd\n--- /dev/null\n+++ b/drivers/usb/host/fhci-hcd.c\n@@ -0,0 +1,798 @@\n+/*\n+ * Freescale QUICC Engine USB Host Controller Driver\n+ *\n+ * Copyright (c) Freescale Semicondutor, Inc. 2006.\n+ * Shlomi Gridish <gridish@freescale.com>\n+ * Jerry Huang <Chang-Ming.Huang@freescale.com>\n+ * Copyright (c) Logic Product Development, Inc. 2007\n+ * Peter Barada <peterb@logicpd.com>\n+ * Copyright (c) MontaVista Software, Inc. 2008.\n+ * Anton Vorontsov <avorontsov@ru.mvista.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License as published by the\n+ * Free Software Foundation; either version 2 of the License, or (at your\n+ * option) any later version.\n+ */\n+\n+#if defined(CONFIG_FHCI_DEBUG) && !defined(DEBUG)\n+#define DEBUG\n+#endif\n+\n+#include <linux/module.h>\n+#include <linux/kernel.h>\n+#include <linux/delay.h>\n+#include <linux/errno.h>\n+#include <linux/list.h>\n+#include <linux/interrupt.h>\n+#include <linux/io.h>\n+#include <linux/usb.h>\n+#include <linux/of_platform.h>\n+#include <linux/of_gpio.h>\n+#include <asm/qe.h>\n+#include <asm/fsl_gtm.h>\n+#include \"../core/hcd.h\"\n+#include \"fhci.h\"\n+#include \"fhci-hub.c\"\n+#include \"fhci-q.c\"\n+#include \"fhci-dbg.c\"\n+#include \"fhci-mem.c\"\n+#include \"fhci-cq.c\"\n+#include \"fhci-tds.c\"\n+#include \"fhci-sched.c\"\n+\n+static void fhci_start_sof_timer(struct fhci_hcd *fhci)\n+{\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\t/* clear frame_n */\n+\tout_be16(&fhci->pram->frame_num, 0);\n+\n+\tout_be16(&fhci->regs->usb_sof_tmr, 0);\n+\tsetbits8(&fhci->regs->usb_mod, USB_MODE_SFTE);\n+\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+}\n+\n+static void fhci_stop_sof_timer(struct fhci_hcd *fhci)\n+{\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\tclrbits8(&fhci->regs->usb_mod, USB_MODE_SFTE);\n+\tgtm_stop_timer16(fhci->timer);\n+\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+}\n+\n+static u16 get_sof_timer_count(struct fhci_usb *usb)\n+{\n+\treturn be16_to_cpu(in_be16(&usb->fhci->regs->usb_sof_tmr) / 12);\n+}\n+\n+/* initialize the endpoint zero */\n+static u32 endpoint_zero_init(struct fhci_usb *usb,\n+\t\t\t enum fhci_mem_alloc data_mem,\n+\t\t\t u32 ring_len)\n+{\n+\tu32 rc;\n+\n+\trc = create_endpoint(usb, data_mem, ring_len);\n+\tif (rc)\n+\t\treturn rc;\n+\n+\t/* inilialize endpoint registers */\n+\tinit_endpoint_registers(usb, usb->ep0, data_mem);\n+\n+\treturn 0;\n+}\n+\n+/* enable the USB interrupts */\n+static void fhci_usb_enable_interrupt(struct fhci_usb *usb)\n+{\n+\tstruct fhci_hcd *fhci = usb->fhci;\n+\n+\tif (usb->intr_nesting_cnt == 1) {\n+\t\t/* initialize the USB interrupt */\n+\t\tenable_irq(fhci_to_hcd(fhci)->irq);\n+\n+\t\t/* initialize the event register and mask register */\n+\t\tout_be16(&usb->fhci->regs->usb_event, 0xffff);\n+\t\tout_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);\n+\n+\t\t/* enable the timer interrupts */\n+\t\tenable_irq(fhci->timer->irq);\n+\t} else if (usb->intr_nesting_cnt > 1)\n+\t\tfhci_info(fhci, \"unbalanced USB interrupts nesting\\n\");\n+\tusb->intr_nesting_cnt--;\n+}\n+\n+/* diable the usb interrupt */\n+static void fhci_usb_disable_interrupt(struct fhci_usb *usb)\n+{\n+\tstruct fhci_hcd *fhci = usb->fhci;\n+\n+\tif (usb->intr_nesting_cnt == 0) {\n+\t\t/* diable the timer interrupt */\n+\t\tdisable_irq_nosync(fhci->timer->irq);\n+\n+\t\t/* disable the usb interrupt */\n+\t\tdisable_irq_nosync(fhci_to_hcd(fhci)->irq);\n+\t\tout_be16(&usb->fhci->regs->usb_mask, 0);\n+\t}\n+\tusb->intr_nesting_cnt++;\n+}\n+\n+/* enable the USB controller */\n+static u32 fhci_usb_enable(struct fhci_hcd *fhci)\n+{\n+\tstruct fhci_usb *usb = fhci->usb_lld;\n+\n+\tout_be16(&usb->fhci->regs->usb_event, 0xffff);\n+\tout_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);\n+\tsetbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);\n+\n+\tmdelay(100);\n+\n+\treturn 0;\n+}\n+\n+/* disable the USB controller */\n+static u32 fhci_usb_disable(struct fhci_hcd *fhci)\n+{\n+\tstruct fhci_usb *usb = fhci->usb_lld;\n+\n+\tfhci_usb_disable_interrupt(usb);\n+\tusb_port_disable(fhci);\n+\n+\t/* disable the usb controller */\n+\tif (usb->port_status == FHCI_PORT_FULL ||\n+\t\t\tusb->port_status == FHCI_PORT_LOW)\n+\t\tdevice_disconnected_interrupt(fhci);\n+\n+\tclrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);\n+\n+\treturn 0;\n+}\n+\n+/* check the bus state by polling the QE bit on the IO ports */\n+static int fhci_ioports_check_bus_state(struct fhci_hcd *fhci)\n+{\n+\tu8 bits = 0;\n+\n+\t/* check USBOE,if transmitting,exit */\n+\tif (!gpio_get_value(fhci->gpios[GPIO_USBOE]))\n+\t\treturn -1;\n+\n+\t/* check USBRP */\n+\tif (gpio_get_value(fhci->gpios[GPIO_USBRP]))\n+\t\tbits |= 0x2;\n+\n+\t/* check USBRN */\n+\tif (gpio_get_value(fhci->gpios[GPIO_USBRN]))\n+\t\tbits |= 0x1;\n+\n+\treturn bits;\n+}\n+\n+static void fhci_mem_free(struct fhci_hcd *fhci)\n+{\n+\tstruct td *td;\n+\tstruct ed *ed;\n+\n+\twhile (!list_empty(&fhci->empty_eds)) {\n+\t\ted = list_entry(fhci->empty_eds.next, struct ed, node);\n+\t\tlist_del(fhci->empty_eds.next);\n+\t}\n+\n+\twhile (!list_empty(&fhci->empty_tds)) {\n+\t\ttd = list_entry(fhci->empty_tds.next, struct td, node);\n+\t\tlist_del(fhci->empty_tds.next);\n+\t}\n+\n+\tkfree(fhci->vroot_hub);\n+\tkfree(fhci->hc_list);\n+}\n+\n+static int fhci_mem_init(struct fhci_hcd *fhci)\n+{\n+\tint i, error = 0;\n+\n+\tfhci->hc_list = kzalloc(sizeof(*fhci->hc_list), GFP_KERNEL);\n+\tif (!fhci->hc_list)\n+\t\treturn -ENOMEM;\n+\n+\tINIT_LIST_HEAD(&fhci->hc_list->ctrl_list);\n+\tINIT_LIST_HEAD(&fhci->hc_list->bulk_list);\n+\tINIT_LIST_HEAD(&fhci->hc_list->iso_list);\n+\tINIT_LIST_HEAD(&fhci->hc_list->intr_list);\n+\tINIT_LIST_HEAD(&fhci->hc_list->done_list);\n+\n+\tfhci->vroot_hub = kzalloc(sizeof(*fhci->vroot_hub), GFP_KERNEL);\n+\tif (!fhci->vroot_hub)\n+\t\treturn -ENOMEM;\n+\n+\n+\tINIT_LIST_HEAD(&fhci->empty_eds);\n+\tINIT_LIST_HEAD(&fhci->empty_tds);\n+\n+\t/* initialize work queue to handle done list */\n+\tfhci_tasklet.data = (unsigned long)fhci;\n+\tfhci->process_done_task = &fhci_tasklet;\n+\n+\tfor (i = 0; i < MAX_TDS; i++) {\n+\t\tstruct td *td = kmalloc(sizeof(*td), GFP_KERNEL);\n+\n+\t\tif (!td) {\n+\t\t\terror = 1;\n+\t\t\tbreak;\n+\t\t}\n+\t\trecycle_empty_td(fhci, td);\n+\t}\n+\tfor (i = 0; i < MAX_EDS; i++) {\n+\t\tstruct ed *ed = kmalloc(sizeof(*ed), GFP_KERNEL);\n+\n+\t\tif (!ed) {\n+\t\t\terror = 1;\n+\t\t\tbreak;\n+\t\t}\n+\t\trecycle_empty_ed(fhci, ed);\n+\t}\n+\n+\tif (error) {\n+\t\tfhci_mem_free(fhci);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tfhci->active_urbs = 0;\n+\n+\treturn error;\n+}\n+\n+/* destroy the fhci_usb structure */\n+static void fhci_usb_free(void *lld)\n+{\n+\tstruct fhci_usb *usb = lld;\n+\tstruct fhci_hcd *fhci = usb->fhci;\n+\n+\tif (usb) {\n+\t\tconfig_transceiver(fhci, FHCI_PORT_POWER_OFF);\n+\t\tendpoint_zero_free(usb);\n+\t\tkfree(usb->actual_frame);\n+\t\tkfree(usb);\n+\t}\n+}\n+\n+/* initialize the USB */\n+static u32 fhci_usb_init(struct fhci_hcd *fhci)\n+{\n+\tstruct fhci_usb *usb = fhci->usb_lld;\n+\n+\tmemset_io(usb->fhci->pram, 0, FHCI_PRAM_SIZE);\n+\n+\tusb->port_status = FHCI_PORT_DISABLED;\n+\tusb->max_frame_usage = FRAME_TIME_USAGE;\n+\tusb->sw_transaction_time = SW_FIX_TIME_BETWEEN_TRANSACTION;\n+\n+\tusb->actual_frame = kzalloc(sizeof(*usb->actual_frame), GFP_KERNEL);\n+\tif (!usb->actual_frame) {\n+\t\tfhci_usb_free(usb);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tINIT_LIST_HEAD(&usb->actual_frame->tds_list);\n+\n+\t/* initializing registers on chip, clear frame number */\n+\tout_be16(&fhci->pram->frame_num, 0);\n+\n+\t/* clear rx state */\n+\tout_be32(&fhci->pram->rx_state, 0);\n+\n+\t/* set mask register */\n+\tusb->saved_msk = (USB_E_TXB_MASK |\n+\t\t\t USB_E_TXE1_MASK |\n+\t\t\t USB_E_IDLE_MASK |\n+\t\t\t USB_E_RESET_MASK | USB_E_SFT_MASK | USB_E_MSF_MASK);\n+\n+\tout_8(&usb->fhci->regs->usb_mod, USB_MODE_HOST | USB_MODE_EN);\n+\n+\t/* clearing the mask register */\n+\tout_be16(&usb->fhci->regs->usb_mask, 0);\n+\n+\t/* initialing the event register */\n+\tout_be16(&usb->fhci->regs->usb_event, 0xffff);\n+\n+\tif (endpoint_zero_init(usb, DEFAULT_DATA_MEM, DEFAULT_RING_LEN) != 0) {\n+\t\tfhci_usb_free(usb);\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/* initialize the fhci_usb struct and the corresponding data staruct */\n+static struct fhci_usb *fhci_create_lld(struct fhci_hcd *fhci)\n+{\n+\tstruct fhci_usb *usb;\n+\n+\t/* allocate memory for SCC data structure */\n+\tusb = kzalloc(sizeof(*usb), GFP_KERNEL);\n+\tif (!usb) {\n+\t\tfhci_err(fhci, \"no memory for SCC data struct\\n\");\n+\t\treturn NULL;\n+\t}\n+\n+\tusb->fhci = fhci;\n+\tusb->hc_list = fhci->hc_list;\n+\tusb->vroot_hub = fhci->vroot_hub;\n+\n+\tusb->transfer_confirm = transfer_confirm_callback;\n+\n+\treturn usb;\n+}\n+\n+static int fhci_start(struct usb_hcd *hcd)\n+{\n+\tint ret;\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\n+\tret = fhci_mem_init(fhci);\n+\n+\tfhci->usb_lld = fhci_create_lld(fhci);\n+\tif (!fhci->usb_lld) {\n+\t\tfhci_err(fhci, \"low level driver config failed\\n\");\n+\t\tfhci_mem_free(fhci);\n+\t\treturn -ENODEV;\n+\t}\n+\tif (fhci_usb_init(fhci)) {\n+\t\tfhci_err(fhci, \"low level driver initialize failed\\n\");\n+\t\tfhci_mem_free(fhci);\n+\t\treturn -ENODEV;\n+\t}\n+\tspin_lock_init(&fhci->lock);\n+\n+\t/* connect the virtual root hub */\n+\tfhci->vroot_hub->dev_num = 1;\t/* this field may be needed to fix */\n+\tfhci->vroot_hub->hub.wHubStatus = 0;\n+\tfhci->vroot_hub->hub.wHubChange = 0;\n+\tfhci->vroot_hub->port.wPortStatus = 0;\n+\tfhci->vroot_hub->port.wPortChange = 0;\n+\n+\thcd->state = HC_STATE_RUNNING;\n+\n+\t/*\n+\t * From here on, khubd concurrently accesses the root\n+\t * hub; drivers will be talking to enumerated devices.\n+\t * (On restart paths, khubd already knows about the root\n+\t * hub and could find work as soon as we wrote FLAG_CF.)\n+\t *\n+\t * Before this point the HC was idle/ready. After, khubd\n+\t * and device drivers may start it running.\n+\t */\n+\tfhci_usb_enable(fhci);\n+\n+\treturn 0;\n+}\n+\n+static void fhci_stop(struct usb_hcd *hcd)\n+{\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\n+\tfhci_usb_disable_interrupt(fhci->usb_lld);\n+\tfhci_usb_disable(fhci);\n+\n+\tfhci_usb_free(fhci->usb_lld);\n+\tfhci->usb_lld = NULL;\n+\tfhci_mem_free(fhci);\n+}\n+\n+static int fhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,\n+\t\t\t gfp_t mem_flags)\n+{\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\tu32 pipe = urb->pipe;\n+\tint i, size = 0;\n+\tstruct urb_priv *urb_priv;\n+\tunsigned long flags;\n+\n+\tswitch (usb_pipetype(pipe)) {\n+\tcase PIPE_CONTROL:\n+\t\t/* 1 td fro setup,1 for ack */\n+\t\tsize = 2;\n+\tcase PIPE_BULK:\n+\t\t/* one td for every 4096 bytes(can be upto 8k) */\n+\t\tsize += urb->transfer_buffer_length / 4096;\n+\t\t/* ...add for any remaining bytes... */\n+\t\tif ((urb->transfer_buffer_length % 4096) != 0)\n+\t\t\tsize++;\n+\t\t/* ..and maybe a zero length packet to wrap it up */\n+\t\tif (size == 0)\n+\t\t\tsize++;\n+\t\telse if ((urb->transfer_flags & URB_ZERO_PACKET) != 0\n+\t\t\t && (urb->transfer_buffer_length\n+\t\t\t % usb_maxpacket(urb->dev, pipe,\n+\t\t\t\t\t usb_pipeout(pipe))) != 0)\n+\t\t\tsize++;\n+\t\tbreak;\n+\tcase PIPE_ISOCHRONOUS:\n+\t\tsize = urb->number_of_packets;\n+\t\tif (size <= 0)\n+\t\t\treturn -EINVAL;\n+\t\tfor (i = 0; i < urb->number_of_packets; i++) {\n+\t\t\turb->iso_frame_desc[i].actual_length = 0;\n+\t\t\turb->iso_frame_desc[i].status = (u32) (-EXDEV);\n+\t\t}\n+\t\tbreak;\n+\tcase PIPE_INTERRUPT:\n+\t\tsize = 1;\n+\t}\n+\n+\t/* allocate the private part of the URB */\n+\turb_priv = kzalloc(sizeof(*urb_priv), mem_flags);\n+\tif (!urb_priv)\n+\t\treturn -ENOMEM;\n+\n+\t/* allocate the private part of the URB */\n+\turb_priv->tds = kzalloc(size * sizeof(struct td), mem_flags);\n+\tif (!urb_priv->tds) {\n+\t\tkfree(urb_priv);\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tspin_lock_irqsave(&fhci->lock, flags);\n+\t/* fill the private part of the URB */\n+\turb_priv->num_of_tds = size;\n+\n+\turb->status = -EINPROGRESS;\n+\turb->actual_length = 0;\n+\turb->error_count = 0;\n+\turb->hcpriv = urb_priv;\n+\n+\tqueue_urb(fhci, urb);\n+\n+\tspin_unlock_irqrestore(&fhci->lock, flags);\n+\treturn 0;\n+}\n+\n+/* dequeue FHCI URB */\n+static int fhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)\n+{\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\tstruct fhci_usb *usb = fhci->usb_lld;\n+\tunsigned long flags;\n+\n+\tif (!urb || !urb->dev || !urb->dev->bus)\n+\t\tgoto out;\n+\n+\tspin_lock_irqsave(&fhci->lock, flags);\n+\n+\tif (usb->port_status != FHCI_PORT_DISABLED) {\n+\t\tstruct urb_priv *urb_priv;\n+\n+\t\t/*\n+\t\t * flag the urb's data for deletion in some upcoming\n+\t\t * SF interrupt's delete list processing\n+\t\t */\n+\t\turb_priv = urb->hcpriv;\n+\n+\t\tif (!urb_priv || (urb_priv->state == URB_DEL))\n+\t\t\tgoto out2;\n+\n+\t\turb_priv->state = URB_DEL;\n+\n+\t\t/* already pending? */\n+\t\turb_priv->ed->state = FHCI_ED_URB_DEL;\n+\t} else\n+\t\turb_complete_free(fhci, urb);\n+\n+out2:\n+\tspin_unlock_irqrestore(&fhci->lock, flags);\n+out:\n+\treturn 0;\n+}\n+\n+static void fhci_endpoint_disable(struct usb_hcd *hcd,\n+\t\t\t\t struct usb_host_endpoint *ep)\n+{\n+\tstruct fhci_hcd *fhci;\n+\tstruct ed *ed;\n+\tunsigned long flags;\n+\n+\tfhci = hcd_to_fhci(hcd);\n+\tspin_lock_irqsave(&fhci->lock, flags);\n+\ted = ep->hcpriv;\n+\tif (ed) {\n+\t\twhile (ed->td_head != NULL) {\n+\t\t\tstruct td *td = remove_td_from_ed(ed);\n+\t\t\turb_complete_free(fhci, td->urb);\n+\t\t}\n+\t\trecycle_empty_ed(fhci, ed);\n+\t\tep->hcpriv = NULL;\n+\t}\n+\tspin_unlock_irqrestore(&fhci->lock, flags);\n+}\n+\n+static int fhci_get_frame_number(struct usb_hcd *hcd)\n+{\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\n+\treturn get_frame_num(fhci);\n+}\n+\n+static const struct hc_driver fhci_driver = {\n+\t.description = \"fsl,usb-fhci\",\n+\t.product_desc = \"FHCI HOST Controller\",\n+\t.hcd_priv_size = sizeof(struct fhci_hcd),\n+\n+\t/* generic hardware linkage */\n+\t.irq = fhci_irq,\n+\t.flags = HCD_USB11 | HCD_MEMORY,\n+\n+\t/* basic lifecycle operation */\n+\t.start = fhci_start,\n+\t.stop = fhci_stop,\n+\n+\t/* managing i/o requests and associated device resources */\n+\t.urb_enqueue = fhci_urb_enqueue,\n+\t.urb_dequeue = fhci_urb_dequeue,\n+\t.endpoint_disable = fhci_endpoint_disable,\n+\n+\t/* scheduling support */\n+\t.get_frame_number = fhci_get_frame_number,\n+\n+\t/* root hub support */\n+\t.hub_status_data = fhci_hub_status_data,\n+\t.hub_control = fhci_hub_control,\n+};\n+\n+struct fhci_probe_info {\n+\tstruct resource regs;\n+\tunsigned long pram_addr;\n+\tstruct resource usb_irq;\n+\tint gpios[NUM_GPIOS];\n+\tenum qe_clock fullspeed_clk;\n+\tenum qe_clock lowspeed_clk;\n+\tunsigned int power_budget;\n+};\n+\n+static int __devinit fhci_probe(struct device *dev, struct fhci_probe_info *pi)\n+{\n+\tunsigned long ret;\n+\tint i;\n+\tstruct usb_hcd *hcd = NULL;\n+\tstruct fhci_hcd *fhci;\n+\n+\tif (usb_disabled())\n+\t\treturn -ENODEV;\n+\n+\thcd = usb_create_hcd(&fhci_driver, dev, dev->bus_id);\n+\tif (!hcd) {\n+\t\tdev_dbg(dev, \"could not create hcd\\n\");\n+\t\treturn -ENOMEM;\n+\t}\n+\n+\tdev_set_drvdata(dev, hcd);\n+\tfhci = hcd_to_fhci(hcd);\n+\n+\thcd->self.controller = dev;\n+\thcd->power_budget = pi->power_budget;\n+\thcd->regs = ioremap(pi->regs.start, pi->regs.end - pi->regs.start + 1);\n+\tfhci->regs = hcd->regs;\n+\tmemcpy(fhci->gpios, pi->gpios, sizeof(fhci->gpios));\n+\n+\tret = cpm_muram_alloc_fixed(pi->pram_addr, FHCI_PRAM_SIZE);\n+\tif (IS_ERR_VALUE(ret) || ret != pi->pram_addr) {\n+\t\tdev_err(dev, \"failed to allocate usb pram\\n\");\n+\t\tgoto err_pram_alloc;\n+\t}\n+\tfhci->pram = cpm_muram_addr(pi->pram_addr);\n+\n+\tfor (i = 0; i < NUM_GPIOS; i++) {\n+\t\tint gpio = fhci->gpios[i];\n+\n+\t\tif (gpio < 0) {\n+\t\t\tif (i < GPIO_SPEED) {\n+\t\t\t\tdev_err(dev, \"incorrect GPIO%d: %d\\n\",\n+\t\t\t\t\ti, gpio);\n+\t\t\t\tgoto err_gpios;\n+\t\t\t} else {\n+\t\t\t\tdev_info(dev, \"assuming board doesn't have \"\n+\t\t\t\t\t\"%s gpio\\n\", i == GPIO_SPEED ?\n+\t\t\t\t\t\"speed\" : \"power\");\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t}\n+\n+\t\tret = gpio_request(gpio, dev->bus_id);\n+\t\tif (ret) {\n+\t\t\tdev_err(dev, \"failed to request gpio %d\", i);\n+\t\t\tgoto err_gpios;\n+\t\t}\n+\n+\t\tif (i >= GPIO_SPEED) {\n+\t\t\tret = gpio_direction_output(gpio, 0);\n+\t\t\tif (ret) {\n+\t\t\t\tdev_err(dev, \"failed to set gpio %d as \"\n+\t\t\t\t\t\"an output\\n\", i);\n+\t\t\t\ti++;\n+\t\t\t\tgoto err_gpios;\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tfhci->timer = gtm_get_timer16();\n+\tif (IS_ERR(fhci->timer)) {\n+\t\tret = PTR_ERR(fhci->timer);\n+\t\tdev_err(dev, \"failed to request qe timer: %li\", ret);\n+\t\tgoto err_get_timer;\n+\t}\n+\n+\tfhci->fullspeed_clk = pi->fullspeed_clk;\n+\tfhci->lowspeed_clk = pi->lowspeed_clk;\n+\n+\tret = request_irq(fhci->timer->irq, fhci_frame_limit_timer_irq,\n+\t\t\t IRQF_DISABLED, \"qe timer (usb)\", hcd);\n+\tif (ret) {\n+\t\tdev_err(dev, \"failed to request timer irq\");\n+\t\tgoto err_timer_irq;\n+\t}\n+\n+\tdev_info(dev, \"at 0x%p,irq %d\\n\", hcd->regs, pi->usb_irq.start);\n+\n+\tconfig_transceiver(fhci, FHCI_PORT_POWER_OFF);\n+\n+\t/* start with full-speed, if possible */\n+\tif (fhci->fullspeed_clk != QE_CLK_NONE) {\n+\t\tconfig_transceiver(fhci, FHCI_PORT_FULL);\n+\t\tqe_usb_clock_set(fhci->fullspeed_clk, USB_CLOCK);\n+\t} else {\n+\t\tconfig_transceiver(fhci, FHCI_PORT_LOW);\n+\t\tqe_usb_clock_set(fhci->lowspeed_clk, USB_CLOCK >> 3);\n+\t}\n+\n+\tret = usb_add_hcd(hcd, pi->usb_irq.start, IRQF_DISABLED);\n+\tif (ret < 0)\n+\t\tgoto err_add_hcd;\n+\n+\tfhci_dfs_create(fhci);\n+\n+\treturn 0;\n+\n+err_add_hcd:\n+\tfree_irq(fhci->timer->irq, hcd);\n+err_timer_irq:\n+\tgtm_put_timer16(fhci->timer);\n+err_get_timer:\n+err_gpios:\n+\twhile (--i >= 0) {\n+\t\tif (fhci->gpios[i] >= 0)\n+\t\t\tgpio_free(fhci->gpios[i]);\n+\t}\n+err_pram_alloc:\n+\tusb_put_hcd(hcd);\n+\treturn ret;\n+}\n+\n+static int __devexit fhci_remove(struct device *dev)\n+{\n+\tstruct usb_hcd *hcd = dev_get_drvdata(dev);\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\n+\tfhci_dfs_destroy(fhci);\n+\tusb_remove_hcd(hcd);\n+\tfree_irq(fhci->timer->irq, hcd);\n+\tgtm_put_timer16(fhci->timer);\n+\tcpm_muram_free(cpm_muram_offset(fhci->pram));\n+\tusb_put_hcd(hcd);\n+\n+\treturn 0;\n+}\n+\n+static int __devinit of_fhci_probe(struct of_device *ofdev,\n+\t\t\t\t const struct of_device_id *ofid)\n+{\n+\tint ret;\n+\tstruct device *dev = &ofdev->dev;\n+\tstruct fhci_probe_info pi = {\n+\t\t.lowspeed_clk = QE_CLK_NONE,\n+\t\t.fullspeed_clk = QE_CLK_NONE,\n+\t};\n+\tconst char *prop;\n+\tint size;\n+\tconst u32 *reg;\n+\tconst u32 *power_budget;\n+\tint i;\n+\n+\tprop = of_get_property(ofdev->node, \"mode\", NULL);\n+\tif (prop && strcmp(prop, \"host\"))\n+\t\treturn -ENODEV;\n+\n+\treg = of_get_property(ofdev->node, \"reg\", &size);\n+\tif (!reg || size < sizeof(*reg) * 4) {\n+\t\tdev_err(dev, \"can't get pram offset\\n\");\n+\t\treturn -EINVAL;;\n+\t}\n+\tpi.pram_addr = reg[2];\n+\n+\tret = of_address_to_resource(ofdev->node, 0, &pi.regs);\n+\tif (ret) {\n+\t\tdev_err(dev, \"can't get regs\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tprop = of_get_property(ofdev->node, \"fsl,fullspeed-clock\", NULL);\n+\tif (prop) {\n+\t\tpi.fullspeed_clk = qe_clock_source(prop);\n+\t\tif (pi.fullspeed_clk == QE_CLK_DUMMY) {\n+\t\t\tdev_err(dev, \"wrong fullspeed-clock\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\tprop = of_get_property(ofdev->node, \"fsl,lowspeed-clock\", NULL);\n+\tif (prop) {\n+\t\tpi.lowspeed_clk = qe_clock_source(prop);\n+\t\tif (pi.lowspeed_clk == QE_CLK_DUMMY) {\n+\t\t\tdev_err(dev, \"wrong lowspeed-clock\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\tif (pi.fullspeed_clk == QE_CLK_NONE &&\n+\t\t\tpi.lowspeed_clk == QE_CLK_NONE) {\n+\t\tdev_err(dev, \"no clocks specified\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tpower_budget = of_get_property(ofdev->node, \"linux,hub-power-budget\",\n+\t\t\t\t &size);\n+\tif (power_budget && size == sizeof(*power_budget))\n+\t\tpi.power_budget = *power_budget;\n+\n+\tret = of_irq_to_resource(ofdev->node, 0, &pi.usb_irq);\n+\tif (ret == NO_IRQ) {\n+\t\tdev_err(dev, \"can't get usb irq\\n\");\n+\t\treturn ret;\n+\t}\n+\n+\t/* gpios error and sanity checks are in the fhci_probe() */\n+\tfor (i = 0; i < NUM_GPIOS; i++)\n+\t\tpi.gpios[i] = of_get_gpio(ofdev->node, i);\n+\n+\treturn fhci_probe(dev, &pi);\n+}\n+\n+static int __devexit of_fhci_remove(struct of_device *ofdev)\n+{\n+\treturn fhci_remove(&ofdev->dev);\n+}\n+\n+static struct of_device_id of_fhci_match[] = {\n+\t{ .compatible = \"fsl,mpc8323-qe-usb\", },\n+\t{},\n+};\n+MODULE_DEVICE_TABLE(of, of_fhci_match);\n+\n+static struct of_platform_driver of_fhci_driver = {\n+\t.name\t\t= \"fsl,usb-fhci\",\n+\t.match_table\t= of_fhci_match,\n+\t.probe\t\t= of_fhci_probe,\n+\t.remove\t\t= __devexit_p(of_fhci_remove),\n+};\n+\n+static int __init fhci_module_init(void)\n+{\n+\treturn of_register_platform_driver(&of_fhci_driver);\n+}\n+module_init(fhci_module_init);\n+\n+static void __exit fhci_module_exit(void)\n+{\n+\tof_unregister_platform_driver(&of_fhci_driver);\n+}\n+module_exit(fhci_module_exit);\n+\n+MODULE_DESCRIPTION(\"USB Freescale Host Controller Interface Driver\");\n+MODULE_AUTHOR(\"Shlomi Gridish <gridish@freescale.com>, \"\n+\t \"Jerry Huang <Chang-Ming.Huang@freescale.com>, \"\n+\t \"Anton Vorontsov <avorontsov@ru.mvista.com>\");\n+MODULE_LICENSE(\"GPL\");\ndiff --git a/drivers/usb/host/fhci-hub.c b/drivers/usb/host/fhci-hub.c\nnew file mode 100644\nindex 0000000..18cc91c\n--- /dev/null\n+++ b/drivers/usb/host/fhci-hub.c\n@@ -0,0 +1,338 @@\n+/*\n+ * Freescale QUICC Engine USB Host Controller Driver\n+ *\n+ * Copyright (c) Freescale Semicondutor, Inc. 2006.\n+ * Shlomi Gridish <gridish@freescale.com>\n+ * Jerry Huang <Chang-Ming.Huang@freescale.com>\n+ * Copyright (c) Logic Product Development, Inc. 2007\n+ * Peter Barada <peterb@logicpd.com>\n+ * Copyright (c) MontaVista Software, Inc. 2008.\n+ * Anton Vorontsov <avorontsov@ru.mvista.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License as published by the\n+ * Free Software Foundation; either version 2 of the License, or (at your\n+ * option) any later version.\n+ */\n+\n+/* virtual root hub specific descriptor */\n+static u8 root_hub_des[] = {\n+\t0x09, /* blength */\n+\t0x29, /* bDescriptorType;hub-descriptor */\n+\t0x01, /* bNbrPorts */\n+\t0x00, /* wHubCharacteristics */\n+\t0x00,\n+\t0x01, /* bPwrOn2pwrGood;2ms */\n+\t0x00, /* bHubContrCurrent;0mA */\n+\t0x00, /* DeviceRemoveable */\n+\t0xff, /* PortPwrCtrlMask */\n+};\n+\n+static void config_transceiver(struct fhci_hcd *fhci,\n+\t\t\t enum fhci_port_status status)\n+{\n+\tfhci_dbg(fhci, \"-> %s: %d\\n\", __func__, status);\n+\n+\tswitch (status) {\n+\tcase FHCI_PORT_POWER_OFF:\n+\t\t/*\n+\t\t * Note: there are only active-low users of POWER (actually\n+\t\t * SUSPN) pin, so power level is inverted for now. We'll make\n+\t\t * this right when implement of_get_gpio() with flags.\n+\t\t */\n+\t\tif (fhci->gpios[GPIO_POWER] >= 0) {\n+\t\t\tgpio_set_value(fhci->gpios[GPIO_POWER], 1);\n+\t\t\tmdelay(5);\n+\t\t}\n+\t\tbreak;\n+\tcase FHCI_PORT_DISABLED:\n+\tcase FHCI_PORT_WAITING:\n+\t\tif (fhci->gpios[GPIO_POWER] >= 0) {\n+\t\t\tgpio_set_value(fhci->gpios[GPIO_POWER], 0);\n+\t\t\tmdelay(5);\n+\t\t}\n+\t\tbreak;\n+\tcase FHCI_PORT_LOW:\n+\t\tif (fhci->gpios[GPIO_SPEED] >= 0) {\n+\t\t\tgpio_set_value(fhci->gpios[GPIO_SPEED], 0);\n+\t\t\tmdelay(5);\n+\t\t}\n+\t\tbreak;\n+\tcase FHCI_PORT_FULL:\n+\t\tif (fhci->gpios[GPIO_SPEED] >= 0) {\n+\t\t\tgpio_set_value(fhci->gpios[GPIO_SPEED], 1);\n+\t\t\tmdelay(5);\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tWARN_ON(1);\n+\t\tbreak;\n+\t}\n+\n+\tfhci_dbg(fhci, \"<- %s: %d\\n\", __func__, status);\n+}\n+\n+/* disable the USB port by clearing the EN bit in the USBMOD register */\n+static void usb_port_disable(struct fhci_hcd *fhci)\n+{\n+\tstruct fhci_usb *usb = (struct fhci_usb *)fhci->usb_lld;\n+\tenum fhci_port_status port_status;\n+\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\tfhci_stop_sof_timer(fhci);\n+\n+\tflush_all_transmissions(usb);\n+\n+\tfhci_usb_disable_interrupt((struct fhci_usb *)fhci->usb_lld);\n+\tport_status = usb->port_status;\n+\tusb->port_status = FHCI_PORT_DISABLED;\n+\n+\t/* Enable IDLE since we want to know if something comes along */\n+\tusb->saved_msk |= USB_E_IDLE_MASK;\n+\tout_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);\n+\n+\t/* check if during the disconnection process attached new device */\n+\tif (port_status == FHCI_PORT_WAITING)\n+\t\tdevice_connected_interrupt(fhci);\n+\tusb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_ENABLE;\n+\tusb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE;\n+\tfhci_usb_enable_interrupt((struct fhci_usb *)fhci->usb_lld);\n+\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+}\n+\n+/* enable the USB port by setting the EN bit in the USBMOD register */\n+static void usb_port_enable(void *lld)\n+{\n+\tstruct fhci_usb *usb = (struct fhci_usb *)lld;\n+\tstruct fhci_hcd *fhci = usb->fhci;\n+\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\tconfig_transceiver(fhci, usb->port_status);\n+\n+\tif ((usb->port_status != FHCI_PORT_FULL) &&\n+\t\t\t(usb->port_status != FHCI_PORT_LOW))\n+\t\tfhci_start_sof_timer(fhci);\n+\n+\tusb->vroot_hub->port.wPortStatus |= USB_PORT_STAT_ENABLE;\n+\tusb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_ENABLE;\n+\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+}\n+\n+static void io_port_generate_reset(struct fhci_hcd *fhci)\n+{\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\tgpio_direction_output(fhci->gpios[GPIO_USBOE], 0);\n+\tgpio_direction_output(fhci->gpios[GPIO_USBTP], 0);\n+\tgpio_direction_output(fhci->gpios[GPIO_USBTN], 0);\n+\n+\tmdelay(5);\n+\n+\tqe_gpio_set_dedicated(fhci->gpios[GPIO_USBOE]);\n+\tqe_gpio_set_dedicated(fhci->gpios[GPIO_USBTP]);\n+\tqe_gpio_set_dedicated(fhci->gpios[GPIO_USBTN]);\n+\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+}\n+\n+/* generate the RESET condition on the bus */\n+static void usb_port_reset(void *lld)\n+{\n+\tstruct fhci_usb *usb = (struct fhci_usb *)lld;\n+\tstruct fhci_hcd *fhci = usb->fhci;\n+\tu8 mode;\n+\tu16 mask;\n+\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\tfhci_stop_sof_timer(fhci);\n+\t/* disable the USB controller */\n+\tmode = in_8(&fhci->regs->usb_mod);\n+\tout_8(&fhci->regs->usb_mod, mode & (~USB_MODE_EN));\n+\n+\t/* disable idle interrupts */\n+\tmask = in_be16(&fhci->regs->usb_mask);\n+\tout_be16(&fhci->regs->usb_mask, mask & (~USB_E_IDLE_MASK));\n+\n+\tio_port_generate_reset(fhci);\n+\n+\t/* enable interrupt on this endpoint */\n+\tout_be16(&fhci->regs->usb_mask, mask);\n+\n+\t/* enable the USB controller */\n+\tmode = in_8(&fhci->regs->usb_mod);\n+\tout_8(&fhci->regs->usb_mod, mode | USB_MODE_EN);\n+\tfhci_start_sof_timer(fhci);\n+\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+}\n+\n+static int fhci_hub_status_data(struct usb_hcd *hcd, char *buf)\n+{\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\tint ret = 0;\n+\tunsigned long flags;\n+\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\tspin_lock_irqsave(&fhci->lock, flags);\n+\n+\tif (fhci->vroot_hub->port.wPortChange & (USB_PORT_STAT_C_CONNECTION |\n+\t\t\tUSB_PORT_STAT_C_ENABLE | USB_PORT_STAT_C_SUSPEND |\n+\t\t\tUSB_PORT_STAT_C_RESET | USB_PORT_STAT_C_OVERCURRENT)) {\n+\t\t*buf = 1 << 1;\n+\t\tret = 1;\n+\t\tfhci_dbg(fhci, \"-- %s\\n\", __func__);\n+\t}\n+\n+\tspin_unlock_irqrestore(&fhci->lock, flags);\n+\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+\n+\treturn ret;\n+}\n+\n+static int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,\n+\t\t\t u16 wIndex, char *buf, u16 wLength)\n+{\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\tint retval = 0;\n+\tint len = 0;\n+\tstruct usb_hub_status *hub_status;\n+\tstruct usb_port_status *port_status;\n+\tunsigned long flags;\n+\n+\tspin_lock_irqsave(&fhci->lock, flags);\n+\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\tswitch (typeReq) {\n+\tcase ClearHubFeature:\n+\t\tswitch (wValue) {\n+\t\tcase C_HUB_LOCAL_POWER:\n+\t\tcase C_HUB_OVER_CURRENT:\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tgoto error;\n+\t\t}\n+\t\tbreak;\n+\tcase ClearPortFeature:\n+\t\tfhci->vroot_hub->feature &= (1 << wValue);\n+\n+\t\tswitch (wValue) {\n+\t\tcase USB_PORT_FEAT_ENABLE:\n+\t\t\tfhci->vroot_hub->port.wPortStatus &=\n+\t\t\t ~USB_PORT_STAT_ENABLE;\n+\t\t\tusb_port_disable(fhci);\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_C_ENABLE:\n+\t\t\tfhci->vroot_hub->port.wPortChange &=\n+\t\t\t ~USB_PORT_STAT_C_ENABLE;\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_SUSPEND:\n+\t\t\tfhci->vroot_hub->port.wPortStatus &=\n+\t\t\t ~USB_PORT_STAT_SUSPEND;\n+\t\t\tfhci_stop_sof_timer(fhci);\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_C_SUSPEND:\n+\t\t\tfhci->vroot_hub->port.wPortChange &=\n+\t\t\t ~USB_PORT_STAT_C_SUSPEND;\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_POWER:\n+\t\t\tfhci->vroot_hub->port.wPortStatus &=\n+\t\t\t ~USB_PORT_STAT_POWER;\n+\t\t\tconfig_transceiver(fhci, FHCI_PORT_POWER_OFF);\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_C_CONNECTION:\n+\t\t\tfhci->vroot_hub->port.wPortChange &=\n+\t\t\t ~USB_PORT_STAT_C_CONNECTION;\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_C_OVER_CURRENT:\n+\t\t\tfhci->vroot_hub->port.wPortChange &=\n+\t\t\t ~USB_PORT_STAT_C_OVERCURRENT;\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_C_RESET:\n+\t\t\tfhci->vroot_hub->port.wPortChange &=\n+\t\t\t ~USB_PORT_STAT_C_RESET;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tgoto error;\n+\t\t}\n+\t\tbreak;\n+\tcase GetHubDescriptor:\n+\t\tmemcpy(buf, root_hub_des, sizeof(root_hub_des));\n+\t\tbuf[3] = 0x11; /* per-port power, no ovrcrnt */\n+\t\tlen = (buf[0] < wLength) ? buf[0] : wLength;\n+\t\tbreak;\n+\tcase GetHubStatus:\n+\t\thub_status = (struct usb_hub_status *)buf;\n+\t\thub_status->wHubStatus =\n+\t\t cpu_to_le16(fhci->vroot_hub->hub.wHubStatus);\n+\t\thub_status->wHubChange =\n+\t\t cpu_to_le16(fhci->vroot_hub->hub.wHubChange);\n+\t\tlen = 4;\n+\t\tbreak;\n+\tcase GetPortStatus:\n+\t\tport_status = (struct usb_port_status *)buf;\n+\t\tport_status->wPortStatus =\n+\t\t cpu_to_le16(fhci->vroot_hub->port.wPortStatus);\n+\t\tport_status->wPortChange =\n+\t\t cpu_to_le16(fhci->vroot_hub->port.wPortChange);\n+\t\tlen = 4;\n+\t\tbreak;\n+\tcase SetHubFeature:\n+\t\tswitch (wValue) {\n+\t\tcase C_HUB_OVER_CURRENT:\n+\t\tcase C_HUB_LOCAL_POWER:\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tgoto error;\n+\t\t}\n+\t\tbreak;\n+\tcase SetPortFeature:\n+\t\tfhci->vroot_hub->feature |= (1 << wValue);\n+\n+\t\tswitch (wValue) {\n+\t\tcase USB_PORT_FEAT_ENABLE:\n+\t\t\tfhci->vroot_hub->port.wPortStatus |=\n+\t\t\t USB_PORT_STAT_ENABLE;\n+\t\t\tusb_port_enable(fhci->usb_lld);\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_SUSPEND:\n+\t\t\tfhci->vroot_hub->port.wPortStatus |=\n+\t\t\t USB_PORT_STAT_SUSPEND;\n+\t\t\tfhci_stop_sof_timer(fhci);\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_RESET:\n+\t\t\tfhci->vroot_hub->port.wPortStatus |=\n+\t\t\t USB_PORT_STAT_RESET;\n+\t\t\tusb_port_reset(fhci->usb_lld);\n+\t\t\tfhci->vroot_hub->port.wPortStatus |=\n+\t\t\t USB_PORT_STAT_ENABLE;\n+\t\t\tfhci->vroot_hub->port.wPortStatus &=\n+\t\t\t ~USB_PORT_STAT_RESET;\n+\t\t\tbreak;\n+\t\tcase USB_PORT_FEAT_POWER:\n+\t\t\tfhci->vroot_hub->port.wPortStatus |=\n+\t\t\t USB_PORT_STAT_POWER;\n+\t\t\tconfig_transceiver(fhci, FHCI_PORT_WAITING);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tgoto error;\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+error:\n+\t\tretval = -EPIPE;\n+\t}\n+\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+\n+\tspin_unlock_irqrestore(&fhci->lock, flags);\n+\n+\treturn retval;\n+}\ndiff --git a/drivers/usb/host/fhci-mem.c b/drivers/usb/host/fhci-mem.c\nnew file mode 100644\nindex 0000000..d9e098e\n--- /dev/null\n+++ b/drivers/usb/host/fhci-mem.c\n@@ -0,0 +1,105 @@\n+/*\n+ * Freescale QUICC Engine USB Host Controller Driver\n+ *\n+ * Copyright (c) Freescale Semicondutor, Inc. 2006.\n+ * Shlomi Gridish <gridish@freescale.com>\n+ * Jerry Huang <Chang-Ming.Huang@freescale.com>\n+ * Copyright (c) Logic Product Development, Inc. 2007\n+ * Peter Barada <peterb@logicpd.com>\n+ * Copyright (c) MontaVista Software, Inc. 2008.\n+ * Anton Vorontsov <avorontsov@ru.mvista.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License as published by the\n+ * Free Software Foundation; either version 2 of the License, or (at your\n+ * option) any later version.\n+ */\n+\n+static void init_td(struct td *td)\n+{\n+\tmemset(td, 0, sizeof(*td));\n+\tINIT_LIST_HEAD(&td->node);\n+\tINIT_LIST_HEAD(&td->frame_lh);\n+}\n+\n+static void init_ed(struct ed *ed)\n+{\n+\tmemset(ed, 0, sizeof(*ed));\n+\tINIT_LIST_HEAD(&ed->td_list);\n+\tINIT_LIST_HEAD(&ed->node);\n+}\n+\n+static struct td *get_empty_td(struct fhci_hcd *fhci)\n+{\n+\tstruct td *td;\n+\n+\tif (!list_empty(&fhci->empty_tds)) {\n+\t\ttd = list_entry(fhci->empty_tds.next, struct td, node);\n+\t\tlist_del(fhci->empty_tds.next);\n+\t} else {\n+\t\ttd = kmalloc(sizeof(*td), GFP_ATOMIC);\n+\t\tif (!td)\n+\t\t\tfhci_err(fhci, \"No memory to allocate to TD\\n\");\n+\t\telse\n+\t\t\tinit_td(td);\n+\t}\n+\n+\treturn td;\n+}\n+\n+static void recycle_empty_td(struct fhci_hcd *fhci, struct td *td)\n+{\n+\tinit_td(td);\n+\tlist_add(&td->node, &fhci->empty_tds);\n+}\n+\n+static struct ed *get_empty_ed(struct fhci_hcd *fhci)\n+{\n+\tstruct ed *ed;\n+\n+\tif (!list_empty(&fhci->empty_eds)) {\n+\t\ted = list_entry(fhci->empty_eds.next, struct ed, node);\n+\t\tlist_del(fhci->empty_eds.next);\n+\t} else {\n+\t\ted = kmalloc(sizeof(*ed), GFP_ATOMIC);\n+\t\tif (!ed)\n+\t\t\tfhci_err(fhci, \"No memory to allocate to ED\\n\");\n+\t\telse\n+\t\t\tinit_ed(ed);\n+\t}\n+\n+\treturn ed;\n+}\n+\n+static void recycle_empty_ed(struct fhci_hcd *fhci, struct ed *ed)\n+{\n+\tinit_ed(ed);\n+\tlist_add(&ed->node, &fhci->empty_eds);\n+}\n+\n+static struct td *td_fill(struct fhci_hcd *fhci, struct urb *urb,\n+\t\tstruct urb_priv *urb_priv, struct ed *ed, u16 index,\n+\t\tenum fhci_ta_type type, int toggle, u8 *data, u32 len,\n+\t\tu16 interval, u16 start_frame, bool ioc)\n+{\n+\tstruct td *td = get_empty_td(fhci);\n+\n+\tif (!td)\n+\t\treturn NULL;\n+\n+\ttd->urb = urb;\n+\ttd->ed = ed;\n+\ttd->type = type;\n+\ttd->toggle = toggle;\n+\ttd->data = data;\n+\ttd->len = len;\n+\ttd->iso_index = index;\n+\ttd->interval = interval;\n+\ttd->start_frame = start_frame;\n+\ttd->ioc = ioc;\n+\ttd->status = USB_TD_OK;\n+\n+\turb_priv->tds[index] = td;\n+\n+\treturn td;\n+}\ndiff --git a/drivers/usb/host/fhci-q.c b/drivers/usb/host/fhci-q.c\nnew file mode 100644\nindex 0000000..493c7a5\n--- /dev/null\n+++ b/drivers/usb/host/fhci-q.c\n@@ -0,0 +1,242 @@\n+/*\n+ * Freescale QUICC Engine USB Host Controller Driver\n+ *\n+ * Copyright (c) Freescale Semicondutor, Inc. 2006.\n+ * Shlomi Gridish <gridish@freescale.com>\n+ * Jerry Huang <Chang-Ming.Huang@freescale.com>\n+ * Copyright (c) Logic Product Development, Inc. 2007\n+ * Peter Barada <peterb@logicpd.com>\n+ * Copyright (c) MontaVista Software, Inc. 2008.\n+ * Anton Vorontsov <avorontsov@ru.mvista.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License as published by the\n+ * Free Software Foundation; either version 2 of the License, or (at your\n+ * option) any later version.\n+ */\n+\n+static void add_td_to_frame(struct fhci_time_frame *frame, struct td *td)\n+{\n+\tlist_add_tail(&td->frame_lh, &frame->tds_list);\n+}\n+\n+static void add_tds_to_ed(struct ed *ed, struct td **td_list, int number)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < number; i++) {\n+\t\tstruct td *td = td_list[i];\n+\t\tlist_add_tail(&td->node, &ed->td_list);\n+\t}\n+\tif (ed->td_head == NULL)\n+\t\ted->td_head = td_list[0];\n+}\n+\n+static struct td *peek_td_from_ed(struct ed *ed)\n+{\n+\tstruct td *td;\n+\n+\tif (!list_empty(&ed->td_list))\n+\t\ttd = list_entry(ed->td_list.next, struct td, node);\n+\telse\n+\t\ttd = NULL;\n+\n+\treturn td;\n+}\n+\n+static struct td *remove_td_from_frame(struct fhci_time_frame *frame)\n+{\n+\tstruct td *td;\n+\n+\tif (!list_empty(&frame->tds_list)) {\n+\t\ttd = list_entry(frame->tds_list.next, struct td, frame_lh);\n+\t\tlist_del_init(frame->tds_list.next);\n+\t} else\n+\t\ttd = NULL;\n+\n+\treturn td;\n+}\n+\n+static struct td *peek_td_from_frame(struct fhci_time_frame *frame)\n+{\n+\tstruct td *td;\n+\n+\tif (!list_empty(&frame->tds_list))\n+\t\ttd = list_entry(frame->tds_list.next, struct td, frame_lh);\n+\telse\n+\t\ttd = NULL;\n+\n+\treturn td;\n+}\n+static struct td *remove_td_from_ed(struct ed *ed)\n+{\n+\tstruct td *td;\n+\n+\tif (!list_empty(&ed->td_list)) {\n+\t\ttd = list_entry(ed->td_list.next, struct td, node);\n+\t\tlist_del_init(ed->td_list.next);\n+\n+\t\t/* if this TD was the ED's head, find next TD */\n+\t\tif (!list_empty(&ed->td_list))\n+\t\t\ted->td_head = list_entry(ed->td_list.next, struct td,\n+\t\t\t\t\t\t node);\n+\t\telse\n+\t\t\ted->td_head = NULL;\n+\t} else\n+\t\ttd = NULL;\n+\n+\treturn td;\n+}\n+\n+static struct td *remove_td_from_done_list(struct fhci_controller_list *p_list)\n+{\n+\tstruct td *td;\n+\n+\tif (!list_empty(&p_list->done_list)) {\n+\t\ttd = list_entry(p_list->done_list.next, struct td, node);\n+\t\tlist_del_init(p_list->done_list.next);\n+\t} else\n+\t\ttd = NULL;\n+\n+\treturn td;\n+}\n+\n+static void move_td_from_ed_to_done_list(struct fhci_usb *usb, struct ed *ed)\n+{\n+\tstruct td *td;\n+\n+\ttd = ed->td_head;\n+\tlist_del_init(&td->node);\n+\n+\t/* If this TD was the ED's head,find next TD */\n+\tif (!list_empty(&ed->td_list))\n+\t\ted->td_head = list_entry(ed->td_list.next, struct td, node);\n+\telse {\n+\t\ted->td_head = NULL;\n+\t\ted->state = FHCI_ED_SKIP;\n+\t}\n+\ted->toggle_carry = td->toggle;\n+\tlist_add_tail(&td->node, &usb->hc_list->done_list);\n+\tif (td->ioc)\n+\t\tusb->transfer_confirm(usb->fhci);\n+}\n+\n+/* free done FHCI URB resource such as ED and TD */\n+static void free_urb_priv(struct fhci_hcd *fhci, struct urb *urb)\n+{\n+\tint i;\n+\tstruct urb_priv *urb_priv = urb->hcpriv;\n+\tstruct ed *ed = urb_priv->ed;\n+\n+\tfor (i = 0; i < urb_priv->num_of_tds; i++) {\n+\t\tlist_del_init(&urb_priv->tds[i]->node);\n+\t\trecycle_empty_td(fhci, urb_priv->tds[i]);\n+\t}\n+\n+\t/* if this TD was the ED's head,find the next TD */\n+\tif (!list_empty(&ed->td_list))\n+\t\ted->td_head = list_entry(ed->td_list.next, struct td, node);\n+\telse\n+\t\ted->td_head = NULL;\n+\n+\tkfree(urb_priv->tds);\n+\tkfree(urb_priv);\n+\turb->hcpriv = NULL;\n+\n+\t/* if this TD was the ED's head,find next TD */\n+\tif (ed->td_head == NULL)\n+\t\tlist_del_init(&ed->node);\n+\tfhci->active_urbs--;\n+}\n+\n+/* this routine called to complete and free done URB */\n+static void urb_complete_free(struct fhci_hcd *fhci, struct urb *urb)\n+{\n+\tfree_urb_priv(fhci, urb);\n+\n+\tif (urb->status == -EINPROGRESS) {\n+\t\tif (urb->actual_length != urb->transfer_buffer_length &&\n+\t\t\t\turb->transfer_flags & URB_SHORT_NOT_OK)\n+\t\t\turb->status = -EREMOTEIO;\n+\t\telse\n+\t\t\turb->status = 0;\n+\t}\n+\tspin_unlock(&fhci->lock);\n+\n+\tusb_hcd_giveback_urb(fhci_to_hcd(fhci), urb, urb->status);\n+\n+\tspin_lock(&fhci->lock);\n+}\n+\n+/*\n+ * caculate transfer length/stats and update the urb\n+ * Precondition: irqsafe(only for urb-?status locking)\n+ */\n+static void done_td(struct urb *urb, struct td *td)\n+{\n+\tstruct ed *ed = td->ed;\n+\tu32 cc = td->status;\n+\n+\t/* ISO...drivers see per-TD length/status */\n+\tif (ed->mode == FHCI_TF_ISO) {\n+\t\tu32 len;\n+\t\tif (!(urb->transfer_flags & URB_SHORT_NOT_OK &&\n+\t\t\t\tcc == USB_TD_RX_DATA_UNDERUN))\n+\t\t\tcc = USB_TD_OK;\n+\n+\t\tif (usb_pipeout(urb->pipe))\n+\t\t\tlen = urb->iso_frame_desc[td->iso_index].length;\n+\t\telse\n+\t\t\tlen = td->actual_len;\n+\n+\t\turb->actual_length += len;\n+\t\turb->iso_frame_desc[td->iso_index].actual_length = len;\n+\t\turb->iso_frame_desc[td->iso_index].status =\n+\t\t\tstatus_to_error(cc);\n+\t}\n+\n+\t/* BULK,INT,CONTROL... drivers see aggregate length/status,\n+\t * except that \"setup\" bytes aren't counted and \"short\" transfers\n+\t * might not be reported as errors.\n+\t */\n+\telse {\n+\t\tif (td->error_cnt >= 3)\n+\t\t\turb->error_count = 3;\n+\n+\t\t/* control endpoint only have soft stalls */\n+\n+\t\t/* update packet status if needed(short may be ok) */\n+\t\tif (!(urb->transfer_flags & URB_SHORT_NOT_OK) &&\n+\t\t\t\tcc == USB_TD_RX_DATA_UNDERUN) {\n+\t\t\ted->state = FHCI_ED_OPER;\n+\t\t\tcc = USB_TD_OK;\n+\t\t}\n+\t\tif (cc != USB_TD_OK) {\n+\t\t\tif (urb->status == -EINPROGRESS)\n+\t\t\t\turb->status = status_to_error(cc);\n+\t\t}\n+\n+\t\t/* count all non-empty packets except control SETUP packet */\n+\t\tif (td->type != FHCI_TA_SETUP || td->iso_index != 0)\n+\t\t\turb->actual_length += td->actual_len;\n+\t}\n+}\n+\n+/* there are some pedning request to unlink */\n+static void del_ed_list(struct fhci_hcd *fhci, struct ed *ed)\n+{\n+\tstruct td *td = peek_td_from_ed(ed);\n+\tstruct urb *urb = td->urb;\n+\tstruct urb_priv *urb_priv = urb->hcpriv;\n+\n+\tif (urb_priv->state == URB_DEL) {\n+\t\ttd = remove_td_from_ed(ed);\n+\t\t/* HC may have partly processed this TD */\n+\t\tif (td->status != USB_TD_INPROGRESS)\n+\t\t\tdone_td(urb, td);\n+\n+\t\t/* URB is done;clean up */\n+\t\tif (++(urb_priv->tds_cnt) == urb_priv->num_of_tds)\n+\t\t\turb_complete_free(fhci, urb);\n+\t}\n+}\ndiff --git a/drivers/usb/host/fhci-sched.c b/drivers/usb/host/fhci-sched.c\nnew file mode 100644\nindex 0000000..e13f3fb\n--- /dev/null\n+++ b/drivers/usb/host/fhci-sched.c\n@@ -0,0 +1,866 @@\n+/*\n+ * Freescale QUICC Engine USB Host Controller Driver\n+ *\n+ * Copyright (c) Freescale Semicondutor, Inc. 2006.\n+ * Shlomi Gridish <gridish@freescale.com>\n+ * Jerry Huang <Chang-Ming.Huang@freescale.com>\n+ * Copyright (c) Logic Product Development, Inc. 2007\n+ * Peter Barada <peterb@logicpd.com>\n+ * Copyright (c) MontaVista Software, Inc. 2008.\n+ * Anton Vorontsov <avorontsov@ru.mvista.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License as published by the\n+ * Free Software Foundation; either version 2 of the License, or (at your\n+ * option) any later version.\n+ */\n+\n+static void recycle_frame(struct fhci_usb *usb, struct packet *pkt)\n+{\n+\tpkt->data = NULL;\n+\tpkt->len = 0;\n+\tpkt->status = USB_TD_OK;\n+\tpkt->info = 0;\n+\tpkt->priv_data = NULL;\n+\n+\tcq_put(usb->ep0->empty_frame_Q, pkt);\n+}\n+\n+/* confirm submitted packet */\n+static void transaction_confirm(struct fhci_usb *usb, struct packet *pkt)\n+{\n+\tstruct td *td;\n+\tstruct packet *td_pkt;\n+\tstruct ed *ed;\n+\tu32 trans_len;\n+\tbool td_done = false;\n+\n+\ttd = remove_td_from_frame(usb->actual_frame);\n+\ttd_pkt = td->pkt;\n+\ttrans_len = pkt->len;\n+\ttd->status = pkt->status;\n+\tif (td->type == FHCI_TA_IN && td_pkt->info & PKT_DUMMY_PACKET) {\n+\t\tif ((td->data + td->actual_len) && trans_len)\n+\t\t\tmemcpy(td->data + td->actual_len, pkt->data,\n+\t\t\t trans_len);\n+\t\tcq_put(usb->ep0->dummy_packets_Q, pkt->data);\n+\t}\n+\n+\trecycle_frame(usb, pkt);\n+\n+\ted = td->ed;\n+\tif (ed->mode == FHCI_TF_ISO) {\n+\t\tif (ed->td_list.next->next != &ed->td_list) {\n+\t\t\tstruct td *td_next =\n+\t\t\t list_entry(ed->td_list.next->next, struct td,\n+\t\t\t\t node);\n+\n+\t\t\ttd_next->start_frame = usb->actual_frame->frame_num;\n+\t\t}\n+\t\ttd->actual_len = trans_len;\n+\t\ttd_done = true;\n+\t} else if ((td->status & USB_TD_ERROR) &&\n+\t\t\t!(td->status & USB_TD_TX_ER_NAK)) {\n+\t\t/*\n+\t\t * There was an error on the transaction (but not NAK).\n+\t\t * If it is fatal error (data underrun, stall, bad pid or 3\n+\t\t * errors exceeded), mark this TD as done.\n+\t\t */\n+\t\tif ((td->status & USB_TD_RX_DATA_UNDERUN) ||\n+\t\t\t\t(td->status & USB_TD_TX_ER_STALL) ||\n+\t\t\t\t(td->status & USB_TD_RX_ER_PID) ||\n+\t\t\t\t(++td->error_cnt >= 3)) {\n+\t\t\ted->state = FHCI_ED_HALTED;\n+\t\t\ttd_done = true;\n+\n+\t\t\tif (td->status & USB_TD_RX_DATA_UNDERUN) {\n+\t\t\t\tfhci_dbg(usb->fhci, \"td err fu\\n\");\n+\t\t\t\ttd->toggle = !td->toggle;\n+\t\t\t\ttd->actual_len += trans_len;\n+\t\t\t} else {\n+\t\t\t\tfhci_dbg(usb->fhci, \"td err f!u\\n\");\n+\t\t\t}\n+\t\t} else {\n+\t\t\tfhci_dbg(usb->fhci, \"td err !f\\n\");\n+\t\t\t/* it is not a fatal error -retry this transaction */\n+\t\t\ttd->nak_cnt = 0;\n+\t\t\ttd->error_cnt++;\n+\t\t\ttd->status = USB_TD_OK;\n+\t\t}\n+\t} else if (td->status & USB_TD_TX_ER_NAK) {\n+\t\t/* there was a NAK response */\n+\t\tfhci_vdbg(usb->fhci, \"td nack\\n\");\n+\t\ttd->nak_cnt++;\n+\t\ttd->error_cnt = 0;\n+\t\ttd->status = USB_TD_OK;\n+\t} else {\n+\t\t/* there was no error on transaction */\n+\t\ttd->error_cnt = 0;\n+\t\ttd->nak_cnt = 0;\n+\t\ttd->toggle = !td->toggle;\n+\t\ttd->actual_len += trans_len;\n+\n+\t\tif (td->len == td->actual_len)\n+\t\t\ttd_done = true;\n+\t}\n+\n+\tif (td_done)\n+\t\tmove_td_from_ed_to_done_list(usb, ed);\n+}\n+\n+/*\n+ * Flush all transmitted packets from BDs\n+ * This routine is called when disabling the USB port to flush all\n+ * transmissions that are allready scheduled in the BDs\n+ */\n+static void flush_all_transmissions(struct fhci_usb *usb)\n+{\n+\tu8 mode;\n+\tstruct td *td;\n+\n+\tmode = in_8(&usb->fhci->regs->usb_mod);\n+\tclrbits8(&usb->fhci->regs->usb_mod, USB_MODE_EN);\n+\n+\tflush_bds(usb);\n+\n+\twhile ((td = peek_td_from_frame(usb->actual_frame)) != NULL) {\n+\t\tstruct packet *pkt = td->pkt;\n+\n+\t\tpkt->status = USB_TD_TX_ER_TIMEOUT;\n+\t\ttransaction_confirm(usb, pkt);\n+\t}\n+\n+\tusb->actual_frame->frame_status = FRAME_END_TRANSMISSION;\n+\n+\t/* reset the event register */\n+\tout_be16(&usb->fhci->regs->usb_event, 0xffff);\n+\t/* enable the USB controller */\n+\tout_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN);\n+}\n+\n+/*\n+ * This function forms the packet and transmit the packet. This function\n+ * will handle all endpoint type:ISO,interrupt,control and bulk\n+ */\n+static int add_packet(struct fhci_usb *usb, struct ed *ed, struct td *td)\n+{\n+\tu32 fw_transaction_time, len = 0;\n+\tstruct packet *pkt;\n+\tu8 *data = NULL;\n+\n+\t/* calcalate data address,len and toggle and then add the transaction */\n+\tif (td->toggle == USB_TD_TOGGLE_CARRY)\n+\t\ttd->toggle = ed->toggle_carry;\n+\n+\tswitch (ed->mode) {\n+\tcase FHCI_TF_ISO:\n+\t\tlen = td->len;\n+\t\tif (td->type != FHCI_TA_IN)\n+\t\t\tdata = td->data;\n+\t\tbreak;\n+\tcase FHCI_TF_CTRL:\n+\tcase FHCI_TF_BULK:\n+\t\tlen = min(td->len - td->actual_len, ed->max_pkt_size);\n+\t\tif (!((td->type == FHCI_TA_IN) &&\n+\t\t ((len + td->actual_len) == td->len)))\n+\t\t\tdata = td->data + td->actual_len;\n+\t\tbreak;\n+\tcase FHCI_TF_INTR:\n+\t\tlen = min(td->len, ed->max_pkt_size);\n+\t\tif (!((td->type == FHCI_TA_IN) &&\n+\t\t ((td->len + CRC_SIZE) >= ed->max_pkt_size)))\n+\t\t\tdata = td->data;\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tif (usb->port_status == FHCI_PORT_FULL)\n+\t\tfw_transaction_time = (((len + PROTOCOL_OVERHEAD) * 11) >> 4);\n+\telse\n+\t\tfw_transaction_time = ((len + PROTOCOL_OVERHEAD) * 6);\n+\n+\t/* check if there's enough space in this frame to submit this TD */\n+\tif (usb->actual_frame->total_bytes + len + PROTOCOL_OVERHEAD >=\n+\t\t\tusb->max_bytes_per_frame) {\n+\t\tfhci_vdbg(usb->fhci, \"not enough space in this frame: \"\n+\t\t\t \"%d %d %d\\n\", usb->actual_frame->total_bytes, len,\n+\t\t\t usb->max_bytes_per_frame);\n+\t\treturn -1;\n+\t}\n+\n+\t/* check if there's enough time in this frame to submit this TD */\n+\tif (usb->actual_frame->frame_status != FRAME_IS_PREPARED &&\n+\t (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION ||\n+\t (fw_transaction_time + usb->sw_transaction_time >=\n+\t 1000 - get_sof_timer_count(usb)))) {\n+\t\tfhci_dbg(usb->fhci, \"not enough time in this frame\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\t/* update frame object fields before transmitting */\n+\tpkt = cq_get(usb->ep0->empty_frame_Q);\n+\tif (!pkt) {\n+\t\tfhci_dbg(usb->fhci, \"there is no empty frame\\n\");\n+\t\treturn -1;\n+\t}\n+\ttd->pkt = pkt;\n+\n+\tpkt->info = 0;\n+\tif (data == NULL) {\n+\t\tdata = cq_get(usb->ep0->dummy_packets_Q);\n+\t\tBUG_ON(!data);\n+\t\tpkt->info = PKT_DUMMY_PACKET;\n+\t}\n+\tpkt->data = data;\n+\tpkt->len = len;\n+\tpkt->status = USB_TD_OK;\n+\t/* update TD status field before transmitting */\n+\ttd->status = USB_TD_INPROGRESS;\n+\t/* update actual frame time object with the actual transmission */\n+\tusb->actual_frame->total_bytes += (len + PROTOCOL_OVERHEAD);\n+\tadd_td_to_frame(usb->actual_frame, td);\n+\n+\tif (usb->port_status != FHCI_PORT_FULL &&\n+\t\t\tusb->port_status != FHCI_PORT_LOW) {\n+\t\tpkt->status = USB_TD_TX_ER_TIMEOUT;\n+\t\tpkt->len = 0;\n+\t\ttransaction_confirm(usb, pkt);\n+\t} else if (host_transaction(usb, pkt, td->type, ed->dev_addr,\n+\t\t\ted->ep_addr, ed->mode, ed->speed, td->toggle)) {\n+\t\t/* remove TD from actual frame */\n+\t\tlist_del_init(&td->frame_lh);\n+\t\ttd->status = USB_TD_OK;\n+\t\tif (pkt->info & PKT_DUMMY_PACKET)\n+\t\t\tcq_put(usb->ep0->dummy_packets_Q, pkt->data);\n+\t\trecycle_frame(usb, pkt);\n+\t\tusb->actual_frame->total_bytes -= (len + PROTOCOL_OVERHEAD);\n+\t\tfhci_err(usb->fhci, \"host transaction failed\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\treturn len;\n+}\n+\n+/*\n+ * This function goes through the endpoint list and schedules the\n+ * transactions within this list\n+ */\n+static int scan_ed_list(struct fhci_usb *usb,\n+\t\t\tstruct list_head *list, enum fhci_tf_mode list_type)\n+{\n+\tstatic const int frame_part[4] = {\n+\t\t[FHCI_TF_CTRL] = MAX_BYTES_PER_FRAME,\n+\t\t[FHCI_TF_ISO] = (MAX_BYTES_PER_FRAME *\n+\t\t\t\t MAX_PERIODIC_FRAME_USAGE) / 100,\n+\t\t[FHCI_TF_BULK] = MAX_BYTES_PER_FRAME,\n+\t\t[FHCI_TF_INTR] = (MAX_BYTES_PER_FRAME *\n+\t\t\t\t MAX_PERIODIC_FRAME_USAGE) / 100\n+\t};\n+\tstruct list_head *ed_lh = NULL;\n+\tstruct ed *ed;\n+\tstruct td *td;\n+\tint ans = 1;\n+\tu32 save_transaction_time = usb->sw_transaction_time;\n+\n+\tlist_for_each(ed_lh, list) {\n+\t\ted = list_entry(ed_lh, struct ed, node);\n+\t\ttd = ed->td_head;\n+\n+\t\tif (!td || (td && td->status == USB_TD_INPROGRESS))\n+\t\t\tcontinue;\n+\n+\t\tif (ed->state != FHCI_ED_OPER) {\n+\t\t\tif (ed->state == FHCI_ED_URB_DEL) {\n+\t\t\t\ttd->status = USB_TD_OK;\n+\t\t\t\tmove_td_from_ed_to_done_list(usb, ed);\n+\t\t\t\ted->state = FHCI_ED_SKIP;\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/*\n+\t\t * if it isn't interrupt pipe or it is not iso pipe and the\n+\t\t * interval time passed\n+\t\t */\n+\t\tif ((list_type == FHCI_TF_INTR || list_type == FHCI_TF_ISO) &&\n+\t\t\t\t(((usb->actual_frame->frame_num -\n+\t\t\t\t td->start_frame) & 0x7ff) < td->interval))\n+\t\t\tcontinue;\n+\n+\t\tif (add_packet(usb, ed, td) < 0)\n+\t\t\tcontinue;\n+\n+\t\t/* update time stamps in the TD */\n+\t\ttd->start_frame = usb->actual_frame->frame_num;\n+\t\tusb->sw_transaction_time += save_transaction_time;\n+\n+\t\tif (usb->actual_frame->total_bytes >=\n+\t\t\t\t\tusb->max_bytes_per_frame) {\n+\t\t\tusb->actual_frame->frame_status =\n+\t\t\t\tFRAME_DATA_END_TRANSMISSION;\n+\t\t\tpush_dummy_bd(usb->ep0);\n+\t\t\tans = 0;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tif (usb->actual_frame->total_bytes >= frame_part[list_type])\n+\t\t\tbreak;\n+\t}\n+\n+\t/* be fair to each ED(move list head around) */\n+\tmove_head_to_tail(list);\n+\tusb->sw_transaction_time = save_transaction_time;\n+\n+\treturn ans;\n+}\n+\n+static u32 rotate_frames(struct fhci_usb *usb)\n+{\n+\tstruct fhci_hcd *fhci = usb->fhci;\n+\n+\tif (!list_empty(&usb->actual_frame->tds_list)) {\n+\t\tif ((((in_be16(&fhci->pram->frame_num) & 0x07ff) -\n+\t\t usb->actual_frame->frame_num) & 0x7ff) > 5)\n+\t\t\tflush_actual_frame(usb);\n+\t\telse\n+\t\t\treturn -EINVAL;\n+\t}\n+\n+\tusb->actual_frame->frame_status = FRAME_IS_PREPARED;\n+\tusb->actual_frame->frame_num = in_be16(&fhci->pram->frame_num) & 0x7ff;\n+\tusb->actual_frame->total_bytes = 0;\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * This function schedule the USB transaction and will process the\n+ * endpoint in the following order: iso, interrupt, control and bulk.\n+ */\n+static void schedule_transactions(struct fhci_usb *usb)\n+{\n+\tint left = 1;\n+\n+\tif (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION)\n+\t\tif (rotate_frames(usb) != 0)\n+\t\t\treturn;\n+\n+\tif (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION)\n+\t\treturn;\n+\n+\tif (usb->actual_frame->total_bytes == 0) {\n+\t\t/*\n+\t\t * schedule the next available ISO transfer\n+\t\t *or next stage of the ISO transfer\n+\t\t */\n+\t\tscan_ed_list(usb, &usb->hc_list->iso_list, FHCI_TF_ISO);\n+\n+\t\t/*\n+\t\t * schedule the next available interrupt transfer or\n+\t\t * the next stage of the interrupt transfer\n+\t\t */\n+\t\tscan_ed_list(usb, &usb->hc_list->intr_list, FHCI_TF_INTR);\n+\n+\t\t/*\n+\t\t * schedule the next available control transfer\n+\t\t * or the next stage of the control transfer\n+\t\t */\n+\t\tleft = scan_ed_list(usb, &usb->hc_list->ctrl_list,\n+\t\t\t\t FHCI_TF_CTRL);\n+\t}\n+\n+\t/*\n+\t * schedule the next available bulk transfer or the next stage of the\n+\t * bulk transfer\n+\t */\n+\tif (left > 0)\n+\t\tscan_ed_list(usb, &usb->hc_list->bulk_list, FHCI_TF_BULK);\n+}\n+\n+/* Handles SOF interrupt */\n+static void sof_interrupt(struct fhci_hcd *fhci)\n+{\n+\tstruct fhci_usb *usb = fhci->usb_lld;\n+\n+\tif ((usb->port_status == FHCI_PORT_DISABLED) &&\n+\t (usb->vroot_hub->port.wPortStatus & USB_PORT_STAT_CONNECTION) &&\n+\t !(usb->vroot_hub->port.wPortChange & USB_PORT_STAT_C_CONNECTION)) {\n+\t\tif (usb->vroot_hub->port.wPortStatus & USB_PORT_STAT_LOW_SPEED)\n+\t\t\tusb->port_status = FHCI_PORT_LOW;\n+\t\telse\n+\t\t\tusb->port_status = FHCI_PORT_FULL;\n+\t\t/* Disable IDLE */\n+\t\tusb->saved_msk &= ~USB_E_IDLE_MASK;\n+\t\tout_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);\n+\t}\n+\n+\tgtm_set_exact_timer16(fhci->timer, usb->max_frame_usage, false);\n+\n+\thost_transmit_actual_frame(usb);\n+\tusb->actual_frame->frame_status = FRAME_IS_TRANSMITTED;\n+\n+\tschedule_transactions(usb);\n+}\n+\n+/* Handles device disconnected interrupt on port */\n+static void device_disconnected_interrupt(struct fhci_hcd *fhci)\n+{\n+\tstruct fhci_usb *usb = fhci->usb_lld;\n+\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\tfhci_usb_disable_interrupt(usb);\n+\tclrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);\n+\tusb->port_status = FHCI_PORT_DISABLED;\n+\n+\tfhci_stop_sof_timer(fhci);\n+\n+\t/* Enable IDLE since we want to know if something comes along */\n+\tusb->saved_msk |= USB_E_IDLE_MASK;\n+\tout_be16(&usb->fhci->regs->usb_mask, usb->saved_msk);\n+\n+\tusb->vroot_hub->port.wPortStatus &= ~USB_PORT_STAT_CONNECTION;\n+\tusb->vroot_hub->port.wPortChange |= USB_PORT_STAT_C_CONNECTION;\n+\tusb->max_bytes_per_frame = 0;\n+\tfhci_usb_enable_interrupt(usb);\n+\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+}\n+\n+/* detect a new device connected on the USB port */\n+static void device_connected_interrupt(struct fhci_hcd *fhci)\n+{\n+\n+\tstruct fhci_usb *usb = fhci->usb_lld;\n+\tint state;\n+\tint ret;\n+\n+\tfhci_dbg(fhci, \"-> %s\\n\", __func__);\n+\n+\tfhci_usb_disable_interrupt(usb);\n+\tstate = fhci_ioports_check_bus_state(fhci);\n+\n+\t/* low-speed device was connected to the USB port */\n+\tif (state == 1) {\n+\t\tret = qe_usb_clock_set(fhci->lowspeed_clk, USB_CLOCK >> 3);\n+\t\tif (ret) {\n+\t\t\tfhci_warn(fhci, \"Low-Speed device is not supported, \"\n+\t\t\t\t \"try use BRGx\\n\");\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tusb->port_status = FHCI_PORT_LOW;\n+\t\tsetbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);\n+\t\tusb->vroot_hub->port.wPortStatus |=\n+\t\t (USB_PORT_STAT_LOW_SPEED |\n+\t\t USB_PORT_STAT_CONNECTION);\n+\t\tusb->vroot_hub->port.wPortChange |=\n+\t\t USB_PORT_STAT_C_CONNECTION;\n+\t\tusb->max_bytes_per_frame =\n+\t\t (MAX_BYTES_PER_FRAME >> 3) - 7;\n+\t\tusb_port_enable(usb);\n+\t} else if (state == 2) {\n+\t\tret = qe_usb_clock_set(fhci->fullspeed_clk, USB_CLOCK);\n+\t\tif (ret) {\n+\t\t\tfhci_warn(fhci, \"Full-Speed device is not supported, \"\n+\t\t\t\t \"try use CLKx\\n\");\n+\t\t\tgoto out;\n+\t\t}\n+\n+\t\tusb->port_status = FHCI_PORT_FULL;\n+\t\tclrbits8(&usb->fhci->regs->usb_mod, USB_MODE_LSS);\n+\t\tusb->vroot_hub->port.wPortStatus &=\n+\t\t ~USB_PORT_STAT_LOW_SPEED;\n+\t\tusb->vroot_hub->port.wPortStatus |=\n+\t\t USB_PORT_STAT_CONNECTION;\n+\t\tusb->vroot_hub->port.wPortChange |=\n+\t\t USB_PORT_STAT_C_CONNECTION;\n+\t\tusb->max_bytes_per_frame = (MAX_BYTES_PER_FRAME - 15);\n+\t\tusb_port_enable(usb);\n+\t}\n+out:\n+\tfhci_usb_enable_interrupt(usb);\n+\tfhci_dbg(fhci, \"<- %s\\n\", __func__);\n+}\n+\n+static irqreturn_t fhci_frame_limit_timer_irq(int irq, void *_hcd)\n+{\n+\tstruct usb_hcd *hcd = _hcd;\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\tstruct fhci_usb *usb = fhci->usb_lld;\n+\n+\tspin_lock(&fhci->lock);\n+\n+\tgtm_set_exact_timer16(fhci->timer, 1000, false);\n+\n+\tif (usb->actual_frame->frame_status == FRAME_IS_TRANSMITTED) {\n+\t\tusb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION;\n+\t\tpush_dummy_bd(usb->ep0);\n+\t}\n+\n+\tschedule_transactions(usb);\n+\n+\tspin_unlock(&fhci->lock);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+/* Cancel transmission on the USB endpoint */\n+static void abort_transmission(struct fhci_usb *usb)\n+{\n+\tfhci_dbg(usb->fhci, \"-> %s\\n\", __func__);\n+\t/* issue stop Tx command */\n+\tqe_issue_cmd(QE_USB_STOP_TX, QE_CR_SUBBLOCK_USB, EP_ZERO, 0);\n+\t/* flush Tx FIFOs */\n+\tout_8(&usb->fhci->regs->usb_comm, USB_CMD_FLUSH_FIFO | EP_ZERO);\n+\tudelay(1000);\n+\t/* reset Tx BDs */\n+\tflush_bds(usb);\n+\t/* issue restart Tx command */\n+\tqe_issue_cmd(QE_USB_RESTART_TX, QE_CR_SUBBLOCK_USB, EP_ZERO, 0);\n+\tfhci_dbg(usb->fhci, \"<- %s\\n\", __func__);\n+}\n+\n+static irqreturn_t fhci_irq(struct usb_hcd *hcd)\n+{\n+\tstruct fhci_hcd *fhci = hcd_to_fhci(hcd);\n+\tstruct fhci_usb *usb;\n+\tu16 usb_er = 0;\n+\tunsigned long flags;\n+\n+\tspin_lock_irqsave(&fhci->lock, flags);\n+\n+\tusb = fhci->usb_lld;\n+\n+\tusb_er |= in_be16(&usb->fhci->regs->usb_event) &\n+\t\t in_be16(&usb->fhci->regs->usb_mask);\n+\n+\t/* clear event bits for next time */\n+\tout_be16(&usb->fhci->regs->usb_event, usb_er);\n+\n+\tfhci_dbg_isr(fhci, usb_er);\n+\n+\tif (usb_er & USB_E_RESET_MASK) {\n+\t\tif ((usb->port_status == FHCI_PORT_FULL) ||\n+\t\t\t\t(usb->port_status == FHCI_PORT_LOW)) {\n+\t\t\tdevice_disconnected_interrupt(fhci);\n+\t\t\tusb_er &= ~USB_E_IDLE_MASK;\n+\t\t} else if (usb->port_status == FHCI_PORT_WAITING) {\n+\t\t\tusb->port_status = FHCI_PORT_DISCONNECTING;\n+\n+\t\t\t/* Turn on IDLE since we want to disconnect */\n+\t\t\tusb->saved_msk |= USB_E_IDLE_MASK;\n+\t\t\tout_be16(&usb->fhci->regs->usb_event,\n+\t\t\t\t usb->saved_msk);\n+\t\t} else if (usb->port_status == FHCI_PORT_DISABLED) {\n+\t\t\tif (fhci_ioports_check_bus_state(fhci) == 1 &&\n+\t\t\t\t\tusb->port_status != FHCI_PORT_LOW &&\n+\t\t\t\t\tusb->port_status != FHCI_PORT_FULL)\n+\t\t\t\tdevice_connected_interrupt(fhci);\n+\t\t}\n+\t\tusb_er &= ~USB_E_RESET_MASK;\n+\t}\n+\n+\tif (usb_er & USB_E_MSF_MASK) {\n+\t\tabort_transmission(fhci->usb_lld);\n+\t\tusb_er &= ~USB_E_MSF_MASK;\n+\t}\n+\n+\tif (usb_er & (USB_E_SOF_MASK | USB_E_SFT_MASK)) {\n+\t\tsof_interrupt(fhci);\n+\t\tusb_er &= ~(USB_E_SOF_MASK | USB_E_SFT_MASK);\n+\t}\n+\n+\tif (usb_er & USB_E_TXB_MASK) {\n+\t\ttx_conf_interrupt(fhci->usb_lld);\n+\t\tusb_er &= ~USB_E_TXB_MASK;\n+\t}\n+\n+\tif (usb_er & USB_E_TXE1_MASK) {\n+\t\ttx_conf_interrupt(fhci->usb_lld);\n+\t\tusb_er &= ~USB_E_TXE1_MASK;\n+\t}\n+\n+\tif (usb_er & USB_E_IDLE_MASK) {\n+\t\tif (usb->port_status == FHCI_PORT_DISABLED &&\n+\t\t\t\tusb->port_status != FHCI_PORT_LOW &&\n+\t\t\t\tusb->port_status != FHCI_PORT_FULL) {\n+\t\t\tusb_er &= ~USB_E_RESET_MASK;\n+\t\t\tdevice_connected_interrupt(fhci);\n+\t\t} else if (usb->port_status ==\n+\t\t\t\tFHCI_PORT_DISCONNECTING) {\n+\t\t\t/* XXX usb->port_status = FHCI_PORT_WAITING; */\n+\t\t\t/* Disable IDLE */\n+\t\t\tusb->saved_msk &= ~USB_E_IDLE_MASK;\n+\t\t\tout_be16(&usb->fhci->regs->usb_mask,\n+\t\t\t\t usb->saved_msk);\n+\t\t} else {\n+\t\t\tfhci_dbg_isr(fhci, -1);\n+\t\t}\n+\n+\t\tusb_er &= ~USB_E_IDLE_MASK;\n+\t}\n+\n+\tspin_unlock_irqrestore(&fhci->lock, flags);\n+\n+\treturn IRQ_HANDLED;\n+}\n+\n+\n+/*\n+ * Process normal completions(error or sucess) and clean the schedule.\n+ *\n+ * This is the main path for handing urbs back to drivers. The only other patth\n+ * is process_del_list(),which unlinks URBs by scanning EDs,instead of scanning\n+ * the (re-reversed) done list as this does.\n+ */\n+static void process_done_list(unsigned long data)\n+{\n+\tstruct urb *urb;\n+\tstruct ed *ed;\n+\tstruct td *td;\n+\tstruct urb_priv *urb_priv;\n+\tstruct fhci_hcd *fhci = (struct fhci_hcd *)data;\n+\n+\tdisable_irq(fhci->timer->irq);\n+\tdisable_irq(fhci_to_hcd(fhci)->irq);\n+\tspin_lock(&fhci->lock);\n+\n+\ttd = remove_td_from_done_list(fhci->hc_list);\n+\twhile (td != NULL) {\n+\t\turb = td->urb;\n+\t\turb_priv = urb->hcpriv;\n+\t\ted = td->ed;\n+\n+\t\t/* update URB's length and status from TD */\n+\t\tdone_td(urb, td);\n+\t\turb_priv->tds_cnt++;\n+\n+\t\t/*\n+\t\t * if all this urb's TDs are done, call complete()\n+\t\t * Interrupt transfers are the onley special case:\n+\t\t * they are reissued,until \"deleted\" by usb_unlink_urb\n+\t\t * (real work done in a SOF intr, by process_del_list)\n+\t\t */\n+\t\tif (urb_priv->tds_cnt == urb_priv->num_of_tds) {\n+\t\t\turb_complete_free(fhci, urb);\n+\t\t} else if (urb_priv->state == URB_DEL &&\n+\t\t\t\ted->state == FHCI_ED_SKIP) {\n+\t\t\tdel_ed_list(fhci, ed);\n+\t\t\ted->state = FHCI_ED_OPER;\n+\t\t} else if (ed->state == FHCI_ED_HALTED) {\n+\t\t\turb_priv->state = URB_DEL;\n+\t\t\ted->state = FHCI_ED_URB_DEL;\n+\t\t\tdel_ed_list(fhci, ed);\n+\t\t\ted->state = FHCI_ED_OPER;\n+\t\t}\n+\n+\t\ttd = remove_td_from_done_list(fhci->hc_list);\n+\t}\n+\n+\tspin_unlock(&fhci->lock);\n+\tenable_irq(fhci->timer->irq);\n+\tenable_irq(fhci_to_hcd(fhci)->irq);\n+}\n+\n+static DECLARE_TASKLET(fhci_tasklet, process_done_list, 0);\n+\n+/* transfer complted callback */\n+static u32 transfer_confirm_callback(struct fhci_hcd *fhci)\n+{\n+\tif (!fhci->process_done_task->state)\n+\t\ttasklet_schedule(fhci->process_done_task);\n+\treturn 0;\n+}\n+\n+/*\n+ * adds urb to the endpoint descriptor list\n+ * arguments:\n+ * fhci\t\tdata structure for the Low level host controller\n+ * ep\t\tUSB Host endpoint data structure\n+ * urb\t\tUSB request block data structure\n+ */\n+static void queue_urb(struct fhci_hcd *fhci, struct urb *urb)\n+{\n+\tstruct ed *ed = urb->ep->hcpriv;\n+\tstruct urb_priv *urb_priv = urb->hcpriv;\n+\tu32 data_len = urb->transfer_buffer_length;\n+\tint urb_state = 0;\n+\tint toggle = 0;\n+\tstruct td *td;\n+\tu8 *data;\n+\tu16 cnt = 0;\n+\n+\tif (ed == NULL) {\n+\t\ted = get_empty_ed(fhci);\n+\t\ted->dev_addr = usb_pipedevice(urb->pipe);\n+\t\ted->ep_addr = usb_pipeendpoint(urb->pipe);\n+\t\tswitch (usb_pipetype(urb->pipe)) {\n+\t\tcase PIPE_CONTROL:\n+\t\t\ted->mode = FHCI_TF_CTRL;\n+\t\t\tbreak;\n+\t\tcase PIPE_BULK:\n+\t\t\ted->mode = FHCI_TF_BULK;\n+\t\t\tbreak;\n+\t\tcase PIPE_INTERRUPT:\n+\t\t\ted->mode = FHCI_TF_INTR;\n+\t\t\tbreak;\n+\t\tcase PIPE_ISOCHRONOUS:\n+\t\t\ted->mode = FHCI_TF_ISO;\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t\ted->speed = (urb->dev->speed == USB_SPEED_LOW) ?\n+\t\t\tFHCI_LOW_SPEED : FHCI_FULL_SPEED;\n+\t\ted->max_pkt_size = usb_maxpacket(urb->dev,\n+\t\t\turb->pipe, usb_pipeout(urb->pipe));\n+\t\turb->ep->hcpriv = ed;\n+\t\tfhci_dbg(fhci, \"new ep speed=%d max_pkt_size=%d\\n\",\n+\t\t\t ed->speed, ed->max_pkt_size);\n+\t}\n+\n+\t/* for ISO transfer calculate start frame index */\n+\tif (ed->mode == FHCI_TF_ISO && urb->transfer_flags & URB_ISO_ASAP)\n+\t\turb->start_frame = ed->td_head ? ed->last_iso + 1 :\n+\t\t\t\t\t\t get_frame_num(fhci);\n+\n+\t/*\n+\t * OHCI handles the DATA toggle itself,we just use the USB\n+\t * toggle bits\n+\t */\n+\tif (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),\n+\t\t\t usb_pipeout(urb->pipe)))\n+\t\ttoggle = USB_TD_TOGGLE_CARRY;\n+\telse {\n+\t\ttoggle = USB_TD_TOGGLE_DATA0;\n+\t\tusb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),\n+\t\t\t usb_pipeout(urb->pipe), 1);\n+\t}\n+\n+\turb_priv->tds_cnt = 0;\n+\turb_priv->ed = ed;\n+\tif (data_len > 0)\n+\t\tdata = urb->transfer_buffer;\n+\telse\n+\t\tdata = NULL;\n+\n+\tswitch (ed->mode) {\n+\tcase FHCI_TF_BULK:\n+\t\tif (urb->transfer_flags & URB_ZERO_PACKET &&\n+\t\t\t\turb->transfer_buffer_length > 0 &&\n+\t\t\t\t((urb->transfer_buffer_length %\n+\t\t\t\tusb_maxpacket(urb->dev, urb->pipe,\n+\t\t\t\tusb_pipeout(urb->pipe))) == 0))\n+\t\t\turb_state = US_BULK0;\n+\t\twhile (data_len > 4096) {\n+\t\t\ttd = td_fill(fhci, urb, urb_priv, ed, cnt,\n+\t\t\t\tusb_pipeout(urb->pipe) ? FHCI_TA_OUT :\n+\t\t\t\t\t\t\t FHCI_TA_IN,\n+\t\t\t\tcnt ? USB_TD_TOGGLE_CARRY :\n+\t\t\t\t toggle,\n+\t\t\t\tdata, 4096, 0, 0, true);\n+\t\t\tdata += 4096;\n+\t\t\tdata_len -= 4096;\n+\t\t\tcnt++;\n+\t\t}\n+\n+\t\ttd = td_fill(fhci, urb, urb_priv, ed, cnt,\n+\t\t\tusb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN,\n+\t\t\tcnt ? USB_TD_TOGGLE_CARRY : toggle,\n+\t\t\tdata, data_len, 0, 0, true);\n+\t\tcnt++;\n+\n+\t\tif (urb->transfer_flags & URB_ZERO_PACKET &&\n+\t\t\t\tcnt < urb_priv->num_of_tds) {\n+\t\t\ttd = td_fill(fhci, urb, urb_priv, ed, cnt,\n+\t\t\t\tusb_pipeout(urb->pipe) ? FHCI_TA_OUT :\n+\t\t\t\t\t\t\t FHCI_TA_IN,\n+\t\t\t\tUSB_TD_TOGGLE_CARRY, NULL, 0, 0, 0, true);\n+\t\t\tcnt++;\n+\t\t}\n+\t\tbreak;\n+\tcase FHCI_TF_INTR:\n+\t\turb->start_frame = get_frame_num(fhci) + 1;\n+\t\ttd = td_fill(fhci, urb, urb_priv, ed, cnt++,\n+\t\t\tusb_pipeout(urb->pipe) ? FHCI_TA_OUT : FHCI_TA_IN,\n+\t\t\tUSB_TD_TOGGLE_DATA0, data, data_len,\n+\t\t\turb->interval, urb->start_frame, true);\n+\t\tbreak;\n+\tcase FHCI_TF_CTRL:\n+\t\ted->dev_addr = usb_pipedevice(urb->pipe);\n+\t\ted->max_pkt_size = usb_maxpacket(urb->dev, urb->pipe,\n+\t\t\tusb_pipeout(urb->pipe));\n+\t\ttd = td_fill(fhci, urb, urb_priv, ed, cnt++, FHCI_TA_SETUP,\n+\t\t\tUSB_TD_TOGGLE_DATA0, urb->setup_packet, 8, 0, 0, true);\n+\n+\t\tif (data_len > 0) {\n+\t\t\ttd = td_fill(fhci, urb, urb_priv, ed, cnt++,\n+\t\t\t\tusb_pipeout(urb->pipe) ? FHCI_TA_OUT :\n+\t\t\t\t\t\t\t FHCI_TA_IN,\n+\t\t\t\tUSB_TD_TOGGLE_DATA1, data, data_len, 0, 0,\n+\t\t\t\ttrue);\n+\t\t}\n+\t\ttd = td_fill(fhci, urb, urb_priv, ed, cnt++,\n+\t\t\tusb_pipeout(urb->pipe) ? FHCI_TA_IN : FHCI_TA_OUT,\n+\t\t\tUSB_TD_TOGGLE_DATA1, data, 0, 0, 0, true);\n+\t\turb_state = US_CTRL_SETUP;\n+\t\tbreak;\n+\tcase FHCI_TF_ISO:\n+\t\tfor (cnt = 0; cnt < urb->number_of_packets; cnt++) {\n+\t\t\tu16 frame = urb->start_frame;\n+\n+\t\t\t/*\n+\t\t\t * FIXME scheduling should handle frame counter\n+\t\t\t * roll-around ... exotic case (and OHCI has\n+\t\t\t * a 2^16 iso range, vs other HCs max of 2^10)\n+\t\t\t */\n+\t\t\tframe += cnt * urb->interval;\n+\t\t\tframe &= 0x07ff;\n+\t\t\ttd = td_fill(fhci, urb, urb_priv, ed, cnt,\n+\t\t\t\tusb_pipeout(urb->pipe) ? FHCI_TA_OUT :\n+\t\t\t\t\t\t\t FHCI_TA_IN,\n+\t\t\t\tUSB_TD_TOGGLE_DATA0,\n+\t\t\t\tdata + urb->iso_frame_desc[cnt].offset,\n+\t\t\t\turb->iso_frame_desc[cnt].length,\n+\t\t\t\turb->interval, frame, true);\n+\t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\t/*\n+\t * set the state of URB\n+\t * control pipe:3 states -- setup,data,status\n+\t * interrupt and bulk pipe:1 state -- data\n+\t */\n+\turb->pipe &= ~0x1f;\n+\turb->pipe |= urb_state & 0x1f;\n+\n+\turb_priv->state = URB_INPROGRESS;\n+\n+\tif (!ed->td_head) {\n+\t\ted->state = FHCI_ED_OPER;\n+\t\tswitch (ed->mode) {\n+\t\tcase FHCI_TF_CTRL:\n+\t\t\tlist_add(&ed->node, &fhci->hc_list->ctrl_list);\n+\t\t\tbreak;\n+\t\tcase FHCI_TF_BULK:\n+\t\t\tlist_add(&ed->node, &fhci->hc_list->bulk_list);\n+\t\t\tbreak;\n+\t\tcase FHCI_TF_INTR:\n+\t\t\tlist_add(&ed->node, &fhci->hc_list->intr_list);\n+\t\t\tbreak;\n+\t\tcase FHCI_TF_ISO:\n+\t\t\tlist_add(&ed->node, &fhci->hc_list->iso_list);\n+\t\t\tbreak;\n+\t\tdefault:\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tadd_tds_to_ed(ed, urb_priv->tds, urb_priv->num_of_tds);\n+\tfhci->active_urbs++;\n+}\ndiff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c\nnew file mode 100644\nindex 0000000..49df9c8\n--- /dev/null\n+++ b/drivers/usb/host/fhci-tds.c\n@@ -0,0 +1,633 @@\n+/*\n+ * Freescale QUICC Engine USB Host Controller Driver\n+ *\n+ * Copyright (c) Freescale Semicondutor, Inc. 2006.\n+ * Shlomi Gridish <gridish@freescale.com>\n+ * Jerry Huang <Chang-Ming.Huang@freescale.com>\n+ * Copyright (c) Logic Product Development, Inc. 2007\n+ * Peter Barada <peterb@logicpd.com>\n+ * Copyright (c) MontaVista Software, Inc. 2008.\n+ * Anton Vorontsov <avorontsov@ru.mvista.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License as published by the\n+ * Free Software Foundation; either version 2 of the License, or (at your\n+ * option) any later version.\n+ */\n+\n+#define DUMMY_BD_BUFFER 0xdeadbeef\n+#define DUMMY2_BD_BUFFER 0xbaadf00d\n+\n+/* Transaction Descriptors bits */\n+#define TD_R\t\t0x8000 /* ready bit */\n+#define TD_W\t\t0x2000 /* wrap bit */\n+#define TD_I\t\t0x1000 /* interrupt on completion */\n+#define TD_L\t\t0x0800 /* last */\n+#define TD_TC\t\t0x0400 /* transmit CRC */\n+#define TD_CNF\t\t0x0200 /* CNF - Must be always 1 */\n+#define TD_LSP\t\t0x0100 /* Low-speed transaction */\n+#define TD_PID\t\t0x00c0 /* packet id */\n+#define TD_RXER\t\t0x0020 /* Rx error or not */\n+\n+#define TD_NAK\t\t0x0010 /* No ack. */\n+#define TD_STAL\t\t0x0008 /* Stall recieved */\n+#define TD_TO\t\t0x0004 /* time out */\n+#define TD_UN\t\t0x0002 /* underrun */\n+#define TD_NO\t\t0x0010 /* Rx Non Octet Aligned Packet */\n+#define TD_AB\t\t0x0008 /* Frame Aborted */\n+#define TD_CR\t\t0x0004 /* CRC Error */\n+#define TD_OV\t\t0x0002 /* Overrun */\n+#define TD_BOV\t\t0x0001 /* Buffer Overrun */\n+\n+#define TD_ERRORS\t(TD_NAK | TD_STAL | TD_TO | TD_UN | \\\n+\t\t\t TD_NO | TD_AB | TD_CR | TD_OV | TD_BOV)\n+\n+#define TD_PID_DATA0\t0x0080 /* Data 0 toggle */\n+#define TD_PID_DATA1\t0x00c0 /* Data 1 toggle */\n+#define TD_PID_TOGGLE\t0x00c0 /* Data 0/1 toggle mask */\n+\n+#define TD_TOK_SETUP\t0x0000\n+#define TD_TOK_OUT\t0x4000\n+#define TD_TOK_IN\t0x8000\n+#define TD_ISO\t\t0x1000\n+#define TD_ENDP\t\t0x0780\n+#define TD_ADDR\t\t0x007f\n+\n+#define TD_ENDP_SHIFT 7\n+\n+struct usb_td {\n+\t__be16 status;\n+\t__be16 length;\n+\t__be32 buf_ptr;\n+\t__be16 extra;\n+\t__be16 reserved;\n+};\n+\n+struct endpoint {\n+\t/* Pointer to ep parameter RAM */\n+\tstruct fhci_ep_pram __iomem *ep_pram_ptr;\n+\n+\t/* Host transactions */\n+\tstruct usb_td __iomem *td_base; /* first TD in the ring */\n+\tstruct usb_td __iomem *conf_td; /* next TD for confirm after transac */\n+\tstruct usb_td __iomem *empty_td; /* next TD for new transaction request */\n+\tvoid *empty_frame_Q;\t/* Empty frames list to use */\n+\tvoid *conf_frame_Q;\t/* frames passed to TDs,waiting for tx */\n+\tvoid *dummy_packets_Q;\t/* dummy packets for the CRC overun */\n+\n+\tbool already_pushed_dummy_bd;\n+};\n+\n+static struct usb_td __iomem *next_bd(struct usb_td __iomem *base,\n+\t\t\t\t struct usb_td __iomem *td,\n+\t\t\t\t u16 status)\n+{\n+\tif (status & TD_W)\n+\t\treturn base;\n+\telse\n+\t\treturn ++td;\n+}\n+\n+static void push_dummy_bd(struct endpoint *ep)\n+{\n+\tif (ep->already_pushed_dummy_bd == false) {\n+\t\tu16 td_status = in_be16(&ep->empty_td->status);\n+\n+\t\tout_be32(&ep->empty_td->buf_ptr, DUMMY_BD_BUFFER);\n+\t\t/* get the next TD in the ring */\n+\t\tep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status);\n+\t\tep->already_pushed_dummy_bd = true;\n+\t}\n+}\n+\n+/* destroy an USB endpoint */\n+static void endpoint_zero_free(struct fhci_usb *usb)\n+{\n+\tstruct endpoint *ep;\n+\tint size;\n+\n+\tep = usb->ep0;\n+\tif (ep) {\n+\t\tif (ep->td_base)\n+\t\t\tcpm_muram_free(cpm_muram_offset(ep->td_base));\n+\n+\t\tif (ep->conf_frame_Q) {\n+\t\t\tsize = cq_howmany(ep->conf_frame_Q);\n+\t\t\tfor (; size; size--) {\n+\t\t\t\tstruct packet *pkt = cq_get(ep->conf_frame_Q);\n+\n+\t\t\t\tkfree(pkt);\n+\t\t\t}\n+\t\t\tcq_delete(ep->conf_frame_Q);\n+\t\t}\n+\n+\t\tif (ep->empty_frame_Q) {\n+\t\t\tsize = cq_howmany(ep->empty_frame_Q);\n+\t\t\tfor (; size; size--) {\n+\t\t\t\tstruct packet *pkt = cq_get(ep->empty_frame_Q);\n+\n+\t\t\t\tkfree(pkt);\n+\t\t\t}\n+\t\t\tcq_delete(ep->empty_frame_Q);\n+\t\t}\n+\n+\t\tif (ep->dummy_packets_Q) {\n+\t\t\tsize = cq_howmany(ep->dummy_packets_Q);\n+\t\t\tfor (; size; size--) {\n+\t\t\t\tu8 *buff = cq_get(ep->dummy_packets_Q);\n+\n+\t\t\t\tkfree(buff);\n+\t\t\t}\n+\t\t\tcq_delete(ep->dummy_packets_Q);\n+\t\t}\n+\n+\t\tkfree(ep);\n+\t\tusb->ep0 = NULL;\n+\t}\n+}\n+\n+/*\n+ * create the endpoint structure\n+ *\n+ * arguments:\n+ * usb\t\tA pointer to the data structure of the USB\n+ * data_mem\tThe data memory partition(BUS)\n+ * ring_len\tTD ring length\n+ */\n+static u32 create_endpoint(struct fhci_usb *usb, enum fhci_mem_alloc data_mem,\n+\t\t\t u32 ring_len)\n+{\n+\tstruct endpoint *ep;\n+\tstruct usb_td __iomem *td;\n+\tunsigned long ep_offset;\n+\tchar *err_for = \"enpoint PRAM\";\n+\tint ep_mem_size;\n+\tu32 i;\n+\n+\t/* we need at least 3 TDs in the ring */\n+\tif (!(ring_len > 2)) {\n+\t\tfhci_err(usb->fhci, \"illegal TD ring length parameters\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\tep = kzalloc(sizeof(*ep), GFP_KERNEL);\n+\tif (!ep)\n+\t\tgoto err;\n+\n+\tep_mem_size = ring_len * sizeof(*td) + sizeof(struct fhci_ep_pram);\n+\tep_offset = cpm_muram_alloc(ep_mem_size, 32);\n+\tif (IS_ERR_VALUE(ep_offset))\n+\t\tgoto err;\n+\tep->td_base = cpm_muram_addr(ep_offset);\n+\n+\t/* zero all queue pointers */\n+\tep->conf_frame_Q = cq_new(ring_len + 2);\n+\tep->empty_frame_Q = cq_new(ring_len + 2);\n+\tep->dummy_packets_Q = cq_new(ring_len + 2);\n+\tif (!ep->conf_frame_Q || !ep->empty_frame_Q || !ep->dummy_packets_Q) {\n+\t\terr_for = \"frame_queues\";\n+\t\tgoto err;\n+\t}\n+\n+\tfor (i = 0; i < (ring_len + 1); i++) {\n+\t\tstruct packet *pkt;\n+\t\tu8 *buff;\n+\n+\t\tpkt = kmalloc(sizeof(*pkt), GFP_KERNEL);\n+\t\tif (!pkt) {\n+\t\t\terr_for = \"frame\";\n+\t\t\tgoto err;\n+\t\t}\n+\n+\t\tbuff = kmalloc(1028 * sizeof(*buff), GFP_KERNEL);\n+\t\tif (!buff) {\n+\t\t\tkfree(pkt);\n+\t\t\terr_for = \"buffer\";\n+\t\t\tgoto err;\n+\t\t}\n+\t\tcq_put(ep->empty_frame_Q, pkt);\n+\t\tcq_put(ep->dummy_packets_Q, buff);\n+\t}\n+\n+\t/* we put the endpoint parameter RAM right behind the TD ring */\n+\tep->ep_pram_ptr = (void __iomem *)ep->td_base + sizeof(*td) * ring_len;\n+\n+\tep->conf_td = ep->td_base;\n+\tep->empty_td = ep->td_base;\n+\n+\tep->already_pushed_dummy_bd = false;\n+\n+\t/* initialize tds */\n+\ttd = ep->td_base;\n+\tfor (i = 0; i < ring_len; i++) {\n+\t\tout_be32(&td->buf_ptr, 0);\n+\t\tout_be16(&td->status, 0);\n+\t\tout_be16(&td->length, 0);\n+\t\tout_be16(&td->extra, 0);\n+\t\ttd++;\n+\t}\n+\ttd--;\n+\tout_be16(&td->status, TD_W); /* for last TD set Wrap bit */\n+\tout_be16(&td->length, 0);\n+\n+\t/* endpoint structure has been created */\n+\tusb->ep0 = ep;\n+\n+\treturn 0;\n+err:\n+\tkfree(ep);\n+\tendpoint_zero_free(usb);\n+\tfhci_err(usb->fhci, \"no memory for the %s\\n\", err_for);\n+\treturn -ENOMEM;\n+}\n+\n+/*\n+ * initialize the endpoint register according to the given parameters\n+ *\n+ * artuments:\n+ * usb\t\tA pointer to the data strucutre of the USB\n+ * ep\t\tA pointer to the endpoint structre\n+ * data_mem\tThe data memory partition(BUS)\n+ */\n+static void init_endpoint_registers(struct fhci_usb *usb,\n+\t\t\t\t struct endpoint *ep,\n+\t\t\t\t enum fhci_mem_alloc data_mem)\n+{\n+\tu8 rt;\n+\n+\t/* set the endpoint registers according to the endpoint */\n+\tout_be16(&usb->fhci->regs->usb_ep[0],\n+\t\t USB_TRANS_CTR | USB_EP_MF | USB_EP_RTE);\n+\tout_be16(&usb->fhci->pram->ep_ptr[0],\n+\t\t cpm_muram_offset(ep->ep_pram_ptr));\n+\n+\trt = (BUS_MODE_BO_BE | BUS_MODE_GBL);\n+#ifdef MULTI_DATA_BUS\n+\tif (data_mem == MEM_SECONDARY)\n+\t\trt |= BUS_MODE_DTB;\n+#endif\n+\tout_8(&ep->ep_pram_ptr->rx_func_code, rt);\n+\tout_8(&ep->ep_pram_ptr->tx_func_code, rt);\n+\tout_be16(&ep->ep_pram_ptr->rx_buff_len, 1028);\n+\tout_be16(&ep->ep_pram_ptr->rx_base, 0);\n+\tout_be16(&ep->ep_pram_ptr->tx_base, cpm_muram_offset(ep->td_base));\n+\tout_be16(&ep->ep_pram_ptr->rx_bd_ptr, 0);\n+\tout_be16(&ep->ep_pram_ptr->tx_bd_ptr, cpm_muram_offset(ep->td_base));\n+\tout_be32(&ep->ep_pram_ptr->tx_state, 0);\n+}\n+\n+/*\n+ * Collect the submitted frames and inform the application about them\n+ * It is also prepearing the TDs for new frames. If the Tx interrupts\n+ * are diabled, the application should call that routine to get\n+ * confirmation about the submitted frames. Otherwise, the routine is\n+ * called frome the interrupt service routine during the Tx interrupt.\n+ * In that case the application is informed by calling the application\n+ * specific 'transaction_confirm' routine\n+ */\n+static void td_transaction_confirm(struct fhci_usb *usb)\n+{\n+\tstruct endpoint *ep = usb->ep0;\n+\tstruct packet *pkt;\n+\tstruct usb_td __iomem *td;\n+\tu16 extra_data;\n+\tu16 td_status;\n+\tu16 td_length;\n+\tu32 buf;\n+\n+\t/*\n+\t * collect transmitted BDs from the chip. The routine clears all BDs\n+\t * with R bit = 0 and the pointer to data buffer is not NULL, that is\n+\t * BDs which point to the transmitted data buffer\n+\t */\n+\twhile (1) {\n+\t\ttd = ep->conf_td;\n+\t\ttd_status = in_be16(&td->status);\n+\t\ttd_length = in_be16(&td->length);\n+\t\tbuf = in_be32(&td->buf_ptr);\n+\t\textra_data = in_be16(&td->extra);\n+\n+\t\t/* check if the TD is empty */\n+\t\tif (!(!(td_status & TD_R) && ((td_status & ~TD_W) || buf)))\n+\t\t\tbreak;\n+\t\t/* check if it is a dummy buffer */\n+\t\telse if ((buf == DUMMY_BD_BUFFER) && !(td_status & ~TD_W))\n+\t\t\tbreak;\n+\n+\t\t/* mark TD as empty */\n+\t\tclrbits16(&td->status, ~TD_W);\n+\t\tout_be16(&td->length, 0);\n+\t\tout_be32(&td->buf_ptr, 0);\n+\t\tout_be16(&td->extra, 0);\n+\t\t/* advance the TD pointer */\n+\t\tep->conf_td = next_bd(ep->td_base, ep->conf_td, td_status);\n+\n+\t\t/* check if it is a dummy buffer(type2) */\n+\t\tif ((buf == DUMMY2_BD_BUFFER) && !(td_status & ~TD_W))\n+\t\t\tcontinue;\n+\n+\t\tpkt = cq_get(ep->conf_frame_Q);\n+\t\tif (!pkt)\n+\t\t\tfhci_err(usb->fhci, \"no frame to confirm\\n\");\n+\n+\t\tif (td_status & TD_ERRORS) {\n+\t\t\tif (td_status & TD_RXER) {\n+\t\t\t\tif (td_status & TD_CR)\n+\t\t\t\t\tpkt->status = USB_TD_RX_ER_CRC;\n+\t\t\t\telse if (td_status & TD_AB)\n+\t\t\t\t\tpkt->status = USB_TD_RX_ER_BITSTUFF;\n+\t\t\t\telse if (td_status & TD_OV)\n+\t\t\t\t\tpkt->status = USB_TD_RX_ER_OVERUN;\n+\t\t\t\telse if (td_status & TD_BOV)\n+\t\t\t\t\tpkt->status = USB_TD_RX_DATA_OVERUN;\n+\t\t\t\telse if (td_status & TD_NO)\n+\t\t\t\t\tpkt->status = USB_TD_RX_ER_NONOCT;\n+\t\t\t\telse\n+\t\t\t\t\tfhci_err(usb->fhci, \"illegal error \"\n+\t\t\t\t\t\t \"occured\\n\");\n+\t\t\t} else if (td_status & TD_NAK)\n+\t\t\t\tpkt->status = USB_TD_TX_ER_NAK;\n+\t\t\telse if (td_status & TD_TO)\n+\t\t\t\tpkt->status = USB_TD_TX_ER_TIMEOUT;\n+\t\t\telse if (td_status & TD_UN)\n+\t\t\t\tpkt->status = USB_TD_TX_ER_UNDERUN;\n+\t\t\telse if (td_status & TD_STAL)\n+\t\t\t\tpkt->status = USB_TD_TX_ER_STALL;\n+\t\t\telse\n+\t\t\t\tfhci_err(usb->fhci, \"illegal error occured\\n\");\n+\t\t} else if ((extra_data & TD_TOK_IN) &&\n+\t\t\t\tpkt->len > td_length - CRC_SIZE) {\n+\t\t\tpkt->status = USB_TD_RX_DATA_UNDERUN;\n+\t\t}\n+\n+\t\tif (extra_data & TD_TOK_IN)\n+\t\t\tpkt->len = td_length - CRC_SIZE;\n+\t\telse if (pkt->info & PKT_ZLP)\n+\t\t\tpkt->len = 0;\n+\t\telse\n+\t\t\tpkt->len = td_length;\n+\n+\t\ttransaction_confirm(usb, pkt);\n+\t}\n+}\n+\n+/*\n+ * Submitting a data frame to a specified endpoint of a USB device\n+ * The frame is put in the driver's transmit queue for this endpoint\n+ *\n+ * Arguments:\n+ * usb A pointer to the USB structure\n+ * pkt A pointer to the user frame structure\n+ * trans_type Transaction tyep - IN,OUT or SETUP\n+ * dest_addr Device address - 0~127\n+ * dest_ep Endpoint number of the device - 0~16\n+ * trans_mode Pipe type - ISO,Interrupt,bulk or control\n+ * dest_speed USB speed - Low speed or FULL speed\n+ * data_toggle Data sequence toggle - 0 or 1\n+ */\n+static u32 host_transaction(struct fhci_usb *usb,\n+\t\t\t struct packet *pkt,\n+\t\t\t enum fhci_ta_type trans_type,\n+\t\t\t u8 dest_addr,\n+\t\t\t u8 dest_ep,\n+\t\t\t enum fhci_tf_mode trans_mode,\n+\t\t\t enum fhci_speed dest_speed, u8 data_toggle)\n+{\n+\tstruct endpoint *ep = usb->ep0;\n+\tstruct usb_td __iomem *td;\n+\tu16 extra_data;\n+\tu16 td_status;\n+\n+\tfhci_usb_disable_interrupt(usb);\n+\t/* start from the next BD that should be filled */\n+\ttd = ep->empty_td;\n+\ttd_status = in_be16(&td->status);\n+\n+\tif (td_status & TD_R && in_be16(&td->length)) {\n+\t\t/* if the TD is not free */\n+\t\tfhci_usb_enable_interrupt(usb);\n+\t\treturn -1;\n+\t}\n+\n+\t/* get the next TD in the ring */\n+\tep->empty_td = next_bd(ep->td_base, ep->empty_td, td_status);\n+\tfhci_usb_enable_interrupt(usb);\n+\tpkt->priv_data = td;\n+\tout_be32(&td->buf_ptr, virt_to_phys(pkt->data));\n+\t/* sets up transaction parameters - addr,endp,dir,and type */\n+\textra_data = (dest_ep << TD_ENDP_SHIFT) | dest_addr;\n+\tswitch (trans_type) {\n+\tcase FHCI_TA_IN:\n+\t\textra_data |= TD_TOK_IN;\n+\t\tbreak;\n+\tcase FHCI_TA_OUT:\n+\t\textra_data |= TD_TOK_OUT;\n+\t\tbreak;\n+\tcase FHCI_TA_SETUP:\n+\t\textra_data |= TD_TOK_SETUP;\n+\t\tbreak;\n+\t}\n+\tif (trans_mode == FHCI_TF_ISO)\n+\t\textra_data |= TD_ISO;\n+\tout_be16(&td->extra, extra_data);\n+\n+\t/* sets up the buffer descriptor */\n+\ttd_status = ((td_status & TD_W) | TD_R | TD_L | TD_I | TD_CNF);\n+\tif (!(pkt->info & PKT_NO_CRC))\n+\t\ttd_status |= TD_TC;\n+\n+\tswitch (trans_type) {\n+\tcase FHCI_TA_IN:\n+\t\tif (data_toggle)\n+\t\t\tpkt->info |= PKT_PID_DATA1;\n+\t\telse\n+\t\t\tpkt->info |= PKT_PID_DATA0;\n+\t\tbreak;\n+\tdefault:\n+\t\tif (data_toggle) {\n+\t\t\ttd_status |= TD_PID_DATA1;\n+\t\t\tpkt->info |= PKT_PID_DATA1;\n+\t\t} else {\n+\t\t\ttd_status |= TD_PID_DATA0;\n+\t\t\tpkt->info |= PKT_PID_DATA0;\n+\t\t}\n+\t\tbreak;\n+\t}\n+\n+\tif ((dest_speed == FHCI_LOW_SPEED) &&\n+\t (usb->port_status == FHCI_PORT_FULL))\n+\t\ttd_status |= TD_LSP;\n+\n+\tout_be16(&td->status, td_status);\n+\n+\t/* set up buffer length */\n+\tif (trans_type == FHCI_TA_IN)\n+\t\tout_be16(&td->length, pkt->len + CRC_SIZE);\n+\telse\n+\t\tout_be16(&td->length, pkt->len);\n+\n+\t/* put the frame to the confirmation queue */\n+\tcq_put(ep->conf_frame_Q, pkt);\n+\n+\tif (cq_howmany(ep->conf_frame_Q) == 1)\n+\t\tout_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);\n+\n+\treturn 0;\n+}\n+\n+/* Reset the Tx BD ring */\n+static void flush_bds(struct fhci_usb *usb)\n+{\n+\tu16 extra_data;\n+\tu16 td_status;\n+\tu32 buf;\n+\tstruct usb_td __iomem *td;\n+\tstruct endpoint *ep = usb->ep0;\n+\n+\ttd = ep->td_base;\n+\twhile (1) {\n+\t\ttd_status = in_be16(&td->status);\n+\t\tbuf = in_be32(&td->buf_ptr);\n+\t\textra_data = in_be16(&td->extra);\n+\n+\t\t/* if the TD is not empty - we'll confirm it as Timeout */\n+\t\tif (td_status & TD_R)\n+\t\t\tout_be16(&td->status, (td_status & ~TD_R) | TD_TO);\n+\t\t/* if this TD is dummy - let's skip this TD */\n+\t\telse if (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER)\n+\t\t\tout_be32(&td->buf_ptr, DUMMY2_BD_BUFFER);\n+\t\t/* if this is the last TD - break */\n+\t\tif (td_status & TD_W)\n+\t\t\tbreak;\n+\n+\t\ttd++;\n+\t}\n+\n+\ttd_transaction_confirm(usb);\n+\n+\ttd = ep->td_base;\n+\tdo {\n+\t\tout_be16(&td->status, 0);\n+\t\tout_be16(&td->length, 0);\n+\t\tout_be32(&td->buf_ptr, 0);\n+\t\tout_be16(&td->extra, 0);\n+\t\ttd++;\n+\t} while (!(in_be16(&td->status) & TD_W));\n+\tout_be16(&td->status, TD_W); /* for last TD set Wrap bit */\n+\tout_be16(&td->length, 0);\n+\tout_be32(&td->buf_ptr, 0);\n+\tout_be16(&td->extra, 0);\n+\n+\tout_be16(&ep->ep_pram_ptr->tx_bd_ptr,\n+\t\t in_be16(&ep->ep_pram_ptr->tx_base));\n+\tout_be32(&ep->ep_pram_ptr->tx_state, 0);\n+\tout_be16(&ep->ep_pram_ptr->tx_cnt, 0);\n+\tep->empty_td = ep->td_base;\n+\tep->conf_td = ep->td_base;\n+}\n+\n+/*\n+ * Flush all transmitted packets from TDs in the actual frame.\n+ * This routine is called when something wrong with the controller and\n+ * we want to get rid of the actual frame and start again next frame\n+ */\n+static void flush_actual_frame(struct fhci_usb *usb)\n+{\n+\tu8 mode;\n+\tu16 tb_ptr;\n+\tu16 extra_data;\n+\tu16 td_status;\n+\tu32 buf_ptr;\n+\tstruct usb_td __iomem *td;\n+\tstruct endpoint *ep = usb->ep0;\n+\n+\t/* disable the USB controller */\n+\tmode = in_8(&usb->fhci->regs->usb_mod);\n+\tout_8(&usb->fhci->regs->usb_mod, mode & ~USB_MODE_EN);\n+\n+\ttb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr);\n+\ttd = cpm_muram_addr(tb_ptr);\n+\ttd_status = in_be16(&td->status);\n+\tbuf_ptr = in_be32(&td->buf_ptr);\n+\textra_data = in_be16(&td->extra);\n+\tdo {\n+\t\tif (td_status & TD_R) {\n+\t\t\tout_be16(&td->status, (td_status & ~TD_R) | TD_TO);\n+\t\t} else {\n+\t\t\tout_be32(&td->buf_ptr, 0);\n+\t\t\tep->already_pushed_dummy_bd = false;\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\t/* advance the TD pointer */\n+\t\ttd = next_bd(ep->td_base, td, td_status);\n+\t\ttd_status = in_be16(&td->status);\n+\t\tbuf_ptr = in_be32(&td->buf_ptr);\n+\t\textra_data = in_be16(&td->extra);\n+\t} while ((td_status & TD_R) || buf_ptr);\n+\n+\ttd_transaction_confirm(usb);\n+\n+\tout_be16(&ep->ep_pram_ptr->tx_bd_ptr,\n+\t\t in_be16(&ep->ep_pram_ptr->tx_base));\n+\tout_be32(&ep->ep_pram_ptr->tx_state, 0);\n+\tout_be16(&ep->ep_pram_ptr->tx_cnt, 0);\n+\tep->empty_td = ep->td_base;\n+\tep->conf_td = ep->td_base;\n+\n+\tusb->actual_frame->frame_status = FRAME_TIMER_END_TRANSMISSION;\n+\n+\t/* reset the event register */\n+\tout_be16(&usb->fhci->regs->usb_event, 0xffff);\n+\t/* enable the USB controller */\n+\tout_8(&usb->fhci->regs->usb_mod, mode | USB_MODE_EN);\n+}\n+\n+/* handles Tx confirm and Tx error interrupt */\n+static void tx_conf_interrupt(struct fhci_usb *usb)\n+{\n+\ttd_transaction_confirm(usb);\n+\n+\t/*\n+\t * Schedule another transaction to this frame only if we have\n+\t * already confirmed all transaction in the frame.\n+\t */\n+\tif (((get_sof_timer_count(usb) < usb->max_frame_usage) ||\n+\t (usb->actual_frame->frame_status & FRAME_END_TRANSMISSION)) &&\n+\t (list_empty(&usb->actual_frame->tds_list)))\n+\t\tschedule_transactions(usb);\n+}\n+\n+static void host_transmit_actual_frame(struct fhci_usb *usb)\n+{\n+\tu16 tb_ptr;\n+\tu16 td_status;\n+\tstruct usb_td __iomem *td;\n+\tstruct endpoint *ep = usb->ep0;\n+\n+\ttb_ptr = in_be16(&ep->ep_pram_ptr->tx_bd_ptr);\n+\ttd = cpm_muram_addr(tb_ptr);\n+\n+\tif (in_be32(&td->buf_ptr) == DUMMY_BD_BUFFER) {\n+\t\tstruct usb_td __iomem *old_td = td;\n+\n+\t\tep->already_pushed_dummy_bd = false;\n+\t\ttd_status = in_be16(&td->status);\n+\t\t/* gets the next TD in the ring */\n+\t\ttd = next_bd(ep->td_base, td, td_status);\n+\t\ttb_ptr = cpm_muram_offset(td);\n+\t\tout_be16(&ep->ep_pram_ptr->tx_bd_ptr, tb_ptr);\n+\n+\t\t/* start transmit only if we have something in the TDs */\n+\t\tif (in_be16(&td->status) & TD_R)\n+\t\t\tout_8(&usb->fhci->regs->usb_comm, USB_CMD_STR_FIFO);\n+\n+\t\tif (in_be32(&ep->conf_td->buf_ptr) == DUMMY_BD_BUFFER) {\n+\t\t\tout_be32(&old_td->buf_ptr, 0);\n+\t\t\tep->conf_td = next_bd(ep->td_base, ep->conf_td,\n+\t\t\t\t\t td_status);\n+\t\t} else {\n+\t\t\tout_be32(&old_td->buf_ptr, DUMMY2_BD_BUFFER);\n+\t\t}\n+\t}\n+}\ndiff --git a/drivers/usb/host/fhci.h b/drivers/usb/host/fhci.h\nnew file mode 100644\nindex 0000000..3df6b21\n--- /dev/null\n+++ b/drivers/usb/host/fhci.h\n@@ -0,0 +1,526 @@\n+/*\n+ * Freescale QUICC Engine USB Host Controller Driver\n+ *\n+ * Copyright (c) Freescale Semicondutor, Inc. 2006.\n+ * Shlomi Gridish <gridish@freescale.com>\n+ * Jerry Huang <Chang-Ming.Huang@freescale.com>\n+ * Copyright (c) Logic Product Development, Inc. 2007\n+ * Peter Barada <peterb@logicpd.com>\n+ * Copyright (c) MontaVista Software, Inc. 2008.\n+ * Anton Vorontsov <avorontsov@ru.mvista.com>\n+ *\n+ * This program is free software; you can redistribute it and/or modify it\n+ * under the terms of the GNU General Public License as published by the\n+ * Free Software Foundation; either version 2 of the License, or (at your\n+ * option) any later version.\n+ */\n+\n+#ifndef __FHCI_H\n+#define __FHCI_H\n+\n+#define USB_CLOCK\t48000000\n+\n+#define FHCI_PRAM_SIZE 0x100\n+\n+#define MAX_EDS\t\t32\n+#define MAX_TDS\t\t32\n+\n+\n+/* CRC16 field size */\n+#define CRC_SIZE 2\n+\n+/* USB protocol overhead for each frame transmitted from the host */\n+#define PROTOCOL_OVERHEAD 7\n+\n+/* Packet structure, info field */\n+#define PKT_PID_DATA0\t\t0x80000000 /* PID - Data toggle zero */\n+#define PKT_PID_DATA1\t\t0x40000000 /* PID - Data toggle one */\n+#define PKT_PID_SETUP\t\t0x20000000 /* PID - Setup bit */\n+#define PKT_SETUP_STATUS\t0x10000000 /* Setup status bit */\n+#define PKT_SETADDR_STATUS\t0x08000000 /* Set address status bit */\n+#define PKT_SET_HOST_LAST\t0x04000000 /* Last data packet */\n+#define PKT_HOST_DATA\t\t0x02000000 /* Data packet */\n+#define PKT_FIRST_IN_FRAME\t0x01000000 /* First packet in the frame */\n+#define PKT_TOKEN_FRAME\t\t0x00800000 /* Token packet */\n+#define PKT_ZLP\t\t\t0x00400000 /* Zero length packet */\n+#define PKT_IN_TOKEN_FRAME\t0x00200000 /* IN token packet */\n+#define PKT_OUT_TOKEN_FRAME\t0x00100000 /* OUT token packet */\n+#define PKT_SETUP_TOKEN_FRAME\t0x00080000 /* SETUP token packet */\n+#define PKT_STALL_FRAME\t\t0x00040000 /* STALL packet */\n+#define PKT_NACK_FRAME\t\t0x00020000 /* NACK packet */\n+#define PKT_NO_PID\t\t0x00010000 /* No PID */\n+#define PKT_NO_CRC\t\t0x00008000 /* don't append CRC */\n+#define PKT_HOST_COMMAND\t0x00004000 /* Host command packet */\n+#define PKT_DUMMY_PACKET\t0x00002000 /* Dummy packet, used for mmm */\n+#define PKT_LOW_SPEED_PACKET\t0x00001000 /* Low-Speed packet */\n+\n+#define TRANS_OK\t\t(0)\n+#define TRANS_INPROGRESS\t(-1)\n+#define TRANS_DISCARD\t\t(-2)\n+#define TRANS_FAIL\t\t(-3)\n+\n+#define PS_INT\t\t0\n+#define PS_DISCONNECTED\t1\n+#define PS_CONNECTED\t2\n+#define PS_READY\t3\n+#define PS_MISSING\t4\n+\n+/* Transfer Descriptor status field */\n+#define USB_TD_OK\t\t0x00000000 /* TD transmited or received ok */\n+#define USB_TD_INPROGRESS\t0x80000000 /* TD is being transmitted */\n+#define USB_TD_RX_ER_NONOCT\t0x40000000 /* Tx Non Octet Aligned Packet */\n+#define USB_TD_RX_ER_BITSTUFF\t0x20000000 /* Frame Aborted-Received pkt */\n+#define USB_TD_RX_ER_CRC\t0x10000000 /* CRC error */\n+#define USB_TD_RX_ER_OVERUN\t0x08000000 /* Over - run occured */\n+#define USB_TD_RX_ER_PID\t0x04000000 /* wrong PID received */\n+#define USB_TD_RX_DATA_UNDERUN\t0x02000000 /* shorter than expected */\n+#define USB_TD_RX_DATA_OVERUN\t0x01000000 /* longer than expected */\n+#define USB_TD_TX_ER_NAK\t0x00800000 /* NAK handshake */\n+#define USB_TD_TX_ER_STALL\t0x00400000 /* STALL handshake */\n+#define USB_TD_TX_ER_TIMEOUT\t0x00200000 /* transmit time out */\n+#define USB_TD_TX_ER_UNDERUN\t0x00100000 /* transmit underrun */\n+\n+#define USB_TD_ERROR (USB_TD_RX_ER_NONOCT | USB_TD_RX_ER_BITSTUFF | \\\n+\t\tUSB_TD_RX_ER_CRC | USB_TD_RX_ER_OVERUN | USB_TD_RX_ER_PID | \\\n+\t\tUSB_TD_RX_DATA_UNDERUN | USB_TD_RX_DATA_OVERUN | \\\n+\t\tUSB_TD_TX_ER_NAK | USB_TD_TX_ER_STALL | \\\n+\t\tUSB_TD_TX_ER_TIMEOUT | USB_TD_TX_ER_UNDERUN)\n+\n+/* Transfer Descriptor toggle field */\n+#define USB_TD_TOGGLE_DATA0\t0\n+#define USB_TD_TOGGLE_DATA1\t1\n+#define USB_TD_TOGGLE_CARRY\t2\n+\n+/* #define MULTI_DATA_BUS */\n+\n+/* Bus mode register RBMR/TBMR */\n+#define BUS_MODE_GBL\t0x20\t/* Global snooping */\n+#define BUS_MODE_BO\t0x18\t/* Byte ordering */\n+#define BUS_MODE_BO_BE\t0x10\t/* Byte ordering - Big-endian */\n+#define BUS_MODE_DTB\t0x02\t/* Data bus */\n+\n+/* FHCI QE USB Register Description */\n+\n+/* USB Mode Register bit define */\n+#define USB_MODE_EN\t\t0x01\n+#define USB_MODE_HOST\t\t0x02\n+#define USB_MODE_TEST\t\t0x04\n+#define USB_MODE_SFTE\t\t0x08\n+#define USB_MODE_RESUME\t\t0x40\n+#define USB_MODE_LSS\t\t0x80\n+\n+/* USB Slave Address Register Mask */\n+#define USB_SLVADDR_MASK\t0x7F\n+\n+/* USB Endpoint register define */\n+#define USB_EPNUM_MASK\t\t0xF000\n+#define USB_EPNUM_SHIFT\t\t12\n+\n+#define USB_TRANS_MODE_SHIFT\t8\n+#define USB_TRANS_CTR\t\t0x0000\n+#define USB_TRANS_INT\t\t0x0100\n+#define USB_TRANS_BULK\t\t0x0200\n+#define USB_TRANS_ISO\t\t0x0300\n+\n+#define USB_EP_MF\t\t0x0020\n+#define USB_EP_RTE\t\t0x0010\n+\n+#define USB_THS_SHIFT\t\t2\n+#define USB_THS_MASK\t\t0x000c\n+#define USB_THS_NORMAL\t\t0x0\n+#define USB_THS_IGNORE_IN\t0x0004\n+#define USB_THS_NACK\t\t0x0008\n+#define USB_THS_STALL\t\t0x000c\n+\n+#define USB_RHS_SHIFT \t0\n+#define USB_RHS_MASK\t\t0x0003\n+#define USB_RHS_NORMAL \t0x0\n+#define USB_RHS_IGNORE_OUT\t0x0001\n+#define USB_RHS_NACK\t\t0x0002\n+#define USB_RHS_STALL\t\t0x0003\n+\n+#define USB_RTHS_MASK\t\t0x000f\n+\n+/* USB Command Register define */\n+#define USB_CMD_STR_FIFO\t0x80\n+#define USB_CMD_FLUSH_FIFO\t0x40\n+#define USB_CMD_ISFT\t\t0x20\n+#define USB_CMD_DSFT\t\t0x10\n+#define USB_CMD_EP_MASK\t\t0x03\n+\n+/* USB Event and Mask Register define */\n+#define USB_E_MSF_MASK\t\t0x0800\n+#define USB_E_SFT_MASK\t\t0x0400\n+#define USB_E_RESET_MASK\t0x0200\n+#define USB_E_IDLE_MASK\t\t0x0100\n+#define USB_E_TXE4_MASK\t\t0x0080\n+#define USB_E_TXE3_MASK\t\t0x0040\n+#define USB_E_TXE2_MASK\t\t0x0020\n+#define USB_E_TXE1_MASK\t\t0x0010\n+#define USB_E_SOF_MASK\t\t0x0008\n+#define USB_E_BSY_MASK\t\t0x0004\n+#define USB_E_TXB_MASK\t\t0x0002\n+#define USB_E_RXB_MASK\t\t0x0001\n+\n+/* Freescale USB Host controller registers */\n+struct fhci_regs {\n+\tu8 usb_mod;\t\t/* mode register */\n+\tu8 usb_addr;\t\t/* address register */\n+\tu8 usb_comm;\t\t/* command register */\n+\tu8 reserved1[1];\n+\t__be16 usb_ep[4];\t/* endpoint register */\n+\tu8 reserved2[4];\n+\t__be16 usb_event;\t/* event register */\n+\tu8 reserved3[2];\n+\t__be16 usb_mask;\t/* mask register */\n+\tu8 reserved4[1];\n+\tu8 usb_status;\t\t/* status register */\n+\t__be16 usb_sof_tmr;\t/* Start Of Frame timer */\n+\tu8 reserved5[2];\n+\t__be16 usb_frame_num;\t/* frame number register */\n+\tu8 reserved6[1];\n+};\n+\n+/* Freescale USB HOST */\n+struct fhci_pram {\n+\t__be16 ep_ptr[4];\t/* Endpoint porter reg */\n+\t__be32 rx_state;\t/* Rx internal state */\n+\t__be32 rx_ptr;\t\t/* Rx internal data pointer */\n+\t__be16 frame_num;\t/* Frame number */\n+\t__be16 rx_cnt;\t\t/* Rx byte count */\n+\t__be32 rx_temp;\t\t/* Rx temp */\n+\t__be32 rx_data_temp;\t/* Rx data temp */\n+\t__be16 rx_u_ptr;\t/* Rx microcode return address temp */\n+\tu8 reserved1[2];\t/* reserved area */\n+\t__be32 sof_tbl;\t\t/* SOF lookup table pointer */\n+\tu8 sof_u_crc_temp;\t/* SOF micorcode CRC5 temp reg */\n+\tu8 reserved2[0xdb];\n+};\n+\n+/* Freescale USB Endpoint*/\n+struct fhci_ep_pram {\n+\t__be16 rx_base;\t\t/* Rx BD base address */\n+\t__be16 tx_base;\t\t/* Tx BD base address */\n+\tu8 rx_func_code;\t/* Rx function code */\n+\tu8 tx_func_code;\t/* Tx function code */\n+\t__be16 rx_buff_len;\t/* Rx buffer length */\n+\t__be16 rx_bd_ptr;\t/* Rx BD pointer */\n+\t__be16 tx_bd_ptr;\t/* Tx BD pointer */\n+\t__be32 tx_state;\t/* Tx internal state */\n+\t__be32 tx_ptr;\t\t/* Tx internal data pointer */\n+\t__be16 tx_crc;\t\t/* temp transmit CRC */\n+\t__be16 tx_cnt;\t\t/* Tx byte count */\n+\t__be32 tx_temp;\t\t/* Tx temp */\n+\t__be16 tx_u_ptr;\t/* Tx microcode return address temp */\n+\t__be16 reserved;\n+};\n+\n+struct fhci_controller_list {\n+\tstruct list_head ctrl_list;\t/* control endpoints */\n+\tstruct list_head bulk_list;\t/* bulk endpoints */\n+\tstruct list_head iso_list;\t/* isochronous endpoints */\n+\tstruct list_head intr_list;\t/* interruput endpoints */\n+\tstruct list_head done_list;\t/* done transfers */\n+};\n+\n+struct virtual_root_hub {\n+\tint dev_num;\t/* USB address of the root hub */\n+\tu32 feature;\t/* indicates what feature has been set */\n+\tstruct usb_hub_status hub;\n+\tstruct usb_port_status port;\n+};\n+\n+enum fhci_gpios {\n+\tGPIO_USBOE = 0,\n+\tGPIO_USBTP,\n+\tGPIO_USBTN,\n+\tGPIO_USBRP,\n+\tGPIO_USBRN,\n+\t/* these are optional */\n+\tGPIO_SPEED,\n+\tGPIO_POWER,\n+};\n+\n+#define NUM_GPIOS (GPIO_POWER + 1)\n+\n+struct fhci_hcd {\n+\tstruct fhci_regs __iomem *regs;\t/* I/O memory used to communicate */\n+\tstruct fhci_pram __iomem *pram;\t/* Parameter RAM */\n+\tstruct gtm_timer *timer;\n+\tint gpios[NUM_GPIOS];\n+\tenum qe_clock fullspeed_clk;\n+\tenum qe_clock lowspeed_clk;\n+\n+\tspinlock_t lock;\n+\tstruct fhci_usb *usb_lld; /* Low-level driver */\n+\tstruct virtual_root_hub *vroot_hub; /* the virtual root hub */\n+\tint active_urbs;\n+\tstruct fhci_controller_list *hc_list;\n+\tstruct tasklet_struct *process_done_task; /* tasklet for done list */\n+\n+\tstruct list_head empty_eds;\n+\tstruct list_head empty_tds;\n+\n+#ifdef CONFIG_FHCI_DEBUG\n+\tint usb_irq_stat[13];\n+\tstruct dentry *dfs_root;\n+\tstruct dentry *dfs_regs;\n+\tstruct dentry *dfs_irq_stat;\n+#endif\n+};\n+\n+#define USB_FRAME_USAGE 90\n+#define FRAME_TIME_USAGE (USB_FRAME_USAGE*10)\t/* frame time usage */\n+#define SW_FIX_TIME_BETWEEN_TRANSACTION 150\t/* SW */\n+#define MAX_BYTES_PER_FRAME (USB_FRAME_USAGE*15)\n+#define MAX_PERIODIC_FRAME_USAGE 90\n+\n+/* transaction type */\n+enum fhci_ta_type {\n+\tFHCI_TA_IN = 0,\t/* input transaction */\n+\tFHCI_TA_OUT,\t/* output transaction */\n+\tFHCI_TA_SETUP,\t/* setup transaction */\n+};\n+\n+/* transfer mode */\n+enum fhci_tf_mode {\n+\tFHCI_TF_CTRL = 0,\n+\tFHCI_TF_ISO,\n+\tFHCI_TF_BULK,\n+\tFHCI_TF_INTR,\n+};\n+\n+enum fhci_speed {\n+\tFHCI_FULL_SPEED,\n+\tFHCI_LOW_SPEED,\n+};\n+\n+/* endpoint state */\n+enum fhci_ed_state {\n+\tFHCI_ED_NEW = 0, /* pipe is new */\n+\tFHCI_ED_OPER, /* pipe is operating */\n+\tFHCI_ED_URB_DEL, /* pipe is in hold because urb is being deleted */\n+\tFHCI_ED_SKIP, /* skip this pipe */\n+\tFHCI_ED_HALTED, /* pipe is halted */\n+};\n+\n+enum fhci_port_status {\n+\tFHCI_PORT_POWER_OFF = 0,\n+\tFHCI_PORT_DISABLED,\n+\tFHCI_PORT_DISCONNECTING,\n+\tFHCI_PORT_WAITING, /* waiting for connection */\n+\tFHCI_PORT_FULL, /* full speed connected */\n+\tFHCI_PORT_LOW, /* low speed connected */\n+};\n+\n+enum fhci_mem_alloc {\n+\tMEM_CACHABLE_SYS = 0x00000001,\t/* primary DDR,cachable */\n+\tMEM_NOCACHE_SYS = 0x00000004,\t/* primary DDR,non-cachable */\n+\tMEM_SECONDARY = 0x00000002,\t/* either secondary DDR or SDRAM */\n+\tMEM_PRAM = 0x00000008,\t/* multi-user RAM identifier */\n+};\n+\n+/* USB default parameters*/\n+#define DEFAULT_RING_LEN\t8\n+#define DEFAULT_DATA_MEM\tMEM_CACHABLE_SYS\n+\n+struct ed {\n+\tu8 dev_addr;\t\t/* device address */\n+\tu8 ep_addr;\t\t/* endpoint address */\n+\tenum fhci_tf_mode mode;\t/* USB transfer mode */\n+\tenum fhci_speed speed;\n+\tunsigned int max_pkt_size;\n+\tenum fhci_ed_state state;\n+\tstruct list_head td_list; /* a list of all queued TD to this pipe */\n+\tstruct list_head node;\n+\n+\t/* read only parameters, should be cleared upon initialization */\n+\tu8 toggle_carry;\t/* toggle carry from the last TD submitted */\n+\tu32 last_iso;\t\t/* time stamp of last queued ISO transfer */\n+\tstruct td *td_head;\t/* a pointer to the current TD handled */\n+};\n+\n+struct td {\n+\tvoid *data;\t\t /* a pointer to the data buffer */\n+\tunsigned int len;\t /* length of the data to be submitted */\n+\tunsigned int actual_len; /* actual bytes transfered on this td */\n+\tenum fhci_ta_type type;\t /* transaction type */\n+\tu8 toggle;\t\t /* toggle for the next transwithin this TD */\n+\tu16 iso_index;\t\t /* ISO transaction index */\n+\tu16 start_frame;\t /* start frame time stamp */\n+\tu16 interval;\t\t /* interval between transaction (for ISO/Intr) */\n+\tu32 status;\t\t /* status of the TD */\n+\tstruct ed *ed;\t\t /* a handle to the corresponding ED */\n+\tstruct urb *urb;\t /* a handle to the corresponding URB */\n+\tbool ioc;\t\t /* Inform On Completion */\n+\tstruct list_head node;\n+\n+\t/* read only parameters should be cleared upon initialization */\n+\tstruct packet *pkt;\n+\tint nak_cnt;\n+\tint error_cnt;\n+\tstruct list_head frame_lh;\n+};\n+\n+struct packet {\n+\tu8 *data;\t/* packet data */\n+\tu32 len;\t/* packet length */\n+\tu32 status;\t/* status of the packet - equivalent to the status\n+\t\t\t * field for the corresponding structure td */\n+\tu32 info;\t/* packet information */\n+\tvoid __iomem *priv_data; /* private data of the driver (TDs or BDs) */\n+};\n+\n+/* struct for each URB */\n+#define URB_INPROGRESS\t0\n+#define URB_DEL\t\t1\n+\n+/* URB states (state field) */\n+#define US_BULK\t\t0\n+#define US_BULK0\t1\n+\n+/* three setup states */\n+#define US_CTRL_SETUP\t2\n+#define US_CTRL_DATA\t1\n+#define US_CTRL_ACK\t0\n+\n+#define EP_ZERO\t0\n+\n+struct urb_priv {\n+\tint num_of_tds;\n+\tint tds_cnt;\n+\tint state;\n+\n+\tstruct td **tds;\n+\tstruct ed *ed;\n+\tstruct timer_list time_out;\n+};\n+\n+/* struct for each 1mSec frame time */\n+#define FRAME_IS_TRANSMITTED\t\t0x00\n+#define FRAME_TIMER_END_TRANSMISSION\t0x01\n+#define FRAME_DATA_END_TRANSMISSION\t0x02\n+#define FRAME_END_TRANSMISSION\t\t0x03\n+#define FRAME_IS_PREPARED\t\t0x04\n+\n+struct fhci_time_frame {\n+\tu16 frame_num;\t /* frame number */\n+\tu16 total_bytes; /* total bytes submitted within this frame */\n+\tu8 frame_status; /* flag that indicates to stop fill this frame */\n+\tstruct list_head tds_list; /* all tds of this frame */\n+};\n+\n+/* internal driver structure*/\n+struct fhci_usb {\n+\tu16 saved_msk;\t\t /* saving of the USB mask register */\n+\tstruct endpoint *ep0;\t /* pointer for endpoint0 structure */\n+\tint intr_nesting_cnt;\t /* interrupt nesting counter */\n+\tu16 max_frame_usage;\t /* max frame time usage,in micro-sec */\n+\tu16 max_bytes_per_frame; /* max byte can be tx in one time frame */\n+\tu32 sw_transaction_time; /* sw complete trans time,in micro-sec */\n+\tstruct fhci_time_frame *actual_frame;\n+\tstruct fhci_controller_list *hc_list;\t/* main structure for hc */\n+\tstruct virtual_root_hub *vroot_hub;\n+\tenum fhci_port_status port_status;\t/* v_rh port status */\n+\n+\tu32 (*transfer_confirm)(struct fhci_hcd *fhci);\n+\n+\tstruct fhci_hcd *fhci;\n+};\n+\n+/*\n+ * Various helpers and prototypes below.\n+ */\n+\n+static void move_head_to_tail(struct list_head *list)\n+{\n+\tstruct list_head *node = list->next;\n+\n+\tif (!list_empty(list)) {\n+\t\tlist_del(node);\n+\t\tlist_add_tail(node, list);\n+\t}\n+}\n+\n+/* maps the hardware error code to the USB error code */\n+static int status_to_error(u32 status)\n+{\n+\tif (status == USB_TD_OK)\n+\t\treturn 0;\n+\telse if (status & USB_TD_RX_ER_CRC)\n+\t\treturn -EILSEQ;\n+\telse if (status & USB_TD_RX_ER_NONOCT)\n+\t\treturn -EPROTO;\n+\telse if (status & USB_TD_RX_ER_OVERUN)\n+\t\treturn -ECOMM;\n+\telse if (status & USB_TD_RX_ER_BITSTUFF)\n+\t\treturn -EPROTO;\n+\telse if (status & USB_TD_RX_ER_PID)\n+\t\treturn -EILSEQ;\n+\telse if (status & (USB_TD_TX_ER_NAK | USB_TD_TX_ER_TIMEOUT))\n+\t\treturn -ETIMEDOUT;\n+\telse if (status & USB_TD_TX_ER_STALL)\n+\t\treturn -EPIPE;\n+\telse if (status & USB_TD_TX_ER_UNDERUN)\n+\t\treturn -ENOSR;\n+\telse if (status & USB_TD_RX_DATA_UNDERUN)\n+\t\treturn -EREMOTEIO;\n+\telse if (status & USB_TD_RX_DATA_OVERUN)\n+\t\treturn -EOVERFLOW;\n+\telse\n+\t\treturn -EINVAL;\n+}\n+\n+static u16 get_frame_num(struct fhci_hcd *fhci)\n+{\n+\treturn in_be16(&fhci->pram->frame_num) & 0x07ff;\n+}\n+\n+#define fhci_dbg(fhci, fmt, args...) \\\n+\t\tdev_dbg(fhci_to_hcd(fhci)->self.controller, fmt, ##args)\n+#define fhci_vdbg(fhci, fmt, args...) \\\n+\t\tdev_vdbg(fhci_to_hcd(fhci)->self.controller, fmt, ##args)\n+#define fhci_err(fhci, fmt, args...) \\\n+\t\tdev_err(fhci_to_hcd(fhci)->self.controller, fmt, ##args)\n+#define fhci_info(fhci, fmt, args...) \\\n+\t\tdev_info(fhci_to_hcd(fhci)->self.controller, fmt, ##args)\n+#define fhci_warn(fhci, fmt, args...) \\\n+\t\tdev_warn(fhci_to_hcd(fhci)->self.controller, fmt, ##args)\n+\n+static struct fhci_hcd *hcd_to_fhci(struct usb_hcd *hcd)\n+{\n+\treturn (struct fhci_hcd *)hcd->hcd_priv;\n+}\n+\n+static struct usb_hcd *fhci_to_hcd(struct fhci_hcd *fhci)\n+{\n+\treturn container_of((void *)fhci, struct usb_hcd, hcd_priv);\n+}\n+\n+/* fhci-hcd.c */\n+static void fhci_start_sof_timer(struct fhci_hcd *fhci);\n+static void fhci_stop_sof_timer(struct fhci_hcd *fhci);\n+static u16 get_sof_timer_count(struct fhci_usb *usb);\n+static void fhci_usb_enable_interrupt(struct fhci_usb *usb);\n+static void fhci_usb_disable_interrupt(struct fhci_usb *usb);\n+static int fhci_ioports_check_bus_state(struct fhci_hcd *fhci);\n+\n+/* fhci-mem.c */\n+static void recycle_empty_td(struct fhci_hcd *fhci, struct td *td);\n+\n+/* fhci-{tds,bds}.c */\n+static void flush_bds(struct fhci_usb *usb);\n+static void flush_actual_frame(struct fhci_usb *usb);\n+static u32 host_transaction(struct fhci_usb *usb,\n+\tstruct packet *pkt, enum fhci_ta_type trans_type,\n+\tu8 dest_addr, u8 dest_ep, enum fhci_tf_mode trans_mode,\n+\tenum fhci_speed dest_speed, u8 data_toggle);\n+static void push_dummy_bd(struct endpoint *ep);\n+\n+/* fhci-sched.c */\n+static void transaction_confirm(struct fhci_usb *usb, struct packet *pkt);\n+static void flush_all_transmissions(struct fhci_usb *usb);\n+static void schedule_transactions(struct fhci_usb *usb);\n+static void device_connected_interrupt(struct fhci_hcd *fhci);\n+\n+#endif /* __FHCI_H */\n", "prefixes": [ "3/3" ] }