diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2008-09-11 03:11:24 -0700 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-09-11 03:11:24 -0700 |
| commit | 48413f29c85b608d373870ddd2ffedabc6f109f7 (patch) | |
| tree | 4bc7a800324694c815f4d8a0118972820e0eca5a /usb | |
| parent | c4c7f685d1b2434cb5974d09fc5f3238d2092114 (diff) | |
| download | patches-48413f29c85b608d373870ddd2ffedabc6f109f7.tar.gz | |
usb and driver core patches
Diffstat (limited to 'usb')
5 files changed, 3528 insertions, 0 deletions
diff --git a/usb/ohci-allow-broken-controllers-to-auto-stop.patch b/usb/ohci-allow-broken-controllers-to-auto-stop.patch new file mode 100644 index 00000000000000..9277efe10e2402 --- /dev/null +++ b/usb/ohci-allow-broken-controllers-to-auto-stop.patch @@ -0,0 +1,151 @@ +From stern+48acf28e@rowland.harvard.edu Thu Sep 11 02:39:45 2008 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Wed, 3 Sep 2008 16:38:32 -0400 (EDT) +Subject: OHCI: Allow broken controllers to auto-stop +To: Greg KH <greg@kroah.com> +Message-ID: <Pine.LNX.4.44L0.0809031637430.2281-100000@iolanthe.rowland.org> + + +This patch (as1134) attempts to improve the way we handle OHCI +controllers with broken Root Hub Status Change interrupt support. In +these controllers the RHSC interrupt bit essentially never turns off, +making RHSC interrupts useless -- they have to remain permanently +disabled. + +Such controllers should still be allowed to turn off their root hubs +when no devices are attached. Polling for new connections can +continue while the root hub is suspended. The patch implements this +feature. (It won't have much effect unless CONFIG_PM is enabled and +CONFIG_USB_SUSPEND is disabled, but since the overhead is very small +we may as well do it.) + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/host/ohci-hub.c | 60 +++++++++++++++++++++++--------------------- + 1 file changed, 32 insertions(+), 28 deletions(-) + +--- a/drivers/usb/host/ohci-hub.c ++++ b/drivers/usb/host/ohci-hub.c +@@ -362,18 +362,23 @@ static int ohci_root_hub_state_changes(s + int any_connected) + { + int poll_rh = 1; +- int rhsc; ++ int rhsc_status, rhsc_enable; + +- rhsc = ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC; +- switch (ohci->hc_control & OHCI_CTRL_HCFS) { ++ /* Some broken controllers never turn off RHCS in the interrupt ++ * status register. For their sake we won't re-enable RHSC ++ * interrupts if the interrupt bit is already active. ++ */ ++ rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) & ++ OHCI_INTR_RHSC; ++ rhsc_enable = ohci_readl(ohci, &ohci->regs->intrenable) & ++ OHCI_INTR_RHSC; + ++ switch (ohci->hc_control & OHCI_CTRL_HCFS) { + case OHCI_USB_OPER: +- /* If no status changes are pending, enable status-change +- * interrupts. +- */ +- if (!rhsc && !changed) { +- rhsc = OHCI_INTR_RHSC; +- ohci_writel(ohci, rhsc, &ohci->regs->intrenable); ++ /* If no status changes are pending, enable RHSC interrupts. */ ++ if (!rhsc_enable && !rhsc_status && !changed) { ++ rhsc_enable = OHCI_INTR_RHSC; ++ ohci_writel(ohci, rhsc_enable, &ohci->regs->intrenable); + } + + /* Keep on polling until we know a device is connected +@@ -383,7 +388,7 @@ static int ohci_root_hub_state_changes(s + if (any_connected || + !device_may_wakeup(&ohci_to_hcd(ohci) + ->self.root_hub->dev)) { +- if (rhsc) ++ if (rhsc_enable) + poll_rh = 0; + } else { + ohci->autostop = 1; +@@ -396,34 +401,36 @@ static int ohci_root_hub_state_changes(s + ohci->autostop = 0; + ohci->next_statechange = jiffies + + STATECHANGE_DELAY; +- } else if (rhsc && time_after_eq(jiffies, ++ } else if (time_after_eq(jiffies, + ohci->next_statechange) + && !ohci->ed_rm_list + && !(ohci->hc_control & + OHCI_SCHED_ENABLES)) { + ohci_rh_suspend(ohci, 1); +- poll_rh = 0; ++ if (rhsc_enable) ++ poll_rh = 0; + } + } + break; + +- /* if there is a port change, autostart or ask to be resumed */ + case OHCI_USB_SUSPEND: + case OHCI_USB_RESUME: ++ /* if there is a port change, autostart or ask to be resumed */ + if (changed) { + if (ohci->autostop) + ohci_rh_resume(ohci); + else + usb_hcd_resume_root_hub(ohci_to_hcd(ohci)); + } else { +- if (!rhsc && (ohci->autostop || ++ if (!rhsc_enable && !rhsc_status && (ohci->autostop || + ohci_to_hcd(ohci)->self.root_hub-> +- do_remote_wakeup)) +- ohci_writel(ohci, OHCI_INTR_RHSC, ++ do_remote_wakeup)) { ++ rhsc_enable = OHCI_INTR_RHSC; ++ ohci_writel(ohci, rhsc_enable, + &ohci->regs->intrenable); +- +- /* everything is idle, no need for polling */ +- poll_rh = 0; ++ } ++ if (rhsc_enable) ++ poll_rh = 0; + } + break; + } +@@ -443,12 +450,16 @@ static inline int ohci_rh_resume(struct + static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed, + int any_connected) + { ++ int rhsc_status; ++ + /* If RHSC is enabled, don't poll */ + if (ohci_readl(ohci, &ohci->regs->intrenable) & OHCI_INTR_RHSC) + return 0; + +- /* If no status changes are pending, enable status-change interrupts */ +- if (!changed) { ++ /* If no status changes are pending, enable RHSC interrupts */ ++ rhsc_status = ohci_readl(ohci, &ohci->regs->intrstatus) & ++ OHCI_INTR_RHSC; ++ if (!changed && !rhsc_status) { + ohci_writel(ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); + return 0; + } +@@ -492,13 +503,6 @@ ohci_hub_status_data (struct usb_hcd *hc + length++; + } + +- /* Some broken controllers never turn off RHCS in the interrupt +- * status register. For their sake we won't re-enable RHSC +- * interrupts if the flag is already set. +- */ +- if (ohci_readl(ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) +- changed = 1; +- + /* look at each port */ + for (i = 0; i < ohci->num_ports; i++) { + u32 status = roothub_portstatus (ohci, i); diff --git a/usb/usb-add-freescale-qe-cpm-usb-peripheral-controller-driver.patch b/usb/usb-add-freescale-qe-cpm-usb-peripheral-controller-driver.patch new file mode 100644 index 00000000000000..7e8da39812a6ab --- /dev/null +++ b/usb/usb-add-freescale-qe-cpm-usb-peripheral-controller-driver.patch @@ -0,0 +1,3257 @@ +From LeoLi@freescale.com Thu Sep 11 02:35:47 2008 +From: Li Yang <leoli@freescale.com> +Date: Tue, 2 Sep 2008 19:58:10 +0800 +Subject: usb: add Freescale QE/CPM USB peripheral controller driver +To: greg@kroah.com, dbrownell@users.sourceforge.net +Cc: <avorontsov@ru.mvista.com>, <arnd@arndb.de>, Li Yang <leoli@freescale.com> +Message-ID: <1220356690-8028-1-git-send-email-leoli@freescale.com> + + +Some of Freescale SoC chips have a QE or CPM co-processor which +supports full speed USB. The driver adds device mode support +of both QE and CPM USB controller to Linux USB gadget. The +driver is tested with MPC8360 and MPC8272, and should work with +other models having QE/CPM given minor tweaks. + +Signed-off-by: Xie Xiaobo <X.Xie@freescale.com> +Signed-off-by: Li Yang <leoli@freescale.com> +Acked-by: Arnd Bergmann <arnd@arndb.de> +Cc: David Brownell <david-b@pacbell.net> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/Kconfig | 19 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/fsl_qe_udc.c | 2723 ++++++++++++++++++++++++++++++++++++++ + drivers/usb/gadget/fsl_qe_udc.h | 436 ++++++ + drivers/usb/gadget/gadget_chips.h | 9 + 5 files changed, 3188 insertions(+) + +--- /dev/null ++++ b/drivers/usb/gadget/fsl_qe_udc.c +@@ -0,0 +1,2723 @@ ++/* ++ * driver/usb/gadget/fsl_qe_udc.c ++ * ++ * Copyright (c) 2006-2008 Freescale Semiconductor, Inc. All rights reserved. ++ * ++ * Xie Xiaobo <X.Xie@freescale.com> ++ * Li Yang <leoli@freescale.com> ++ * Based on bareboard code from Shlomi Gridish. ++ * ++ * Description: ++ * Freescle QE/CPM USB Pheripheral Controller Driver ++ * The controller can be found on MPC8360, MPC8272, and etc. ++ * MPC8360 Rev 1.1 may need QE mircocode update ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ */ ++ ++#undef USB_TRACE ++ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/init.h> ++#include <linux/ioport.h> ++#include <linux/types.h> ++#include <linux/errno.h> ++#include <linux/slab.h> ++#include <linux/list.h> ++#include <linux/interrupt.h> ++#include <linux/io.h> ++#include <linux/moduleparam.h> ++#include <linux/of_platform.h> ++#include <linux/dma-mapping.h> ++#include <linux/usb/ch9.h> ++#include <linux/usb/gadget.h> ++#include <linux/usb/otg.h> ++#include <asm/qe.h> ++#include <asm/cpm.h> ++#include <asm/dma.h> ++#include <asm/reg.h> ++#include "fsl_qe_udc.h" ++ ++#define DRIVER_DESC "Freescale QE/CPM USB Device Controller driver" ++#define DRIVER_AUTHOR "Xie XiaoBo" ++#define DRIVER_VERSION "1.0" ++ ++#define DMA_ADDR_INVALID (~(dma_addr_t)0) ++ ++static const char driver_name[] = "fsl_qe_udc"; ++static const char driver_desc[] = DRIVER_DESC; ++ ++/*ep name is important in gadget, it should obey the convention of ep_match()*/ ++static const char *const ep_name[] = { ++ "ep0-control", /* everyone has ep0 */ ++ /* 3 configurable endpoints */ ++ "ep1", ++ "ep2", ++ "ep3", ++}; ++ ++static struct usb_endpoint_descriptor qe_ep0_desc = { ++ .bLength = USB_DT_ENDPOINT_SIZE, ++ .bDescriptorType = USB_DT_ENDPOINT, ++ ++ .bEndpointAddress = 0, ++ .bmAttributes = USB_ENDPOINT_XFER_CONTROL, ++ .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD, ++}; ++ ++/* it is initialized in probe() */ ++static struct qe_udc *udc_controller; ++ ++/******************************************************************** ++ * Internal Used Function Start ++********************************************************************/ ++/*----------------------------------------------------------------- ++ * done() - retire a request; caller blocked irqs ++ *--------------------------------------------------------------*/ ++static void done(struct qe_ep *ep, struct qe_req *req, int status) ++{ ++ struct qe_udc *udc = ep->udc; ++ unsigned char stopped = ep->stopped; ++ ++ /* the req->queue pointer is used by ep_queue() func, in which ++ * the request will be added into a udc_ep->queue 'd tail ++ * so here the req will be dropped from the ep->queue ++ */ ++ list_del_init(&req->queue); ++ ++ /* req.status should be set as -EINPROGRESS in ep_queue() */ ++ if (req->req.status == -EINPROGRESS) ++ req->req.status = status; ++ else ++ status = req->req.status; ++ ++ if (req->mapped) { ++ dma_unmap_single(udc->gadget.dev.parent, ++ req->req.dma, req->req.length, ++ ep_is_in(ep) ++ ? DMA_TO_DEVICE ++ : DMA_FROM_DEVICE); ++ req->req.dma = DMA_ADDR_INVALID; ++ req->mapped = 0; ++ } else ++ dma_sync_single_for_cpu(udc->gadget.dev.parent, ++ req->req.dma, req->req.length, ++ ep_is_in(ep) ++ ? DMA_TO_DEVICE ++ : DMA_FROM_DEVICE); ++ ++ if (status && (status != -ESHUTDOWN)) ++ dev_vdbg(udc->dev, "complete %s req %p stat %d len %u/%u\n", ++ ep->ep.name, &req->req, status, ++ req->req.actual, req->req.length); ++ ++ /* don't modify queue heads during completion callback */ ++ ep->stopped = 1; ++ spin_unlock(&udc->lock); ++ ++ /* this complete() should a func implemented by gadget layer, ++ * eg fsg->bulk_in_complete() */ ++ if (req->req.complete) ++ req->req.complete(&ep->ep, &req->req); ++ ++ spin_lock(&udc->lock); ++ ++ ep->stopped = stopped; ++} ++ ++/*----------------------------------------------------------------- ++ * nuke(): delete all requests related to this ep ++ *--------------------------------------------------------------*/ ++static void nuke(struct qe_ep *ep, int status) ++{ ++ /* Whether this eq has request linked */ ++ while (!list_empty(&ep->queue)) { ++ struct qe_req *req = NULL; ++ req = list_entry(ep->queue.next, struct qe_req, queue); ++ ++ done(ep, req, status); ++ } ++} ++ ++/*---------------------------------------------------------------------------* ++ * USB and Endpoint manipulate process, include parameter and register * ++ *---------------------------------------------------------------------------*/ ++/* @value: 1--set stall 0--clean stall */ ++static int qe_eprx_stall_change(struct qe_ep *ep, int value) ++{ ++ u16 tem_usep; ++ u8 epnum = ep->epnum; ++ struct qe_udc *udc = ep->udc; ++ ++ tem_usep = in_be16(&udc->usb_regs->usb_usep[epnum]); ++ tem_usep = tem_usep & ~USB_RHS_MASK; ++ if (value == 1) ++ tem_usep |= USB_RHS_STALL; ++ else if (ep->dir == USB_DIR_IN) ++ tem_usep |= USB_RHS_IGNORE_OUT; ++ ++ out_be16(&udc->usb_regs->usb_usep[epnum], tem_usep); ++ return 0; ++} ++ ++static int qe_eptx_stall_change(struct qe_ep *ep, int value) ++{ ++ u16 tem_usep; ++ u8 epnum = ep->epnum; ++ struct qe_udc *udc = ep->udc; ++ ++ tem_usep = in_be16(&udc->usb_regs->usb_usep[epnum]); ++ tem_usep = tem_usep & ~USB_THS_MASK; ++ if (value == 1) ++ tem_usep |= USB_THS_STALL; ++ else if (ep->dir == USB_DIR_OUT) ++ tem_usep |= USB_THS_IGNORE_IN; ++ ++ out_be16(&udc->usb_regs->usb_usep[epnum], tem_usep); ++ ++ return 0; ++} ++ ++static int qe_ep0_stall(struct qe_udc *udc) ++{ ++ qe_eptx_stall_change(&udc->eps[0], 1); ++ qe_eprx_stall_change(&udc->eps[0], 1); ++ udc_controller->ep0_state = WAIT_FOR_SETUP; ++ udc_controller->ep0_dir = 0; ++ return 0; ++} ++ ++static int qe_eprx_nack(struct qe_ep *ep) ++{ ++ u8 epnum = ep->epnum; ++ struct qe_udc *udc = ep->udc; ++ ++ if (ep->state == EP_STATE_IDLE) { ++ /* Set the ep's nack */ ++ clrsetbits_be16(&udc->usb_regs->usb_usep[epnum], ++ USB_RHS_MASK, USB_RHS_NACK); ++ ++ /* Mask Rx and Busy interrupts */ ++ clrbits16(&udc->usb_regs->usb_usbmr, ++ (USB_E_RXB_MASK | USB_E_BSY_MASK)); ++ ++ ep->state = EP_STATE_NACK; ++ } ++ return 0; ++} ++ ++static int qe_eprx_normal(struct qe_ep *ep) ++{ ++ struct qe_udc *udc = ep->udc; ++ ++ if (ep->state == EP_STATE_NACK) { ++ clrsetbits_be16(&udc->usb_regs->usb_usep[ep->epnum], ++ USB_RTHS_MASK, USB_THS_IGNORE_IN); ++ ++ /* Unmask RX interrupts */ ++ out_be16(&udc->usb_regs->usb_usber, ++ USB_E_BSY_MASK | USB_E_RXB_MASK); ++ setbits16(&udc->usb_regs->usb_usbmr, ++ (USB_E_RXB_MASK | USB_E_BSY_MASK)); ++ ++ ep->state = EP_STATE_IDLE; ++ ep->has_data = 0; ++ } ++ ++ return 0; ++} ++ ++static int qe_ep_cmd_stoptx(struct qe_ep *ep) ++{ ++ if (ep->udc->soc_type == PORT_CPM) ++ cpm_command(CPM_USB_STOP_TX | (ep->epnum << CPM_USB_EP_SHIFT), ++ CPM_USB_STOP_TX_OPCODE); ++ else ++ qe_issue_cmd(QE_USB_STOP_TX, QE_CR_SUBBLOCK_USB, ++ ep->epnum, 0); ++ ++ return 0; ++} ++ ++static int qe_ep_cmd_restarttx(struct qe_ep *ep) ++{ ++ if (ep->udc->soc_type == PORT_CPM) ++ cpm_command(CPM_USB_RESTART_TX | (ep->epnum << ++ CPM_USB_EP_SHIFT), CPM_USB_RESTART_TX_OPCODE); ++ else ++ qe_issue_cmd(QE_USB_RESTART_TX, QE_CR_SUBBLOCK_USB, ++ ep->epnum, 0); ++ ++ return 0; ++} ++ ++static int qe_ep_flushtxfifo(struct qe_ep *ep) ++{ ++ struct qe_udc *udc = ep->udc; ++ int i; ++ ++ i = (int)ep->epnum; ++ ++ qe_ep_cmd_stoptx(ep); ++ out_8(&udc->usb_regs->usb_uscom, ++ USB_CMD_FLUSH_FIFO | (USB_CMD_EP_MASK & (ep->epnum))); ++ out_be16(&udc->ep_param[i]->tbptr, in_be16(&udc->ep_param[i]->tbase)); ++ out_be32(&udc->ep_param[i]->tstate, 0); ++ out_be16(&udc->ep_param[i]->tbcnt, 0); ++ ++ ep->c_txbd = ep->txbase; ++ ep->n_txbd = ep->txbase; ++ qe_ep_cmd_restarttx(ep); ++ return 0; ++} ++ ++static int qe_ep_filltxfifo(struct qe_ep *ep) ++{ ++ struct qe_udc *udc = ep->udc; ++ ++ out_8(&udc->usb_regs->usb_uscom, ++ USB_CMD_STR_FIFO | (USB_CMD_EP_MASK & (ep->epnum))); ++ return 0; ++} ++ ++static int qe_epbds_reset(struct qe_udc *udc, int pipe_num) ++{ ++ struct qe_ep *ep; ++ u32 bdring_len; ++ struct qe_bd __iomem *bd; ++ int i; ++ ++ ep = &udc->eps[pipe_num]; ++ ++ if (ep->dir == USB_DIR_OUT) ++ bdring_len = USB_BDRING_LEN_RX; ++ else ++ bdring_len = USB_BDRING_LEN; ++ ++ bd = ep->rxbase; ++ for (i = 0; i < (bdring_len - 1); i++) { ++ out_be32((u32 __iomem *)bd, R_E | R_I); ++ bd++; ++ } ++ out_be32((u32 __iomem *)bd, R_E | R_I | R_W); ++ ++ bd = ep->txbase; ++ for (i = 0; i < USB_BDRING_LEN_TX - 1; i++) { ++ out_be32(&bd->buf, 0); ++ out_be32((u32 __iomem *)bd, 0); ++ bd++; ++ } ++ out_be32((u32 __iomem *)bd, T_W); ++ ++ return 0; ++} ++ ++static int qe_ep_reset(struct qe_udc *udc, int pipe_num) ++{ ++ struct qe_ep *ep; ++ u16 tmpusep; ++ ++ ep = &udc->eps[pipe_num]; ++ tmpusep = in_be16(&udc->usb_regs->usb_usep[pipe_num]); ++ tmpusep &= ~USB_RTHS_MASK; ++ ++ switch (ep->dir) { ++ case USB_DIR_BOTH: ++ qe_ep_flushtxfifo(ep); ++ break; ++ case USB_DIR_OUT: ++ tmpusep |= USB_THS_IGNORE_IN; ++ break; ++ case USB_DIR_IN: ++ qe_ep_flushtxfifo(ep); ++ tmpusep |= USB_RHS_IGNORE_OUT; ++ break; ++ default: ++ break; ++ } ++ out_be16(&udc->usb_regs->usb_usep[pipe_num], tmpusep); ++ ++ qe_epbds_reset(udc, pipe_num); ++ ++ return 0; ++} ++ ++static int qe_ep_toggledata01(struct qe_ep *ep) ++{ ++ ep->data01 ^= 0x1; ++ return 0; ++} ++ ++static int qe_ep_bd_init(struct qe_udc *udc, unsigned char pipe_num) ++{ ++ struct qe_ep *ep = &udc->eps[pipe_num]; ++ unsigned long tmp_addr = 0; ++ struct usb_ep_para __iomem *epparam; ++ int i; ++ struct qe_bd __iomem *bd; ++ int bdring_len; ++ ++ if (ep->dir == USB_DIR_OUT) ++ bdring_len = USB_BDRING_LEN_RX; ++ else ++ bdring_len = USB_BDRING_LEN; ++ ++ epparam = udc->ep_param[pipe_num]; ++ /* alloc multi-ram for BD rings and set the ep parameters */ ++ tmp_addr = cpm_muram_alloc(sizeof(struct qe_bd) * (bdring_len + ++ USB_BDRING_LEN_TX), QE_ALIGNMENT_OF_BD); ++ out_be16(&epparam->rbase, (u16)tmp_addr); ++ out_be16(&epparam->tbase, (u16)(tmp_addr + ++ (sizeof(struct qe_bd) * bdring_len))); ++ ++ out_be16(&epparam->rbptr, in_be16(&epparam->rbase)); ++ out_be16(&epparam->tbptr, in_be16(&epparam->tbase)); ++ ++ ep->rxbase = cpm_muram_addr(tmp_addr); ++ ep->txbase = cpm_muram_addr(tmp_addr + (sizeof(struct qe_bd) ++ * bdring_len)); ++ ep->n_rxbd = ep->rxbase; ++ ep->e_rxbd = ep->rxbase; ++ ep->n_txbd = ep->txbase; ++ ep->c_txbd = ep->txbase; ++ ep->data01 = 0; /* data0 */ ++ ++ /* Init TX and RX bds */ ++ bd = ep->rxbase; ++ for (i = 0; i < bdring_len - 1; i++) { ++ out_be32(&bd->buf, 0); ++ out_be32((u32 __iomem *)bd, 0); ++ bd++; ++ } ++ out_be32(&bd->buf, 0); ++ out_be32((u32 __iomem *)bd, R_W); ++ ++ bd = ep->txbase; ++ for (i = 0; i < USB_BDRING_LEN_TX - 1; i++) { ++ out_be32(&bd->buf, 0); ++ out_be32((u32 __iomem *)bd, 0); ++ bd++; ++ } ++ out_be32(&bd->buf, 0); ++ out_be32((u32 __iomem *)bd, T_W); ++ ++ return 0; ++} ++ ++static int qe_ep_rxbd_update(struct qe_ep *ep) ++{ ++ unsigned int size; ++ int i; ++ unsigned int tmp; ++ struct qe_bd __iomem *bd; ++ unsigned int bdring_len; ++ ++ if (ep->rxbase == NULL) ++ return -EINVAL; ++ ++ bd = ep->rxbase; ++ ++ ep->rxframe = kmalloc(sizeof(*ep->rxframe), GFP_ATOMIC); ++ if (ep->rxframe == NULL) { ++ dev_err(ep->udc->dev, "malloc rxframe failed\n"); ++ return -ENOMEM; ++ } ++ ++ qe_frame_init(ep->rxframe); ++ ++ if (ep->dir == USB_DIR_OUT) ++ bdring_len = USB_BDRING_LEN_RX; ++ else ++ bdring_len = USB_BDRING_LEN; ++ ++ size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (bdring_len + 1); ++ ep->rxbuffer = kzalloc(size, GFP_ATOMIC); ++ if (ep->rxbuffer == NULL) { ++ dev_err(ep->udc->dev, "malloc rxbuffer failed,size=%d\n", ++ size); ++ kfree(ep->rxframe); ++ return -ENOMEM; ++ } ++ ++ ep->rxbuf_d = virt_to_phys((void *)ep->rxbuffer); ++ if (ep->rxbuf_d == DMA_ADDR_INVALID) { ++ ep->rxbuf_d = dma_map_single(udc_controller->gadget.dev.parent, ++ ep->rxbuffer, ++ size, ++ DMA_FROM_DEVICE); ++ ep->rxbufmap = 1; ++ } else { ++ dma_sync_single_for_device(udc_controller->gadget.dev.parent, ++ ep->rxbuf_d, size, ++ DMA_FROM_DEVICE); ++ ep->rxbufmap = 0; ++ } ++ ++ size = ep->ep.maxpacket + USB_CRC_SIZE + 2; ++ tmp = ep->rxbuf_d; ++ tmp = (u32)(((tmp >> 2) << 2) + 4); ++ ++ for (i = 0; i < bdring_len - 1; i++) { ++ out_be32(&bd->buf, tmp); ++ out_be32((u32 __iomem *)bd, (R_E | R_I)); ++ tmp = tmp + size; ++ bd++; ++ } ++ out_be32(&bd->buf, tmp); ++ out_be32((u32 __iomem *)bd, (R_E | R_I | R_W)); ++ ++ return 0; ++} ++ ++static int qe_ep_register_init(struct qe_udc *udc, unsigned char pipe_num) ++{ ++ struct qe_ep *ep = &udc->eps[pipe_num]; ++ struct usb_ep_para __iomem *epparam; ++ u16 usep, logepnum; ++ u16 tmp; ++ u8 rtfcr = 0; ++ ++ epparam = udc->ep_param[pipe_num]; ++ ++ usep = 0; ++ logepnum = (ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); ++ usep |= (logepnum << USB_EPNUM_SHIFT); ++ ++ switch (ep->desc->bmAttributes & 0x03) { ++ case USB_ENDPOINT_XFER_BULK: ++ usep |= USB_TRANS_BULK; ++ break; ++ case USB_ENDPOINT_XFER_ISOC: ++ usep |= USB_TRANS_ISO; ++ break; ++ case USB_ENDPOINT_XFER_INT: ++ usep |= USB_TRANS_INT; ++ break; ++ default: ++ usep |= USB_TRANS_CTR; ++ break; ++ } ++ ++ switch (ep->dir) { ++ case USB_DIR_OUT: ++ usep |= USB_THS_IGNORE_IN; ++ break; ++ case USB_DIR_IN: ++ usep |= USB_RHS_IGNORE_OUT; ++ break; ++ default: ++ break; ++ } ++ out_be16(&udc->usb_regs->usb_usep[pipe_num], usep); ++ ++ rtfcr = 0x30; ++ out_8(&epparam->rbmr, rtfcr); ++ out_8(&epparam->tbmr, rtfcr); ++ ++ tmp = (u16)(ep->ep.maxpacket + USB_CRC_SIZE); ++ /* MRBLR must be divisble by 4 */ ++ tmp = (u16)(((tmp >> 2) << 2) + 4); ++ out_be16(&epparam->mrblr, tmp); ++ ++ return 0; ++} ++ ++static int qe_ep_init(struct qe_udc *udc, ++ unsigned char pipe_num, ++ const struct usb_endpoint_descriptor *desc) ++{ ++ struct qe_ep *ep = &udc->eps[pipe_num]; ++ unsigned long flags; ++ int reval = 0; ++ u16 max = 0; ++ ++ max = le16_to_cpu(desc->wMaxPacketSize); ++ ++ /* check the max package size validate for this endpoint */ ++ /* Refer to USB2.0 spec table 9-13, ++ */ ++ if (pipe_num != 0) { ++ switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { ++ case USB_ENDPOINT_XFER_BULK: ++ if (strstr(ep->ep.name, "-iso") ++ || strstr(ep->ep.name, "-int")) ++ goto en_done; ++ switch (udc->gadget.speed) { ++ case USB_SPEED_HIGH: ++ if ((max == 128) || (max == 256) || (max == 512)) ++ break; ++ default: ++ switch (max) { ++ case 4: ++ case 8: ++ case 16: ++ case 32: ++ case 64: ++ break; ++ default: ++ case USB_SPEED_LOW: ++ goto en_done; ++ } ++ } ++ break; ++ case USB_ENDPOINT_XFER_INT: ++ if (strstr(ep->ep.name, "-iso")) /* bulk is ok */ ++ goto en_done; ++ switch (udc->gadget.speed) { ++ case USB_SPEED_HIGH: ++ if (max <= 1024) ++ break; ++ case USB_SPEED_FULL: ++ if (max <= 64) ++ break; ++ default: ++ if (max <= 8) ++ break; ++ goto en_done; ++ } ++ break; ++ case USB_ENDPOINT_XFER_ISOC: ++ if (strstr(ep->ep.name, "-bulk") ++ || strstr(ep->ep.name, "-int")) ++ goto en_done; ++ switch (udc->gadget.speed) { ++ case USB_SPEED_HIGH: ++ if (max <= 1024) ++ break; ++ case USB_SPEED_FULL: ++ if (max <= 1023) ++ break; ++ default: ++ goto en_done; ++ } ++ break; ++ case USB_ENDPOINT_XFER_CONTROL: ++ if (strstr(ep->ep.name, "-iso") ++ || strstr(ep->ep.name, "-int")) ++ goto en_done; ++ switch (udc->gadget.speed) { ++ case USB_SPEED_HIGH: ++ case USB_SPEED_FULL: ++ switch (max) { ++ case 1: ++ case 2: ++ case 4: ++ case 8: ++ case 16: ++ case 32: ++ case 64: ++ break; ++ default: ++ goto en_done; ++ } ++ case USB_SPEED_LOW: ++ switch (max) { ++ case 1: ++ case 2: ++ case 4: ++ case 8: ++ break; ++ default: ++ goto en_done; ++ } ++ default: ++ goto en_done; ++ } ++ break; ++ ++ default: ++ goto en_done; ++ } ++ } /* if ep0*/ ++ ++ spin_lock_irqsave(&udc->lock, flags); ++ ++ /* initialize ep structure */ ++ ep->ep.maxpacket = max; ++ ep->tm = (u8)(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); ++ ep->desc = desc; ++ ep->stopped = 0; ++ ep->init = 1; ++ ++ if (pipe_num == 0) { ++ ep->dir = USB_DIR_BOTH; ++ udc->ep0_dir = USB_DIR_OUT; ++ udc->ep0_state = WAIT_FOR_SETUP; ++ } else { ++ switch (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) { ++ case USB_DIR_OUT: ++ ep->dir = USB_DIR_OUT; ++ break; ++ case USB_DIR_IN: ++ ep->dir = USB_DIR_IN; ++ default: ++ break; ++ } ++ } ++ ++ /* hardware special operation */ ++ qe_ep_bd_init(udc, pipe_num); ++ if ((ep->tm == USBP_TM_CTL) || (ep->dir == USB_DIR_OUT)) { ++ reval = qe_ep_rxbd_update(ep); ++ if (reval) ++ goto en_done1; ++ } ++ ++ if ((ep->tm == USBP_TM_CTL) || (ep->dir == USB_DIR_IN)) { ++ ep->txframe = kmalloc(sizeof(*ep->txframe), GFP_ATOMIC); ++ if (ep->txframe == NULL) { ++ dev_err(udc->dev, "malloc txframe failed\n"); ++ goto en_done2; ++ } ++ qe_frame_init(ep->txframe); ++ } ++ ++ qe_ep_register_init(udc, pipe_num); ++ ++ /* Now HW will be NAKing transfers to that EP, ++ * until a buffer is queued to it. */ ++ spin_unlock_irqrestore(&udc->lock, flags); ++ ++ return 0; ++en_done2: ++ kfree(ep->rxbuffer); ++ kfree(ep->rxframe); ++en_done1: ++ spin_unlock_irqrestore(&udc->lock, flags); ++en_done: ++ dev_dbg(udc->dev, "failed to initialize %s\n", ep->ep.name); ++ return -ENODEV; ++} ++ ++static inline void qe_usb_enable(void) ++{ ++ setbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN); ++} ++ ++static inline void qe_usb_disable(void) ++{ ++ clrbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN); ++} ++ ++/*----------------------------------------------------------------------------* ++ * USB and EP basic manipulate function end * ++ *----------------------------------------------------------------------------*/ ++ ++ ++/****************************************************************************** ++ UDC transmit and receive process ++ ******************************************************************************/ ++static void recycle_one_rxbd(struct qe_ep *ep) ++{ ++ u32 bdstatus; ++ ++ bdstatus = in_be32((u32 __iomem *)ep->e_rxbd); ++ bdstatus = R_I | R_E | (bdstatus & R_W); ++ out_be32((u32 __iomem *)ep->e_rxbd, bdstatus); ++ ++ if (bdstatus & R_W) ++ ep->e_rxbd = ep->rxbase; ++ else ++ ep->e_rxbd++; ++} ++ ++static void recycle_rxbds(struct qe_ep *ep, unsigned char stopatnext) ++{ ++ u32 bdstatus; ++ struct qe_bd __iomem *bd, *nextbd; ++ unsigned char stop = 0; ++ ++ nextbd = ep->n_rxbd; ++ bd = ep->e_rxbd; ++ bdstatus = in_be32((u32 __iomem *)bd); ++ ++ while (!(bdstatus & R_E) && !(bdstatus & BD_LENGTH_MASK) && !stop) { ++ bdstatus = R_E | R_I | (bdstatus & R_W); ++ out_be32((u32 __iomem *)bd, bdstatus); ++ ++ if (bdstatus & R_W) ++ bd = ep->rxbase; ++ else ++ bd++; ++ ++ bdstatus = in_be32((u32 __iomem *)bd); ++ if (stopatnext && (bd == nextbd)) ++ stop = 1; ++ } ++ ++ ep->e_rxbd = bd; ++} ++ ++static void ep_recycle_rxbds(struct qe_ep *ep) ++{ ++ struct qe_bd __iomem *bd = ep->n_rxbd; ++ u32 bdstatus; ++ u8 epnum = ep->epnum; ++ struct qe_udc *udc = ep->udc; ++ ++ bdstatus = in_be32((u32 __iomem *)bd); ++ if (!(bdstatus & R_E) && !(bdstatus & BD_LENGTH_MASK)) { ++ bd = ep->rxbase + ++ ((in_be16(&udc->ep_param[epnum]->rbptr) - ++ in_be16(&udc->ep_param[epnum]->rbase)) ++ >> 3); ++ bdstatus = in_be32((u32 __iomem *)bd); ++ ++ if (bdstatus & R_W) ++ bd = ep->rxbase; ++ else ++ bd++; ++ ++ ep->e_rxbd = bd; ++ recycle_rxbds(ep, 0); ++ ep->e_rxbd = ep->n_rxbd; ++ } else ++ recycle_rxbds(ep, 1); ++ ++ if (in_be16(&udc->usb_regs->usb_usber) & USB_E_BSY_MASK) ++ out_be16(&udc->usb_regs->usb_usber, USB_E_BSY_MASK); ++ ++ if (ep->has_data <= 0 && (!list_empty(&ep->queue))) ++ qe_eprx_normal(ep); ++ ++ ep->localnack = 0; ++} ++ ++static void setup_received_handle(struct qe_udc *udc, ++ struct usb_ctrlrequest *setup); ++static int qe_ep_rxframe_handle(struct qe_ep *ep); ++static void ep0_req_complete(struct qe_udc *udc, struct qe_req *req); ++/* when BD PID is setup, handle the packet */ ++static int ep0_setup_handle(struct qe_udc *udc) ++{ ++ struct qe_ep *ep = &udc->eps[0]; ++ struct qe_frame *pframe; ++ unsigned int fsize; ++ u8 *cp; ++ ++ pframe = ep->rxframe; ++ if ((frame_get_info(pframe) & PID_SETUP) ++ && (udc->ep0_state == WAIT_FOR_SETUP)) { ++ fsize = frame_get_length(pframe); ++ if (unlikely(fsize != 8)) ++ return -EINVAL; ++ cp = (u8 *)&udc->local_setup_buff; ++ memcpy(cp, pframe->data, fsize); ++ ep->data01 = 1; ++ ++ /* handle the usb command base on the usb_ctrlrequest */ ++ setup_received_handle(udc, &udc->local_setup_buff); ++ return 0; ++ } ++ return -EINVAL; ++} ++ ++static int qe_ep0_rx(struct qe_udc *udc) ++{ ++ struct qe_ep *ep = &udc->eps[0]; ++ struct qe_frame *pframe; ++ struct qe_bd __iomem *bd; ++ u32 bdstatus, length; ++ u32 vaddr; ++ ++ pframe = ep->rxframe; ++ ++ if (ep->dir == USB_DIR_IN) { ++ dev_err(udc->dev, "ep0 not a control endpoint\n"); ++ return -EINVAL; ++ } ++ ++ bd = ep->n_rxbd; ++ bdstatus = in_be32((u32 __iomem *)bd); ++ length = bdstatus & BD_LENGTH_MASK; ++ ++ while (!(bdstatus & R_E) && length) { ++ if ((bdstatus & R_F) && (bdstatus & R_L) ++ && !(bdstatus & R_ERROR)) { ++ if (length == USB_CRC_SIZE) { ++ udc->ep0_state = WAIT_FOR_SETUP; ++ dev_vdbg(udc->dev, ++ "receive a ZLP in status phase\n"); ++ } else { ++ qe_frame_clean(pframe); ++ vaddr = (u32)phys_to_virt(in_be32(&bd->buf)); ++ frame_set_data(pframe, (u8 *)vaddr); ++ frame_set_length(pframe, ++ (length - USB_CRC_SIZE)); ++ frame_set_status(pframe, FRAME_OK); ++ switch (bdstatus & R_PID) { ++ case R_PID_SETUP: ++ frame_set_info(pframe, PID_SETUP); ++ break; ++ case R_PID_DATA1: ++ frame_set_info(pframe, PID_DATA1); ++ break; ++ default: ++ frame_set_info(pframe, PID_DATA0); ++ break; ++ } ++ ++ if ((bdstatus & R_PID) == R_PID_SETUP) ++ ep0_setup_handle(udc); ++ else ++ qe_ep_rxframe_handle(ep); ++ } ++ } else { ++ dev_err(udc->dev, "The receive frame with error!\n"); ++ } ++ ++ /* note: don't clear the rxbd's buffer address */ ++ recycle_one_rxbd(ep); ++ ++ /* Get next BD */ ++ if (bdstatus & R_W) ++ bd = ep->rxbase; ++ else ++ bd++; ++ ++ bdstatus = in_be32((u32 __iomem *)bd); ++ length = bdstatus & BD_LENGTH_MASK; ++ ++ } ++ ++ ep->n_rxbd = bd; ++ ++ return 0; ++} ++ ++static int qe_ep_rxframe_handle(struct qe_ep *ep) ++{ ++ struct qe_frame *pframe; ++ u8 framepid = 0; ++ unsigned int fsize; ++ u8 *cp; ++ struct qe_req *req; ++ ++ pframe = ep->rxframe; ++ ++ if (frame_get_info(pframe) & PID_DATA1) ++ framepid = 0x1; ++ ++ if (framepid != ep->data01) { ++ dev_err(ep->udc->dev, "the data01 error!\n"); ++ return -EIO; ++ } ++ ++ fsize = frame_get_length(pframe); ++ if (list_empty(&ep->queue)) { ++ dev_err(ep->udc->dev, "the %s have no requeue!\n", ep->name); ++ } else { ++ req = list_entry(ep->queue.next, struct qe_req, queue); ++ ++ cp = (u8 *)(req->req.buf) + req->req.actual; ++ if (cp) { ++ memcpy(cp, pframe->data, fsize); ++ req->req.actual += fsize; ++ if ((fsize < ep->ep.maxpacket) || ++ (req->req.actual >= req->req.length)) { ++ if (ep->epnum == 0) ++ ep0_req_complete(ep->udc, req); ++ else ++ done(ep, req, 0); ++ if (list_empty(&ep->queue) && ep->epnum != 0) ++ qe_eprx_nack(ep); ++ } ++ } ++ } ++ ++ qe_ep_toggledata01(ep); ++ ++ return 0; ++} ++ ++static void ep_rx_tasklet(unsigned long data) ++{ ++ struct qe_udc *udc = (struct qe_udc *)data; ++ struct qe_ep *ep; ++ struct qe_frame *pframe; ++ struct qe_bd __iomem *bd; ++ unsigned long flags; ++ u32 bdstatus, length; ++ u32 vaddr, i; ++ ++ spin_lock_irqsave(&udc->lock, flags); ++ ++ for (i = 1; i < USB_MAX_ENDPOINTS; i++) { ++ ep = &udc->eps[i]; ++ ++ if (ep->dir == USB_DIR_IN || ep->enable_tasklet == 0) { ++ dev_dbg(udc->dev, ++ "This is a transmit ep or disable tasklet!\n"); ++ continue; ++ } ++ ++ pframe = ep->rxframe; ++ bd = ep->n_rxbd; ++ bdstatus = in_be32((u32 __iomem *)bd); ++ length = bdstatus & BD_LENGTH_MASK; ++ ++ while (!(bdstatus & R_E) && length) { ++ if (list_empty(&ep->queue)) { ++ qe_eprx_nack(ep); ++ dev_dbg(udc->dev, ++ "The rxep have noreq %d\n", ++ ep->has_data); ++ break; ++ } ++ ++ if ((bdstatus & R_F) && (bdstatus & R_L) ++ && !(bdstatus & R_ERROR)) { ++ qe_frame_clean(pframe); ++ vaddr = (u32)phys_to_virt(in_be32(&bd->buf)); ++ frame_set_data(pframe, (u8 *)vaddr); ++ frame_set_length(pframe, ++ (length - USB_CRC_SIZE)); ++ frame_set_status(pframe, FRAME_OK); ++ switch (bdstatus & R_PID) { ++ case R_PID_DATA1: ++ frame_set_info(pframe, PID_DATA1); ++ break; ++ case R_PID_SETUP: ++ frame_set_info(pframe, PID_SETUP); ++ break; ++ default: ++ frame_set_info(pframe, PID_DATA0); ++ break; ++ } ++ /* handle the rx frame */ ++ qe_ep_rxframe_handle(ep); ++ } else { ++ dev_err(udc->dev, ++ "error in received frame\n"); ++ } ++ /* note: don't clear the rxbd's buffer address */ ++ /*clear the length */ ++ out_be32((u32 __iomem *)bd, bdstatus & BD_STATUS_MASK); ++ ep->has_data--; ++ if (!(ep->localnack)) ++ recycle_one_rxbd(ep); ++ ++ /* Get next BD */ ++ if (bdstatus & R_W) ++ bd = ep->rxbase; ++ else ++ bd++; ++ ++ bdstatus = in_be32((u32 __iomem *)bd); ++ length = bdstatus & BD_LENGTH_MASK; ++ } ++ ++ ep->n_rxbd = bd; ++ ++ if (ep->localnack) ++ ep_recycle_rxbds(ep); ++ ++ ep->enable_tasklet = 0; ++ } /* for i=1 */ ++ ++ spin_unlock_irqrestore(&udc->lock, flags); ++} ++ ++static int qe_ep_rx(struct qe_ep *ep) ++{ ++ struct qe_udc *udc; ++ struct qe_frame *pframe; ++ struct qe_bd __iomem *bd; ++ u16 swoffs, ucoffs, emptybds; ++ ++ udc = ep->udc; ++ pframe = ep->rxframe; ++ ++ if (ep->dir == USB_DIR_IN) { ++ dev_err(udc->dev, "transmit ep in rx function\n"); ++ return -EINVAL; ++ } ++ ++ bd = ep->n_rxbd; ++ ++ swoffs = (u16)(bd - ep->rxbase); ++ ucoffs = (u16)((in_be16(&udc->ep_param[ep->epnum]->rbptr) - ++ in_be16(&udc->ep_param[ep->epnum]->rbase)) >> 3); ++ if (swoffs < ucoffs) ++ emptybds = USB_BDRING_LEN_RX - ucoffs + swoffs; ++ else ++ emptybds = swoffs - ucoffs; ++ ++ if (emptybds < MIN_EMPTY_BDS) { ++ qe_eprx_nack(ep); ++ ep->localnack = 1; ++ dev_vdbg(udc->dev, "%d empty bds, send NACK\n", emptybds); ++ } ++ ep->has_data = USB_BDRING_LEN_RX - emptybds; ++ ++ if (list_empty(&ep->queue)) { ++ qe_eprx_nack(ep); ++ dev_vdbg(udc->dev, "The rxep have no req queued with %d BDs\n", ++ ep->has_data); ++ return 0; ++ } ++ ++ tasklet_schedule(&udc->rx_tasklet); ++ ep->enable_tasklet = 1; ++ ++ return 0; ++} ++ ++/* send data from a frame, no matter what tx_req */ ++static int qe_ep_tx(struct qe_ep *ep, struct qe_frame *frame) ++{ ++ struct qe_udc *udc = ep->udc; ++ struct qe_bd __iomem *bd; ++ u16 saveusbmr; ++ u32 bdstatus, pidmask; ++ u32 paddr; ++ ++ if (ep->dir == USB_DIR_OUT) { ++ dev_err(udc->dev, "receive ep passed to tx function\n"); ++ return -EINVAL; ++ } ++ ++ /* Disable the Tx interrupt */ ++ saveusbmr = in_be16(&udc->usb_regs->usb_usbmr); ++ out_be16(&udc->usb_regs->usb_usbmr, ++ saveusbmr & ~(USB_E_TXB_MASK | USB_E_TXE_MASK)); ++ ++ bd = ep->n_txbd; ++ bdstatus = in_be32((u32 __iomem *)bd); ++ ++ if (!(bdstatus & (T_R | BD_LENGTH_MASK))) { ++ if (frame_get_length(frame) == 0) { ++ frame_set_data(frame, udc->nullbuf); ++ frame_set_length(frame, 2); ++ frame->info |= (ZLP | NO_CRC); ++ dev_vdbg(udc->dev, "the frame size = 0\n"); ++ } ++ paddr = virt_to_phys((void *)frame->data); ++ out_be32(&bd->buf, paddr); ++ bdstatus = (bdstatus&T_W); ++ if (!(frame_get_info(frame) & NO_CRC)) ++ bdstatus |= T_R | T_I | T_L | T_TC ++ | frame_get_length(frame); ++ else ++ bdstatus |= T_R | T_I | T_L | frame_get_length(frame); ++ ++ /* if the packet is a ZLP in status phase */ ++ if ((ep->epnum == 0) && (udc->ep0_state == DATA_STATE_NEED_ZLP)) ++ ep->data01 = 0x1; ++ ++ if (ep->data01) { ++ pidmask = T_PID_DATA1; ++ frame->info |= PID_DATA1; ++ } else { ++ pidmask = T_PID_DATA0; ++ frame->info |= PID_DATA0; ++ } ++ bdstatus |= T_CNF; ++ bdstatus |= pidmask; ++ out_be32((u32 __iomem *)bd, bdstatus); ++ qe_ep_filltxfifo(ep); ++ ++ /* enable the TX interrupt */ ++ out_be16(&udc->usb_regs->usb_usbmr, saveusbmr); ++ ++ qe_ep_toggledata01(ep); ++ if (bdstatus & T_W) ++ ep->n_txbd = ep->txbase; ++ else ++ ep->n_txbd++; ++ ++ return 0; ++ } else { ++ out_be16(&udc->usb_regs->usb_usbmr, saveusbmr); ++ dev_vdbg(udc->dev, "The tx bd is not ready!\n"); ++ return -EBUSY; ++ } ++} ++ ++/* when an bd was transmitted, the function can * ++ * handle the tx_req, not include ep0 */ ++static int txcomplete(struct qe_ep *ep, unsigned char restart) ++{ ++ if (ep->tx_req != NULL) { ++ if (!restart) { ++ int asent = ep->last; ++ ep->sent += asent; ++ ep->last -= asent; ++ } else { ++ ep->last = 0; ++ } ++ ++ /* a request already were transmitted completely */ ++ if ((ep->tx_req->req.length - ep->sent) <= 0) { ++ ep->tx_req->req.actual = (unsigned int)ep->sent; ++ done(ep, ep->tx_req, 0); ++ ep->tx_req = NULL; ++ ep->last = 0; ++ ep->sent = 0; ++ } ++ } ++ ++ /* we should gain a new tx_req fot this endpoint */ ++ if (ep->tx_req == NULL) { ++ if (!list_empty(&ep->queue)) { ++ ep->tx_req = list_entry(ep->queue.next, struct qe_req, ++ queue); ++ ep->last = 0; ++ ep->sent = 0; ++ } ++ } ++ ++ return 0; ++} ++ ++/* give a frame and a tx_req,send some data */ ++static int qe_usb_senddata(struct qe_ep *ep, struct qe_frame *frame) ++{ ++ unsigned int size; ++ u8 *buf; ++ ++ qe_frame_clean(frame); ++ size = min_t(u32, (ep->tx_req->req.length - ep->sent), ++ ep->ep.maxpacket); ++ buf = (u8 *)ep->tx_req->req.buf + ep->sent; ++ if (buf && size) { ++ ep->last = size; ++ frame_set_data(frame, buf); ++ frame_set_length(frame, size); ++ frame_set_status(frame, FRAME_OK); ++ frame_set_info(frame, 0); ++ return qe_ep_tx(ep, frame); ++ } ++ return -EIO; ++} ++ ++/* give a frame struct,send a ZLP */ ++static int sendnulldata(struct qe_ep *ep, struct qe_frame *frame, uint infor) ++{ ++ struct qe_udc *udc = ep->udc; ++ ++ if (frame == NULL) ++ return -ENODEV; ++ ++ qe_frame_clean(frame); ++ frame_set_data(frame, (u8 *)udc->nullbuf); ++ frame_set_length(frame, 2); ++ frame_set_status(frame, FRAME_OK); ++ frame_set_info(frame, (ZLP | NO_CRC | infor)); ++ ++ return qe_ep_tx(ep, frame); ++} ++ ++static int frame_create_tx(struct qe_ep *ep, struct qe_frame *frame) ++{ ++ struct qe_req *req = ep->tx_req; ++ int reval; ++ ++ if (req == NULL) ++ return -ENODEV; ++ ++ if ((req->req.length - ep->sent) > 0) ++ reval = qe_usb_senddata(ep, frame); ++ else ++ reval = sendnulldata(ep, frame, 0); ++ ++ return reval; ++} ++ ++/* if direction is DIR_IN, the status is Device->Host ++ * if direction is DIR_OUT, the status transaction is Device<-Host ++ * in status phase, udc create a request and gain status */ ++static int ep0_prime_status(struct qe_udc *udc, int direction) ++{ ++ ++ struct qe_ep *ep = &udc->eps[0]; ++ ++ if (direction == USB_DIR_IN) { ++ udc->ep0_state = DATA_STATE_NEED_ZLP; ++ udc->ep0_dir = USB_DIR_IN; ++ sendnulldata(ep, ep->txframe, SETUP_STATUS | NO_REQ); ++ } else { ++ udc->ep0_dir = USB_DIR_OUT; ++ udc->ep0_state = WAIT_FOR_OUT_STATUS; ++ } ++ ++ return 0; ++} ++ ++/* a request complete in ep0, whether gadget request or udc request */ ++static void ep0_req_complete(struct qe_udc *udc, struct qe_req *req) ++{ ++ struct qe_ep *ep = &udc->eps[0]; ++ /* because usb and ep's status already been set in ch9setaddress() */ ++ ++ switch (udc->ep0_state) { ++ case DATA_STATE_XMIT: ++ done(ep, req, 0); ++ /* receive status phase */ ++ if (ep0_prime_status(udc, USB_DIR_OUT)) ++ qe_ep0_stall(udc); ++ break; ++ ++ case DATA_STATE_NEED_ZLP: ++ done(ep, req, 0); ++ udc->ep0_state = WAIT_FOR_SETUP; ++ break; ++ ++ case DATA_STATE_RECV: ++ done(ep, req, 0); ++ /* send status phase */ ++ if (ep0_prime_status(udc, USB_DIR_IN)) ++ qe_ep0_stall(udc); ++ break; ++ ++ case WAIT_FOR_OUT_STATUS: ++ done(ep, req, 0); ++ udc->ep0_state = WAIT_FOR_SETUP; ++ break; ++ ++ case WAIT_FOR_SETUP: ++ dev_vdbg(udc->dev, "Unexpected interrupt\n"); ++ break; ++ ++ default: ++ qe_ep0_stall(udc); ++ break; ++ } ++} ++ ++static int ep0_txcomplete(struct qe_ep *ep, unsigned char restart) ++{ ++ struct qe_req *tx_req = NULL; ++ struct qe_frame *frame = ep->txframe; ++ ++ if ((frame_get_info(frame) & (ZLP | NO_REQ)) == (ZLP | NO_REQ)) { ++ if (!restart) ++ ep->udc->ep0_state = WAIT_FOR_SETUP; ++ else ++ sendnulldata(ep, ep->txframe, SETUP_STATUS | NO_REQ); ++ return 0; ++ } ++ ++ tx_req = ep->tx_req; ++ if (tx_req != NULL) { ++ if (!restart) { ++ int asent = ep->last; ++ ep->sent += asent; ++ ep->last -= asent; ++ } else { ++ ep->last = 0; ++ } ++ ++ /* a request already were transmitted completely */ ++ if ((ep->tx_req->req.length - ep->sent) <= 0) { ++ ep->tx_req->req.actual = (unsigned int)ep->sent; ++ ep0_req_complete(ep->udc, ep->tx_req); ++ ep->tx_req = NULL; ++ ep->last = 0; ++ ep->sent = 0; ++ } ++ } else { ++ dev_vdbg(ep->udc->dev, "the ep0_controller have no req\n"); ++ } ++ ++ return 0; ++} ++ ++static int ep0_txframe_handle(struct qe_ep *ep) ++{ ++ /* if have error, transmit again */ ++ if (frame_get_status(ep->txframe) & FRAME_ERROR) { ++ qe_ep_flushtxfifo(ep); ++ dev_vdbg(ep->udc->dev, "The EP0 transmit data have error!\n"); ++ if (frame_get_info(ep->txframe) & PID_DATA0) ++ ep->data01 = 0; ++ else ++ ep->data01 = 1; ++ ++ ep0_txcomplete(ep, 1); ++ } else ++ ep0_txcomplete(ep, 0); ++ ++ frame_create_tx(ep, ep->txframe); ++ return 0; ++} ++ ++static int qe_ep0_txconf(struct qe_ep *ep) ++{ ++ struct qe_bd __iomem *bd; ++ struct qe_frame *pframe; ++ u32 bdstatus; ++ ++ bd = ep->c_txbd; ++ bdstatus = in_be32((u32 __iomem *)bd); ++ while (!(bdstatus & T_R) && (bdstatus & ~T_W)) { ++ pframe = ep->txframe; ++ ++ /* clear and recycle the BD */ ++ out_be32((u32 __iomem *)bd, bdstatus & T_W); ++ out_be32(&bd->buf, 0); ++ if (bdstatus & T_W) ++ ep->c_txbd = ep->txbase; ++ else ++ ep->c_txbd++; ++ ++ if (ep->c_txbd == ep->n_txbd) { ++ if (bdstatus & DEVICE_T_ERROR) { ++ frame_set_status(pframe, FRAME_ERROR); ++ if (bdstatus & T_TO) ++ pframe->status |= TX_ER_TIMEOUT; ++ if (bdstatus & T_UN) ++ pframe->status |= TX_ER_UNDERUN; ++ } ++ ep0_txframe_handle(ep); ++ } ++ ++ bd = ep->c_txbd; ++ bdstatus = in_be32((u32 __iomem *)bd); ++ } ++ ++ return 0; ++} ++ ++static int ep_txframe_handle(struct qe_ep *ep) ++{ ++ if (frame_get_status(ep->txframe) & FRAME_ERROR) { ++ qe_ep_flushtxfifo(ep); ++ dev_vdbg(ep->udc->dev, "The EP0 transmit data have error!\n"); ++ if (frame_get_info(ep->txframe) & PID_DATA0) ++ ep->data01 = 0; ++ else ++ ep->data01 = 1; ++ ++ txcomplete(ep, 1); ++ } else ++ txcomplete(ep, 0); ++ ++ frame_create_tx(ep, ep->txframe); /* send the data */ ++ return 0; ++} ++ ++/* confirm the already trainsmited bd */ ++static int qe_ep_txconf(struct qe_ep *ep) ++{ ++ struct qe_bd __iomem *bd; ++ struct qe_frame *pframe = NULL; ++ u32 bdstatus; ++ unsigned char breakonrxinterrupt = 0; ++ ++ bd = ep->c_txbd; ++ bdstatus = in_be32((u32 __iomem *)bd); ++ while (!(bdstatus & T_R) && (bdstatus & ~T_W)) { ++ pframe = ep->txframe; ++ if (bdstatus & DEVICE_T_ERROR) { ++ frame_set_status(pframe, FRAME_ERROR); ++ if (bdstatus & T_TO) ++ pframe->status |= TX_ER_TIMEOUT; ++ if (bdstatus & T_UN) ++ pframe->status |= TX_ER_UNDERUN; ++ } ++ ++ /* clear and recycle the BD */ ++ out_be32((u32 __iomem *)bd, bdstatus & T_W); ++ out_be32(&bd->buf, 0); ++ if (bdstatus & T_W) ++ ep->c_txbd = ep->txbase; ++ else ++ ep->c_txbd++; ++ ++ /* handle the tx frame */ ++ ep_txframe_handle(ep); ++ bd = ep->c_txbd; ++ bdstatus = in_be32((u32 __iomem *)bd); ++ } ++ if (breakonrxinterrupt) ++ return -EIO; ++ else ++ return 0; ++} ++ ++/* Add a request in queue, and try to transmit a packet */ ++static int ep_req_send(struct qe_ep *ep, struct qe_req *req) ++{ ++ int reval = 0; ++ ++ if (ep->tx_req == NULL) { ++ ep->sent = 0; ++ ep->last = 0; ++ txcomplete(ep, 0); /* can gain a new tx_req */ ++ reval = frame_create_tx(ep, ep->txframe); ++ } ++ return reval; ++} ++ ++/* Maybe this is a good ideal */ ++static int ep_req_rx(struct qe_ep *ep, struct qe_req *req) ++{ ++ struct qe_udc *udc = ep->udc; ++ struct qe_frame *pframe = NULL; ++ struct qe_bd __iomem *bd; ++ u32 bdstatus, length; ++ u32 vaddr, fsize; ++ u8 *cp; ++ u8 finish_req = 0; ++ u8 framepid; ++ ++ if (list_empty(&ep->queue)) { ++ dev_vdbg(udc->dev, "the req already finish!\n"); ++ return 0; ++ } ++ pframe = ep->rxframe; ++ ++ bd = ep->n_rxbd; ++ bdstatus = in_be32((u32 __iomem *)bd); ++ length = bdstatus & BD_LENGTH_MASK; ++ ++ while (!(bdstatus & R_E) && length) { ++ if (finish_req) ++ break; ++ if ((bdstatus & R_F) && (bdstatus & R_L) ++ && !(bdstatus & R_ERROR)) { ++ qe_frame_clean(pframe); ++ vaddr = (u32)phys_to_virt(in_be32(&bd->buf)); ++ frame_set_data(pframe, (u8 *)vaddr); ++ frame_set_length(pframe, (length - USB_CRC_SIZE)); ++ frame_set_status(pframe, FRAME_OK); ++ switch (bdstatus & R_PID) { ++ case R_PID_DATA1: ++ frame_set_info(pframe, PID_DATA1); break; ++ default: ++ frame_set_info(pframe, PID_DATA0); break; ++ } ++ /* handle the rx frame */ ++ ++ if (frame_get_info(pframe) & PID_DATA1) ++ framepid = 0x1; ++ else ++ framepid = 0; ++ ++ if (framepid != ep->data01) { ++ dev_vdbg(udc->dev, "the data01 error!\n"); ++ } else { ++ fsize = frame_get_length(pframe); ++ ++ cp = (u8 *)(req->req.buf) + req->req.actual; ++ if (cp) { ++ memcpy(cp, pframe->data, fsize); ++ req->req.actual += fsize; ++ if ((fsize < ep->ep.maxpacket) ++ || (req->req.actual >= ++ req->req.length)) { ++ finish_req = 1; ++ done(ep, req, 0); ++ if (list_empty(&ep->queue)) ++ qe_eprx_nack(ep); ++ } ++ } ++ qe_ep_toggledata01(ep); ++ } ++ } else { ++ dev_err(udc->dev, "The receive frame with error!\n"); ++ } ++ ++ /* note: don't clear the rxbd's buffer address * ++ * only Clear the length */ ++ out_be32((u32 __iomem *)bd, (bdstatus & BD_STATUS_MASK)); ++ ep->has_data--; ++ ++ /* Get next BD */ ++ if (bdstatus & R_W) ++ bd = ep->rxbase; ++ else ++ bd++; ++ ++ bdstatus = in_be32((u32 __iomem *)bd); ++ length = bdstatus & BD_LENGTH_MASK; ++ } ++ ++ ep->n_rxbd = bd; ++ ep_recycle_rxbds(ep); ++ ++ return 0; ++} ++ ++/* only add the request in queue */ ++static int ep_req_receive(struct qe_ep *ep, struct qe_req *req) ++{ ++ if (ep->state == EP_STATE_NACK) { ++ if (ep->has_data <= 0) { ++ /* Enable rx and unmask rx interrupt */ ++ qe_eprx_normal(ep); ++ } else { ++ /* Copy the exist BD data */ ++ ep_req_rx(ep, req); ++ } ++ } ++ ++ return 0; ++} ++ ++/******************************************************************** ++ Internal Used Function End ++********************************************************************/ ++ ++/*----------------------------------------------------------------------- ++ Endpoint Management Functions For Gadget ++ -----------------------------------------------------------------------*/ ++static int qe_ep_enable(struct usb_ep *_ep, ++ const struct usb_endpoint_descriptor *desc) ++{ ++ struct qe_udc *udc; ++ struct qe_ep *ep; ++ int retval = 0; ++ unsigned char epnum; ++ ++ ep = container_of(_ep, struct qe_ep, ep); ++ ++ /* catch various bogus parameters */ ++ if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] || ++ (desc->bDescriptorType != USB_DT_ENDPOINT)) ++ return -EINVAL; ++ ++ udc = ep->udc; ++ if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN)) ++ return -ESHUTDOWN; ++ ++ epnum = (u8)desc->bEndpointAddress & 0xF; ++ ++ retval = qe_ep_init(udc, epnum, desc); ++ if (retval != 0) { ++ cpm_muram_free(cpm_muram_offset(ep->rxbase)); ++ dev_dbg(udc->dev, "enable ep%d failed\n", ep->epnum); ++ return -EINVAL; ++ } ++ dev_dbg(udc->dev, "enable ep%d successful\n", ep->epnum); ++ return 0; ++} ++ ++static int qe_ep_disable(struct usb_ep *_ep) ++{ ++ struct qe_udc *udc; ++ struct qe_ep *ep; ++ unsigned long flags; ++ unsigned int size; ++ ++ ep = container_of(_ep, struct qe_ep, ep); ++ udc = ep->udc; ++ ++ if (!_ep || !ep->desc) { ++ dev_dbg(udc->dev, "%s not enabled\n", _ep ? ep->ep.name : NULL); ++ return -EINVAL; ++ } ++ ++ spin_lock_irqsave(&udc->lock, flags); ++ /* Nuke all pending requests (does flush) */ ++ nuke(ep, -ESHUTDOWN); ++ ep->desc = NULL; ++ ep->stopped = 1; ++ spin_unlock_irqrestore(&udc->lock, flags); ++ ++ cpm_muram_free(cpm_muram_offset(ep->rxbase)); ++ ++ if (ep->dir == USB_DIR_OUT) ++ size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * ++ (USB_BDRING_LEN_RX + 1); ++ else ++ size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * ++ (USB_BDRING_LEN + 1); ++ ++ if (ep->dir != USB_DIR_IN) { ++ kfree(ep->rxframe); ++ if (ep->rxbufmap) { ++ dma_unmap_single(udc_controller->gadget.dev.parent, ++ ep->rxbuf_d, size, ++ DMA_FROM_DEVICE); ++ ep->rxbuf_d = DMA_ADDR_INVALID; ++ } else { ++ dma_sync_single_for_cpu( ++ udc_controller->gadget.dev.parent, ++ ep->rxbuf_d, size, ++ DMA_FROM_DEVICE); ++ } ++ kfree(ep->rxbuffer); ++ } ++ ++ if (ep->dir != USB_DIR_OUT) ++ kfree(ep->txframe); ++ ++ dev_dbg(udc->dev, "disabled %s OK\n", _ep->name); ++ return 0; ++} ++ ++static struct usb_request *qe_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) ++{ ++ struct qe_req *req; ++ ++ req = kzalloc(sizeof(*req), gfp_flags); ++ if (!req) ++ return NULL; ++ ++ req->req.dma = DMA_ADDR_INVALID; ++ ++ INIT_LIST_HEAD(&req->queue); ++ ++ return &req->req; ++} ++ ++static void qe_free_request(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct qe_req *req; ++ ++ req = container_of(_req, struct qe_req, req); ++ ++ if (_req) ++ kfree(req); ++} ++ ++/* queues (submits) an I/O request to an endpoint */ ++static int qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req, ++ gfp_t gfp_flags) ++{ ++ struct qe_ep *ep = container_of(_ep, struct qe_ep, ep); ++ struct qe_req *req = container_of(_req, struct qe_req, req); ++ struct qe_udc *udc; ++ unsigned long flags; ++ int reval; ++ ++ udc = ep->udc; ++ /* catch various bogus parameters */ ++ if (!_req || !req->req.complete || !req->req.buf ++ || !list_empty(&req->queue)) { ++ dev_dbg(udc->dev, "bad params\n"); ++ return -EINVAL; ++ } ++ if (!_ep || (!ep->desc && ep_index(ep))) { ++ dev_dbg(udc->dev, "bad ep\n"); ++ return -EINVAL; ++ } ++ ++ if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN) ++ return -ESHUTDOWN; ++ ++ req->ep = ep; ++ ++ /* map virtual address to hardware */ ++ if (req->req.dma == DMA_ADDR_INVALID) { ++ req->req.dma = dma_map_single(ep->udc->gadget.dev.parent, ++ req->req.buf, ++ req->req.length, ++ ep_is_in(ep) ++ ? DMA_TO_DEVICE : ++ DMA_FROM_DEVICE); ++ req->mapped = 1; ++ } else { ++ dma_sync_single_for_device(ep->udc->gadget.dev.parent, ++ req->req.dma, req->req.length, ++ ep_is_in(ep) ++ ? DMA_TO_DEVICE : ++ DMA_FROM_DEVICE); ++ req->mapped = 0; ++ } ++ ++ req->req.status = -EINPROGRESS; ++ req->req.actual = 0; ++ ++ list_add_tail(&req->queue, &ep->queue); ++ dev_vdbg(udc->dev, "gadget have request in %s! %d\n", ++ ep->name, req->req.length); ++ spin_lock_irqsave(&udc->lock, flags); ++ /* push the request to device */ ++ if (ep_is_in(ep)) ++ reval = ep_req_send(ep, req); ++ ++ /* EP0 */ ++ if (ep_index(ep) == 0 && req->req.length > 0) { ++ if (ep_is_in(ep)) ++ udc->ep0_state = DATA_STATE_XMIT; ++ else ++ udc->ep0_state = DATA_STATE_RECV; ++ } ++ ++ if (ep->dir == USB_DIR_OUT) ++ reval = ep_req_receive(ep, req); ++ ++ spin_unlock_irqrestore(&udc->lock, flags); ++ ++ return 0; ++} ++ ++/* dequeues (cancels, unlinks) an I/O request from an endpoint */ ++static int qe_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct qe_ep *ep = container_of(_ep, struct qe_ep, ep); ++ struct qe_req *req; ++ unsigned long flags; ++ ++ if (!_ep || !_req) ++ return -EINVAL; ++ ++ spin_lock_irqsave(&ep->udc->lock, flags); ++ ++ /* make sure it's actually queued on this endpoint */ ++ list_for_each_entry(req, &ep->queue, queue) { ++ if (&req->req == _req) ++ break; ++ } ++ ++ if (&req->req != _req) { ++ spin_unlock_irqrestore(&ep->udc->lock, flags); ++ return -EINVAL; ++ } ++ ++ done(ep, req, -ECONNRESET); ++ ++ spin_unlock_irqrestore(&ep->udc->lock, flags); ++ return 0; ++} ++ ++/*----------------------------------------------------------------- ++ * modify the endpoint halt feature ++ * @ep: the non-isochronous endpoint being stalled ++ * @value: 1--set halt 0--clear halt ++ * Returns zero, or a negative error code. ++*----------------------------------------------------------------*/ ++static int qe_ep_set_halt(struct usb_ep *_ep, int value) ++{ ++ struct qe_ep *ep; ++ unsigned long flags; ++ int status = -EOPNOTSUPP; ++ struct qe_udc *udc; ++ ++ ep = container_of(_ep, struct qe_ep, ep); ++ if (!_ep || !ep->desc) { ++ status = -EINVAL; ++ goto out; ++ } ++ ++ if (ep->epnum != 0) { ++ status = 0; ++ goto out; ++ } ++ ++ udc = ep->udc; ++ /* Attempt to halt IN ep will fail if any transfer requests ++ * are still queue */ ++ if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { ++ status = -EAGAIN; ++ goto out; ++ } ++ ++ status = 0; ++ spin_lock_irqsave(&ep->udc->lock, flags); ++ qe_eptx_stall_change(ep, value); ++ qe_eprx_stall_change(ep, value); ++ spin_unlock_irqrestore(&ep->udc->lock, flags); ++ ++ if (ep->epnum == 0) { ++ udc->ep0_state = WAIT_FOR_SETUP; ++ udc->ep0_dir = 0; ++ } ++out: ++ dev_vdbg(udc->dev, " %s %s halt stat %d\n", ep->ep.name, ++ value ? "set" : "clear", status); ++ ++ return status; ++} ++ ++static struct usb_ep_ops qe_ep_ops = { ++ .enable = qe_ep_enable, ++ .disable = qe_ep_disable, ++ ++ .alloc_request = qe_alloc_request, ++ .free_request = qe_free_request, ++ ++ .queue = qe_ep_queue, ++ .dequeue = qe_ep_dequeue, ++ ++ .set_halt = qe_ep_set_halt, ++}; ++ ++/*------------------------------------------------------------------------ ++ Gadget Driver Layer Operations ++ ------------------------------------------------------------------------*/ ++ ++/* Get the current frame number */ ++static int qe_get_frame(struct usb_gadget *gadget) ++{ ++ u16 tmp; ++ ++ tmp = in_be16(&udc_controller->usb_param->frame_n); ++ if (tmp & 0x8000) ++ tmp = tmp & 0x07ff; ++ else ++ tmp = -EINVAL; ++ ++ return (int)tmp; ++} ++ ++/* Tries to wake up the host connected to this gadget ++ * ++ * Return : 0-success ++ * Negative-this feature not enabled by host or not supported by device hw ++ */ ++static int qe_wakeup(struct usb_gadget *gadget) ++{ ++ return -ENOTSUPP; ++} ++ ++/* Notify controller that VBUS is powered, Called by whatever ++ detects VBUS sessions */ ++static int qe_vbus_session(struct usb_gadget *gadget, int is_active) ++{ ++ return -ENOTSUPP; ++} ++ ++/* constrain controller's VBUS power usage ++ * This call is used by gadget drivers during SET_CONFIGURATION calls, ++ * reporting how much power the device may consume. For example, this ++ * could affect how quickly batteries are recharged. ++ * ++ * Returns zero on success, else negative errno. ++ */ ++static int qe_vbus_draw(struct usb_gadget *gadget, unsigned mA) ++{ ++ return -ENOTSUPP; ++} ++ ++/* Change Data+ pullup status ++ * this func is used by usb_gadget_connect/disconnect ++ */ ++static int qe_pullup(struct usb_gadget *gadget, int is_on) ++{ ++ return -ENOTSUPP; ++} ++ ++/* defined in usb_gadget.h */ ++static struct usb_gadget_ops qe_gadget_ops = { ++ .get_frame = qe_get_frame, ++ .wakeup = qe_wakeup, ++/* .set_selfpowered = qe_set_selfpowered,*/ /* always selfpowered */ ++ .vbus_session = qe_vbus_session, ++ .vbus_draw = qe_vbus_draw, ++ .pullup = qe_pullup, ++}; ++ ++/*------------------------------------------------------------------------- ++ USB ep0 Setup process in BUS Enumeration ++ -------------------------------------------------------------------------*/ ++static int udc_reset_ep_queue(struct qe_udc *udc, u8 pipe) ++{ ++ struct qe_ep *ep = &udc->eps[pipe]; ++ ++ nuke(ep, -ECONNRESET); ++ ep->tx_req = NULL; ++ return 0; ++} ++ ++static int reset_queues(struct qe_udc *udc) ++{ ++ u8 pipe; ++ ++ for (pipe = 0; pipe < USB_MAX_ENDPOINTS; pipe++) ++ udc_reset_ep_queue(udc, pipe); ++ ++ /* report disconnect; the driver is already quiesced */ ++ spin_unlock(&udc->lock); ++ udc->driver->disconnect(&udc->gadget); ++ spin_lock(&udc->lock); ++ ++ return 0; ++} ++ ++static void ch9setaddress(struct qe_udc *udc, u16 value, u16 index, ++ u16 length) ++{ ++ /* Save the new address to device struct */ ++ udc->device_address = (u8) value; ++ /* Update usb state */ ++ udc->usb_state = USB_STATE_ADDRESS; ++ ++ /* Status phase , send a ZLP */ ++ if (ep0_prime_status(udc, USB_DIR_IN)) ++ qe_ep0_stall(udc); ++} ++ ++static void ownercomplete(struct usb_ep *_ep, struct usb_request *_req) ++{ ++ struct qe_req *req = container_of(_req, struct qe_req, req); ++ ++ req->req.buf = NULL; ++ kfree(req); ++} ++ ++static void ch9getstatus(struct qe_udc *udc, u16 value, u16 index, ++ u16 length) ++{ ++ u16 usb_status = 0; /* fix me to give correct status */ ++ ++ struct qe_req *req; ++ struct qe_ep *ep; ++ int status = 0; ++ ++ ep = &udc->eps[0]; ++ ++ req = container_of(qe_alloc_request(&ep->ep, GFP_KERNEL), ++ struct qe_req, req); ++ req->req.length = 2; ++ req->req.buf = udc->nullbuf; ++ memcpy(req->req.buf, (u8 *)&usb_status, 2); ++ req->req.status = -EINPROGRESS; ++ req->req.actual = 0; ++ req->req.complete = ownercomplete; ++ ++ udc->ep0_dir = USB_DIR_IN; ++ ++ /* data phase */ ++ status = qe_ep_queue(&ep->ep, &req->req, GFP_ATOMIC); ++ ++ if (status) { ++ dev_err(udc->dev, "Can't respond to getstatus request \n"); ++ qe_ep0_stall(udc); ++ } ++} ++ ++/* only handle the setup request, suppose the device in normal status */ ++static void setup_received_handle(struct qe_udc *udc, ++ struct usb_ctrlrequest *setup) ++{ ++ /* Fix Endian (udc->local_setup_buff is cpu Endian now)*/ ++ u16 wValue = le16_to_cpu(setup->wValue); ++ u16 wIndex = le16_to_cpu(setup->wIndex); ++ u16 wLength = le16_to_cpu(setup->wLength); ++ ++ /* clear the previous request in the ep0 */ ++ udc_reset_ep_queue(udc, 0); ++ ++ if (setup->bRequestType & USB_DIR_IN) ++ udc->ep0_dir = USB_DIR_IN; ++ else ++ udc->ep0_dir = USB_DIR_OUT; ++ ++ switch (setup->bRequest) { ++ case USB_REQ_GET_STATUS: ++ /* Data+Status phase form udc */ ++ if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) ++ != (USB_DIR_IN | USB_TYPE_STANDARD)) ++ break; ++ ch9getstatus(udc, wValue, wIndex, wLength); ++ return; ++ ++ case USB_REQ_SET_ADDRESS: ++ /* Status phase from udc */ ++ if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | ++ USB_RECIP_DEVICE)) ++ break; ++ ch9setaddress(udc, wValue, wIndex, wLength); ++ return; ++ ++ case USB_REQ_CLEAR_FEATURE: ++ case USB_REQ_SET_FEATURE: ++ /* Requests with no data phase, status phase from udc */ ++ if ((setup->bRequestType & USB_TYPE_MASK) ++ != USB_TYPE_STANDARD) ++ break; ++ ++ if ((setup->bRequestType & USB_RECIP_MASK) ++ == USB_RECIP_ENDPOINT) { ++ int pipe = wIndex & USB_ENDPOINT_NUMBER_MASK; ++ struct qe_ep *ep; ++ ++ if (wValue != 0 || wLength != 0 ++ || pipe > USB_MAX_ENDPOINTS) ++ break; ++ ep = &udc->eps[pipe]; ++ ++ spin_unlock(&udc->lock); ++ qe_ep_set_halt(&ep->ep, ++ (setup->bRequest == USB_REQ_SET_FEATURE) ++ ? 1 : 0); ++ spin_lock(&udc->lock); ++ } ++ ++ ep0_prime_status(udc, USB_DIR_IN); ++ ++ return; ++ ++ default: ++ break; ++ } ++ ++ if (wLength) { ++ /* Data phase from gadget, status phase from udc */ ++ if (setup->bRequestType & USB_DIR_IN) { ++ udc->ep0_state = DATA_STATE_XMIT; ++ udc->ep0_dir = USB_DIR_IN; ++ } else{ ++ udc->ep0_state = DATA_STATE_RECV; ++ udc->ep0_dir = USB_DIR_OUT; ++ } ++ spin_unlock(&udc->lock); ++ if (udc->driver->setup(&udc->gadget, ++ &udc->local_setup_buff) < 0) ++ qe_ep0_stall(udc); ++ spin_lock(&udc->lock); ++ } else { ++ /* No data phase, IN status from gadget */ ++ udc->ep0_dir = USB_DIR_IN; ++ spin_unlock(&udc->lock); ++ if (udc->driver->setup(&udc->gadget, ++ &udc->local_setup_buff) < 0) ++ qe_ep0_stall(udc); ++ spin_lock(&udc->lock); ++ udc->ep0_state = DATA_STATE_NEED_ZLP; ++ } ++} ++ ++/*------------------------------------------------------------------------- ++ USB Interrupt handlers ++ -------------------------------------------------------------------------*/ ++static void suspend_irq(struct qe_udc *udc) ++{ ++ udc->resume_state = udc->usb_state; ++ udc->usb_state = USB_STATE_SUSPENDED; ++ ++ /* report suspend to the driver ,serial.c not support this*/ ++ if (udc->driver->suspend) ++ udc->driver->suspend(&udc->gadget); ++} ++ ++static void resume_irq(struct qe_udc *udc) ++{ ++ udc->usb_state = udc->resume_state; ++ udc->resume_state = 0; ++ ++ /* report resume to the driver , serial.c not support this*/ ++ if (udc->driver->resume) ++ udc->driver->resume(&udc->gadget); ++} ++ ++static void idle_irq(struct qe_udc *udc) ++{ ++ u8 usbs; ++ ++ usbs = in_8(&udc->usb_regs->usb_usbs); ++ if (usbs & USB_IDLE_STATUS_MASK) { ++ if ((udc->usb_state) != USB_STATE_SUSPENDED) ++ suspend_irq(udc); ++ } else { ++ if (udc->usb_state == USB_STATE_SUSPENDED) ++ resume_irq(udc); ++ } ++} ++ ++static int reset_irq(struct qe_udc *udc) ++{ ++ unsigned char i; ++ ++ qe_usb_disable(); ++ out_8(&udc->usb_regs->usb_usadr, 0); ++ ++ for (i = 0; i < USB_MAX_ENDPOINTS; i++) { ++ if (udc->eps[i].init) ++ qe_ep_reset(udc, i); ++ } ++ ++ reset_queues(udc); ++ udc->usb_state = USB_STATE_DEFAULT; ++ udc->ep0_state = WAIT_FOR_SETUP; ++ udc->ep0_dir = USB_DIR_OUT; ++ qe_usb_enable(); ++ return 0; ++} ++ ++static int bsy_irq(struct qe_udc *udc) ++{ ++ return 0; ++} ++ ++static int txe_irq(struct qe_udc *udc) ++{ ++ return 0; ++} ++ ++/* ep0 tx interrupt also in here */ ++static int tx_irq(struct qe_udc *udc) ++{ ++ struct qe_ep *ep; ++ struct qe_bd __iomem *bd; ++ int i, res = 0; ++ ++ if ((udc->usb_state == USB_STATE_ADDRESS) ++ && (in_8(&udc->usb_regs->usb_usadr) == 0)) ++ out_8(&udc->usb_regs->usb_usadr, udc->device_address); ++ ++ for (i = (USB_MAX_ENDPOINTS-1); ((i >= 0) && (res == 0)); i--) { ++ ep = &udc->eps[i]; ++ if (ep && ep->init && (ep->dir != USB_DIR_OUT)) { ++ bd = ep->c_txbd; ++ if (!(in_be32((u32 __iomem *)bd) & T_R) ++ && (in_be32(&bd->buf))) { ++ /* Disable the TX Interrupt */ ++ /*confirm the transmitted bd*/ ++ if (ep->epnum == 0) ++ res = qe_ep0_txconf(ep); ++ else ++ res = qe_ep_txconf(ep); ++ /* Enable the TX Interrupt */ ++ } ++ } ++ } ++ return res; ++} ++ ++ ++/* setup packect's rx is handle in the function too */ ++static void rx_irq(struct qe_udc *udc) ++{ ++ struct qe_ep *ep; ++ struct qe_bd __iomem *bd; ++ int i; ++ ++ for (i = 0; i < USB_MAX_ENDPOINTS; i++) { ++ ep = &udc->eps[i]; ++ if (ep && ep->init && (ep->dir != USB_DIR_IN)) { ++ bd = ep->n_rxbd; ++ if (!(in_be32((u32 __iomem *)bd) & R_E) ++ && (in_be32(&bd->buf))) { ++ if (ep->epnum == 0) { ++ qe_ep0_rx(udc); ++ } else { ++ /*non-setup package receive*/ ++ qe_ep_rx(ep); ++ } ++ } ++ } ++ } ++} ++ ++static irqreturn_t qe_udc_irq(int irq, void *_udc) ++{ ++ struct qe_udc *udc = (struct qe_udc *)_udc; ++ u16 irq_src; ++ irqreturn_t status = IRQ_NONE; ++ unsigned long flags; ++ ++ ++ spin_lock_irqsave(&udc->lock, flags); ++ ++ irq_src = in_be16(&udc->usb_regs->usb_usber) & ++ in_be16(&udc->usb_regs->usb_usbmr); ++ /* Clear notification bits */ ++ out_be16(&udc->usb_regs->usb_usber, irq_src); ++ /* USB Interrupt */ ++ if (irq_src & USB_E_IDLE_MASK) { ++ idle_irq(udc); ++ irq_src &= ~USB_E_IDLE_MASK; ++ status = IRQ_HANDLED; ++ } ++ ++ if (irq_src & USB_E_TXB_MASK) { ++ tx_irq(udc); ++ irq_src &= ~USB_E_TXB_MASK; ++ status = IRQ_HANDLED; ++ } ++ ++ if (irq_src & USB_E_RXB_MASK) { ++ rx_irq(udc); ++ irq_src &= ~USB_E_RXB_MASK; ++ status = IRQ_HANDLED; ++ } ++ ++ if (irq_src & USB_E_RESET_MASK) { ++ reset_irq(udc); ++ irq_src &= ~USB_E_RESET_MASK; ++ status = IRQ_HANDLED; ++ } ++ ++ if (irq_src & USB_E_BSY_MASK) { ++ bsy_irq(udc); ++ irq_src &= ~USB_E_BSY_MASK; ++ status = IRQ_HANDLED; ++ } ++ ++ if (irq_src & USB_E_TXE_MASK) { ++ txe_irq(udc); ++ irq_src &= ~USB_E_TXE_MASK; ++ status = IRQ_HANDLED; ++ } ++ ++ spin_unlock_irqrestore(&udc->lock, flags); ++ ++ return status; ++} ++ ++/*------------------------------------------------------------------------- ++ Gadget driver register and unregister. ++ --------------------------------------------------------------------------*/ ++int usb_gadget_register_driver(struct usb_gadget_driver *driver) ++{ ++ int retval; ++ unsigned long flags = 0; ++ ++ /* standard operations */ ++ if (!udc_controller) ++ return -ENODEV; ++ ++ if (!driver || (driver->speed != USB_SPEED_FULL ++ && driver->speed != USB_SPEED_HIGH) ++ || !driver->bind || !driver->disconnect ++ || !driver->setup) ++ return -EINVAL; ++ ++ if (udc_controller->driver) ++ return -EBUSY; ++ ++ /* lock is needed but whether should use this lock or another */ ++ spin_lock_irqsave(&udc_controller->lock, flags); ++ ++ driver->driver.bus = NULL; ++ /* hook up the driver */ ++ udc_controller->driver = driver; ++ udc_controller->gadget.dev.driver = &driver->driver; ++ udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed); ++ spin_unlock_irqrestore(&udc_controller->lock, flags); ++ ++ retval = driver->bind(&udc_controller->gadget); ++ if (retval) { ++ dev_err(udc_controller->dev, "bind to %s --> %d", ++ driver->driver.name, retval); ++ udc_controller->gadget.dev.driver = NULL; ++ udc_controller->driver = NULL; ++ return retval; ++ } ++ ++ /* Enable IRQ reg and Set usbcmd reg EN bit */ ++ qe_usb_enable(); ++ ++ out_be16(&udc_controller->usb_regs->usb_usber, 0xffff); ++ out_be16(&udc_controller->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE); ++ udc_controller->usb_state = USB_STATE_ATTACHED; ++ udc_controller->ep0_state = WAIT_FOR_SETUP; ++ udc_controller->ep0_dir = USB_DIR_OUT; ++ dev_info(udc_controller->dev, "%s bind to driver %s \n", ++ udc_controller->gadget.name, driver->driver.name); ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_register_driver); ++ ++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) ++{ ++ struct qe_ep *loop_ep; ++ unsigned long flags; ++ ++ if (!udc_controller) ++ return -ENODEV; ++ ++ if (!driver || driver != udc_controller->driver) ++ return -EINVAL; ++ ++ /* stop usb controller, disable intr */ ++ qe_usb_disable(); ++ ++ /* in fact, no needed */ ++ udc_controller->usb_state = USB_STATE_ATTACHED; ++ udc_controller->ep0_state = WAIT_FOR_SETUP; ++ udc_controller->ep0_dir = 0; ++ ++ /* stand operation */ ++ spin_lock_irqsave(&udc_controller->lock, flags); ++ udc_controller->gadget.speed = USB_SPEED_UNKNOWN; ++ nuke(&udc_controller->eps[0], -ESHUTDOWN); ++ list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list, ++ ep.ep_list) ++ nuke(loop_ep, -ESHUTDOWN); ++ spin_unlock_irqrestore(&udc_controller->lock, flags); ++ ++ /* unbind gadget and unhook driver. */ ++ driver->unbind(&udc_controller->gadget); ++ udc_controller->gadget.dev.driver = NULL; ++ udc_controller->driver = NULL; ++ ++ dev_info(udc_controller->dev, "unregistered gadget driver '%s'\r\n", ++ driver->driver.name); ++ return 0; ++} ++EXPORT_SYMBOL(usb_gadget_unregister_driver); ++ ++/* udc structure's alloc and setup, include ep-param alloc */ ++static struct qe_udc __devinit *qe_udc_config(struct of_device *ofdev) ++{ ++ struct qe_udc *udc; ++ struct device_node *np = ofdev->node; ++ unsigned int tmp_addr = 0; ++ struct usb_device_para __iomem *usbpram; ++ unsigned int i; ++ u64 size; ++ u32 offset; ++ ++ udc = kzalloc(sizeof(*udc), GFP_KERNEL); ++ if (udc == NULL) { ++ dev_err(&ofdev->dev, "malloc udc failed\n"); ++ goto cleanup; ++ } ++ ++ udc->dev = &ofdev->dev; ++ ++ /* get default address of usb parameter in MURAM from device tree */ ++ offset = *of_get_address(np, 1, &size, NULL); ++ udc->usb_param = cpm_muram_addr(offset); ++ memset_io(udc->usb_param, 0, size); ++ ++ usbpram = udc->usb_param; ++ out_be16(&usbpram->frame_n, 0); ++ out_be32(&usbpram->rstate, 0); ++ ++ tmp_addr = cpm_muram_alloc((USB_MAX_ENDPOINTS * ++ sizeof(struct usb_ep_para)), ++ USB_EP_PARA_ALIGNMENT); ++ ++ for (i = 0; i < USB_MAX_ENDPOINTS; i++) { ++ out_be16(&usbpram->epptr[i], (u16)tmp_addr); ++ udc->ep_param[i] = cpm_muram_addr(tmp_addr); ++ tmp_addr += 32; ++ } ++ ++ memset_io(udc->ep_param[0], 0, ++ USB_MAX_ENDPOINTS * sizeof(struct usb_ep_para)); ++ ++ udc->resume_state = USB_STATE_NOTATTACHED; ++ udc->usb_state = USB_STATE_POWERED; ++ udc->ep0_dir = 0; ++ ++ spin_lock_init(&udc->lock); ++ return udc; ++ ++cleanup: ++ kfree(udc); ++ return NULL; ++} ++ ++/* USB Controller register init */ ++static int __devinit qe_udc_reg_init(struct qe_udc *udc) ++{ ++ struct usb_ctlr __iomem *qe_usbregs; ++ qe_usbregs = udc->usb_regs; ++ ++ /* Init the usb register */ ++ out_8(&qe_usbregs->usb_usmod, 0x01); ++ out_be16(&qe_usbregs->usb_usbmr, 0); ++ out_8(&qe_usbregs->usb_uscom, 0); ++ out_be16(&qe_usbregs->usb_usber, USBER_ALL_CLEAR); ++ ++ return 0; ++} ++ ++static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) ++{ ++ struct qe_ep *ep = &udc->eps[pipe_num]; ++ ++ ep->udc = udc; ++ strcpy(ep->name, ep_name[pipe_num]); ++ ep->ep.name = ep_name[pipe_num]; ++ ++ ep->ep.ops = &qe_ep_ops; ++ ep->stopped = 1; ++ ep->ep.maxpacket = (unsigned short) ~0; ++ ep->desc = NULL; ++ ep->dir = 0xff; ++ ep->epnum = (u8)pipe_num; ++ ep->sent = 0; ++ ep->last = 0; ++ ep->init = 0; ++ ep->rxframe = NULL; ++ ep->txframe = NULL; ++ ep->tx_req = NULL; ++ ep->state = EP_STATE_IDLE; ++ ep->has_data = 0; ++ ++ /* the queue lists any req for this ep */ ++ INIT_LIST_HEAD(&ep->queue); ++ ++ /* gagdet.ep_list used for ep_autoconfig so no ep0*/ ++ if (pipe_num != 0) ++ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); ++ ++ ep->gadget = &udc->gadget; ++ ++ return 0; ++} ++ ++/*----------------------------------------------------------------------- ++ * UDC device Driver operation functions * ++ *----------------------------------------------------------------------*/ ++static void qe_udc_release(struct device *dev) ++{ ++ int i = 0; ++ ++ complete(udc_controller->done); ++ cpm_muram_free(cpm_muram_offset(udc_controller->ep_param[0])); ++ for (i = 0; i < USB_MAX_ENDPOINTS; i++) ++ udc_controller->ep_param[i] = NULL; ++ ++ kfree(udc_controller); ++ udc_controller = NULL; ++} ++ ++/* Driver probe functions */ ++static int __devinit qe_udc_probe(struct of_device *ofdev, ++ const struct of_device_id *match) ++{ ++ struct device_node *np = ofdev->node; ++ struct qe_ep *ep; ++ unsigned int ret = 0; ++ unsigned int i; ++ const void *prop; ++ ++ prop = of_get_property(np, "mode", NULL); ++ if (!prop || strcmp(prop, "peripheral")) ++ return -ENODEV; ++ ++ /* Initialize the udc structure including QH member and other member */ ++ udc_controller = qe_udc_config(ofdev); ++ if (!udc_controller) { ++ dev_dbg(&ofdev->dev, "udc_controll is NULL\n"); ++ return -ENOMEM; ++ } ++ ++ udc_controller->soc_type = (unsigned long)np->data; ++ udc_controller->usb_regs = of_iomap(np, 0); ++ if (!udc_controller->usb_regs) { ++ ret = -ENOMEM; ++ goto err1; ++ } ++ ++ /* initialize usb hw reg except for regs for EP, ++ * leave usbintr reg untouched*/ ++ qe_udc_reg_init(udc_controller); ++ ++ /* here comes the stand operations for probe ++ * set the qe_udc->gadget.xxx */ ++ udc_controller->gadget.ops = &qe_gadget_ops; ++ ++ /* gadget.ep0 is a pointer */ ++ udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; ++ ++ INIT_LIST_HEAD(&udc_controller->gadget.ep_list); ++ ++ /* modify in register gadget process */ ++ udc_controller->gadget.speed = USB_SPEED_UNKNOWN; ++ ++ /* name: Identifies the controller hardware type. */ ++ udc_controller->gadget.name = driver_name; ++ ++ device_initialize(&udc_controller->gadget.dev); ++ ++ strcpy(udc_controller->gadget.dev.bus_id, "gadget"); ++ ++ udc_controller->gadget.dev.release = qe_udc_release; ++ udc_controller->gadget.dev.parent = &ofdev->dev; ++ ++ ++ /* EP:intialization qe_ep struct */ ++ for (i = 0; i < USB_MAX_ENDPOINTS ; i++) { ++ /*because the ep type isn't decide here so ++ * qe_ep_init() should be called in ep_enable() */ ++ ++ /* setup the qe_ep struct and link ep.ep.list ++ * into gadget.ep_list */ ++ qe_ep_config(udc_controller, (unsigned char)i); ++ } ++ ++ /* ep0 initialization in here */ ++ ret = qe_ep_init(udc_controller, 0, &qe_ep0_desc); ++ if (ret) ++ goto err2; ++ ++ /* create a buf for ZLP send */ ++ udc_controller->nullbuf = kzalloc(256, GFP_KERNEL); ++ if (udc_controller->nullbuf == NULL) { ++ dev_dbg(udc_controller->dev, "cannot alloc nullbuf\n"); ++ ret = -ENOMEM; ++ goto err3; ++ } ++ ++ udc_controller->nullp = virt_to_phys((void *)udc_controller->nullbuf); ++ if (udc_controller->nullp == DMA_ADDR_INVALID) { ++ udc_controller->nullp = dma_map_single( ++ udc_controller->gadget.dev.parent, ++ udc_controller->nullbuf, ++ 256, ++ DMA_TO_DEVICE); ++ udc_controller->nullmap = 1; ++ } else { ++ dma_sync_single_for_device(udc_controller->gadget.dev.parent, ++ udc_controller->nullp, 256, ++ DMA_TO_DEVICE); ++ } ++ ++ tasklet_init(&udc_controller->rx_tasklet, ep_rx_tasklet, ++ (unsigned long)udc_controller); ++ /* request irq and disable DR */ ++ udc_controller->usb_irq = irq_of_parse_and_map(np, 0); ++ ++ ret = request_irq(udc_controller->usb_irq, qe_udc_irq, 0, ++ driver_name, udc_controller); ++ if (ret) { ++ dev_err(udc_controller->dev, "cannot request irq %d err %d \n", ++ udc_controller->usb_irq, ret); ++ goto err4; ++ } ++ ++ ret = device_add(&udc_controller->gadget.dev); ++ if (ret) ++ goto err5; ++ ++ dev_info(udc_controller->dev, ++ "QE/CPM USB controller initialized as device\n"); ++ return 0; ++ ++err5: ++ free_irq(udc_controller->usb_irq, udc_controller); ++err4: ++ if (udc_controller->nullmap) { ++ dma_unmap_single(udc_controller->gadget.dev.parent, ++ udc_controller->nullp, 256, ++ DMA_TO_DEVICE); ++ udc_controller->nullp = DMA_ADDR_INVALID; ++ } else { ++ dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, ++ udc_controller->nullp, 256, ++ DMA_TO_DEVICE); ++ } ++ kfree(udc_controller->nullbuf); ++err3: ++ ep = &udc_controller->eps[0]; ++ cpm_muram_free(cpm_muram_offset(ep->rxbase)); ++ kfree(ep->rxframe); ++ kfree(ep->rxbuffer); ++ kfree(ep->txframe); ++err2: ++ iounmap(udc_controller->usb_regs); ++err1: ++ kfree(udc_controller); ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM ++static int qe_udc_suspend(struct of_device *dev, pm_message_t state) ++{ ++ return -ENOTSUPP; ++} ++ ++static int qe_udc_resume(struct of_device *dev) ++{ ++ return -ENOTSUPP; ++} ++#endif ++ ++static int __devexit qe_udc_remove(struct of_device *ofdev) ++{ ++ struct qe_ep *ep; ++ unsigned int size; ++ ++ DECLARE_COMPLETION(done); ++ ++ if (!udc_controller) ++ return -ENODEV; ++ ++ udc_controller->done = &done; ++ tasklet_disable(&udc_controller->rx_tasklet); ++ ++ if (udc_controller->nullmap) { ++ dma_unmap_single(udc_controller->gadget.dev.parent, ++ udc_controller->nullp, 256, ++ DMA_TO_DEVICE); ++ udc_controller->nullp = DMA_ADDR_INVALID; ++ } else { ++ dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, ++ udc_controller->nullp, 256, ++ DMA_TO_DEVICE); ++ } ++ kfree(udc_controller->nullbuf); ++ ++ ep = &udc_controller->eps[0]; ++ cpm_muram_free(cpm_muram_offset(ep->rxbase)); ++ size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (USB_BDRING_LEN + 1); ++ ++ kfree(ep->rxframe); ++ if (ep->rxbufmap) { ++ dma_unmap_single(udc_controller->gadget.dev.parent, ++ ep->rxbuf_d, size, ++ DMA_FROM_DEVICE); ++ ep->rxbuf_d = DMA_ADDR_INVALID; ++ } else { ++ dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, ++ ep->rxbuf_d, size, ++ DMA_FROM_DEVICE); ++ } ++ ++ kfree(ep->rxbuffer); ++ kfree(ep->txframe); ++ ++ free_irq(udc_controller->usb_irq, udc_controller); ++ ++ tasklet_kill(&udc_controller->rx_tasklet); ++ ++ iounmap(udc_controller->usb_regs); ++ ++ device_unregister(&udc_controller->gadget.dev); ++ /* wait for release() of gadget.dev to free udc */ ++ wait_for_completion(&done); ++ ++ return 0; ++} ++ ++/*-------------------------------------------------------------------------*/ ++static struct of_device_id __devinitdata qe_udc_match[] = { ++ { ++ .compatible = "fsl,mpc8360-qe-usb", ++ .data = (void *)PORT_QE, ++ }, ++ { ++ .compatible = "fsl,mpc8272-cpm-usb", ++ .data = (void *)PORT_CPM, ++ }, ++ {}, ++}; ++ ++MODULE_DEVICE_TABLE(of, qe_udc_match); ++ ++static struct of_platform_driver udc_driver = { ++ .name = (char *)driver_name, ++ .match_table = qe_udc_match, ++ .probe = qe_udc_probe, ++ .remove = __devexit_p(qe_udc_remove), ++#ifdef CONFIG_PM ++ .suspend = qe_udc_suspend, ++ .resume = qe_udc_resume, ++#endif ++}; ++ ++static int __init qe_udc_init(void) ++{ ++ printk(KERN_INFO "%s: %s, %s\n", driver_name, driver_desc, ++ DRIVER_VERSION); ++ return of_register_platform_driver(&udc_driver); ++} ++ ++static void __exit qe_udc_exit(void) ++{ ++ of_unregister_platform_driver(&udc_driver); ++} ++ ++module_init(qe_udc_init); ++module_exit(qe_udc_exit); ++ ++MODULE_DESCRIPTION(DRIVER_DESC); ++MODULE_AUTHOR(DRIVER_AUTHOR); ++MODULE_LICENSE("GPL"); ++ +--- /dev/null ++++ b/drivers/usb/gadget/fsl_qe_udc.h +@@ -0,0 +1,436 @@ ++/* ++ * drivers/usb/gadget/qe_udc.h ++ * ++ * Copyright (C) 2006-2008 Freescale Semiconductor, Inc. All rights reserved. ++ * ++ * Xiaobo Xie <X.Xie@freescale.com> ++ * Li Yang <leoli@freescale.com> ++ * ++ * Description: ++ * Freescale USB device/endpoint management registers ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or (at ++ * your option) any later version. ++ */ ++ ++#ifndef __FSL_QE_UDC_H ++#define __FSL_QE_UDC_H ++ ++/* SoC type */ ++#define PORT_CPM 0 ++#define PORT_QE 1 ++ ++#define USB_MAX_ENDPOINTS 4 ++#define USB_MAX_PIPES USB_MAX_ENDPOINTS ++#define USB_EP0_MAX_SIZE 64 ++#define USB_MAX_CTRL_PAYLOAD 0x4000 ++#define USB_BDRING_LEN 16 ++#define USB_BDRING_LEN_RX 256 ++#define USB_BDRING_LEN_TX 16 ++#define MIN_EMPTY_BDS 128 ++#define MAX_DATA_BDS 8 ++#define USB_CRC_SIZE 2 ++#define USB_DIR_BOTH 0x88 ++#define R_BUF_MAXSIZE 0x800 ++#define USB_EP_PARA_ALIGNMENT 32 ++ ++/* USB Mode Register bit define */ ++#define USB_MODE_EN 0x01 ++#define USB_MODE_HOST 0x02 ++#define USB_MODE_TEST 0x04 ++#define USB_MODE_SFTE 0x08 ++#define USB_MODE_RESUME 0x40 ++#define USB_MODE_LSS 0x80 ++ ++/* USB Slave Address Register Mask */ ++#define USB_SLVADDR_MASK 0x7F ++ ++/* USB Endpoint register define */ ++#define USB_EPNUM_MASK 0xF000 ++#define USB_EPNUM_SHIFT 12 ++ ++#define USB_TRANS_MODE_SHIFT 8 ++#define USB_TRANS_CTR 0x0000 ++#define USB_TRANS_INT 0x0100 ++#define USB_TRANS_BULK 0x0200 ++#define USB_TRANS_ISO 0x0300 ++ ++#define USB_EP_MF 0x0020 ++#define USB_EP_RTE 0x0010 ++ ++#define USB_THS_SHIFT 2 ++#define USB_THS_MASK 0x000c ++#define USB_THS_NORMAL 0x0 ++#define USB_THS_IGNORE_IN 0x0004 ++#define USB_THS_NACK 0x0008 ++#define USB_THS_STALL 0x000c ++ ++#define USB_RHS_SHIFT 0 ++#define USB_RHS_MASK 0x0003 ++#define USB_RHS_NORMAL 0x0 ++#define USB_RHS_IGNORE_OUT 0x0001 ++#define USB_RHS_NACK 0x0002 ++#define USB_RHS_STALL 0x0003 ++ ++#define USB_RTHS_MASK 0x000f ++ ++/* USB Command Register define */ ++#define USB_CMD_STR_FIFO 0x80 ++#define USB_CMD_FLUSH_FIFO 0x40 ++#define USB_CMD_ISFT 0x20 ++#define USB_CMD_DSFT 0x10 ++#define USB_CMD_EP_MASK 0x03 ++ ++/* USB Event and Mask Register define */ ++#define USB_E_MSF_MASK 0x0800 ++#define USB_E_SFT_MASK 0x0400 ++#define USB_E_RESET_MASK 0x0200 ++#define USB_E_IDLE_MASK 0x0100 ++#define USB_E_TXE4_MASK 0x0080 ++#define USB_E_TXE3_MASK 0x0040 ++#define USB_E_TXE2_MASK 0x0020 ++#define USB_E_TXE1_MASK 0x0010 ++#define USB_E_SOF_MASK 0x0008 ++#define USB_E_BSY_MASK 0x0004 ++#define USB_E_TXB_MASK 0x0002 ++#define USB_E_RXB_MASK 0x0001 ++#define USBER_ALL_CLEAR 0x0fff ++ ++#define USB_E_DEFAULT_DEVICE (USB_E_RESET_MASK | USB_E_TXE4_MASK | \ ++ USB_E_TXE3_MASK | USB_E_TXE2_MASK | \ ++ USB_E_TXE1_MASK | USB_E_BSY_MASK | \ ++ USB_E_TXB_MASK | USB_E_RXB_MASK) ++ ++#define USB_E_TXE_MASK (USB_E_TXE4_MASK | USB_E_TXE3_MASK|\ ++ USB_E_TXE2_MASK | USB_E_TXE1_MASK) ++/* USB Status Register define */ ++#define USB_IDLE_STATUS_MASK 0x01 ++ ++/* USB Start of Frame Timer */ ++#define USB_USSFT_MASK 0x3FFF ++ ++/* USB Frame Number Register */ ++#define USB_USFRN_MASK 0xFFFF ++ ++struct usb_device_para{ ++ u16 epptr[4]; ++ u32 rstate; ++ u32 rptr; ++ u16 frame_n; ++ u16 rbcnt; ++ u32 rtemp; ++ u32 rxusb_data; ++ u16 rxuptr; ++ u8 reso[2]; ++ u32 softbl; ++ u8 sofucrctemp; ++}; ++ ++struct usb_ep_para{ ++ u16 rbase; ++ u16 tbase; ++ u8 rbmr; ++ u8 tbmr; ++ u16 mrblr; ++ u16 rbptr; ++ u16 tbptr; ++ u32 tstate; ++ u32 tptr; ++ u16 tcrc; ++ u16 tbcnt; ++ u32 ttemp; ++ u16 txusbu_ptr; ++ u8 reserve[2]; ++}; ++ ++#define USB_BUSMODE_GBL 0x20 ++#define USB_BUSMODE_BO_MASK 0x18 ++#define USB_BUSMODE_BO_SHIFT 0x3 ++#define USB_BUSMODE_BE 0x2 ++#define USB_BUSMODE_CETM 0x04 ++#define USB_BUSMODE_DTB 0x02 ++ ++/* Endpoint basic handle */ ++#define ep_index(EP) ((EP)->desc->bEndpointAddress & 0xF) ++#define ep_maxpacket(EP) ((EP)->ep.maxpacket) ++#define ep_is_in(EP) ((ep_index(EP) == 0) ? (EP->udc->ep0_dir == \ ++ USB_DIR_IN) : ((EP)->desc->bEndpointAddress \ ++ & USB_DIR_IN) == USB_DIR_IN) ++ ++/* ep0 transfer state */ ++#define WAIT_FOR_SETUP 0 ++#define DATA_STATE_XMIT 1 ++#define DATA_STATE_NEED_ZLP 2 ++#define WAIT_FOR_OUT_STATUS 3 ++#define DATA_STATE_RECV 4 ++ ++/* ep tramsfer mode */ ++#define USBP_TM_CTL 0 ++#define USBP_TM_ISO 1 ++#define USBP_TM_BULK 2 ++#define USBP_TM_INT 3 ++ ++/*----------------------------------------------------------------------------- ++ USB RX And TX DATA Frame ++ -----------------------------------------------------------------------------*/ ++struct qe_frame{ ++ u8 *data; ++ u32 len; ++ u32 status; ++ u32 info; ++ ++ void *privdata; ++ struct list_head node; ++}; ++ ++/* Frame structure, info field. */ ++#define PID_DATA0 0x80000000 /* Data toggle zero */ ++#define PID_DATA1 0x40000000 /* Data toggle one */ ++#define PID_SETUP 0x20000000 /* setup bit */ ++#define SETUP_STATUS 0x10000000 /* setup status bit */ ++#define SETADDR_STATUS 0x08000000 /* setupup address status bit */ ++#define NO_REQ 0x04000000 /* Frame without request */ ++#define HOST_DATA 0x02000000 /* Host data frame */ ++#define FIRST_PACKET_IN_FRAME 0x01000000 /* first packet in the frame */ ++#define TOKEN_FRAME 0x00800000 /* Host token frame */ ++#define ZLP 0x00400000 /* Zero length packet */ ++#define IN_TOKEN_FRAME 0x00200000 /* In token package */ ++#define OUT_TOKEN_FRAME 0x00100000 /* Out token package */ ++#define SETUP_TOKEN_FRAME 0x00080000 /* Setup token package */ ++#define STALL_FRAME 0x00040000 /* Stall handshake */ ++#define NACK_FRAME 0x00020000 /* Nack handshake */ ++#define NO_PID 0x00010000 /* No send PID */ ++#define NO_CRC 0x00008000 /* No send CRC */ ++#define HOST_COMMAND 0x00004000 /* Host command frame */ ++ ++/* Frame status field */ ++/* Receive side */ ++#define FRAME_OK 0x00000000 /* Frame tranmitted or received OK */ ++#define FRAME_ERROR 0x80000000 /* Error occured on frame */ ++#define START_FRAME_LOST 0x40000000 /* START_FRAME_LOST */ ++#define END_FRAME_LOST 0x20000000 /* END_FRAME_LOST */ ++#define RX_ER_NONOCT 0x10000000 /* Rx Non Octet Aligned Packet */ ++#define RX_ER_BITSTUFF 0x08000000 /* Frame Aborted --Received packet ++ with bit stuff error */ ++#define RX_ER_CRC 0x04000000 /* Received packet with CRC error */ ++#define RX_ER_OVERUN 0x02000000 /* Over-run occured on reception */ ++#define RX_ER_PID 0x01000000 /* Wrong PID received */ ++/* Tranmit side */ ++#define TX_ER_NAK 0x00800000 /* Received NAK handshake */ ++#define TX_ER_STALL 0x00400000 /* Received STALL handshake */ ++#define TX_ER_TIMEOUT 0x00200000 /* Transmit time out */ ++#define TX_ER_UNDERUN 0x00100000 /* Transmit underrun */ ++#define FRAME_INPROGRESS 0x00080000 /* Frame is being transmitted */ ++#define ER_DATA_UNDERUN 0x00040000 /* Frame is shorter then expected */ ++#define ER_DATA_OVERUN 0x00020000 /* Frame is longer then expected */ ++ ++/* QE USB frame operation functions */ ++#define frame_get_length(frm) (frm->len) ++#define frame_set_length(frm, leng) (frm->len = leng) ++#define frame_get_data(frm) (frm->data) ++#define frame_set_data(frm, dat) (frm->data = dat) ++#define frame_get_info(frm) (frm->info) ++#define frame_set_info(frm, inf) (frm->info = inf) ++#define frame_get_status(frm) (frm->status) ++#define frame_set_status(frm, stat) (frm->status = stat) ++#define frame_get_privdata(frm) (frm->privdata) ++#define frame_set_privdata(frm, dat) (frm->privdata = dat) ++ ++static inline void qe_frame_clean(struct qe_frame *frm) ++{ ++ frame_set_data(frm, NULL); ++ frame_set_length(frm, 0); ++ frame_set_status(frm, FRAME_OK); ++ frame_set_info(frm, 0); ++ frame_set_privdata(frm, NULL); ++} ++ ++static inline void qe_frame_init(struct qe_frame *frm) ++{ ++ qe_frame_clean(frm); ++ INIT_LIST_HEAD(&(frm->node)); ++} ++ ++struct qe_req { ++ struct usb_request req; ++ struct list_head queue; ++ /* ep_queue() func will add ++ a request->queue into a udc_ep->queue 'd tail */ ++ struct qe_ep *ep; ++ unsigned mapped:1; ++}; ++ ++struct qe_ep { ++ struct usb_ep ep; ++ struct list_head queue; ++ struct qe_udc *udc; ++ const struct usb_endpoint_descriptor *desc; ++ struct usb_gadget *gadget; ++ ++ u8 state; ++ ++ struct qe_bd __iomem *rxbase; ++ struct qe_bd __iomem *n_rxbd; ++ struct qe_bd __iomem *e_rxbd; ++ ++ struct qe_bd __iomem *txbase; ++ struct qe_bd __iomem *n_txbd; ++ struct qe_bd __iomem *c_txbd; ++ ++ struct qe_frame *rxframe; ++ u8 *rxbuffer; ++ dma_addr_t rxbuf_d; ++ u8 rxbufmap; ++ unsigned char localnack; ++ int has_data; ++ ++ struct qe_frame *txframe; ++ struct qe_req *tx_req; ++ int sent; /*data already sent */ ++ int last; /*data sent in the last time*/ ++ ++ u8 dir; ++ u8 epnum; ++ u8 tm; /* transfer mode */ ++ u8 data01; ++ u8 init; ++ ++ u8 already_seen; ++ u8 enable_tasklet; ++ u8 setup_stage; ++ u32 last_io; /* timestamp */ ++ ++ char name[14]; ++ ++ unsigned double_buf:1; ++ unsigned stopped:1; ++ unsigned fnf:1; ++ unsigned has_dma:1; ++ ++ u8 ackwait; ++ u8 dma_channel; ++ u16 dma_counter; ++ int lch; ++ ++ struct timer_list timer; ++}; ++ ++struct qe_udc { ++ struct usb_gadget gadget; ++ struct usb_gadget_driver *driver; ++ struct device *dev; ++ struct qe_ep eps[USB_MAX_ENDPOINTS]; ++ struct usb_ctrlrequest local_setup_buff; ++ spinlock_t lock; /* lock for set/config qe_udc */ ++ unsigned long soc_type; /* QE or CPM soc */ ++ ++ struct qe_req *status_req; /* ep0 status request */ ++ ++ /* USB and EP Parameter Block pointer */ ++ struct usb_device_para __iomem *usb_param; ++ struct usb_ep_para __iomem *ep_param[4]; ++ ++ u32 max_pipes; /* Device max pipes */ ++ u32 max_use_endpts; /* Max endpointes to be used */ ++ u32 bus_reset; /* Device is bus reseting */ ++ u32 resume_state; /* USB state to resume*/ ++ u32 usb_state; /* USB current state */ ++ u32 usb_next_state; /* USB next state */ ++ u32 ep0_state; /* Enpoint zero state */ ++ u32 ep0_dir; /* Enpoint zero direction: can be ++ USB_DIR_IN or USB_DIR_OUT*/ ++ u32 usb_sof_count; /* SOF count */ ++ u32 errors; /* USB ERRORs count */ ++ ++ u8 *tmpbuf; ++ u32 c_start; ++ u32 c_end; ++ ++ u8 *nullbuf; ++ dma_addr_t nullp; ++ u8 nullmap; ++ u8 device_address; /* Device USB address */ ++ ++ unsigned int usb_clock; ++ unsigned int usb_irq; ++ struct usb_ctlr __iomem *usb_regs; ++ ++ struct tasklet_struct rx_tasklet; ++ ++ struct completion *done; /* to make sure release() is done */ ++}; ++ ++#define EP_STATE_IDLE 0 ++#define EP_STATE_NACK 1 ++#define EP_STATE_STALL 2 ++ ++/* ++ * transmit BD's status ++ */ ++#define T_R 0x80000000 /* ready bit */ ++#define T_W 0x20000000 /* wrap bit */ ++#define T_I 0x10000000 /* interrupt on completion */ ++#define T_L 0x08000000 /* last */ ++#define T_TC 0x04000000 /* transmit CRC */ ++#define T_CNF 0x02000000 /* wait for transmit confirm */ ++#define T_LSP 0x01000000 /* Low-speed transaction */ ++#define T_PID 0x00c00000 /* packet id */ ++#define T_NAK 0x00100000 /* No ack. */ ++#define T_STAL 0x00080000 /* Stall recieved */ ++#define T_TO 0x00040000 /* time out */ ++#define T_UN 0x00020000 /* underrun */ ++ ++#define DEVICE_T_ERROR (T_UN | T_TO) ++#define HOST_T_ERROR (T_UN | T_TO | T_NAK | T_STAL) ++#define DEVICE_T_BD_MASK DEVICE_T_ERROR ++#define HOST_T_BD_MASK HOST_T_ERROR ++ ++#define T_PID_SHIFT 6 ++#define T_PID_DATA0 0x00800000 /* Data 0 toggle */ ++#define T_PID_DATA1 0x00c00000 /* Data 1 toggle */ ++ ++/* ++ * receive BD's status ++ */ ++#define R_E 0x80000000 /* buffer empty */ ++#define R_W 0x20000000 /* wrap bit */ ++#define R_I 0x10000000 /* interrupt on reception */ ++#define R_L 0x08000000 /* last */ ++#define R_F 0x04000000 /* first */ ++#define R_PID 0x00c00000 /* packet id */ ++#define R_NO 0x00100000 /* Rx Non Octet Aligned Packet */ ++#define R_AB 0x00080000 /* Frame Aborted */ ++#define R_CR 0x00040000 /* CRC Error */ ++#define R_OV 0x00020000 /* Overrun */ ++ ++#define R_ERROR (R_NO | R_AB | R_CR | R_OV) ++#define R_BD_MASK R_ERROR ++ ++#define R_PID_DATA0 0x00000000 ++#define R_PID_DATA1 0x00400000 ++#define R_PID_SETUP 0x00800000 ++ ++#define CPM_USB_STOP_TX 0x2e600000 ++#define CPM_USB_RESTART_TX 0x2e600000 ++#define CPM_USB_STOP_TX_OPCODE 0x0a ++#define CPM_USB_RESTART_TX_OPCODE 0x0b ++#define CPM_USB_EP_SHIFT 5 ++ ++#ifndef CONFIG_CPM ++inline int cpm_command(u32 command, u8 opcode) ++{ ++ return -EOPNOTSUPP; ++} ++#endif ++ ++#ifndef CONFIG_QUICC_ENGINE ++inline int qe_issue_cmd(u32 cmd, u32 device, u8 mcn_protocol, ++ u32 cmd_input) ++{ ++ return -EOPNOTSUPP; ++} ++#endif ++ ++#endif /* __FSL_QE_UDC_H */ +--- a/drivers/usb/gadget/gadget_chips.h ++++ b/drivers/usb/gadget/gadget_chips.h +@@ -151,6 +151,13 @@ + #define gadget_is_m66592(g) 0 + #endif + ++/* Freescale CPM/QE UDC SUPPORT */ ++#ifdef CONFIG_USB_GADGET_FSL_QE ++#define gadget_is_fsl_qe(g) !strcmp("fsl_qe_udc", (g)->name) ++#else ++#define gadget_is_fsl_qe(g) 0 ++#endif ++ + + // CONFIG_USB_GADGET_SX2 + // CONFIG_USB_GADGET_AU1X00 +@@ -216,6 +223,8 @@ static inline int usb_gadget_controller_ + return 0x20; + else if (gadget_is_m66592(gadget)) + return 0x21; ++ else if (gadget_is_fsl_qe(gadget)) ++ return 0x22; + return -ENOENT; + } + +--- a/drivers/usb/gadget/Kconfig ++++ b/drivers/usb/gadget/Kconfig +@@ -341,6 +341,25 @@ config USB_AMD5536UDC + default USB_GADGET + select USB_GADGET_SELECTED + ++config USB_GADGET_FSL_QE ++ boolean "Freescale QE/CPM USB Device Controller" ++ depends on FSL_SOC && (QUICC_ENGINE || CPM) ++ help ++ Some of Freescale PowerPC processors have a Full Speed ++ QE/CPM2 USB controller, which support device mode with 4 ++ programmable endpoints. This driver supports the ++ controller in the MPC8360 and MPC8272, and should work with ++ controllers having QE or CPM2, given minor tweaks. ++ ++ Set CONFIG_USB_GADGET to "m" to build this driver as a ++ dynmically linked module called "fsl_qe_udc". ++ ++config USB_FSL_QE ++ tristate ++ depends on USB_GADGET_FSL_QE ++ default USB_GADGET ++ select USB_GADGET_SELECTED ++ + config USB_GADGET_NET2280 + boolean "NetChip 228x" + depends on PCI +--- a/drivers/usb/gadget/Makefile ++++ b/drivers/usb/gadget/Makefile +@@ -18,6 +18,7 @@ obj-$(CONFIG_USB_AT91) += at91_udc.o + obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o + obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o + obj-$(CONFIG_USB_M66592) += m66592-udc.o ++obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o + + # + # USB gadget drivers diff --git a/usb/usb-drivers-usb-misc-use-an-is_err-test-rather-than-a-null-test.patch b/usb/usb-drivers-usb-misc-use-an-is_err-test-rather-than-a-null-test.patch new file mode 100644 index 00000000000000..31242e5f2a04db --- /dev/null +++ b/usb/usb-drivers-usb-misc-use-an-is_err-test-rather-than-a-null-test.patch @@ -0,0 +1,49 @@ +From brunel@diku.dk Thu Sep 11 02:34:58 2008 +From: Julien Brunel <brunel@diku.dk> +Date: Mon, 1 Sep 2008 10:57:27 +0200 +Subject: USB: drivers/usb/misc: Use an IS_ERR test rather than a NULL test +To: gregkh@suse.de +Message-ID: <200809011057.28293.brunel@diku.dk> +Content-Disposition: inline + + +From: Julien Brunel <brunel@diku.dk> + +In case of error, the function backlight_device_register returns an +ERR pointer, but never returns a NULL pointer. So a NULL test that may +come after a call to this function should be strengthened by an IS_ERR +test. + +The semantic match that finds this problem is as follows: +(http://www.emn.fr/x-info/coccinelle/) + +// <smpl> +@match_bad_null_test@ +expression x, E; +statement S1,S2; +@@ +x = backlight_device_register(...) +... when != x = E +* if (x != NULL) +S1 else S2 +// </smpl> + +Signed-off-by: Julien Brunel <brunel@diku.dk> +Signed-off-by: Julia Lawall <julia@diku.dk> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/misc/appledisplay.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/misc/appledisplay.c ++++ b/drivers/usb/misc/appledisplay.c +@@ -314,7 +314,7 @@ error: + pdata->urbdata, pdata->urb->transfer_dma); + usb_free_urb(pdata->urb); + } +- if (pdata->bd) ++ if (pdata->bd && !IS_ERR(pdata->bd)) + backlight_device_unregister(pdata->bd); + kfree(pdata->msgdata); + } diff --git a/usb/usb-remove-unused-include-version.h.patch b/usb/usb-remove-unused-include-version.h.patch new file mode 100644 index 00000000000000..3388a20b5bbb20 --- /dev/null +++ b/usb/usb-remove-unused-include-version.h.patch @@ -0,0 +1,32 @@ +From weiyi.huang@gmail.com Thu Sep 11 02:32:59 2008 +From: Huang Weiyi <weiyi.huang@gmail.com> +Date: Sat, 23 Aug 2008 13:56:30 +0800 +Subject: USB: remove unused #include <version.h> +To: gregkh@suse.de, greg@kroah.com +Cc: linux-usb@vger.kernel.org +Message-ID: <20080823133422.128C.WEIYI.HUANG@gmail.com> + +From: Huang Weiyi <weiyi.huang@gmail.com> + +The driver(s) below do not use LINUX_VERSION_CODE nor KERNEL_VERSION. + drivers/usb/gadget/pxa27x_udc.c + +This patch removes the said #include <version.h>. + +Signed-off-by: Huang Weiyi <weiyi.huang@gmail.com> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/gadget/pxa27x_udc.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/drivers/usb/gadget/pxa27x_udc.c ++++ b/drivers/usb/gadget/pxa27x_udc.c +@@ -22,7 +22,6 @@ + #include <linux/module.h> + #include <linux/kernel.h> + #include <linux/types.h> +-#include <linux/version.h> + #include <linux/errno.h> + #include <linux/platform_device.h> + #include <linux/delay.h> diff --git a/usb/usb-storage-report-underflow-with-no-sense-data.patch b/usb/usb-storage-report-underflow-with-no-sense-data.patch new file mode 100644 index 00000000000000..6bb6db74711de3 --- /dev/null +++ b/usb/usb-storage-report-underflow-with-no-sense-data.patch @@ -0,0 +1,39 @@ +From stern+48acf28e@rowland.harvard.edu Thu Sep 11 02:37:35 2008 +From: Alan Stern <stern@rowland.harvard.edu> +Date: Tue, 2 Sep 2008 10:12:11 -0400 (EDT) +Subject: usb-storage: report underflow with no sense data +To: Matthew Dharm <mdharm-usb@one-eyed-alien.net>, Greg KH <greg@kroah.com> +Cc: USB Storage list <usb-storage@lists.one-eyed-alien.net>, USB list <linux-usb@vger.kernel.org> +Message-ID: <Pine.LNX.4.44L0.0808281707040.4308-100000@iolanthe.rowland.org> + + +This patch (as1118) addresses a problem with certain USB mass-storage +devices. These devices sometimes return less data than asked for and +then provide no sense data to explain the problem. Currently +usb-storage leaves it up to the SCSI layer to decide how this should +be handled, and the SCSI layer interprets the lack of sense data to +mean that nothing went wrong. But if we got less data than required +then something definitely _did_ go wrong, and we should say so. + +The patch tells the SCSI layer to retry the command when this sort of +thing happens. Retrying may not solve the underlying problem, but +it's better than believing that data was transferred when it wasn't. + +Signed-off-by: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/usb/storage/transport.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/storage/transport.c ++++ b/drivers/usb/storage/transport.c +@@ -663,7 +663,7 @@ void usb_stor_invoke_transport(struct sc + } + + /* Did we transfer less than the minimum amount required? */ +- if (srb->result == SAM_STAT_GOOD && ++ if ((srb->result == SAM_STAT_GOOD || srb->sense_buffer[2] == 0) && + scsi_bufflen(srb) - scsi_get_resid(srb) < srb->underflow) + srb->result = (DID_ERROR << 16) | (SUGGEST_RETRY << 24); + |
