diff options
Diffstat (limited to 'drivers/usb/gadget')
-rw-r--r-- | drivers/usb/gadget/Kconfig | 57 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/amd5536udc.c | 3454 | ||||
-rw-r--r-- | drivers/usb/gadget/amd5536udc.h | 626 | ||||
-rw-r--r-- | drivers/usb/gadget/ether.c | 4 | ||||
-rw-r--r-- | drivers/usb/gadget/gadget_chips.h | 10 | ||||
-rw-r--r-- | drivers/usb/gadget/m66592-udc.c | 255 | ||||
-rw-r--r-- | drivers/usb/gadget/m66592-udc.h | 610 | ||||
-rw-r--r-- | drivers/usb/gadget/serial.c | 25 |
9 files changed, 4577 insertions, 465 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 45e01e28945..767aed5b4be 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -82,6 +82,27 @@ choice Many controller drivers are platform-specific; these often need board-specific hooks. +config USB_GADGET_AMD5536UDC + boolean "AMD5536 UDC" + depends on PCI + select USB_GADGET_DUALSPEED + help + The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge. + It is a USB Highspeed DMA capable USB device controller. Beside ep0 + it provides 4 IN and 4 OUT endpoints (bulk or interrupt type). + The UDC port supports OTG operation, and may be used as a host port + if it's not being used to implement peripheral or OTG roles. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "amd5536udc" and force all + gadget drivers to also be dynamically linked. + +config USB_AMD5536UDC + tristate + depends on USB_GADGET_AMD5536UDC + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_FSL_USB2 boolean "Freescale Highspeed USB DR Peripheral Controller" depends on MPC834x || PPC_MPC831x @@ -156,6 +177,24 @@ config USB_PXA2XX_SMALL default y if USB_ETH default y if USB_G_SERIAL +config USB_GADGET_M66592 + boolean "Renesas M66592 USB Peripheral Controller" + select USB_GADGET_DUALSPEED + help + M66592 is a discrete USB peripheral controller chip that + supports both full and high speed USB 2.0 data transfers. + It has seven configurable endpoints, and endpoint zero. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "m66592_udc" and force all + gadget drivers to also be dynamically linked. + +config USB_M66592 + tristate + depends on USB_GADGET_M66592 + default USB_GADGET + select USB_GADGET_SELECTED + config USB_GADGET_GOKU boolean "Toshiba TC86C001 'Goku-S'" depends on PCI @@ -261,24 +300,6 @@ config USB_AT91 depends on USB_GADGET_AT91 default USB_GADGET -config USB_GADGET_M66592 - boolean "M66592 driver" - select USB_GADGET_DUALSPEED - help - M66592 is a USB 2.0 peripheral controller. - - It has seven configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "m66592_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_M66592 - tristate - depends on USB_GADGET_M66592 - default USB_GADGET - select USB_GADGET_SELECTED - config USB_GADGET_DUMMY_HCD boolean "Dummy HCD (DEVELOPMENT)" depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 8ae76f73863..1bc0f03550c 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -7,6 +7,7 @@ endif obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o obj-$(CONFIG_USB_NET2280) += net2280.o +obj-$(CONFIG_USB_AMD5536UDC) += amd5536udc.o obj-$(CONFIG_USB_PXA2XX) += pxa2xx_udc.o obj-$(CONFIG_USB_GOKU) += goku_udc.o obj-$(CONFIG_USB_OMAP) += omap_udc.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c new file mode 100644 index 00000000000..714156ca8fe --- /dev/null +++ b/drivers/usb/gadget/amd5536udc.c @@ -0,0 +1,3454 @@ +/* + * amd5536.c -- AMD 5536 UDC high/full speed USB device controller + * + * Copyright (C) 2005-2007 AMD (http://www.amd.com) + * Author: Thomas Dahlmann + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * The AMD5536 UDC is part of the x86 southbridge AMD Geode CS5536. + * It is a USB Highspeed DMA capable USB device controller. Beside ep0 it + * provides 4 IN and 4 OUT endpoints (bulk or interrupt type). + * + * Make sure that UDC is assigned to port 4 by BIOS settings (port can also + * be used as host port) and UOC bits PAD_EN and APU are set (should be done + * by BIOS init). + * + * UDC DMA requires 32-bit aligned buffers so DMA with gadget ether does not + * work without updating NET_IP_ALIGN. Or PIO mode (module param "use_dma=0") + * can be used with gadget ether. + */ + +/* debug control */ +/* #define UDC_VERBOSE */ + +/* Driver strings */ +#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller" +#define UDC_DRIVER_VERSION_STRING "01.00.0206 - $Revision: #3 $" + +/* system */ +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/kernel.h> +#include <linux/version.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/timer.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/ioctl.h> +#include <linux/fs.h> +#include <linux/dmapool.h> +#include <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/irq.h> + +#include <asm/byteorder.h> +#include <asm/system.h> +#include <asm/unaligned.h> + +/* gadget stack */ +#include <linux/usb/ch9.h> +#include <linux/usb_gadget.h> + +/* udc specific */ +#include "amd5536udc.h" + + +static void udc_tasklet_disconnect(unsigned long); +static void empty_req_queue(struct udc_ep *); +static int udc_probe(struct udc *dev); +static void udc_basic_init(struct udc *dev); +static void udc_setup_endpoints(struct udc *dev); +static void udc_soft_reset(struct udc *dev); +static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep); +static void udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq); +static int udc_free_dma_chain(struct udc *dev, struct udc_request *req); +static int udc_create_dma_chain(struct udc_ep *ep, struct udc_request *req, + unsigned long buf_len, gfp_t gfp_flags); +static int udc_remote_wakeup(struct udc *dev); +static int udc_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id); +static void udc_pci_remove(struct pci_dev *pdev); + +/* description */ +static const char mod_desc[] = UDC_MOD_DESCRIPTION; +static const char name[] = "amd5536udc"; + +/* structure to hold endpoint function pointers */ +static const struct usb_ep_ops udc_ep_ops; + +/* received setup data */ +static union udc_setup_data setup_data; + +/* pointer to device object */ +static struct udc *udc; + +/* irq spin lock for soft reset */ +static DEFINE_SPINLOCK(udc_irq_spinlock); +/* stall spin lock */ +static DEFINE_SPINLOCK(udc_stall_spinlock); + +/* +* slave mode: pending bytes in rx fifo after nyet, +* used if EPIN irq came but no req was available +*/ +static unsigned int udc_rxfifo_pending; + +/* count soft resets after suspend to avoid loop */ +static int soft_reset_occured; +static int soft_reset_after_usbreset_occured; + +/* timer */ +static struct timer_list udc_timer; +static int stop_timer; + +/* set_rde -- Is used to control enabling of RX DMA. Problem is + * that UDC has only one bit (RDE) to enable/disable RX DMA for + * all OUT endpoints. So we have to handle race conditions like + * when OUT data reaches the fifo but no request was queued yet. + * This cannot be solved by letting the RX DMA disabled until a + * request gets queued because there may be other OUT packets + * in the FIFO (important for not blocking control traffic). + * The value of set_rde controls the correspondig timer. + * + * set_rde -1 == not used, means it is alloed to be set to 0 or 1 + * set_rde 0 == do not touch RDE, do no start the RDE timer + * set_rde 1 == timer function will look whether FIFO has data + * set_rde 2 == set by timer function to enable RX DMA on next call + */ +static int set_rde = -1; + +static DECLARE_COMPLETION(on_exit); +static struct timer_list udc_pollstall_timer; +static int stop_pollstall_timer; +static DECLARE_COMPLETION(on_pollstall_exit); + +/* tasklet for usb disconnect */ +static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect, + (unsigned long) &udc); + + +/* endpoint names used for print */ +static const char ep0_string[] = "ep0in"; +static const char *ep_string[] = { + ep0_string, + "ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk", + "ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk", + "ep11in-bulk", "ep12in-bulk", "ep13in-bulk", "ep14in-bulk", + "ep15in-bulk", "ep0out", "ep1out-bulk", "ep2out-bulk", "ep3out-bulk", + "ep4out-bulk", "ep5out-bulk", "ep6out-bulk", "ep7out-bulk", + "ep8out-bulk", "ep9out-bulk", "ep10out-bulk", "ep11out-bulk", + "ep12out-bulk", "ep13out-bulk", "ep14out-bulk", "ep15out-bulk" +}; + +/* DMA usage flag */ +static int use_dma = 1; +/* packet per buffer dma */ +static int use_dma_ppb = 1; +/* with per descr. update */ +static int use_dma_ppb_du; +/* buffer fill mode */ +static int use_dma_bufferfill_mode; +/* full speed only mode */ +static int use_fullspeed; +/* tx buffer size for high speed */ +static unsigned long hs_tx_buf = UDC_EPIN_BUFF_SIZE; + +/* module parameters */ +module_param(use_dma, bool, S_IRUGO); +MODULE_PARM_DESC(use_dma, "true for DMA"); +module_param(use_dma_ppb, bool, S_IRUGO); +MODULE_PARM_DESC(use_dma_ppb, "true for DMA in packet per buffer mode"); +module_param(use_dma_ppb_du, bool, S_IRUGO); +MODULE_PARM_DESC(use_dma_ppb_du, + "true for DMA in packet per buffer mode with descriptor update"); +module_param(use_fullspeed, bool, S_IRUGO); +MODULE_PARM_DESC(use_fullspeed, "true for fullspeed only"); + +/*---------------------------------------------------------------------------*/ +/* Prints UDC device registers and endpoint irq registers */ +static void print_regs(struct udc *dev) +{ + DBG(dev, "------- Device registers -------\n"); + DBG(dev, "dev config = %08x\n", readl(&dev->regs->cfg)); + DBG(dev, "dev control = %08x\n", readl(&dev->regs->ctl)); + DBG(dev, "dev status = %08x\n", readl(&dev->regs->sts)); + DBG(dev, "\n"); + DBG(dev, "dev int's = %08x\n", readl(&dev->regs->irqsts)); + DBG(dev, "dev intmask = %08x\n", readl(&dev->regs->irqmsk)); + DBG(dev, "\n"); + DBG(dev, "dev ep int's = %08x\n", readl(&dev->regs->ep_irqsts)); + DBG(dev, "dev ep intmask = %08x\n", readl(&dev->regs->ep_irqmsk)); + DBG(dev, "\n"); + DBG(dev, "USE DMA = %d\n", use_dma); + if (use_dma && use_dma_ppb && !use_dma_ppb_du) { + DBG(dev, "DMA mode = PPBNDU (packet per buffer " + "WITHOUT desc. update)\n"); + dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBNDU"); + } else if (use_dma && use_dma_ppb_du && use_dma_ppb_du) { + DBG(dev, "DMA mode = PPBDU (packet per buffer " + "WITH desc. update)\n"); + dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "PPBDU"); + } + if (use_dma && use_dma_bufferfill_mode) { + DBG(dev, "DMA mode = BF (buffer fill mode)\n"); + dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF"); + } + if (!use_dma) { + dev_info(&dev->pdev->dev, "FIFO mode\n"); + } + DBG(dev, "-------------------------------------------------------\n"); +} + +/* Masks unused interrupts */ +static int udc_mask_unused_interrupts(struct udc *dev) +{ + u32 tmp; + + /* mask all dev interrupts */ + tmp = AMD_BIT(UDC_DEVINT_SVC) | + AMD_BIT(UDC_DEVINT_ENUM) | + AMD_BIT(UDC_DEVINT_US) | + AMD_BIT(UDC_DEVINT_UR) | + AMD_BIT(UDC_DEVINT_ES) | + AMD_BIT(UDC_DEVINT_SI) | + AMD_BIT(UDC_DEVINT_SOF)| + AMD_BIT(UDC_DEVINT_SC); + writel(tmp, &dev->regs->irqmsk); + + /* mask all ep interrupts */ + writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqmsk); + + return 0; +} + +/* Enables endpoint 0 interrupts */ +static int udc_enable_ep0_interrupts(struct udc *dev) +{ + u32 tmp; + + DBG(dev, "udc_enable_ep0_interrupts()\n"); + + /* read irq mask */ + tmp = readl(&dev->regs->ep_irqmsk); + /* enable ep0 irq's */ + tmp &= AMD_UNMASK_BIT(UDC_EPINT_IN_EP0) + & AMD_UNMASK_BIT(UDC_EPINT_OUT_EP0); + writel(tmp, &dev->regs->ep_irqmsk); + + return 0; +} + +/* Enables device interrupts for SET_INTF and SET_CONFIG */ +static int udc_enable_dev_setup_interrupts(struct udc *dev) +{ + u32 tmp; + + DBG(dev, "enable device interrupts for setup data\n"); + + /* read irq mask */ + tmp = readl(&dev->regs->irqmsk); + + /* enable SET_INTERFACE, SET_CONFIG and other needed irq's */ + tmp &= AMD_UNMASK_BIT(UDC_DEVINT_SI) + & AMD_UNMASK_BIT(UDC_DEVINT_SC) + & AMD_UNMASK_BIT(UDC_DEVINT_UR) + & AMD_UNMASK_BIT(UDC_DEVINT_SVC) + & AMD_UNMASK_BIT(UDC_DEVINT_ENUM); + writel(tmp, &dev->regs->irqmsk); + + return 0; +} + +/* Calculates fifo start of endpoint based on preceeding endpoints */ +static int udc_set_txfifo_addr(struct udc_ep *ep) +{ + struct udc *dev; + u32 tmp; + int i; + + if (!ep || !(ep->in)) + return -EINVAL; + + dev = ep->dev; + ep->txfifo = dev->txfifo; + + /* traverse ep's */ + for (i = 0; i < ep->num; i++) { + if (dev->ep[i].regs) { + /* read fifo size */ + tmp = readl(&dev->ep[i].regs->bufin_framenum); + tmp = AMD_GETBITS(tmp, UDC_EPIN_BUFF_SIZE); + ep->txfifo += tmp; + } + } + return 0; +} + +/* CNAK pending field: bit0 = ep0in, bit16 = ep0out */ +static u32 cnak_pending; + +static void UDC_QUEUE_CNAK(struct udc_ep *ep, unsigned num) +{ + if (readl(&ep->regs->ctl) & AMD_BIT(UDC_EPCTL_NAK)) { + DBG(ep->dev, "NAK could not be cleared for ep%d\n", num); + cnak_pending |= 1 << (num); + ep->naking = 1; + } else + cnak_pending = cnak_pending & (~(1 << (num))); +} + + +/* Enables endpoint, is called by gadget driver */ +static int +udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) +{ + struct udc_ep *ep; + struct udc *dev; + u32 tmp; + unsigned long iflags; + u8 udc_csr_epix; + + if (!usbep + || usbep->name == ep0_string + || !desc + || desc->bDescriptorType != USB_DT_ENDPOINT) + return -EINVAL; + + ep = container_of(usbep, struct udc_ep, ep); + dev = ep->dev; + + DBG(dev, "udc_ep_enable() ep %d\n", ep->num); + + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + spin_lock_irqsave(&dev->lock, iflags); + ep->desc = desc; + + ep->halted = 0; + + /* set traffic type */ + tmp = readl(&dev->ep[ep->num].regs->ctl); + tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_EPCTL_ET); + writel(tmp, &dev->ep[ep->num].regs->ctl); + + /* set max packet size */ + tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt); + tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_EP_MAX_PKT_SIZE); + ep->ep.maxpacket = desc->wMaxPacketSize; + writel(tmp, &dev->ep[ep->num].regs->bufout_maxpkt); + + /* IN ep */ + if (ep->in) { + + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num; + + /* set buffer size (tx fifo entries) */ + tmp = readl(&dev->ep[ep->num].regs->bufin_framenum); + /* double buffering: fifo size = 2 x max packet size */ + tmp = AMD_ADDBITS( + tmp, + desc->wMaxPacketSize * UDC_EPIN_BUFF_SIZE_MULT + / UDC_DWORD_BYTES, + UDC_EPIN_BUFF_SIZE); + writel(tmp, &dev->ep[ep->num].regs->bufin_framenum); + + /* calc. tx fifo base addr */ + udc_set_txfifo_addr(ep); + + /* flush fifo */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_F); + writel(tmp, &ep->regs->ctl); + + /* OUT ep */ + } else { + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS; + + /* set max packet size UDC CSR */ + tmp = readl(&dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); + tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, + UDC_CSR_NE_MAX_PKT); + writel(tmp, &dev->csr->ne[ep->num - UDC_CSR_EP_OUT_IX_OFS]); + + if (use_dma && !ep->in) { + /* alloc and init BNA dummy request */ + ep->bna_dummy_req = udc_alloc_bna_dummy(ep); + ep->bna_occurred = 0; + } + + if (ep->num != UDC_EP0OUT_IX) + dev->data_ep_enabled = 1; + } + + /* set ep values */ + tmp = readl(&dev->csr->ne[udc_csr_epix]); + /* max packet */ + tmp = AMD_ADDBITS(tmp, desc->wMaxPacketSize, UDC_CSR_NE_MAX_PKT); + /* ep number */ + tmp = AMD_ADDBITS(tmp, desc->bEndpointAddress, UDC_CSR_NE_NUM); + /* ep direction */ + tmp = AMD_ADDBITS(tmp, ep->in, UDC_CSR_NE_DIR); + /* ep type */ + tmp = AMD_ADDBITS(tmp, desc->bmAttributes, UDC_CSR_NE_TYPE); + /* ep config */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, UDC_CSR_NE_CFG); + /* ep interface */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, UDC_CSR_NE_INTF); + /* ep alt */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, UDC_CSR_NE_ALT); + /* write reg */ + writel(tmp, &dev->csr->ne[udc_csr_epix]); + + /* enable ep irq */ + tmp = readl(&dev->regs->ep_irqmsk); + tmp &= AMD_UNMASK_BIT(ep->num); + writel(tmp, &dev->regs->ep_irqmsk); + + /* + * clear NAK by writing CNAK + * avoid BNA for OUT DMA, don't clear NAK until DMA desc. written + */ + if (!use_dma || ep->in) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + tmp = desc->bEndpointAddress; + DBG(dev, "%s enabled\n", usbep->name); + + spin_unlock_irqrestore(&dev->lock, iflags); + return 0; +} + +/* Resets endpoint */ +static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep) +{ + u32 tmp; + + VDBG(ep->dev, "ep-%d reset\n", ep->num); + ep->desc = NULL; + ep->ep.ops = &udc_ep_ops; + INIT_LIST_HEAD(&ep->queue); + + ep->ep.maxpacket = (u16) ~0; + /* set NAK */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_SNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 1; + + /* disable interrupt */ + tmp = readl(®s->ep_irqmsk); + tmp |= AMD_BIT(ep->num); + writel(tmp, ®s->ep_irqmsk); + + if (ep->in) { + /* unset P and IN bit of potential former DMA */ + tmp = readl(&ep->regs->ctl); + tmp &= AMD_UNMASK_BIT(UDC_EPCTL_P); + writel(tmp, &ep->regs->ctl); + + tmp = readl(&ep->regs->sts); + tmp |= AMD_BIT(UDC_EPSTS_IN); + writel(tmp, &ep->regs->sts); + + /* flush the fifo */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_F); + writel(tmp, &ep->regs->ctl); + + } + /* reset desc pointer */ + writel(0, &ep->regs->desptr); +} + +/* Disables endpoint, is called by gadget driver */ +static int udc_ep_disable(struct usb_ep *usbep) +{ + struct udc_ep *ep = NULL; + unsigned long iflags; + + if (!usbep) + return -EINVAL; + + ep = container_of(usbep, struct udc_ep, ep); + if (usbep->name == ep0_string || !ep->desc) + return -EINVAL; + + DBG(ep->dev, "Disable ep-%d\n", ep->num); + + spin_lock_irqsave(&ep->dev->lock, iflags); + udc_free_request(&ep->ep, &ep->bna_dummy_req->req); + empty_req_queue(ep); + ep_init(ep->dev->regs, ep); + spin_unlock_irqrestore(&ep->dev->lock, iflags); + + return 0; +} + +/* Allocates request packet, called by gadget driver */ +static struct usb_request * +udc_alloc_request(struct usb_ep *usbep, gfp_t gfp) +{ + struct udc_request *req; + struct udc_data_dma *dma_desc; + struct udc_ep *ep; + + if (!usbep) + return NULL; + + ep = container_of(usbep, struct udc_ep, ep); + + VDBG(ep->dev, "udc_alloc_req(): ep%d\n", ep->num); + req = kzalloc(sizeof(struct udc_request), gfp); + if (!req) + return NULL; + + req->req.dma = DMA_DONT_USE; + INIT_LIST_HEAD(&req->queue); + + if (ep->dma) { + /* ep0 in requests are allocated from data pool here */ + dma_desc = pci_pool_alloc(ep->dev->data_requests, gfp, + &req->td_phys); + if (!dma_desc) { + kfree(req); + return NULL; + } + + VDBG(ep->dev, "udc_alloc_req: req = %p dma_desc = %p, " + "td_phys = %lx\n", + req, dma_desc, + (unsigned long)req->td_phys); + /* prevent from using desc. - set HOST BUSY */ + dma_desc->status = AMD_ADDBITS(dma_desc->status, + UDC_DMA_STP_STS_BS_HOST_BUSY, + UDC_DMA_STP_STS_BS); + dma_desc->bufptr = __constant_cpu_to_le32(DMA_DONT_USE); + req->td_data = dma_desc; + req->td_data_last = NULL; + req->chain_len = 1; + } + + return &req->req; +} + +/* Frees request packet, called by gadget driver */ +static void +udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq) +{ + struct udc_ep *ep; + struct udc_request *req; + + if (!usbep || !usbreq) + return; + + ep = container_of(usbep, struct udc_ep, ep); + req = container_of(usbreq, struct udc_request, req); + VDBG(ep->dev, "free_req req=%p\n", req); + BUG_ON(!list_empty(&req->queue)); + if (req->td_data) { + VDBG(ep->dev, "req->td_data=%p\n", req->td_data); + + /* free dma chain if created */ + if (req->chain_len > 1) { + udc_free_dma_chain(ep->dev, req); + } + + pci_pool_free(ep->dev->data_requests, req->td_data, + req->td_phys); + } + kfree(req); +} + +/* Init BNA dummy descriptor for HOST BUSY and pointing to itself */ +static void udc_init_bna_dummy(struct udc_request *req) +{ + if (req) { + /* set last bit */ + req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L); + /* set next pointer to itself */ + req->td_data->next = req->td_phys; + /* set HOST BUSY */ + req->td_data->status + = AMD_ADDBITS(req->td_data->status, + UDC_DMA_STP_STS_BS_DMA_DONE, + UDC_DMA_STP_STS_BS); +#ifdef UDC_VERBOSE + pr_debug("bna desc = %p, sts = %08x\n", + req->td_data, req->td_data->status); +#endif + } +} + +/* Allocate BNA dummy descriptor */ +static struct udc_request *udc_alloc_bna_dummy(struct udc_ep *ep) +{ + struct udc_request *req = NULL; + struct usb_request *_req = NULL; + + /* alloc the dummy request */ + _req = udc_alloc_request(&ep->ep, GFP_ATOMIC); + if (_req) { + req = container_of(_req, struct udc_request, req); + ep->bna_dummy_req = req; + udc_init_bna_dummy(req); + } + return req; +} + +/* Write data to TX fifo for IN packets */ +static void +udc_txfifo_write(struct udc_ep *ep, struct usb_request *req) +{ + u8 *req_buf; + u32 *buf; + int i, j; + unsigned bytes = 0; + unsigned remaining = 0; + + if (!req || !ep) + return; + + req_buf = req->buf + req->actual; + prefetch(req_buf); + remaining = req->length - req->actual; + + buf = (u32 *) req_buf; + + bytes = ep->ep.maxpacket; + if (bytes > remaining) + bytes = remaining; + + /* dwords first */ + for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) { + writel(*(buf + i), ep->txfifo); + } + + /* remaining bytes must be written by byte access */ + for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) { + writeb((u8)(*(buf + i) >> (j << UDC_BITS_PER_BYTE_SHIFT)), + ep->txfifo); + } + + /* dummy write confirm */ + writel(0, &ep->regs->confirm); +} + +/* Read dwords from RX fifo for OUT transfers */ +static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords) +{ + int i; + + VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords); + + for (i = 0; i < dwords; i++) { + *(buf + i) = readl(dev->rxfifo); + } + return 0; +} + +/* Read bytes from RX fifo for OUT transfers */ +static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes) +{ + int i, j; + u32 tmp; + + VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes); + + /* dwords first */ + for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) { + *((u32 *)(buf + (i<<2))) = readl(dev->rxfifo); + } + + /* remaining bytes must be read by byte access */ + if (bytes % UDC_DWORD_BYTES) { + tmp = readl(dev->rxfifo); + for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) { + *(buf + (i<<2) + j) = (u8)(tmp & UDC_BYTE_MASK); + tmp = tmp >> UDC_BITS_PER_BYTE; + } + } + + return 0; +} + +/* Read data from RX fifo for OUT transfers */ +static int +udc_rxfifo_read(struct udc_ep *ep, struct udc_request *req) +{ + u8 *buf; + unsigned buf_space; + unsigned bytes = 0; + unsigned finished = 0; + + /* received number bytes */ + bytes = readl(&ep->regs->sts); + bytes = AMD_GETBITS(bytes, UDC_EPSTS_RX_PKT_SIZE); + + buf_space = req->req.length - req->req.actual; + buf = req->req.buf + req->req.actual; + if (bytes > buf_space) { + if ((buf_space % ep->ep.maxpacket) != 0) { + DBG(ep->dev, + "%s: rx %d bytes, rx-buf space = %d bytesn\n", + ep->ep.name, bytes, buf_space); + req->req.status = -EOVERFLOW; + } + bytes = buf_space; + } + req->req.actual += bytes; + + /* last packet ? */ + if (((bytes % ep->ep.maxpacket) != 0) || (!bytes) + || ((req->req.actual == req->req.length) && !req->req.zero)) + finished = 1; + + /* read rx fifo bytes */ + VDBG(ep->dev, "ep %s: rxfifo read %d bytes\n", ep->ep.name, bytes); + udc_rxfifo_read_bytes(ep->dev, buf, bytes); + + return finished; +} + +/* create/re-init a DMA descriptor or a DMA descriptor chain */ +static int prep_dma(struct udc_ep *ep, struct udc_request *req, gfp_t gfp) +{ + int retval = 0; + u32 tmp; + + VDBG(ep->dev, "prep_dma\n"); + VDBG(ep->dev, "prep_dma ep%d req->td_data=%p\n", + ep->num, req->td_data); + + /* set buffer pointer */ + req->td_data->bufptr = req->req.dma; + + /* set last bit */ + req->td_data->status |= AMD_BIT(UDC_DMA_IN_STS_L); + + /* build/re-init dma chain if maxpkt scatter mode, not for EP0 */ + if (use_dma_ppb) { + + retval = udc_create_dma_chain(ep, req, ep->ep.maxpacket, gfp); + if (retval != 0) { + if (retval == -ENOMEM) + DBG(ep->dev, "Out of DMA memory\n"); + return retval; + } + if (ep->in) { + if (req->req.length == ep->ep.maxpacket) { + /* write tx bytes */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + ep->ep.maxpacket, + UDC_DMA_IN_STS_TXBYTES); + + } + } + + } + + if (ep->in) { + VDBG(ep->dev, "IN: use_dma_ppb=%d req->req.len=%d " + "maxpacket=%d ep%d\n", + use_dma_ppb, req->req.length, + ep->ep.maxpacket, ep->num); + /* + * if bytes < max packet then tx bytes must + * be written in packet per buffer mode + */ + if (!use_dma_ppb || req->req.length < ep->ep.maxpacket + || ep->num == UDC_EP0OUT_IX + || ep->num == UDC_EP0IN_IX) { + /* write tx bytes */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + req->req.length, + UDC_DMA_IN_STS_TXBYTES); + /* reset frame num */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + 0, + UDC_DMA_IN_STS_FRAMENUM); + } + /* set HOST BUSY */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + UDC_DMA_STP_STS_BS_HOST_BUSY, + UDC_DMA_STP_STS_BS); + } else { + VDBG(ep->dev, "OUT set host ready\n"); + /* set HOST READY */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + UDC_DMA_STP_STS_BS_HOST_READY, + UDC_DMA_STP_STS_BS); + + + /* clear NAK by writing CNAK */ + if (ep->naking) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + + } + + return retval; +} + +/* Completes request packet ... caller MUST hold lock */ +static void +complete_req(struct udc_ep *ep, struct udc_request *req, int sts) +__releases(ep->dev->lock) +__acquires(ep->dev->lock) +{ + struct udc *dev; + unsigned halted; + + VDBG(ep->dev, "complete_req(): ep%d\n", ep->num); + + dev = ep->dev; + /* unmap DMA */ + if (req->dma_mapping) { + if (ep->in) + pci_unmap_single(dev->pdev, + req->req.dma, + req->req.length, + PCI_DMA_TODEVICE); + else + pci_unmap_single(dev->pdev, + req->req.dma, + req->req.length, + PCI_DMA_FROMDEVICE); + req->dma_mapping = 0; + req->req.dma = DMA_DONT_USE; + } + + halted = ep->halted; + ep->halted = 1; + + /* set new status if pending */ + if (req->req.status == -EINPROGRESS) + req->req.status = sts; + + /* remove from ep queue */ + list_del_init(&req->queue); + + VDBG(ep->dev, "req %p => complete %d bytes at %s with sts %d\n", + &req->req, req->req.length, ep->ep.name, sts); + + spin_unlock(&dev->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&dev->lock); + ep->halted = halted; +} + +/* frees pci pool descriptors of a DMA chain */ +static int udc_free_dma_chain(struct udc *dev, struct udc_request *req) +{ + + int ret_val = 0; + struct udc_data_dma *td; + struct udc_data_dma *td_last = NULL; + unsigned int i; + + DBG(dev, "free chain req = %p\n", req); + + /* do not free first desc., will be done by free for request */ + td_last = req->td_data; + td = phys_to_virt(td_last->next); + + for (i = 1; i < req->chain_len; i++) { + + pci_pool_free(dev->data_requests, td, + (dma_addr_t) td_last->next); + td_last = td; + td = phys_to_virt(td_last->next); + } + + return ret_val; +} + +/* Iterates to the end of a DMA chain and returns last descriptor */ +static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req) +{ + struct udc_data_dma *td; + + td = req->td_data; + while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) { + td = phys_to_virt(td->next); + } + + return td; + +} + +/* Iterates to the end of a DMA chain and counts bytes received */ +static u32 udc_get_ppbdu_rxbytes(struct udc_request *req) +{ + struct udc_data_dma *td; + u32 count; + + td = req->td_data; + /* received number bytes */ + count = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_RXBYTES); + + while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) { + td = phys_to_virt(td->next); + /* received number bytes */ + if (td) { + count += AMD_GETBITS(td->status, + UDC_DMA_OUT_STS_RXBYTES); + } + } + + return count; + +} + +/* Creates or re-inits a DMA chain */ +static int udc_create_dma_chain( + struct udc_ep *ep, + struct udc_request *req, + unsigned long buf_len, gfp_t gfp_flags +) +{ + unsigned long bytes = req->req.length; + unsigned int i; + dma_addr_t dma_addr; + struct udc_data_dma *td = NULL; + struct udc_data_dma *last = NULL; + unsigned long txbytes; + unsigned create_new_chain = 0; + unsigned len; + + VDBG(ep->dev, "udc_create_dma_chain: bytes=%ld buf_len=%ld\n", + bytes, buf_len); + dma_addr = DMA_DONT_USE; + + /* unset L bit in first desc for OUT */ + if (!ep->in) { + req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L); + } + + /* alloc only new desc's if not already available */ + len = req->req.length / ep->ep.maxpacket; + if (req->req.length % ep->ep.maxpacket) { + len++; + } + + if (len > req->chain_len) { + /* shorter chain already allocated before */ + if (req->chain_len > 1) { + udc_free_dma_chain(ep->dev, req); + } + req->chain_len = len; + create_new_chain = 1; + } + + td = req->td_data; + /* gen. required number of descriptors and buffers */ + for (i = buf_len; i < bytes; i += buf_len) { + /* create or determine next desc. */ + if (create_new_chain) { + + td = pci_pool_alloc(ep->dev->data_requests, + gfp_flags, &dma_addr); + if (!td) + return -ENOMEM; + + td->status = 0; + } else if (i == buf_len) { + /* first td */ + td = (struct udc_data_dma *) phys_to_virt( + req->td_data->next); + td->status = 0; + } else { + td = (struct udc_data_dma *) phys_to_virt(last->next); + td->status = 0; + } + + + if (td) + td->bufptr = req->req.dma + i; /* assign buffer */ + else + break; + + /* short packet ? */ + if ((bytes - i) >= buf_len) { + txbytes = buf_len; + } else { + /* short packet */ + txbytes = bytes - i; + } + + /* link td and assign tx bytes */ + if (i == buf_len) { + if (create_new_chain) { + req->td_data->next = dma_addr; + } else { + /* req->td_data->next = virt_to_phys(td); */ + } + /* write tx bytes */ + if (ep->in) { + /* first desc */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + ep->ep.maxpacket, + UDC_DMA_IN_STS_TXBYTES); + /* second desc */ + td->status = AMD_ADDBITS(td->status, + txbytes, + UDC_DMA_IN_STS_TXBYTES); + } + } else { + if (create_new_chain) { + last->next = dma_addr; + } else { + /* last->next = virt_to_phys(td); */ + } + if (ep->in) { + /* write tx bytes */ + td->status = AMD_ADDBITS(td->status, + txbytes, + UDC_DMA_IN_STS_TXBYTES); + } + } + last = td; + } + /* set last bit */ + if (td) { + td->status |= AMD_BIT(UDC_DMA_IN_STS_L); + /* last desc. points to itself */ + req->td_data_last = td; + } + + return 0; +} + +/* Enabling RX DMA */ +static void udc_set_rde(struct udc *dev) +{ + u32 tmp; + + VDBG(dev, "udc_set_rde()\n"); + /* stop RDE timer */ + if (timer_pending(&udc_timer)) { + set_rde = 0; + mod_timer(&udc_timer, jiffies - 1); + } + /* set RDE */ + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_RDE); + writel(tmp, &dev->regs->ctl); +} + +/* Queues a request packet, called by gadget driver */ +static int +udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) +{ + int retval = 0; + u8 open_rxfifo = 0; + unsigned long iflags; + struct udc_ep *ep; + struct udc_request *req; + struct udc *dev; + u32 tmp; + + /* check the inputs */ + req = container_of(usbreq, struct udc_request, req); + + if (!usbep || !usbreq || !usbreq->complete || !usbreq->buf + || !list_empty(&req->queue)) + return -EINVAL; + + ep = container_of(usbep, struct udc_ep, ep); + if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) + return -EINVAL; + + VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in); + dev = ep->dev; + + if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + /* map dma (usually done before) */ + if (ep->dma && usbreq->length != 0 + && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) { + VDBG(dev, "DMA map req %p\n", req); + if (ep->in) + usbreq->dma = pci_map_single(dev->pdev, + usbreq->buf, + usbreq->length, + PCI_DMA_TODEVICE); + else + usbreq->dma = pci_map_single(dev->pdev, + usbreq->buf, + usbreq->length, + PCI_DMA_FROMDEVICE); + req->dma_mapping = 1; + } + + VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n", + usbep->name, usbreq, usbreq->length, + req->td_data, usbreq->buf); + + spin_lock_irqsave(&dev->lock, iflags); + usbreq->actual = 0; + usbreq->status = -EINPROGRESS; + req->dma_done = 0; + + /* on empty queue just do first transfer */ + if (list_empty(&ep->queue)) { + /* zlp */ + if (usbreq->length == 0) { + /* IN zlp's are handled by hardware */ + complete_req(ep, req, 0); + VDBG(dev, "%s: zlp\n", ep->ep.name); + /* + * if set_config or set_intf is waiting for ack by zlp + * then set CSR_DONE + */ + if (dev->set_cfg_not_acked) { + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_CSR_DONE); + writel(tmp, &dev->regs->ctl); + dev->set_cfg_not_acked = 0; + } + /* setup command is ACK'ed now by zlp */ + if (dev->waiting_zlp_ack_ep0in) { + /* clear NAK by writing CNAK in EP0_IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + dev->ep[UDC_EP0IN_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], + UDC_EP0IN_IX); + dev->waiting_zlp_ack_ep0in = 0; + } + goto finished; + } + if (ep->dma) { + retval = prep_dma(ep, req, gfp); + if (retval != 0) + goto finished; + /* write desc pointer to enable DMA */ + if (ep->in) { + /* set HOST READY */ + req->td_data->status = + AMD_ADDBITS(req->td_data->status, + UDC_DMA_IN_STS_BS_HOST_READY, + UDC_DMA_IN_STS_BS); + } + + /* disabled rx dma while descriptor update */ + if (!ep->in) { + /* stop RDE timer */ + if (timer_pending(&udc_timer)) { + set_rde = 0; + mod_timer(&udc_timer, jiffies - 1); + } + /* clear RDE */ + tmp = readl(&dev->regs->ctl); + tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE); + writel(tmp, &dev->regs->ctl); + open_rxfifo = 1; + + /* + * if BNA occurred then let BNA dummy desc. + * point to current desc. + */ + if (ep->bna_occurred) { + VDBG(dev, "copy to BNA dummy desc.\n"); + memcpy(ep->bna_dummy_req->td_data, + req->td_data, + sizeof(struct udc_data_dma)); + } + } + /* write desc pointer */ + writel(req->td_phys, &ep->regs->desptr); + + /* clear NAK by writing CNAK */ + if (ep->naking) { + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->naking = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + + if (ep->in) { + /* enable ep irq */ + tmp = readl(&dev->regs->ep_irqmsk); + tmp &= AMD_UNMASK_BIT(ep->num); + writel(tmp, &dev->regs->ep_irqmsk); + } + } + + } else if (ep->dma) { + + /* + * prep_dma not used for OUT ep's, this is not possible + * for PPB modes, because of chain creation reasons + */ + if (ep->in) { + retval = prep_dma(ep, req, gfp); + if (retval != 0) + goto finished; + } + } + VDBG(dev, "list_add\n"); + /* add request to ep queue */ + if (req) { + + list_add_tail(&req->queue, &ep->queue); + + /* open rxfifo if out data queued */ + if (open_rxfifo) { + /* enable DMA */ + req->dma_going = 1; + udc_set_rde(dev); + if (ep->num != UDC_EP0OUT_IX) + dev->data_ep_queued = 1; + } + /* stop OUT naking */ + if (!ep->in) { + if (!use_dma && udc_rxfifo_pending) { + DBG(dev, "udc_queue(): pending bytes in" + "rxfifo after nyet\n"); + /* + * read pending bytes afer nyet: + * referring to isr + */ + if (udc_rxfifo_read(ep, req)) { + /* finish */ + complete_req(ep, req, 0); + } + udc_rxfifo_pending = 0; + + } + } + } + +finished: + spin_unlock_irqrestore(&dev->lock, iflags); + return retval; +} + +/* Empty request queue of an endpoint; caller holds spinlock */ +static void empty_req_queue(struct udc_ep *ep) +{ + struct udc_request *req; + + ep->halted = 1; + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct udc_request, + queue); + complete_req(ep, req, -ESHUTDOWN); + } +} + +/* Dequeues a request packet, called by gadget driver */ +static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq) +{ + struct udc_ep *ep; + struct udc_request *req; + unsigned halted; + unsigned long iflags; + + ep = container_of(usbep, struct udc_ep, ep); + if (!usbep || !usbreq || (!ep->desc && (ep->num != 0 + && ep->num != UDC_EP0OUT_IX))) + return -EINVAL; + + req = container_of(usbreq, struct udc_request, req); + + spin_lock_irqsave(&ep->dev->lock, iflags); + halted = ep->halted; + ep->halted = 1; + /* request in processing or next one */ + if (ep->queue.next == &req->queue) { + if (ep->dma && req->dma_going) { + if (ep->in) + ep->cancel_transfer = 1; + else { + u32 tmp; + u32 dma_sts; + /* stop potential receive DMA */ + tmp = readl(&udc->regs->ctl); + writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE), + &udc->regs->ctl); + /* + * Cancel transfer later in ISR + * if descriptor was touched. + */ + dma_sts = AMD_GETBITS(req->td_data->status, + UDC_DMA_OUT_STS_BS); + if (dma_sts != UDC_DMA_OUT_STS_BS_HOST_READY) + ep->cancel_transfer = 1; + else { + udc_init_bna_dummy(ep->req); + writel(ep->bna_dummy_req->td_phys, + &ep->regs->desptr); + } + writel(tmp, &udc->regs->ctl); + } + } + } + complete_req(ep, req, -ECONNRESET); + ep->halted = halted; + + spin_unlock_irqrestore(&ep->dev->lock, iflags); + return 0; +} + +/* Halt or clear halt of endpoint */ +static int +udc_set_halt(struct usb_ep *usbep, int halt) +{ + struct udc_ep *ep; + u32 tmp; + unsigned long iflags; + int retval = 0; + + if (!usbep) + return -EINVAL; + + pr_debug("set_halt %s: halt=%d\n", usbep->name, halt); + + ep = container_of(usbep, struct udc_ep, ep); + if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) + return -EINVAL; + if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) + return -ESHUTDOWN; + + spin_lock_irqsave(&udc_stall_spinlock, iflags); + /* halt or clear halt */ + if (halt) { + if (ep->num == 0) + ep->dev->stall_ep0in = 1; + else { + /* + * set STALL + * rxfifo empty not taken into acount + */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl); + ep->halted = 1; + + /* setup poll timer */ + if (!timer_pending(&udc_pollstall_timer)) { + udc_pollstall_timer.expires = jiffies + + HZ * UDC_POLLSTALL_TIMER_USECONDS + / (1000 * 1000); + if (!stop_pollstall_timer) { + DBG(ep->dev, "start polltimer\n"); + add_timer(&udc_pollstall_timer); + } + } + } + } else { + /* ep is halted by set_halt() before */ + if (ep->halted) { + tmp = readl(&ep->regs->ctl); + /* clear stall bit */ + tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S); + /* clear NAK by writing CNAK */ + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->halted = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + } + spin_unlock_irqrestore(&udc_stall_spinlock, iflags); + return retval; +} + +/* gadget interface */ +static const struct usb_ep_ops udc_ep_ops = { + .enable = udc_ep_enable, + .disable = udc_ep_disable, + + .alloc_request = udc_alloc_request, + .free_request = udc_free_request, + + .queue = udc_queue, + .dequeue = udc_dequeue, + + .set_halt = udc_set_halt, + /* fifo ops not implemented */ +}; + +/*-------------------------------------------------------------------------*/ + +/* Get frame counter (not implemented) */ +static int udc_get_frame(struct usb_gadget *gadget) +{ + return -EOPNOTSUPP; +} + +/* Remote wakeup gadget interface */ +static int udc_wakeup(struct usb_gadget *gadget) +{ + struct udc *dev; + + if (!gadget) + return -EINVAL; + dev = container_of(gadget, struct udc, gadget); + udc_remote_wakeup(dev); + + return 0; +} + +/* gadget operations */ +static const struct usb_gadget_ops udc_ops = { + .wakeup = udc_wakeup, + .get_frame = udc_get_frame, +}; + +/* Setups endpoint parameters, adds endpoints to linked list */ +static void make_ep_lists(struct udc *dev) +{ + /* make gadget ep lists */ + INIT_LIST_HEAD(&dev->gadget.ep_list); + list_add_tail(&dev->ep[UDC_EPIN_STATUS_IX].ep.ep_list, + &dev->gadget.ep_list); + list_add_tail(&dev->ep[UDC_EPIN_IX].ep.ep_list, + &dev->gadget.ep_list); + list_add_tail(&dev->ep[UDC_EPOUT_IX].ep.ep_list, + &dev->gadget.ep_list); + + /* fifo config */ + dev->ep[UDC_EPIN_STATUS_IX].fifo_depth = UDC_EPIN_SMALLINT_BUFF_SIZE; + if (dev->gadget.speed == USB_SPEED_FULL) + dev->ep[UDC_EPIN_IX].fifo_depth = UDC_FS_EPIN_BUFF_SIZE; + else if (dev->gadget.speed == USB_SPEED_HIGH) + dev->ep[UDC_EPIN_IX].fifo_depth = hs_tx_buf; + dev->ep[UDC_EPOUT_IX].fifo_depth = UDC_RXFIFO_SIZE; +} + +/* init registers at driver load time */ +static int startup_registers(struct udc *dev) +{ + u32 tmp; + + /* init controller by soft reset */ + udc_soft_reset(dev); + + /* mask not needed interrupts */ + udc_mask_unused_interrupts(dev); + + /* put into initial config */ + udc_basic_init(dev); + /* link up all endpoints */ + udc_setup_endpoints(dev); + + /* program speed */ + tmp = readl(&dev->regs->cfg); + if (use_fullspeed) { + tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD); + } else { + tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD); + } + writel(tmp, &dev->regs->cfg); + + return 0; +} + +/* Inits UDC context */ +static void udc_basic_init(struct udc *dev) +{ + u32 tmp; + + DBG(dev, "udc_basic_init()\n"); + + dev->gadget.speed = USB_SPEED_UNKNOWN; + + /* stop RDE timer */ + if (timer_pending(&udc_timer)) { + set_rde = 0; + mod_timer(&udc_timer, jiffies - 1); + } + /* stop poll stall timer */ + if (timer_pending(&udc_pollstall_timer)) { + mod_timer(&udc_pollstall_timer, jiffies - 1); + } + /* disable DMA */ + tmp = readl(&dev->regs->ctl); + tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE); + tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_TDE); + writel(tmp, &dev->regs->ctl); + + /* enable dynamic CSR programming */ + tmp = readl(&dev->regs->cfg); + tmp |= AMD_BIT(UDC_DEVCFG_CSR_PRG); + /* set self powered */ + tmp |= AMD_BIT(UDC_DEVCFG_SP); + /* set remote wakeupable */ + tmp |= AMD_BIT(UDC_DEVCFG_RWKP); + writel(tmp, &dev->regs->cfg); + + make_ep_lists(dev); + + dev->data_ep_enabled = 0; + dev->data_ep_queued = 0; +} + +/* Sets initial endpoint parameters */ +static void udc_setup_endpoints(struct udc *dev) +{ + struct udc_ep *ep; + u32 tmp; + u32 reg; + + DBG(dev, "udc_setup_endpoints()\n"); + + /* read enum speed */ + tmp = readl(&dev->regs->sts); + tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED); + if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) { + dev->gadget.speed = USB_SPEED_HIGH; + } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) { + dev->gadget.speed = USB_SPEED_FULL; + } + + /* set basic ep parameters */ + for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { + ep = &dev->ep[tmp]; + ep->dev = dev; + ep->ep.name = ep_string[tmp]; + ep->num = tmp; + /* txfifo size is calculated at enable time */ + ep->txfifo = dev->txfifo; + + /* fifo size */ + if (tmp < UDC_EPIN_NUM) { + ep->fifo_depth = UDC_TXFIFO_SIZE; + ep->in = 1; + } else { + ep->fifo_depth = UDC_RXFIFO_SIZE; + ep->in = 0; + + } + ep->regs = &dev->ep_regs[tmp]; + /* + * ep will be reset only if ep was not enabled before to avoid + * disabling ep interrupts when ENUM interrupt occurs but ep is + * not enabled by gadget driver + */ + if (!ep->desc) { + ep_init(dev->regs, ep); + } + + if (use_dma) { + /* + * ep->dma is not really used, just to indicate that + * DMA is active: remove this + * dma regs = dev control regs + */ + ep->dma = &dev->regs->ctl; + + /* nak OUT endpoints until enable - not for ep0 */ + if (tmp != UDC_EP0IN_IX && tmp != UDC_EP0OUT_IX + && tmp > UDC_EPIN_NUM) { + /* set NAK */ + reg = readl(&dev->ep[tmp].regs->ctl); + reg |= AMD_BIT(UDC_EPCTL_SNAK); + writel(reg, &dev->ep[tmp].regs->ctl); + dev->ep[tmp].naking = 1; + + } + } + } + /* EP0 max packet */ + if (dev->gadget.speed == USB_SPEED_FULL) { + dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_FS_EP0IN_MAX_PKT_SIZE; + dev->ep[UDC_EP0OUT_IX].ep.maxpacket = + UDC_FS_EP0OUT_MAX_PKT_SIZE; + } else if (dev->gadget.speed == USB_SPEED_HIGH) { + dev->ep[UDC_EP0IN_IX].ep.maxpacket = UDC_EP0IN_MAX_PKT_SIZE; + dev->ep[UDC_EP0OUT_IX].ep.maxpacket = UDC_EP0OUT_MAX_PKT_SIZE; + } + + /* + * with suspend bug workaround, ep0 params for gadget driver + * are set at gadget driver bind() call + */ + dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep; + dev->ep[UDC_EP0IN_IX].halted = 0; + INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); + + /* init cfg/alt/int */ + dev->cur_config = 0; + dev->cur_intf = 0; + dev->cur_alt = 0; +} + +/* Bringup after Connect event, initial bringup to be ready for ep0 events */ +static void usb_connect(struct udc *dev) +{ + + dev_info(&dev->pdev->dev, "USB Connect\n"); + + dev->connected = 1; + + /* put into initial config */ + udc_basic_init(dev); + + /* enable device setup interrupts */ + udc_enable_dev_setup_interrupts(dev); +} + +/* + * Calls gadget with disconnect event and resets the UDC and makes + * initial bringup to be ready for ep0 events + */ +static void usb_disconnect(struct udc *dev) +{ + + dev_info(&dev->pdev->dev, "USB Disconnect\n"); + + dev->connected = 0; + + /* mask interrupts */ + udc_mask_unused_interrupts(dev); + + /* REVISIT there doesn't seem to be a point to having this + * talk to a tasklet ... do it directly, we already hold + * the spinlock needed to process the disconnect. + */ + + tasklet_schedule(&disconnect_tasklet); +} + +/* Tasklet for disconnect to be outside of interrupt context */ +static void udc_tasklet_disconnect(unsigned long par) +{ + struct udc *dev = (struct udc *)(*((struct udc **) par)); + u32 tmp; + + DBG(dev, "Tasklet disconnect\n"); + spin_lock_irq(&dev->lock); + + if (dev->driver) { + spin_unlock(&dev->lock); + dev->driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + + /* empty queues */ + for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { + empty_req_queue(&dev->ep[tmp]); + } + + } + + /* disable ep0 */ + ep_init(dev->regs, + &dev->ep[UDC_EP0IN_IX]); + + + if (!soft_reset_occured) { + /* init controller by soft reset */ + udc_soft_reset(dev); + soft_reset_occured++; + } + + /* re-enable dev interrupts */ + udc_enable_dev_setup_interrupts(dev); + /* back to full speed ? */ + if (use_fullspeed) { + tmp = readl(&dev->regs->cfg); + tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD); + writel(tmp, &dev->regs->cfg); + } + + spin_unlock_irq(&dev->lock); +} + +/* Reset the UDC core */ +static void udc_soft_reset(struct udc *dev) +{ + unsigned long flags; + + DBG(dev, "Soft reset\n"); + /* + * reset possible waiting interrupts, because int. + * status is lost after soft reset, + * ep int. status reset + */ + writel(UDC_EPINT_MSK_DISABLE_ALL, &dev->regs->ep_irqsts); + /* device int. status reset */ + writel(UDC_DEV_MSK_DISABLE, &dev->regs->irqsts); + + spin_lock_irqsave(&udc_irq_spinlock, flags); + writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); + readl(&dev->regs->cfg); + spin_unlock_irqrestore(&udc_irq_spinlock, flags); + +} + +/* RDE timer callback to set RDE bit */ +static void udc_timer_function(unsigned long v) +{ + u32 tmp; + + spin_lock_irq(&udc_irq_spinlock); + + if (set_rde > 0) { + /* + * open the fifo if fifo was filled on last timer call + * conditionally + */ + if (set_rde > 1) { + /* set RDE to receive setup data */ + tmp = readl(&udc->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_RDE); + writel(tmp, &udc->regs->ctl); + set_rde = -1; + } else if (readl(&udc->regs->sts) + & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) { + /* + * if fifo empty setup polling, do not just + * open the fifo + */ + udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV; + if (!stop_timer) { + add_timer(&udc_timer); + } + } else { + /* + * fifo contains data now, setup timer for opening + * the fifo when timer expires to be able to receive + * setup packets, when data packets gets queued by + * gadget layer then timer will forced to expire with + * set_rde=0 (RDE is set in udc_queue()) + */ + set_rde++; + /* debug: lhadmot_timer_start = 221070 */ + udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS; + if (!stop_timer) { + add_timer(&udc_timer); + } + } + + } else + set_rde = -1; /* RDE was set by udc_queue() */ + spin_unlock_irq(&udc_irq_spinlock); + if (stop_timer) + complete(&on_exit); + +} + +/* Handle halt state, used in stall poll timer */ +static void udc_handle_halt_state(struct udc_ep *ep) +{ + u32 tmp; + /* set stall as long not halted */ + if (ep->halted == 1) { + tmp = readl(&ep->regs->ctl); + /* STALL cleared ? */ + if (!(tmp & AMD_BIT(UDC_EPCTL_S))) { + /* + * FIXME: MSC spec requires that stall remains + * even on receivng of CLEAR_FEATURE HALT. So + * we would set STALL again here to be compliant. + * But with current mass storage drivers this does + * not work (would produce endless host retries). + * So we clear halt on CLEAR_FEATURE. + * + DBG(ep->dev, "ep %d: set STALL again\n", ep->num); + tmp |= AMD_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl);*/ + + /* clear NAK by writing CNAK */ + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &ep->regs->ctl); + ep->halted = 0; + UDC_QUEUE_CNAK(ep, ep->num); + } + } +} + +/* Stall timer callback to poll S bit and set it again after */ +static void udc_pollstall_timer_function(unsigned long v) +{ + struct udc_ep *ep; + int halted = 0; + + spin_lock_irq(&udc_stall_spinlock); + /* + * only one IN and OUT endpoints are handled + * IN poll stall + */ + ep = &udc->ep[UDC_EPIN_IX]; + udc_handle_halt_state(ep); + if (ep->halted) + halted = 1; + /* OUT poll stall */ + ep = &udc->ep[UDC_EPOUT_IX]; + udc_handle_halt_state(ep); + if (ep->halted) + halted = 1; + + /* setup timer again when still halted */ + if (!stop_pollstall_timer && halted) { + udc_pollstall_timer.expires = jiffies + + HZ * UDC_POLLSTALL_TIMER_USECONDS + / (1000 * 1000); + add_timer(&udc_pollstall_timer); + } + spin_unlock_irq(&udc_stall_spinlock); + + if (stop_pollstall_timer) + complete(&on_pollstall_exit); +} + +/* Inits endpoint 0 so that SETUP packets are processed */ +static void activate_control_endpoints(struct udc *dev) +{ + u32 tmp; + + DBG(dev, "activate_control_endpoints\n"); + + /* flush fifo */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_F); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + + /* set ep0 directions */ + dev->ep[UDC_EP0IN_IX].in = 1; + dev->ep[UDC_EP0OUT_IX].in = 0; + + /* set buffer size (tx fifo entries) of EP0_IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufin_framenum); + if (dev->gadget.speed == USB_SPEED_FULL) + tmp = AMD_ADDBITS(tmp, UDC_FS_EPIN0_BUFF_SIZE, + UDC_EPIN_BUFF_SIZE); + else if (dev->gadget.speed == USB_SPEED_HIGH) + tmp = AMD_ADDBITS(tmp, UDC_EPIN0_BUFF_SIZE, + UDC_EPIN_BUFF_SIZE); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufin_framenum); + + /* set max packet size of EP0_IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt); + if (dev->gadget.speed == USB_SPEED_FULL) + tmp = AMD_ADDBITS(tmp, UDC_FS_EP0IN_MAX_PKT_SIZE, + UDC_EP_MAX_PKT_SIZE); + else if (dev->gadget.speed == USB_SPEED_HIGH) + tmp = AMD_ADDBITS(tmp, UDC_EP0IN_MAX_PKT_SIZE, + UDC_EP_MAX_PKT_SIZE); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->bufout_maxpkt); + + /* set max packet size of EP0_OUT */ + tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt); + if (dev->gadget.speed == USB_SPEED_FULL) + tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, + UDC_EP_MAX_PKT_SIZE); + else if (dev->gadget.speed == USB_SPEED_HIGH) + tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, + UDC_EP_MAX_PKT_SIZE); + writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->bufout_maxpkt); + + /* set max packet size of EP0 in UDC CSR */ + tmp = readl(&dev->csr->ne[0]); + if (dev->gadget.speed == USB_SPEED_FULL) + tmp = AMD_ADDBITS(tmp, UDC_FS_EP0OUT_MAX_PKT_SIZE, + UDC_CSR_NE_MAX_PKT); + else if (dev->gadget.speed == USB_SPEED_HIGH) + tmp = AMD_ADDBITS(tmp, UDC_EP0OUT_MAX_PKT_SIZE, + UDC_CSR_NE_MAX_PKT); + writel(tmp, &dev->csr->ne[0]); + + if (use_dma) { + dev->ep[UDC_EP0OUT_IX].td->status |= + AMD_BIT(UDC_DMA_OUT_STS_L); + /* write dma desc address */ + writel(dev->ep[UDC_EP0OUT_IX].td_stp_dma, + &dev->ep[UDC_EP0OUT_IX].regs->subptr); + writel(dev->ep[UDC_EP0OUT_IX].td_phys, + &dev->ep[UDC_EP0OUT_IX].regs->desptr); + /* stop RDE timer */ + if (timer_pending(&udc_timer)) { + set_rde = 0; + mod_timer(&udc_timer, jiffies - 1); + } + /* stop pollstall timer */ + if (timer_pending(&udc_pollstall_timer)) { + mod_timer(&udc_pollstall_timer, jiffies - 1); + } + /* enable DMA */ + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_MODE) + | AMD_BIT(UDC_DEVCTL_RDE) + | AMD_BIT(UDC_DEVCTL_TDE); + if (use_dma_bufferfill_mode) { + tmp |= AMD_BIT(UDC_DEVCTL_BF); + } else if (use_dma_ppb_du) { + tmp |= AMD_BIT(UDC_DEVCTL_DU); + } + writel(tmp, &dev->regs->ctl); + } + + /* clear NAK by writing CNAK for EP0IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + dev->ep[UDC_EP0IN_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX); + + /* clear NAK by writing CNAK for EP0OUT */ + tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl); + dev->ep[UDC_EP0OUT_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX); +} + +/* Make endpoint 0 ready for control traffic */ +static int setup_ep0(struct udc *dev) +{ + activate_control_endpoints(dev); + /* enable ep0 interrupts */ + udc_enable_ep0_interrupts(dev); + /* enable device setup interrupts */ + udc_enable_dev_setup_interrupts(dev); + + return 0; +} + +/* Called by gadget driver to register itself */ +int usb_gadget_register_driver(struct usb_gadget_driver *driver) +{ + struct udc *dev = udc; + int retval; + u32 tmp; + + if (!driver || !driver->bind || !driver->setup + || driver->speed != USB_SPEED_HIGH) + return -EINVAL; + if (!dev) + return -ENODEV; + if (dev->driver) + return -EBUSY; + + driver->driver.bus = NULL; + dev->driver = driver; + dev->gadget.dev.driver = &driver->driver; + + retval = driver->bind(&dev->gadget); + + /* Some gadget drivers use both ep0 directions. + * NOTE: to gadget driver, ep0 is just one endpoint... + */ + dev->ep[UDC_EP0OUT_IX].ep.driver_data = + dev->ep[UDC_EP0IN_IX].ep.driver_data; + + if (retval) { + DBG(dev, "binding to %s returning %d\n", + driver->driver.name, retval); + dev->driver = NULL; + dev->gadget.dev.driver = NULL; + return retval; + } + + /* get ready for ep0 traffic */ + setup_ep0(dev); + + /* clear SD */ + tmp = readl(&dev->regs->ctl); + tmp = tmp & AMD_CLEAR_BIT(UDC_DEVCTL_SD); + writel(tmp, &dev->regs->ctl); + + usb_connect(dev); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_register_driver); + +/* shutdown requests and disconnect from gadget */ +static void +shutdown(struct udc *dev, struct usb_gadget_driver *driver) +__releases(dev->lock) +__acquires(dev->lock) +{ + int tmp; + + /* empty queues and init hardware */ + udc_basic_init(dev); + for (tmp = 0; tmp < UDC_EP_NUM; tmp++) { + empty_req_queue(&dev->ep[tmp]); + } + + if (dev->gadget.speed != USB_SPEED_UNKNOWN) { + spin_unlock(&dev->lock); + driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + } + /* init */ + udc_setup_endpoints(dev); +} + +/* Called by gadget driver to unregister itself */ +int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) +{ + struct udc *dev = udc; + unsigned long flags; + u32 tmp; + + if (!dev) + return -ENODEV; + if (!driver || driver != dev->driver || !driver->unbind) + return -EINVAL; + + spin_lock_irqsave(&dev->lock, flags); + udc_mask_unused_interrupts(dev); + shutdown(dev, driver); + spin_unlock_irqrestore(&dev->lock, flags); + + driver->unbind(&dev->gadget); + dev->driver = NULL; + + /* set SD */ + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_SD); + writel(tmp, &dev->regs->ctl); + + + DBG(dev, "%s: unregistered\n", driver->driver.name); + + return 0; +} +EXPORT_SYMBOL(usb_gadget_unregister_driver); + + +/* Clear pending NAK bits */ +static void udc_process_cnak_queue(struct udc *dev) +{ + u32 tmp; + u32 reg; + + /* check epin's */ + DBG(dev, "CNAK pending queue processing\n"); + for (tmp = 0; tmp < UDC_EPIN_NUM_USED; tmp++) { + if (cnak_pending & (1 << tmp)) { + DBG(dev, "CNAK pending for ep%d\n", tmp); + /* clear NAK by writing CNAK */ + reg = readl(&dev->ep[tmp].regs->ctl); + reg |= AMD_BIT(UDC_EPCTL_CNAK); + writel(reg, &dev->ep[tmp].regs->ctl); + dev->ep[tmp].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[tmp], dev->ep[tmp].num); + } + } + /* ... and ep0out */ + if (cnak_pending & (1 << UDC_EP0OUT_IX)) { + DBG(dev, "CNAK pending for ep%d\n", UDC_EP0OUT_IX); + /* clear NAK by writing CNAK */ + reg = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); + reg |= AMD_BIT(UDC_EPCTL_CNAK); + writel(reg, &dev->ep[UDC_EP0OUT_IX].regs->ctl); + dev->ep[UDC_EP0OUT_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], + dev->ep[UDC_EP0OUT_IX].num); + } +} + +/* Enabling RX DMA after setup packet */ +static void udc_ep0_set_rde(struct udc *dev) +{ + if (use_dma) { + /* + * only enable RXDMA when no data endpoint enabled + * or data is queued + */ + if (!dev->data_ep_enabled || dev->data_ep_queued) { + udc_set_rde(dev); + } else { + /* + * setup timer for enabling RDE (to not enable + * RXFIFO DMA for data endpoints to early) + */ + if (set_rde != 0 && !timer_pending(&udc_timer)) { + udc_timer.expires = + jiffies + HZ/UDC_RDE_TIMER_DIV; + set_rde = 1; + if (!stop_timer) { + add_timer(&udc_timer); + } + } + } + } +} + + +/* Interrupt handler for data OUT traffic */ +static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + struct udc_ep *ep; + struct udc_request *req; + unsigned int count; + struct udc_data_dma *td = NULL; + unsigned dma_done; + + VDBG(dev, "ep%d irq\n", ep_ix); + ep = &dev->ep[ep_ix]; + + tmp = readl(&ep->regs->sts); + if (use_dma) { + /* BNA event ? */ + if (tmp & AMD_BIT(UDC_EPSTS_BNA)) { + DBG(dev, "BNA ep%dout occured - DESPTR = %x \n", + ep->num, readl(&ep->regs->desptr)); + /* clear BNA */ + writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts); + if (!ep->cancel_transfer) + ep->bna_occurred = 1; + else + ep->cancel_transfer = 0; + ret_val = IRQ_HANDLED; + goto finished; + } + } + /* HE event ? */ + if (tmp & AMD_BIT(UDC_EPSTS_HE)) { + dev_err(&dev->pdev->dev, "HE ep%dout occured\n", ep->num); + + /* clear HE */ + writel(tmp | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts); + ret_val = IRQ_HANDLED; + goto finished; + } + + if (!list_empty(&ep->queue)) { + + /* next request */ + req = list_entry(ep->queue.next, + struct udc_request, queue); + } else { + req = NULL; + udc_rxfifo_pending = 1; + } + VDBG(dev, "req = %p\n", req); + /* fifo mode */ + if (!use_dma) { + + /* read fifo */ + if (req && udc_rxfifo_read(ep, req)) { + ret_val = IRQ_HANDLED; + + /* finish */ + complete_req(ep, req, 0); + /* next request */ + if (!list_empty(&ep->queue) && !ep->halted) { + req = list_entry(ep->queue.next, + struct udc_request, queue); + } else + req = NULL; + } + + /* DMA */ + } else if (!ep->cancel_transfer && req != NULL) { + ret_val = IRQ_HANDLED; + + /* check for DMA done */ + if (!use_dma_ppb) { + dma_done = AMD_GETBITS(req->td_data->status, + UDC_DMA_OUT_STS_BS); + /* packet per buffer mode - rx bytes */ + } else { + /* + * if BNA occurred then recover desc. from + * BNA dummy desc. + */ + if (ep->bna_occurred) { + VDBG(dev, "Recover desc. from BNA dummy\n"); + memcpy(req->td_data, ep->bna_dummy_req->td_data, + sizeof(struct udc_data_dma)); + ep->bna_occurred = 0; + udc_init_bna_dummy(ep->req); + } + td = udc_get_last_dma_desc(req); + dma_done = AMD_GETBITS(td->status, UDC_DMA_OUT_STS_BS); + } + if (dma_done == UDC_DMA_OUT_STS_BS_DMA_DONE) { + /* buffer fill mode - rx bytes */ + if (!use_dma_ppb) { + /* received number bytes */ + count = AMD_GETBITS(req->td_data->status, + UDC_DMA_OUT_STS_RXBYTES); + VDBG(dev, "rx bytes=%u\n", count); + /* packet per buffer mode - rx bytes */ + } else { + VDBG(dev, "req->td_data=%p\n", req->td_data); + VDBG(dev, "last desc = %p\n", td); + /* received number bytes */ + if (use_dma_ppb_du) { + /* every desc. counts bytes */ + count = udc_get_ppbdu_rxbytes(req); + } else { + /* last desc. counts bytes */ + count = AMD_GETBITS(td->status, + UDC_DMA_OUT_STS_RXBYTES); + if (!count && req->req.length + == UDC_DMA_MAXPACKET) { + /* + * on 64k packets the RXBYTES + * field is zero + */ + count = UDC_DMA_MAXPACKET; + } + } + VDBG(dev, "last desc rx bytes=%u\n", count); + } + + tmp = req->req.length - req->req.actual; + if (count > tmp) { + if ((tmp % ep->ep.maxpacket) != 0) { + DBG(dev, "%s: rx %db, space=%db\n", + ep->ep.name, count, tmp); + req->req.status = -EOVERFLOW; + } + count = tmp; + } + req->req.actual += count; + req->dma_going = 0; + /* complete request */ + complete_req(ep, req, 0); + + /* next request */ + if (!list_empty(&ep->queue) && !ep->halted) { + req = list_entry(ep->queue.next, + struct udc_request, + queue); + /* + * DMA may be already started by udc_queue() + * called by gadget drivers completion + * routine. This happens when queue + * holds one request only. + */ + if (req->dma_going == 0) { + /* next dma */ + if (prep_dma(ep, req, GFP_ATOMIC) != 0) + goto finished; + /* write desc pointer */ + writel(req->td_phys, + &ep->regs->desptr); + req->dma_going = 1; + /* enable DMA */ + udc_set_rde(dev); + } + } else { + /* + * implant BNA dummy descriptor to allow + * RXFIFO opening by RDE + */ + if (ep->bna_dummy_req) { + /* write desc pointer */ + writel(ep->bna_dummy_req->td_phys, + &ep->regs->desptr); + ep->bna_occurred = 0; + } + + /* + * schedule timer for setting RDE if queue + * remains empty to allow ep0 packets pass + * through + */ + if (set_rde != 0 + && !timer_pending(&udc_timer)) { + udc_timer.expires = + jiffies + + HZ*UDC_RDE_TIMER_SECONDS; + set_rde = 1; + if (!stop_timer) { + add_timer(&udc_timer); + } + } + if (ep->num != UDC_EP0OUT_IX) + dev->data_ep_queued = 0; + } + + } else { + /* + * RX DMA must be reenabled for each desc in PPBDU mode + * and must be enabled for PPBNDU mode in case of BNA + */ + udc_set_rde(dev); + } + + } else if (ep->cancel_transfer) { + ret_val = IRQ_HANDLED; + ep->cancel_transfer = 0; + } + + /* check pending CNAKS */ + if (cnak_pending) { + /* CNAk processing when rxfifo empty only */ + if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) { + udc_process_cnak_queue(dev); + } + } + + /* clear OUT bits in ep status */ + writel(UDC_EPSTS_OUT_CLEAR, &ep->regs->sts); +finished: + return ret_val; +} + +/* Interrupt handler for data IN traffic */ +static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + u32 epsts; + struct udc_ep *ep; + struct udc_request *req; + struct udc_data_dma *td; + unsigned dma_done; + unsigned len; + + ep = &dev->ep[ep_ix]; + + epsts = readl(&ep->regs->sts); + if (use_dma) { + /* BNA ? */ + if (epsts & AMD_BIT(UDC_EPSTS_BNA)) { + dev_err(&dev->pdev->dev, + "BNA ep%din occured - DESPTR = %08lx \n", + ep->num, + (unsigned long) readl(&ep->regs->desptr)); + + /* clear BNA */ + writel(epsts, &ep->regs->sts); + ret_val = IRQ_HANDLED; + goto finished; + } + } + /* HE event ? */ + if (epsts & AMD_BIT(UDC_EPSTS_HE)) { + dev_err(&dev->pdev->dev, + "HE ep%dn occured - DESPTR = %08lx \n", + ep->num, (unsigned long) readl(&ep->regs->desptr)); + + /* clear HE */ + writel(epsts | AMD_BIT(UDC_EPSTS_HE), &ep->regs->sts); + ret_val = IRQ_HANDLED; + goto finished; + } + + /* DMA completion */ + if (epsts & AMD_BIT(UDC_EPSTS_TDC)) { + VDBG(dev, "TDC set- completion\n"); + ret_val = IRQ_HANDLED; + if (!ep->cancel_transfer && !list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, + struct udc_request, queue); + if (req) { + /* + * length bytes transfered + * check dma done of last desc. in PPBDU mode + */ + if (use_dma_ppb_du) { + td = udc_get_last_dma_desc(req); + if (td) { + dma_done = + AMD_GETBITS(td->status, + UDC_DMA_IN_STS_BS); + /* don't care DMA done */ + req->req.actual = + req->req.length; + } + } else { + /* assume all bytes transferred */ + req->req.actual = req->req.length; + } + + if (req->req.actual == req->req.length) { + /* complete req */ + complete_req(ep, req, 0); + req->dma_going = 0; + /* further request available ? */ + if (list_empty(&ep->queue)) { + /* disable interrupt */ + tmp = readl( + &dev->regs->ep_irqmsk); + tmp |= AMD_BIT(ep->num); + writel(tmp, + &dev->regs->ep_irqmsk); + } + + } + } + } + ep->cancel_transfer = 0; + + } + /* + * status reg has IN bit set and TDC not set (if TDC was handled, + * IN must not be handled (UDC defect) ? + */ + if ((epsts & AMD_BIT(UDC_EPSTS_IN)) + && !(epsts & AMD_BIT(UDC_EPSTS_TDC))) { + ret_val = IRQ_HANDLED; + if (!list_empty(&ep->queue)) { + /* next request */ + req = list_entry(ep->queue.next, + struct udc_request, queue); + /* FIFO mode */ + if (!use_dma) { + /* write fifo */ + udc_txfifo_write(ep, &req->req); + len = req->req.length - req->req.actual; + if (len > ep->ep.maxpacket) + len = ep->ep.maxpacket; + req->req.actual += len; + if (req->req.actual == req->req.length + || (len != ep->ep.maxpacket)) { + /* complete req */ + complete_req(ep, req, 0); + } + /* DMA */ + } else if (req && !req->dma_going) { + VDBG(dev, "IN DMA : req=%p req->td_data=%p\n", + req, req->td_data); + if (req->td_data) { + + req->dma_going = 1; + + /* + * unset L bit of first desc. + * for chain + */ + if (use_dma_ppb && req->req.length > + ep->ep.maxpacket) { + req->td_data->status &= + AMD_CLEAR_BIT( + UDC_DMA_IN_STS_L); + } + + /* write desc pointer */ + writel(req->td_phys, &ep->regs->desptr); + + /* set HOST READY */ + req->td_data->status = + AMD_ADDBITS( + req->td_data->status, + UDC_DMA_IN_STS_BS_HOST_READY, + UDC_DMA_IN_STS_BS); + + /* set poll demand bit */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_P); + writel(tmp, &ep->regs->ctl); + } + } + + } + } + /* clear status bits */ + writel(epsts, &ep->regs->sts); + +finished: + return ret_val; + +} + +/* Interrupt handler for Control OUT traffic */ +static irqreturn_t udc_control_out_isr(struct udc *dev) +__releases(dev->lock) +__acquires(dev->lock) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + int setup_supported; + u32 count; + int set = 0; + struct udc_ep *ep; + struct udc_ep *ep_tmp; + + ep = &dev->ep[UDC_EP0OUT_IX]; + + /* clear irq */ + writel(AMD_BIT(UDC_EPINT_OUT_EP0), &dev->regs->ep_irqsts); + + tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts); + /* check BNA and clear if set */ + if (tmp & AMD_BIT(UDC_EPSTS_BNA)) { + VDBG(dev, "ep0: BNA set\n"); + writel(AMD_BIT(UDC_EPSTS_BNA), + &dev->ep[UDC_EP0OUT_IX].regs->sts); + ep->bna_occurred = 1; + ret_val = IRQ_HANDLED; + goto finished; + } + + /* type of data: SETUP or DATA 0 bytes */ + tmp = AMD_GETBITS(tmp, UDC_EPSTS_OUT); + VDBG(dev, "data_typ = %x\n", tmp); + + /* setup data */ + if (tmp == UDC_EPSTS_OUT_SETUP) { + ret_val = IRQ_HANDLED; + + ep->dev->stall_ep0in = 0; + dev->waiting_zlp_ack_ep0in = 0; + + /* set NAK for EP0_IN */ + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_SNAK); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + dev->ep[UDC_EP0IN_IX].naking = 1; + /* get setup data */ + if (use_dma) { + + /* clear OUT bits in ep status */ + writel(UDC_EPSTS_OUT_CLEAR, + &dev->ep[UDC_EP0OUT_IX].regs->sts); + + setup_data.data[0] = + dev->ep[UDC_EP0OUT_IX].td_stp->data12; + setup_data.data[1] = + dev->ep[UDC_EP0OUT_IX].td_stp->data34; + /* set HOST READY */ + dev->ep[UDC_EP0OUT_IX].td_stp->status = + UDC_DMA_STP_STS_BS_HOST_READY; + } else { + /* read fifo */ + udc_rxfifo_read_dwords(dev, setup_data.data, 2); + } + + /* determine direction of control data */ + if ((setup_data.request.bRequestType & USB_DIR_IN) != 0) { + dev->gadget.ep0 = &dev->ep[UDC_EP0IN_IX].ep; + /* enable RDE */ + udc_ep0_set_rde(dev); + set = 0; + } else { + dev->gadget.ep0 = &dev->ep[UDC_EP0OUT_IX].ep; + /* + * implant BNA dummy descriptor to allow RXFIFO opening + * by RDE + */ + if (ep->bna_dummy_req) { + /* write desc pointer */ + writel(ep->bna_dummy_req->td_phys, + &dev->ep[UDC_EP0OUT_IX].regs->desptr); + ep->bna_occurred = 0; + } + + set = 1; + dev->ep[UDC_EP0OUT_IX].naking = 1; + /* + * setup timer for enabling RDE (to not enable + * RXFIFO DMA for data to early) + */ + set_rde = 1; + if (!timer_pending(&udc_timer)) { + udc_timer.expires = jiffies + + HZ/UDC_RDE_TIMER_DIV; + if (!stop_timer) { + add_timer(&udc_timer); + } + } + } + + /* + * mass storage reset must be processed here because + * next packet may be a CLEAR_FEATURE HALT which would not + * clear the stall bit when no STALL handshake was received + * before (autostall can cause this) + */ + if (setup_data.data[0] == UDC_MSCRES_DWORD0 + && setup_data.data[1] == UDC_MSCRES_DWORD1) { + DBG(dev, "MSC Reset\n"); + /* + * clear stall bits + * only one IN and OUT endpoints are handled + */ + ep_tmp = &udc->ep[UDC_EPIN_IX]; + udc_set_halt(&ep_tmp->ep, 0); + ep_tmp = &udc->ep[UDC_EPOUT_IX]; + udc_set_halt(&ep_tmp->ep, 0); + } + + /* call gadget with setup data received */ + spin_unlock(&dev->lock); + setup_supported = dev->driver->setup(&dev->gadget, + &setup_data.request); + spin_lock(&dev->lock); + + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + /* ep0 in returns data (not zlp) on IN phase */ + if (setup_supported >= 0 && setup_supported < + UDC_EP0IN_MAXPACKET) { + /* clear NAK by writing CNAK in EP0_IN */ + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + dev->ep[UDC_EP0IN_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0IN_IX], UDC_EP0IN_IX); + + /* if unsupported request then stall */ + } else if (setup_supported < 0) { + tmp |= AMD_BIT(UDC_EPCTL_S); + writel(tmp, &dev->ep[UDC_EP0IN_IX].regs->ctl); + } else + dev->waiting_zlp_ack_ep0in = 1; + + + /* clear NAK by writing CNAK in EP0_OUT */ + if (!set) { + tmp = readl(&dev->ep[UDC_EP0OUT_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_CNAK); + writel(tmp, &dev->ep[UDC_EP0OUT_IX].regs->ctl); + dev->ep[UDC_EP0OUT_IX].naking = 0; + UDC_QUEUE_CNAK(&dev->ep[UDC_EP0OUT_IX], UDC_EP0OUT_IX); + } + + if (!use_dma) { + /* clear OUT bits in ep status */ + writel(UDC_EPSTS_OUT_CLEAR, + &dev->ep[UDC_EP0OUT_IX].regs->sts); + } + + /* data packet 0 bytes */ + } else if (tmp == UDC_EPSTS_OUT_DATA) { + /* clear OUT bits in ep status */ + writel(UDC_EPSTS_OUT_CLEAR, &dev->ep[UDC_EP0OUT_IX].regs->sts); + + /* get setup data: only 0 packet */ + if (use_dma) { + /* no req if 0 packet, just reactivate */ + if (list_empty(&dev->ep[UDC_EP0OUT_IX].queue)) { + VDBG(dev, "ZLP\n"); + + /* set HOST READY */ + dev->ep[UDC_EP0OUT_IX].td->status = + AMD_ADDBITS( + dev->ep[UDC_EP0OUT_IX].td->status, + UDC_DMA_OUT_STS_BS_HOST_READY, + UDC_DMA_OUT_STS_BS); + /* enable RDE */ + udc_ep0_set_rde(dev); + ret_val = IRQ_HANDLED; + + } else { + /* control write */ + ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX); + /* re-program desc. pointer for possible ZLPs */ + writel(dev->ep[UDC_EP0OUT_IX].td_phys, + &dev->ep[UDC_EP0OUT_IX].regs->desptr); + /* enable RDE */ + udc_ep0_set_rde(dev); + } + } else { + + /* received number bytes */ + count = readl(&dev->ep[UDC_EP0OUT_IX].regs->sts); + count = AMD_GETBITS(count, UDC_EPSTS_RX_PKT_SIZE); + /* out data for fifo mode not working */ + count = 0; + + /* 0 packet or real data ? */ + if (count != 0) { + ret_val |= udc_data_out_isr(dev, UDC_EP0OUT_IX); + } else { + /* dummy read confirm */ + readl(&dev->ep[UDC_EP0OUT_IX].regs->confirm); + ret_val = IRQ_HANDLED; + } + } + } + + /* check pending CNAKS */ + if (cnak_pending) { + /* CNAk processing when rxfifo empty only */ + if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) { + udc_process_cnak_queue(dev); + } + } + +finished: + return ret_val; +} + +/* Interrupt handler for Control IN traffic */ +static irqreturn_t udc_control_in_isr(struct udc *dev) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + struct udc_ep *ep; + struct udc_request *req; + unsigned len; + + ep = &dev->ep[UDC_EP0IN_IX]; + + /* clear irq */ + writel(AMD_BIT(UDC_EPINT_IN_EP0), &dev->regs->ep_irqsts); + + tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts); + /* DMA completion */ + if (tmp & AMD_BIT(UDC_EPSTS_TDC)) { + VDBG(dev, "isr: TDC clear \n"); + ret_val = IRQ_HANDLED; + + /* clear TDC bit */ + writel(AMD_BIT(UDC_EPSTS_TDC), + &dev->ep[UDC_EP0IN_IX].regs->sts); + + /* status reg has IN bit set ? */ + } else if (tmp & AMD_BIT(UDC_EPSTS_IN)) { + ret_val = IRQ_HANDLED; + + if (ep->dma) { + /* clear IN bit */ + writel(AMD_BIT(UDC_EPSTS_IN), + &dev->ep[UDC_EP0IN_IX].regs->sts); + } + if (dev->stall_ep0in) { + DBG(dev, "stall ep0in\n"); + /* halt ep0in */ + tmp = readl(&ep->regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl); + } else { + if (!list_empty(&ep->queue)) { + /* next request */ + req = list_entry(ep->queue.next, + struct udc_request, queue); + + if (ep->dma) { + /* write desc pointer */ + writel(req->td_phys, &ep->regs->desptr); + /* set HOST READY */ + req->td_data->status = + AMD_ADDBITS( + req->td_data->status, + UDC_DMA_STP_STS_BS_HOST_READY, + UDC_DMA_STP_STS_BS); + + /* set poll demand bit */ + tmp = + readl(&dev->ep[UDC_EP0IN_IX].regs->ctl); + tmp |= AMD_BIT(UDC_EPCTL_P); + writel(tmp, + &dev->ep[UDC_EP0IN_IX].regs->ctl); + + /* all bytes will be transferred */ + req->req.actual = req->req.length; + + /* complete req */ + complete_req(ep, req, 0); + + } else { + /* write fifo */ + udc_txfifo_write(ep, &req->req); + + /* lengh bytes transfered */ + len = req->req.length - req->req.actual; + if (len > ep->ep.maxpacket) + len = ep->ep.maxpacket; + + req->req.actual += len; + if (req->req.actual == req->req.length + || (len != ep->ep.maxpacket)) { + /* complete req */ + complete_req(ep, req, 0); + } + } + + } + } + ep->halted = 0; + dev->stall_ep0in = 0; + if (!ep->dma) { + /* clear IN bit */ + writel(AMD_BIT(UDC_EPSTS_IN), + &dev->ep[UDC_EP0IN_IX].regs->sts); + } + } + + return ret_val; +} + + +/* Interrupt handler for global device events */ +static irqreturn_t udc_dev_isr(struct udc *dev, u32 dev_irq) +__releases(dev->lock) +__acquires(dev->lock) +{ + irqreturn_t ret_val = IRQ_NONE; + u32 tmp; + u32 cfg; + struct udc_ep *ep; + u16 i; + u8 udc_csr_epix; + + /* SET_CONFIG irq ? */ + if (dev_irq & AMD_BIT(UDC_DEVINT_SC)) { + ret_val = IRQ_HANDLED; + + /* read config value */ + tmp = readl(&dev->regs->sts); + cfg = AMD_GETBITS(tmp, UDC_DEVSTS_CFG); + DBG(dev, "SET_CONFIG interrupt: config=%d\n", cfg); + dev->cur_config = cfg; + dev->set_cfg_not_acked = 1; + + /* make usb request for gadget driver */ + memset(&setup_data, 0 , sizeof(union udc_setup_data)); + setup_data.request.bRequest = USB_REQ_SET_CONFIGURATION; + setup_data.request.wValue = dev->cur_config; + + /* programm the NE registers */ + for (i = 0; i < UDC_EP_NUM; i++) { + ep = &dev->ep[i]; + if (ep->in) { + + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num; + + + /* OUT ep */ + } else { + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS; + } + + tmp = readl(&dev->csr->ne[udc_csr_epix]); + /* ep cfg */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_config, + UDC_CSR_NE_CFG); + /* write reg */ + writel(tmp, &dev->csr->ne[udc_csr_epix]); + + /* clear stall bits */ + ep->halted = 0; + tmp = readl(&ep->regs->ctl); + tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl); + } + /* call gadget zero with setup data received */ + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &setup_data.request); + spin_lock(&dev->lock); + + } /* SET_INTERFACE ? */ + if (dev_irq & AMD_BIT(UDC_DEVINT_SI)) { + ret_val = IRQ_HANDLED; + + dev->set_cfg_not_acked = 1; + /* read interface and alt setting values */ + tmp = readl(&dev->regs->sts); + dev->cur_alt = AMD_GETBITS(tmp, UDC_DEVSTS_ALT); + dev->cur_intf = AMD_GETBITS(tmp, UDC_DEVSTS_INTF); + + /* make usb request for gadget driver */ + memset(&setup_data, 0 , sizeof(union udc_setup_data)); + setup_data.request.bRequest = USB_REQ_SET_INTERFACE; + setup_data.request.bRequestType = USB_RECIP_INTERFACE; + setup_data.request.wValue = dev->cur_alt; + setup_data.request.wIndex = dev->cur_intf; + + DBG(dev, "SET_INTERFACE interrupt: alt=%d intf=%d\n", + dev->cur_alt, dev->cur_intf); + + /* programm the NE registers */ + for (i = 0; i < UDC_EP_NUM; i++) { + ep = &dev->ep[i]; + if (ep->in) { + + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num; + + + /* OUT ep */ + } else { + /* ep ix in UDC CSR register space */ + udc_csr_epix = ep->num - UDC_CSR_EP_OUT_IX_OFS; + } + + /* UDC CSR reg */ + /* set ep values */ + tmp = readl(&dev->csr->ne[udc_csr_epix]); + /* ep interface */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_intf, + UDC_CSR_NE_INTF); + /* tmp = AMD_ADDBITS(tmp, 2, UDC_CSR_NE_INTF); */ + /* ep alt */ + tmp = AMD_ADDBITS(tmp, ep->dev->cur_alt, + UDC_CSR_NE_ALT); + /* write reg */ + writel(tmp, &dev->csr->ne[udc_csr_epix]); + + /* clear stall bits */ + ep->halted = 0; + tmp = readl(&ep->regs->ctl); + tmp = tmp & AMD_CLEAR_BIT(UDC_EPCTL_S); + writel(tmp, &ep->regs->ctl); + } + + /* call gadget zero with setup data received */ + spin_unlock(&dev->lock); + tmp = dev->driver->setup(&dev->gadget, &setup_data.request); + spin_lock(&dev->lock); + + } /* USB reset */ + if (dev_irq & AMD_BIT(UDC_DEVINT_UR)) { + DBG(dev, "USB Reset interrupt\n"); + ret_val = IRQ_HANDLED; + + /* allow soft reset when suspend occurs */ + soft_reset_occured = 0; + + dev->waiting_zlp_ack_ep0in = 0; + dev->set_cfg_not_acked = 0; + + /* mask not needed interrupts */ + udc_mask_unused_interrupts(dev); + + /* call gadget to resume and reset configs etc. */ + spin_unlock(&dev->lock); + if (dev->sys_suspended && dev->driver->resume) { + dev->driver->resume(&dev->gadget); + dev->sys_suspended = 0; + } + dev->driver->disconnect(&dev->gadget); + spin_lock(&dev->lock); + + /* disable ep0 to empty req queue */ + empty_req_queue(&dev->ep[UDC_EP0IN_IX]); + ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]); + + /* soft reset when rxfifo not empty */ + tmp = readl(&dev->regs->sts); + if (!(tmp & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) + && !soft_reset_after_usbreset_occured) { + udc_soft_reset(dev); + soft_reset_after_usbreset_occured++; + } + + /* + * DMA reset to kill potential old DMA hw hang, + * POLL bit is already reset by ep_init() through + * disconnect() + */ + DBG(dev, "DMA machine reset\n"); + tmp = readl(&dev->regs->cfg); + writel(tmp | AMD_BIT(UDC_DEVCFG_DMARST), &dev->regs->cfg); + writel(tmp, &dev->regs->cfg); + + /* put into initial config */ + udc_basic_init(dev); + + /* enable device setup interrupts */ + udc_enable_dev_setup_interrupts(dev); + + /* enable suspend interrupt */ + tmp = readl(&dev->regs->irqmsk); + tmp &= AMD_UNMASK_BIT(UDC_DEVINT_US); + writel(tmp, &dev->regs->irqmsk); + + } /* USB suspend */ + if (dev_irq & AMD_BIT(UDC_DEVINT_US)) { + DBG(dev, "USB Suspend interrupt\n"); + ret_val = IRQ_HANDLED; + if (dev->driver->suspend) { + spin_unlock(&dev->lock); + dev->sys_suspended = 1; + dev->driver->suspend(&dev->gadget); + spin_lock(&dev->lock); + } + } /* new speed ? */ + if (dev_irq & AMD_BIT(UDC_DEVINT_ENUM)) { + DBG(dev, "ENUM interrupt\n"); + ret_val = IRQ_HANDLED; + soft_reset_after_usbreset_occured = 0; + + /* disable ep0 to empty req queue */ + empty_req_queue(&dev->ep[UDC_EP0IN_IX]); + ep_init(dev->regs, &dev->ep[UDC_EP0IN_IX]); + + /* link up all endpoints */ + udc_setup_endpoints(dev); + if (dev->gadget.speed == USB_SPEED_HIGH) { + dev_info(&dev->pdev->dev, "Connect: speed = %s\n", + "high"); + } else if (dev->gadget.speed == USB_SPEED_FULL) { + dev_info(&dev->pdev->dev, "Connect: speed = %s\n", + "full"); + } + + /* init ep 0 */ + activate_control_endpoints(dev); + + /* enable ep0 interrupts */ + udc_enable_ep0_interrupts(dev); + } + /* session valid change interrupt */ + if (dev_irq & AMD_BIT(UDC_DEVINT_SVC)) { + DBG(dev, "USB SVC interrupt\n"); + ret_val = IRQ_HANDLED; + + /* check that session is not valid to detect disconnect */ + tmp = readl(&dev->regs->sts); + if (!(tmp & AMD_BIT(UDC_DEVSTS_SESSVLD))) { + /* disable suspend interrupt */ + tmp = readl(&dev->regs->irqmsk); + tmp |= AMD_BIT(UDC_DEVINT_US); + writel(tmp, &dev->regs->irqmsk); + DBG(dev, "USB Disconnect (session valid low)\n"); + /* cleanup on disconnect */ + usb_disconnect(udc); + } + + } + + return ret_val; +} + +/* Interrupt Service Routine, see Linux Kernel Doc for parameters */ +static irqreturn_t udc_irq(int irq, void *pdev) +{ + struct udc *dev = pdev; + u32 reg; + u16 i; + u32 ep_irq; + irqreturn_t ret_val = IRQ_NONE; + + spin_lock(&dev->lock); + + /* check for ep irq */ + reg = readl(&dev->regs->ep_irqsts); + if (reg) { + if (reg & AMD_BIT(UDC_EPINT_OUT_EP0)) + ret_val |= udc_control_out_isr(dev); + if (reg & AMD_BIT(UDC_EPINT_IN_EP0)) + ret_val |= udc_control_in_isr(dev); + + /* + * data endpoint + * iterate ep's + */ + for (i = 1; i < UDC_EP_NUM; i++) { + ep_irq = 1 << i; + if (!(reg & ep_irq) || i == UDC_EPINT_OUT_EP0) + continue; + + /* clear irq status */ + writel(ep_irq, &dev->regs->ep_irqsts); + + /* irq for out ep ? */ + if (i > UDC_EPIN_NUM) + ret_val |= udc_data_out_isr(dev, i); + else + ret_val |= udc_data_in_isr(dev, i); + } + + } + + + /* check for dev irq */ + reg = readl(&dev->regs->irqsts); + if (reg) { + /* clear irq */ + writel(reg, &dev->regs->irqsts); + ret_val |= udc_dev_isr(dev, reg); + } + + + spin_unlock(&dev->lock); + return ret_val; +} + +/* Tears down device */ +static void gadget_release(struct device *pdev) +{ + struct amd5536udc *dev = dev_get_drvdata(pdev); + kfree(dev); +} + +/* Cleanup on device remove */ +static void udc_remove(struct udc *dev) +{ + /* remove timer */ + stop_timer++; + if (timer_pending(&udc_timer)) + wait_for_completion(&on_exit); + if (udc_timer.data) + del_timer_sync(&udc_timer); + /* remove pollstall timer */ + stop_pollstall_timer++; + if (timer_pending(&udc_pollstall_timer)) + wait_for_completion(&on_pollstall_exit); + if (udc_pollstall_timer.data) + del_timer_sync(&udc_pollstall_timer); + udc = NULL; +} + +/* Reset all pci context */ +static void udc_pci_remove(struct pci_dev *pdev) +{ + struct udc *dev; + + dev = pci_get_drvdata(pdev); + + /* gadget driver must not be registered */ + BUG_ON(dev->driver != NULL); + + /* dma pool cleanup */ + if (dev->data_requests) + pci_pool_destroy(dev->data_requests); + + if (dev->stp_requests) { + /* cleanup DMA desc's for ep0in */ + pci_pool_free(dev->stp_requests, + dev->ep[UDC_EP0OUT_IX].td_stp, + dev->ep[UDC_EP0OUT_IX].td_stp_dma); + pci_pool_free(dev->stp_requests, + dev->ep[UDC_EP0OUT_IX].td, + dev->ep[UDC_EP0OUT_IX].td_phys); + + pci_pool_destroy(dev->stp_requests); + } + + /* reset controller */ + writel(AMD_BIT(UDC_DEVCFG_SOFTRESET), &dev->regs->cfg); + if (dev->irq_registered) + free_irq(pdev->irq, dev); + if (dev->regs) + iounmap(dev->regs); + if (dev->mem_region) + release_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + if (dev->active) + pci_disable_device(pdev); + + device_unregister(&dev->gadget.dev); + pci_set_drvdata(pdev, NULL); + + udc_remove(dev); +} + +/* create dma pools on init */ +static int init_dma_pools(struct udc *dev) +{ + struct udc_stp_dma *td_stp; + struct udc_data_dma *td_data; + int retval; + + /* consistent DMA mode setting ? */ + if (use_dma_ppb) { + use_dma_bufferfill_mode = 0; + } else { + use_dma_ppb_du = 0; + use_dma_bufferfill_mode = 1; + } + + /* DMA setup */ + dev->data_requests = dma_pool_create("data_requests", NULL, + sizeof(struct udc_data_dma), 0, 0); + if (!dev->data_requests) { + DBG(dev, "can't get request data pool\n"); + retval = -ENOMEM; + goto finished; + } + + /* EP0 in dma regs = dev control regs */ + dev->ep[UDC_EP0IN_IX].dma = &dev->regs->ctl; + + /* dma desc for setup data */ + dev->stp_requests = dma_pool_create("setup requests", NULL, + sizeof(struct udc_stp_dma), 0, 0); + if (!dev->stp_requests) { + DBG(dev, "can't get stp request pool\n"); + retval = -ENOMEM; + goto finished; + } + /* setup */ + td_stp = dma_pool_alloc(dev->stp_requests, GFP_KERNEL, + &dev->ep[UDC_EP0OUT_IX].td_stp_dma); + if (td_stp == NULL) { + retval = -ENOMEM; + goto finished; + } + dev->ep[UDC_EP0OUT_IX].td_stp = td_stp; + + /* data: 0 packets !? */ + td_data = dma_pool_alloc(dev->stp_requests, GFP_KERNEL, + &dev->ep[UDC_EP0OUT_IX].td_phys); + if (td_data == NULL) { + retval = -ENOMEM; + goto finished; + } + dev->ep[UDC_EP0OUT_IX].td = td_data; + return 0; + +finished: + return retval; +} + +/* Called by pci bus driver to init pci context */ +static int udc_pci_probe( + struct pci_dev *pdev, + const struct pci_device_id *id +) +{ + struct udc *dev; + unsigned long resource; + unsigned long len; + int retval = 0; + + /* one udc only */ + if (udc) { + dev_dbg(&pdev->dev, "already probed\n"); + return -EBUSY; + } + + /* init */ + dev = kzalloc(sizeof(struct udc), GFP_KERNEL); + if (!dev) { + retval = -ENOMEM; + goto finished; + } + memset(dev, 0, sizeof(struct udc)); + + /* pci setup */ + if (pci_enable_device(pdev) < 0) { + retval = -ENODEV; + goto finished; + } + dev->active = 1; + + /* PCI resource allocation */ + resource = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + + if (!request_mem_region(resource, len, name)) { + dev_dbg(&pdev->dev, "pci device used already\n"); + retval = -EBUSY; + goto finished; + } + dev->mem_region = 1; + + dev->virt_addr = ioremap_nocache(resource, len); + if (dev->virt_addr == NULL) { + dev_dbg(&pdev->dev, "start address cannot be mapped\n"); + retval = -EFAULT; + goto finished; + } + + if (!pdev->irq) { + dev_err(&dev->pdev->dev, "irq not set\n"); + retval = -ENODEV; + goto finished; + } + + if (request_irq(pdev->irq, udc_irq, IRQF_SHARED, name, dev) != 0) { + dev_dbg(&dev->pdev->dev, "request_irq(%d) fail\n", pdev->irq); + retval = -EBUSY; + goto finished; + } + dev->irq_registered = 1; + + pci_set_drvdata(pdev, dev); + + /* chip revision */ + dev->chiprev = 0; + + pci_set_master(pdev); + pci_set_mwi(pdev); + + /* chip rev for Hs AMD5536 */ + pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev); + /* init dma pools */ + if (use_dma) { + retval = init_dma_pools(dev); + if (retval != 0) + goto finished; + } + + dev->phys_addr = resource; + dev->irq = pdev->irq; + dev->pdev = pdev; + dev->gadget.dev.parent = &pdev->dev; + dev->gadget.dev.dma_mask = pdev->dev.dma_mask; + + /* general probing */ + if (udc_probe(dev) == 0) + return 0; + +finished: + if (dev) + udc_pci_remove(pdev); + return retval; +} + +/* general probe */ +static int udc_probe(struct udc *dev) +{ + char tmp[128]; + u32 reg; + int retval; + + /* mark timer as not initialized */ + udc_timer.data = 0; + udc_pollstall_timer.data = 0; + + /* device struct setup */ + spin_lock_init(&dev->lock); + dev->gadget.ops = &udc_ops; + + strcpy(dev->gadget.dev.bus_id, "gadget"); + dev->gadget.dev.release = gadget_release; + dev->gadget.name = name; + dev->gadget.name = name; + dev->gadget.is_dualspeed = 1; + + /* udc csr registers base */ + dev->csr = dev->virt_addr + UDC_CSR_ADDR; + /* dev registers base */ + dev->regs = dev->virt_addr + UDC_DEVCFG_ADDR; + /* ep registers base */ + dev->ep_regs = dev->virt_addr + UDC_EPREGS_ADDR; + /* fifo's base */ + dev->rxfifo = (u32 __iomem *)(dev->virt_addr + UDC_RXFIFO_ADDR); + dev->txfifo = (u32 __iomem *)(dev->virt_addr + UDC_TXFIFO_ADDR); + + /* init registers, interrupts, ... */ + startup_registers(dev); + + dev_info(&dev->pdev->dev, "%s\n", mod_desc); + + snprintf(tmp, sizeof tmp, "%d", dev->irq); + dev_info(&dev->pdev->dev, + "irq %s, pci mem %08lx, chip rev %02x(Geode5536 %s)\n", + tmp, dev->phys_addr, dev->chiprev, + (dev->chiprev == UDC_HSA0_REV) ? "A0" : "B1"); + strcpy(tmp, UDC_DRIVER_VERSION_STRING); + if (dev->chiprev == UDC_HSA0_REV) { + dev_err(&dev->pdev->dev, "chip revision is A0; too old\n"); + retval = -ENODEV; + goto finished; + } + dev_info(&dev->pdev->dev, + "driver version: %s(for Geode5536 B1)\n", tmp); + udc = dev; + + retval = device_register(&dev->gadget.dev); + if (retval) + goto finished; + + /* timer init */ + init_timer(&udc_timer); + udc_timer.function = udc_timer_function; + udc_timer.data = 1; + /* timer pollstall init */ + init_timer(&udc_pollstall_timer); + udc_pollstall_timer.function = udc_pollstall_timer_function; + udc_pollstall_timer.data = 1; + + /* set SD */ + reg = readl(&dev->regs->ctl); + reg |= AMD_BIT(UDC_DEVCTL_SD); + writel(reg, &dev->regs->ctl); + + /* print dev register info */ + print_regs(dev); + + return 0; + +finished: + return retval; +} + +/* Initiates a remote wakeup */ +static int udc_remote_wakeup(struct udc *dev) +{ + unsigned long flags; + u32 tmp; + + DBG(dev, "UDC initiates remote wakeup\n"); + + spin_lock_irqsave(&dev->lock, flags); + + tmp = readl(&dev->regs->ctl); + tmp |= AMD_BIT(UDC_DEVCTL_RES); + writel(tmp, &dev->regs->ctl); + tmp &= AMD_CLEAR_BIT(UDC_DEVCTL_RES); + writel(tmp, &dev->regs->ctl); + + spin_unlock_irqrestore(&dev->lock, flags); + return 0; +} + +/* PCI device parameters */ +static const struct pci_device_id pci_id[] = { + { + PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096), + .class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe, + .class_mask = 0xffffffff, + }, + {}, +}; +MODULE_DEVICE_TABLE(pci, pci_id); + +/* PCI functions */ +static struct pci_driver udc_pci_driver = { + .name = (char *) name, + .id_table = pci_id, + .probe = udc_pci_probe, + .remove = udc_pci_remove, +}; + +/* Inits driver */ +static int __init init(void) +{ + return pci_register_driver(&udc_pci_driver); +} +module_init(init); + +/* Cleans driver */ +static void __exit cleanup(void) +{ + pci_unregister_driver(&udc_pci_driver); +} +module_exit(cleanup); + +MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION); +MODULE_AUTHOR("Thomas Dahlmann"); +MODULE_LICENSE("GPL"); + diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h new file mode 100644 index 00000000000..4bbabbbfc93 --- /dev/null +++ b/drivers/usb/gadget/amd5536udc.h @@ -0,0 +1,626 @@ +/* + * amd5536.h -- header for AMD 5536 UDC high/full speed USB device controller + * + * Copyright (C) 2007 AMD (http://www.amd.com) + * Author: Thomas Dahlmann + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef AMD5536UDC_H +#define AMD5536UDC_H + +/* various constants */ +#define UDC_RDE_TIMER_SECONDS 1 +#define UDC_RDE_TIMER_DIV 10 +#define UDC_POLLSTALL_TIMER_USECONDS 500 + +/* Hs AMD5536 chip rev. */ +#define UDC_HSA0_REV 1 +#define UDC_HSB1_REV 2 + +/* + * SETUP usb commands + * needed, because some SETUP's are handled in hw, but must be passed to + * gadget driver above + * SET_CONFIG + */ +#define UDC_SETCONFIG_DWORD0 0x00000900 +#define UDC_SETCONFIG_DWORD0_VALUE_MASK 0xffff0000 +#define UDC_SETCONFIG_DWORD0_VALUE_OFS 16 + +#define UDC_SETCONFIG_DWORD1 0x00000000 + +/* SET_INTERFACE */ +#define UDC_SETINTF_DWORD0 0x00000b00 +#define UDC_SETINTF_DWORD0_ALT_MASK 0xffff0000 +#define UDC_SETINTF_DWORD0_ALT_OFS 16 + +#define UDC_SETINTF_DWORD1 0x00000000 +#define UDC_SETINTF_DWORD1_INTF_MASK 0x0000ffff +#define UDC_SETINTF_DWORD1_INTF_OFS 0 + +/* Mass storage reset */ +#define UDC_MSCRES_DWORD0 0x0000ff21 +#define UDC_MSCRES_DWORD1 0x00000000 + +/* Global CSR's -------------------------------------------------------------*/ +#define UDC_CSR_ADDR 0x500 + +/* EP NE bits */ +/* EP number */ +#define UDC_CSR_NE_NUM_MASK 0x0000000f +#define UDC_CSR_NE_NUM_OFS 0 +/* EP direction */ +#define UDC_CSR_NE_DIR_MASK 0x00000010 +#define UDC_CSR_NE_DIR_OFS 4 +/* EP type */ +#define UDC_CSR_NE_TYPE_MASK 0x00000060 +#define UDC_CSR_NE_TYPE_OFS 5 +/* EP config number */ +#define UDC_CSR_NE_CFG_MASK 0x00000780 +#define UDC_CSR_NE_CFG_OFS 7 +/* EP interface number */ +#define UDC_CSR_NE_INTF_MASK 0x00007800 +#define UDC_CSR_NE_INTF_OFS 11 +/* EP alt setting */ +#define UDC_CSR_NE_ALT_MASK 0x00078000 +#define UDC_CSR_NE_ALT_OFS 15 + +/* max pkt */ +#define UDC_CSR_NE_MAX_PKT_MASK 0x3ff80000 +#define UDC_CSR_NE_MAX_PKT_OFS 19 + +/* Device Config Register ---------------------------------------------------*/ +#define UDC_DEVCFG_ADDR 0x400 + +#define UDC_DEVCFG_SOFTRESET 31 +#define UDC_DEVCFG_HNPSFEN 30 +#define UDC_DEVCFG_DMARST 29 +#define UDC_DEVCFG_SET_DESC 18 +#define UDC_DEVCFG_CSR_PRG 17 +#define UDC_DEVCFG_STATUS 7 +#define UDC_DEVCFG_DIR 6 +#define UDC_DEVCFG_PI 5 +#define UDC_DEVCFG_SS 4 +#define UDC_DEVCFG_SP 3 +#define UDC_DEVCFG_RWKP 2 + +#define UDC_DEVCFG_SPD_MASK 0x3 +#define UDC_DEVCFG_SPD_OFS 0 +#define UDC_DEVCFG_SPD_HS 0x0 +#define UDC_DEVCFG_SPD_FS 0x1 +#define UDC_DEVCFG_SPD_LS 0x2 +/*#define UDC_DEVCFG_SPD_FS 0x3*/ + + +/* Device Control Register --------------------------------------------------*/ +#define UDC_DEVCTL_ADDR 0x404 + +#define UDC_DEVCTL_THLEN_MASK 0xff000000 +#define UDC_DEVCTL_THLEN_OFS 24 + +#define UDC_DEVCTL_BRLEN_MASK 0x00ff0000 +#define UDC_DEVCTL_BRLEN_OFS 16 + +#define UDC_DEVCTL_CSR_DONE 13 +#define UDC_DEVCTL_DEVNAK 12 +#define UDC_DEVCTL_SD 10 +#define UDC_DEVCTL_MODE 9 +#define UDC_DEVCTL_BREN 8 +#define UDC_DEVCTL_THE 7 +#define UDC_DEVCTL_BF 6 +#define UDC_DEVCTL_BE 5 +#define UDC_DEVCTL_DU 4 +#define UDC_DEVCTL_TDE 3 +#define UDC_DEVCTL_RDE 2 +#define UDC_DEVCTL_RES 0 + + +/* Device Status Register ---------------------------------------------------*/ +#define UDC_DEVSTS_ADDR 0x408 + +#define UDC_DEVSTS_TS_MASK 0xfffc0000 +#define UDC_DEVSTS_TS_OFS 18 + +#define UDC_DEVSTS_SESSVLD 17 +#define UDC_DEVSTS_PHY_ERROR 16 +#define UDC_DEVSTS_RXFIFO_EMPTY 15 + +#define UDC_DEVSTS_ENUM_SPEED_MASK 0x00006000 +#define UDC_DEVSTS_ENUM_SPEED_OFS 13 +#define UDC_DEVSTS_ENUM_SPEED_FULL 1 +#define UDC_DEVSTS_ENUM_SPEED_HIGH 0 + +#define UDC_DEVSTS_SUSP 12 + +#define UDC_DEVSTS_ALT_MASK 0x00000f00 +#define UDC_DEVSTS_ALT_OFS 8 + +#define UDC_DEVSTS_INTF_MASK 0x000000f0 +#define UDC_DEVSTS_INTF_OFS 4 + +#define UDC_DEVSTS_CFG_MASK 0x0000000f +#define UDC_DEVSTS_CFG_OFS 0 + + +/* Device Interrupt Register ------------------------------------------------*/ +#define UDC_DEVINT_ADDR 0x40c + +#define UDC_DEVINT_SVC 7 +#define UDC_DEVINT_ENUM 6 +#define UDC_DEVINT_SOF 5 +#define UDC_DEVINT_US 4 +#define UDC_DEVINT_UR 3 +#define UDC_DEVINT_ES 2 +#define UDC_DEVINT_SI 1 +#define UDC_DEVINT_SC 0 + +/* Device Interrupt Mask Register -------------------------------------------*/ +#define UDC_DEVINT_MSK_ADDR 0x410 + +#define UDC_DEVINT_MSK 0x7f + +/* Endpoint Interrupt Register ----------------------------------------------*/ +#define UDC_EPINT_ADDR 0x414 + +#define UDC_EPINT_OUT_MASK 0xffff0000 +#define UDC_EPINT_OUT_OFS 16 +#define UDC_EPINT_IN_MASK 0x0000ffff +#define UDC_EPINT_IN_OFS 0 + +#define UDC_EPINT_IN_EP0 0 +#define UDC_EPINT_IN_EP1 1 +#define UDC_EPINT_IN_EP2 2 +#define UDC_EPINT_IN_EP3 3 +#define UDC_EPINT_OUT_EP0 16 +#define UDC_EPINT_OUT_EP1 17 +#define UDC_EPINT_OUT_EP2 18 +#define UDC_EPINT_OUT_EP3 19 + +#define UDC_EPINT_EP0_ENABLE_MSK 0x001e001e + +/* Endpoint Interrupt Mask Register -----------------------------------------*/ +#define UDC_EPINT_MSK_ADDR 0x418 + +#define UDC_EPINT_OUT_MSK_MASK 0xffff0000 +#define UDC_EPINT_OUT_MSK_OFS 16 +#define UDC_EPINT_IN_MSK_MASK 0x0000ffff +#define UDC_EPINT_IN_MSK_OFS 0 + +#define UDC_EPINT_MSK_DISABLE_ALL 0xffffffff +/* mask non-EP0 endpoints */ +#define UDC_EPDATAINT_MSK_DISABLE 0xfffefffe +/* mask all dev interrupts */ +#define UDC_DEV_MSK_DISABLE 0x7f + +/* Endpoint-specific CSR's --------------------------------------------------*/ +#define UDC_EPREGS_ADDR 0x0 +#define UDC_EPIN_REGS_ADDR 0x0 +#define UDC_EPOUT_REGS_ADDR 0x200 + +#define UDC_EPCTL_ADDR 0x0 + +#define UDC_EPCTL_RRDY 9 +#define UDC_EPCTL_CNAK 8 +#define UDC_EPCTL_SNAK 7 +#define UDC_EPCTL_NAK 6 + +#define UDC_EPCTL_ET_MASK 0x00000030 +#define UDC_EPCTL_ET_OFS 4 +#define UDC_EPCTL_ET_CONTROL 0 +#define UDC_EPCTL_ET_ISO 1 +#define UDC_EPCTL_ET_BULK 2 +#define UDC_EPCTL_ET_INTERRUPT 3 + +#define UDC_EPCTL_P 3 +#define UDC_EPCTL_SN 2 +#define UDC_EPCTL_F 1 +#define UDC_EPCTL_S 0 + +/* Endpoint Status Registers ------------------------------------------------*/ +#define UDC_EPSTS_ADDR 0x4 + +#define UDC_EPSTS_RX_PKT_SIZE_MASK 0x007ff800 +#define UDC_EPSTS_RX_PKT_SIZE_OFS 11 + +#define UDC_EPSTS_TDC 10 +#define UDC_EPSTS_HE 9 +#define UDC_EPSTS_BNA 7 +#define UDC_EPSTS_IN 6 + +#define UDC_EPSTS_OUT_MASK 0x00000030 +#define UDC_EPSTS_OUT_OFS 4 +#define UDC_EPSTS_OUT_DATA 1 +#define UDC_EPSTS_OUT_DATA_CLEAR 0x10 +#define UDC_EPSTS_OUT_SETUP 2 +#define UDC_EPSTS_OUT_SETUP_CLEAR 0x20 +#define UDC_EPSTS_OUT_CLEAR 0x30 + +/* Endpoint Buffer Size IN/ Receive Packet Frame Number OUT Registers ------*/ +#define UDC_EPIN_BUFF_SIZE_ADDR 0x8 +#define UDC_EPOUT_FRAME_NUMBER_ADDR 0x8 + +#define UDC_EPIN_BUFF_SIZE_MASK 0x0000ffff +#define UDC_EPIN_BUFF_SIZE_OFS 0 +/* EP0in txfifo = 128 bytes*/ +#define UDC_EPIN0_BUFF_SIZE 32 +/* EP0in fullspeed txfifo = 128 bytes*/ +#define UDC_FS_EPIN0_BUFF_SIZE 32 + +/* fifo size mult = fifo size / max packet */ +#define UDC_EPIN_BUFF_SIZE_MULT 2 + +/* EPin data fifo size = 1024 bytes DOUBLE BUFFERING */ +#define UDC_EPIN_BUFF_SIZE 256 +/* EPin small INT data fifo size = 128 bytes */ +#define UDC_EPIN_SMALLINT_BUFF_SIZE 32 + +/* EPin fullspeed data fifo size = 128 bytes DOUBLE BUFFERING */ +#define UDC_FS_EPIN_BUFF_SIZE 32 + +#define UDC_EPOUT_FRAME_NUMBER_MASK 0x0000ffff +#define UDC_EPOUT_FRAME_NUMBER_OFS 0 + +/* Endpoint Buffer Size OUT/Max Packet Size Registers -----------------------*/ +#define UDC_EPOUT_BUFF_SIZE_ADDR 0x0c +#define UDC_EP_MAX_PKT_SIZE_ADDR 0x0c + +#define UDC_EPOUT_BUFF_SIZE_MASK 0xffff0000 +#define UDC_EPOUT_BUFF_SIZE_OFS 16 +#define UDC_EP_MAX_PKT_SIZE_MASK 0x0000ffff +#define UDC_EP_MAX_PKT_SIZE_OFS 0 +/* EP0in max packet size = 64 bytes */ +#define UDC_EP0IN_MAX_PKT_SIZE 64 +/* EP0out max packet size = 64 bytes */ +#define UDC_EP0OUT_MAX_PKT_SIZE 64 +/* EP0in fullspeed max packet size = 64 bytes */ +#define UDC_FS_EP0IN_MAX_PKT_SIZE 64 +/* EP0out fullspeed max packet size = 64 bytes */ +#define UDC_FS_EP0OUT_MAX_PKT_SIZE 64 + +/* + * Endpoint dma descriptors ------------------------------------------------ + * + * Setup data, Status dword + */ +#define UDC_DMA_STP_STS_CFG_MASK 0x0fff0000 +#define UDC_DMA_STP_STS_CFG_OFS 16 +#define UDC_DMA_STP_STS_CFG_ALT_MASK 0x000f0000 +#define UDC_DMA_STP_STS_CFG_ALT_OFS 16 +#define UDC_DMA_STP_STS_CFG_INTF_MASK 0x00f00000 +#define UDC_DMA_STP_STS_CFG_INTF_OFS 20 +#define UDC_DMA_STP_STS_CFG_NUM_MASK 0x0f000000 +#define UDC_DMA_STP_STS_CFG_NUM_OFS 24 +#define UDC_DMA_STP_STS_RX_MASK 0x30000000 +#define UDC_DMA_STP_STS_RX_OFS 28 +#define UDC_DMA_STP_STS_BS_MASK 0xc0000000 +#define UDC_DMA_STP_STS_BS_OFS 30 +#define UDC_DMA_STP_STS_BS_HOST_READY 0 +#define UDC_DMA_STP_STS_BS_DMA_BUSY 1 +#define UDC_DMA_STP_STS_BS_DMA_DONE 2 +#define UDC_DMA_STP_STS_BS_HOST_BUSY 3 +/* IN data, Status dword */ +#define UDC_DMA_IN_STS_TXBYTES_MASK 0x0000ffff +#define UDC_DMA_IN_STS_TXBYTES_OFS 0 +#define UDC_DMA_IN_STS_FRAMENUM_MASK 0x07ff0000 +#define UDC_DMA_IN_STS_FRAMENUM_OFS 0 +#define UDC_DMA_IN_STS_L 27 +#define UDC_DMA_IN_STS_TX_MASK 0x30000000 +#define UDC_DMA_IN_STS_TX_OFS 28 +#define UDC_DMA_IN_STS_BS_MASK 0xc0000000 +#define UDC_DMA_IN_STS_BS_OFS 30 +#define UDC_DMA_IN_STS_BS_HOST_READY 0 +#define UDC_DMA_IN_STS_BS_DMA_BUSY 1 +#define UDC_DMA_IN_STS_BS_DMA_DONE 2 +#define UDC_DMA_IN_STS_BS_HOST_BUSY 3 +/* OUT data, Status dword */ +#define UDC_DMA_OUT_STS_RXBYTES_MASK 0x0000ffff +#define UDC_DMA_OUT_STS_RXBYTES_OFS 0 +#define UDC_DMA_OUT_STS_FRAMENUM_MASK 0x07ff0000 +#define UDC_DMA_OUT_STS_FRAMENUM_OFS 0 +#define UDC_DMA_OUT_STS_L 27 +#define UDC_DMA_OUT_STS_RX_MASK 0x30000000 +#define UDC_DMA_OUT_STS_RX_OFS 28 +#define UDC_DMA_OUT_STS_BS_MASK 0xc0000000 +#define UDC_DMA_OUT_STS_BS_OFS 30 +#define UDC_DMA_OUT_STS_BS_HOST_READY 0 +#define UDC_DMA_OUT_STS_BS_DMA_BUSY 1 +#define UDC_DMA_OUT_STS_BS_DMA_DONE 2 +#define UDC_DMA_OUT_STS_BS_HOST_BUSY 3 +/* max ep0in packet */ +#define UDC_EP0IN_MAXPACKET 1000 +/* max dma packet */ +#define UDC_DMA_MAXPACKET 65536 + +/* un-usable DMA address */ +#define DMA_DONT_USE (~(dma_addr_t) 0 ) + +/* other Endpoint register addresses and values-----------------------------*/ +#define UDC_EP_SUBPTR_ADDR 0x10 +#define UDC_EP_DESPTR_ADDR 0x14 +#define UDC_EP_WRITE_CONFIRM_ADDR 0x1c + +/* EP number as layouted in AHB space */ +#define UDC_EP_NUM 32 +#define UDC_EPIN_NUM 16 +#define UDC_EPIN_NUM_USED 5 +#define UDC_EPOUT_NUM 16 +/* EP number of EP's really used = EP0 + 8 data EP's */ +#define UDC_USED_EP_NUM 9 +/* UDC CSR regs are aligned but AHB regs not - offset for OUT EP's */ +#define UDC_CSR_EP_OUT_IX_OFS 12 + +#define UDC_EP0OUT_IX 16 +#define UDC_EP0IN_IX 0 + +/* Rx fifo address and size = 1k -------------------------------------------*/ +#define UDC_RXFIFO_ADDR 0x800 +#define UDC_RXFIFO_SIZE 0x400 + +/* Tx fifo address and size = 1.5k -----------------------------------------*/ +#define UDC_TXFIFO_ADDR 0xc00 +#define UDC_TXFIFO_SIZE 0x600 + +/* default data endpoints --------------------------------------------------*/ +#define UDC_EPIN_STATUS_IX 1 +#define UDC_EPIN_IX 2 +#define UDC_EPOUT_IX 18 + +/* general constants -------------------------------------------------------*/ +#define UDC_DWORD_BYTES 4 +#define UDC_BITS_PER_BYTE_SHIFT 3 +#define UDC_BYTE_MASK 0xff +#define UDC_BITS_PER_BYTE 8 + +/*---------------------------------------------------------------------------*/ +/* UDC CSR's */ +struct udc_csrs { + + /* sca - setup command address */ + u32 sca; + + /* ep ne's */ + u32 ne[UDC_USED_EP_NUM]; +} __attribute__ ((packed)); + +/* AHB subsystem CSR registers */ +struct udc_regs { + + /* device configuration */ + u32 cfg; + + /* device control */ + u32 ctl; + + /* device status */ + u32 sts; + + /* device interrupt */ + u32 irqsts; + + /* device interrupt mask */ + u32 irqmsk; + + /* endpoint interrupt */ + u32 ep_irqsts; + + /* endpoint interrupt mask */ + u32 ep_irqmsk; +} __attribute__ ((packed)); + +/* endpoint specific registers */ +struct udc_ep_regs { + + /* endpoint control */ + u32 ctl; + + /* endpoint status */ + u32 sts; + + /* endpoint buffer size in/ receive packet frame number out */ + u32 bufin_framenum; + + /* endpoint buffer size out/max packet size */ + u32 bufout_maxpkt; + + /* endpoint setup buffer pointer */ + u32 subptr; + + /* endpoint data descriptor pointer */ + u32 desptr; + + /* reserverd */ + u32 reserved; + + /* write/read confirmation */ + u32 confirm; + +} __attribute__ ((packed)); + +/* control data DMA desc */ +struct udc_stp_dma { + /* status quadlet */ + u32 status; + /* reserved */ + u32 _reserved; + /* first setup word */ + u32 data12; + /* second setup word */ + u32 data34; +} __attribute__ ((aligned (16))); + +/* normal data DMA desc */ +struct udc_data_dma { + /* status quadlet */ + u32 status; + /* reserved */ + u32 _reserved; + /* buffer pointer */ + u32 bufptr; + /* next descriptor pointer */ + u32 next; +} __attribute__ ((aligned (16))); + +/* request packet */ +struct udc_request { + /* embedded gadget ep */ + struct usb_request req; + + /* flags */ + unsigned dma_going : 1, + dma_mapping : 1, + dma_done : 1; + /* phys. address */ + dma_addr_t td_phys; + /* first dma desc. of chain */ + struct udc_data_dma *td_data; + /* last dma desc. of chain */ + struct udc_data_dma *td_data_last; + struct list_head queue; + + /* chain length */ + unsigned chain_len; + +}; + +/* UDC specific endpoint parameters */ +struct udc_ep { + struct usb_ep ep; + struct udc_ep_regs __iomem *regs; + u32 __iomem *txfifo; + u32 __iomem *dma; + dma_addr_t td_phys; + dma_addr_t td_stp_dma; + struct udc_stp_dma *td_stp; + struct udc_data_dma *td; + /* temp request */ + struct udc_request *req; + unsigned req_used; + unsigned req_completed; + /* dummy DMA desc for BNA dummy */ + struct udc_request *bna_dummy_req; + unsigned bna_occurred; + + /* NAK state */ + unsigned naking; + + struct udc *dev; + + /* queue for requests */ + struct list_head queue; + const struct usb_endpoint_descriptor *desc; + unsigned halted; + unsigned cancel_transfer; + unsigned num : 5, + fifo_depth : 14, + in : 1; +}; + +/* device struct */ +struct udc { + struct usb_gadget gadget; + spinlock_t lock; /* protects all state */ + /* all endpoints */ + struct udc_ep ep[UDC_EP_NUM]; + struct usb_gadget_driver *driver; + /* operational flags */ + unsigned active : 1, + stall_ep0in : 1, + waiting_zlp_ack_ep0in : 1, + set_cfg_not_acked : 1, + irq_registered : 1, + data_ep_enabled : 1, + data_ep_queued : 1, + mem_region : 1, + sys_suspended : 1, + connected; + + u16 chiprev; + + /* registers */ + struct pci_dev *pdev; + struct udc_csrs __iomem *csr; + struct udc_regs __iomem *regs; + struct udc_ep_regs __iomem *ep_regs; + u32 __iomem *rxfifo; + u32 __iomem *txfifo; + + /* DMA desc pools */ + struct pci_pool *data_requests; + struct pci_pool *stp_requests; + + /* device data */ + unsigned long phys_addr; + void __iomem *virt_addr; + unsigned irq; + + /* states */ + u16 cur_config; + u16 cur_intf; + u16 cur_alt; +}; + +/* setup request data */ +union udc_setup_data { + u32 data[2]; + struct usb_ctrlrequest request; +}; + +/* + *--------------------------------------------------------------------------- + * SET and GET bitfields in u32 values + * via constants for mask/offset: + * <bit_field_stub_name> is the text between + * UDC_ and _MASK|_OFS of appropiate + * constant + * + * set bitfield value in u32 u32Val + */ +#define AMD_ADDBITS(u32Val, bitfield_val, bitfield_stub_name) \ + (((u32Val) & (((u32) ~((u32) bitfield_stub_name##_MASK)))) \ + | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \ + & ((u32) bitfield_stub_name##_MASK))) + +/* + * set bitfield value in zero-initialized u32 u32Val + * => bitfield bits in u32Val are all zero + */ +#define AMD_INIT_SETBITS(u32Val, bitfield_val, bitfield_stub_name) \ + ((u32Val) \ + | (((bitfield_val) << ((u32) bitfield_stub_name##_OFS)) \ + & ((u32) bitfield_stub_name##_MASK))) + +/* get bitfield value from u32 u32Val */ +#define AMD_GETBITS(u32Val, bitfield_stub_name) \ + ((u32Val & ((u32) bitfield_stub_name##_MASK)) \ + >> ((u32) bitfield_stub_name##_OFS)) + +/* SET and GET bits in u32 values ------------------------------------------*/ +#define AMD_BIT(bit_stub_name) (1 << bit_stub_name) +#define AMD_UNMASK_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name)) +#define AMD_CLEAR_BIT(bit_stub_name) (~AMD_BIT(bit_stub_name)) + +/* debug macros ------------------------------------------------------------*/ + +#define DBG(udc , args...) dev_dbg(&(udc)->pdev->dev, args) + +#ifdef UDC_VERBOSE +#define VDBG DBG +#else +#define VDBG(udc , args...) do {} while (0) +#endif + +#endif /* #ifdef AMD5536UDC_H */ diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c index dbaf867436d..a3376739a81 100644 --- a/drivers/usb/gadget/ether.c +++ b/drivers/usb/gadget/ether.c @@ -305,6 +305,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address"); #define DEV_CONFIG_CDC #endif +#ifdef CONFIG_USB_GADGET_AMD5536UDC +#define DEV_CONFIG_CDC +#endif + /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index 53e9139ba38..f7f159c1002 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -17,6 +17,12 @@ #define gadget_is_net2280(g) 0 #endif +#ifdef CONFIG_USB_GADGET_AMD5536UDC +#define gadget_is_amd5536udc(g) !strcmp("amd5536udc", (g)->name) +#else +#define gadget_is_amd5536udc(g) 0 +#endif + #ifdef CONFIG_USB_GADGET_DUMMY_HCD #define gadget_is_dummy(g) !strcmp("dummy_udc", (g)->name) #else @@ -202,7 +208,9 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x18; else if (gadget_is_fsl_usb2(gadget)) return 0x19; - else if (gadget_is_m66592(gadget)) + else if (gadget_is_amd5536udc(gadget)) return 0x20; + else if (gadget_is_m66592(gadget)) + return 0x21; return -ENOENT; } diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 0174a322e00..700dda8a915 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -21,26 +21,18 @@ */ #include <linux/module.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp_lock.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/delay.h> -#include <linux/list.h> #include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/io.h> #include <linux/platform_device.h> + #include <linux/usb/ch9.h> #include <linux/usb_gadget.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/system.h> - #include "m66592-udc.h" -MODULE_DESCRIPTION("M66592 USB gadget driiver"); + +MODULE_DESCRIPTION("M66592 USB gadget driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yoshihiro Shimoda"); @@ -49,16 +41,21 @@ MODULE_AUTHOR("Yoshihiro Shimoda"); /* module parameters */ static unsigned short clock = M66592_XTAL24; module_param(clock, ushort, 0644); -MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=16384)"); +MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 " + "(default=16384)"); + static unsigned short vif = M66592_LDRV; module_param(vif, ushort, 0644); -MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)"); -static unsigned short endian = 0; +MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0 (default=32768)"); + +static unsigned short endian; module_param(endian, ushort, 0644); -MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)"); +MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)"); + static unsigned short irq_sense = M66592_INTL; module_param(irq_sense, ushort, 0644); -MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0(default=2)"); +MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0 " + "(default=2)"); static const char udc_name[] = "m66592_udc"; static const char *m66592_ep_name[] = { @@ -72,8 +69,8 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags); static void transfer_complete(struct m66592_ep *ep, - struct m66592_request *req, - int status); + struct m66592_request *req, int status); + /*-------------------------------------------------------------------------*/ static inline u16 get_usb_speed(struct m66592 *m66592) { @@ -81,25 +78,25 @@ static inline u16 get_usb_speed(struct m66592 *m66592) } static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum, - unsigned long reg) + unsigned long reg) { u16 tmp; tmp = m66592_read(m66592, M66592_INTENB0); m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, - M66592_INTENB0); + M66592_INTENB0); m66592_bset(m66592, (1 << pipenum), reg); m66592_write(m66592, tmp, M66592_INTENB0); } static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum, - unsigned long reg) + unsigned long reg) { u16 tmp; tmp = m66592_read(m66592, M66592_INTENB0); m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE, - M66592_INTENB0); + M66592_INTENB0); m66592_bclr(m66592, (1 << pipenum), reg); m66592_write(m66592, tmp, M66592_INTENB0); } @@ -108,17 +105,19 @@ static void m66592_usb_connect(struct m66592 *m66592) { m66592_bset(m66592, M66592_CTRE, M66592_INTENB0); m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, - M66592_INTENB0); + M66592_INTENB0); m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG); } static void m66592_usb_disconnect(struct m66592 *m66592) +__releases(m66592->lock) +__acquires(m66592->lock) { m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0); m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL, - M66592_INTENB0); + M66592_INTENB0); m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0); m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG); @@ -148,7 +147,7 @@ static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum) } static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum, - u16 pid) + u16 pid) { unsigned long offset; @@ -250,7 +249,7 @@ static inline void pipe_change(struct m66592 *m66592, u16 pipenum) } static int pipe_buffer_setting(struct m66592 *m66592, - struct m66592_pipe_info *info) + struct m66592_pipe_info *info) { u16 bufnum = 0, buf_bsize = 0; u16 pipecfg = 0; @@ -287,7 +286,7 @@ static int pipe_buffer_setting(struct m66592 *m66592, } if (m66592->bi_bufnum > M66592_MAX_BUFNUM) { printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n", - m66592->bi_bufnum); + m66592->bi_bufnum); return -ENOMEM; } @@ -328,7 +327,7 @@ static void pipe_buffer_release(struct m66592 *m66592, m66592->bulk--; } else printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n", - info->pipe); + info->pipe); } static void pipe_initialize(struct m66592_ep *ep) @@ -350,8 +349,8 @@ static void pipe_initialize(struct m66592_ep *ep) } static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, - const struct usb_endpoint_descriptor *desc, - u16 pipenum, int dma) + const struct usb_endpoint_descriptor *desc, + u16 pipenum, int dma) { if ((pipenum != 0) && dma) { if (m66592->num_dma == 0) { @@ -385,7 +384,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep, ep->pipectr = get_pipectr_addr(pipenum); ep->pipenum = pipenum; - ep->ep.maxpacket = desc->wMaxPacketSize; + ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize); m66592->pipenum2ep[pipenum] = ep; m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep; INIT_LIST_HEAD(&ep->queue); @@ -407,7 +406,7 @@ static void m66592_ep_release(struct m66592_ep *ep) } static int alloc_pipe_config(struct m66592_ep *ep, - const struct usb_endpoint_descriptor *desc) + const struct usb_endpoint_descriptor *desc) { struct m66592 *m66592 = ep->m66592; struct m66592_pipe_info info; @@ -419,15 +418,15 @@ static int alloc_pipe_config(struct m66592_ep *ep, BUG_ON(ep->pipenum); - switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { + switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { case USB_ENDPOINT_XFER_BULK: if (m66592->bulk >= M66592_MAX_NUM_BULK) { if (m66592->isochronous >= M66592_MAX_NUM_ISOC) { printk(KERN_ERR "bulk pipe is insufficient\n"); return -ENODEV; } else { - info.pipe = M66592_BASE_PIPENUM_ISOC + - m66592->isochronous; + info.pipe = M66592_BASE_PIPENUM_ISOC + + m66592->isochronous; counter = &m66592->isochronous; } } else { @@ -462,7 +461,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, ep->type = info.type; info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - info.maxpacket = desc->wMaxPacketSize; + info.maxpacket = le16_to_cpu(desc->wMaxPacketSize); info.interval = desc->bInterval; if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) info.dir_in = 1; @@ -525,8 +524,8 @@ static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req) pipe_change(m66592, ep->pipenum); m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0, - (M66592_ISEL | M66592_CURPIPE), - M66592_CFIFOSEL); + (M66592_ISEL | M66592_CURPIPE), + M66592_CFIFOSEL); m66592_write(m66592, M66592_BCLR, ep->fifoctr); if (req->req.length == 0) { m66592_bset(m66592, M66592_BVAL, ep->fifoctr); @@ -561,8 +560,8 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) if (ep->pipenum == 0) { m66592_mdfy(m66592, M66592_PIPE0, - (M66592_ISEL | M66592_CURPIPE), - M66592_CFIFOSEL); + (M66592_ISEL | M66592_CURPIPE), + M66592_CFIFOSEL); m66592_write(m66592, M66592_BCLR, ep->fifoctr); pipe_start(m66592, pipenum); pipe_irq_enable(m66592, pipenum); @@ -572,8 +571,9 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) pipe_change(m66592, pipenum); m66592_bset(m66592, M66592_TRENB, ep->fifosel); m66592_write(m66592, - (req->req.length + ep->ep.maxpacket - 1) / - ep->ep.maxpacket, ep->fifotrn); + (req->req.length + ep->ep.maxpacket - 1) + / ep->ep.maxpacket, + ep->fifotrn); } pipe_start(m66592, pipenum); /* trigger once */ pipe_irq_enable(m66592, pipenum); @@ -614,7 +614,7 @@ static void start_ep0(struct m66592_ep *ep, struct m66592_request *req) static void init_controller(struct m66592 *m66592) { m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND), - M66592_PINCFG); + M66592_PINCFG); m66592_bset(m66592, M66592_HSE, M66592_SYSCFG); /* High spd */ m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG); @@ -634,7 +634,7 @@ static void init_controller(struct m66592 *m66592) m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1); m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR, - M66592_DMA0CFG); + M66592_DMA0CFG); } static void disable_controller(struct m66592 *m66592) @@ -659,8 +659,9 @@ static void m66592_start_xclock(struct m66592 *m66592) /*-------------------------------------------------------------------------*/ static void transfer_complete(struct m66592_ep *ep, - struct m66592_request *req, - int status) + struct m66592_request *req, int status) +__releases(m66592->lock) +__acquires(m66592->lock) { int restart = 0; @@ -680,8 +681,9 @@ static void transfer_complete(struct m66592_ep *ep, if (!list_empty(&ep->queue)) restart = 1; - if (likely(req->req.complete)) - req->req.complete(&ep->ep, &req->req); + spin_unlock(&ep->m66592->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&ep->m66592->lock); if (restart) { req = list_entry(ep->queue.next, struct m66592_request, queue); @@ -693,7 +695,7 @@ static void transfer_complete(struct m66592_ep *ep, static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) { int i; - volatile u16 tmp; + u16 tmp; unsigned bufsize; size_t size; void *buf; @@ -731,8 +733,9 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req) req->req.actual += size; /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) || - (size % ep->ep.maxpacket) || (size == 0)) { + if ((!req->req.zero && (req->req.actual == req->req.length)) + || (size % ep->ep.maxpacket) + || (size == 0)) { disable_irq_ready(m66592, pipenum); disable_irq_empty(m66592, pipenum); } else { @@ -768,16 +771,19 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req) /* write fifo */ if (req->req.buf) { m66592_write_fifo(m66592, ep->fifoaddr, buf, size); - if ((size == 0) || ((size % ep->ep.maxpacket) != 0) || - ((bufsize != ep->ep.maxpacket) && (bufsize > size))) + if ((size == 0) + || ((size % ep->ep.maxpacket) != 0) + || ((bufsize != ep->ep.maxpacket) + && (bufsize > size))) m66592_bset(m66592, M66592_BVAL, ep->fifoctr); } /* update parameters */ req->req.actual += size; /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) || - (size % ep->ep.maxpacket) || (size == 0)) { + if ((!req->req.zero && (req->req.actual == req->req.length)) + || (size % ep->ep.maxpacket) + || (size == 0)) { disable_irq_ready(m66592, pipenum); enable_irq_empty(m66592, pipenum); } else { @@ -821,8 +827,9 @@ static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req) req->req.actual += size; /* check transfer finish */ - if ((!req->req.zero && (req->req.actual == req->req.length)) || - (size % ep->ep.maxpacket) || (size == 0)) { + if ((!req->req.zero && (req->req.actual == req->req.length)) + || (size % ep->ep.maxpacket) + || (size == 0)) { pipe_stop(m66592, pipenum); pipe_irq_disable(m66592, pipenum); finish = 1; @@ -850,7 +857,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb) if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) { m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS); m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE, - M66592_CFIFOSEL); + M66592_CFIFOSEL); ep = &m66592->ep[0]; req = list_entry(ep->queue.next, struct m66592_request, queue); @@ -909,23 +916,26 @@ static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb) } static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) +__releases(m66592->lock) +__acquires(m66592->lock) { struct m66592_ep *ep; u16 pid; u16 status = 0; + u16 w_index = le16_to_cpu(ctrl->wIndex); switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - status = 1; /* selfpower */ + status = 1 << USB_DEVICE_SELF_POWERED; break; case USB_RECIP_INTERFACE: status = 0; break; case USB_RECIP_ENDPOINT: - ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK]; + ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; pid = control_reg_get_pid(m66592, ep->pipenum); if (pid == M66592_PID_STALL) - status = 1; + status = 1 << USB_ENDPOINT_HALT; else status = 0; break; @@ -934,11 +944,13 @@ static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) return; /* exit */ } - *m66592->ep0_buf = status; - m66592->ep0_req->buf = m66592->ep0_buf; + m66592->ep0_data = cpu_to_le16(status); + m66592->ep0_req->buf = &m66592->ep0_data; m66592->ep0_req->length = 2; /* AV: what happens if we get called again before that gets through? */ + spin_unlock(&m66592->lock); m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL); + spin_lock(&m66592->lock); } static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) @@ -953,8 +965,9 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) case USB_RECIP_ENDPOINT: { struct m66592_ep *ep; struct m66592_request *req; + u16 w_index = le16_to_cpu(ctrl->wIndex); - ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK]; + ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; pipe_stop(m66592, ep->pipenum); control_reg_sqclr(m66592, ep->pipenum); @@ -989,8 +1002,9 @@ static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl) break; case USB_RECIP_ENDPOINT: { struct m66592_ep *ep; + u16 w_index = le16_to_cpu(ctrl->wIndex); - ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK]; + ep = m66592->epaddr2ep[w_index & USB_ENDPOINT_NUMBER_MASK]; pipe_stall(m66592, ep->pipenum); control_end(m66592, 1); @@ -1066,14 +1080,16 @@ static void irq_device_state(struct m66592 *m66592) } if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG) m66592_update_usb_speed(m66592); - if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) && - m66592->gadget.speed == USB_SPEED_UNKNOWN) + if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) + && m66592->gadget.speed == USB_SPEED_UNKNOWN) m66592_update_usb_speed(m66592); m66592->old_dvsq = dvsq; } static void irq_control_stage(struct m66592 *m66592) +__releases(m66592->lock) +__acquires(m66592->lock) { struct usb_ctrlrequest ctrl; u16 ctsq; @@ -1095,8 +1111,10 @@ static void irq_control_stage(struct m66592 *m66592) case M66592_CS_WRDS: case M66592_CS_WRND: if (setup_packet(m66592, &ctrl)) { + spin_unlock(&m66592->lock); if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0) pipe_stall(m66592, 0); + spin_lock(&m66592->lock); } break; case M66592_CS_RDSS: @@ -1119,6 +1137,8 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) u16 savepipe; u16 mask0; + spin_lock(&m66592->lock); + intsts0 = m66592_read(m66592, M66592_INTSTS0); intenb0 = m66592_read(m66592, M66592_INTENB0); @@ -1134,27 +1154,27 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) bempenb = m66592_read(m66592, M66592_BEMPENB); if (mask0 & M66592_VBINT) { - m66592_write(m66592, (u16)~M66592_VBINT, - M66592_INTSTS0); + m66592_write(m66592, 0xffff & ~M66592_VBINT, + M66592_INTSTS0); m66592_start_xclock(m66592); /* start vbus sampling */ m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0) - & M66592_VBSTS; + & M66592_VBSTS; m66592->scount = M66592_MAX_SAMPLING; mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); + jiffies + msecs_to_jiffies(50)); } if (intsts0 & M66592_DVSQ) irq_device_state(m66592); - if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) && - (brdysts & brdyenb)) { + if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) + && (brdysts & brdyenb)) { irq_pipe_ready(m66592, brdysts, brdyenb); } - if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) && - (bempsts & bempenb)) { + if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) + && (bempsts & bempenb)) { irq_pipe_empty(m66592, bempsts, bempenb); } @@ -1164,6 +1184,7 @@ static irqreturn_t m66592_irq(int irq, void *_m66592) m66592_write(m66592, savepipe, M66592_CFIFOSEL); + spin_unlock(&m66592->lock); return IRQ_HANDLED; } @@ -1191,13 +1212,13 @@ static void m66592_timer(unsigned long _m66592) m66592_usb_disconnect(m66592); } else { mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); + jiffies + msecs_to_jiffies(50)); } } else { m66592->scount = M66592_MAX_SAMPLING; m66592->old_vbus = tmp; mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); + jiffies + msecs_to_jiffies(50)); } } spin_unlock_irqrestore(&m66592->lock, flags); @@ -1335,11 +1356,6 @@ out: return ret; } -static int m66592_fifo_status(struct usb_ep *_ep) -{ - return -EOPNOTSUPP; -} - static void m66592_fifo_flush(struct usb_ep *_ep) { struct m66592_ep *ep; @@ -1365,7 +1381,6 @@ static struct usb_ep_ops m66592_ep_ops = { .dequeue = m66592_dequeue, .set_halt = m66592_set_halt, - .fifo_status = m66592_fifo_status, .fifo_flush = m66592_fifo_flush, }; @@ -1377,11 +1392,10 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) struct m66592 *m66592 = the_controller; int retval; - if (!driver || - driver->speed != USB_SPEED_HIGH || - !driver->bind || - !driver->unbind || - !driver->setup) + if (!driver + || driver->speed != USB_SPEED_HIGH + || !driver->bind + || !driver->setup) return -EINVAL; if (!m66592) return -ENODEV; @@ -1413,8 +1427,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver) m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS; m66592->scount = M66592_MAX_SAMPLING; - mod_timer(&m66592->timer, - jiffies + msecs_to_jiffies(50)); + mod_timer(&m66592->timer, jiffies + msecs_to_jiffies(50)); } return 0; @@ -1432,6 +1445,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) struct m66592 *m66592 = the_controller; unsigned long flags; + if (driver != m66592->driver || !driver->unbind) + return -EINVAL; + spin_lock_irqsave(&m66592->lock, flags); if (m66592->gadget.speed != USB_SPEED_UNKNOWN) m66592_usb_disconnect(m66592); @@ -1461,46 +1477,35 @@ static struct usb_gadget_ops m66592_gadget_ops = { .get_frame = m66592_get_frame, }; -#if defined(CONFIG_PM) -static int m66592_suspend(struct platform_device *pdev, pm_message_t state) -{ - pdev->dev.power.power_state = state; - return 0; -} - -static int m66592_resume(struct platform_device *pdev) -{ - pdev->dev.power.power_state = PMSG_ON; - return 0; -} -#else /* if defined(CONFIG_PM) */ -#define m66592_suspend NULL -#define m66592_resume NULL -#endif - -static int __init_or_module m66592_remove(struct platform_device *pdev) +static int __exit m66592_remove(struct platform_device *pdev) { struct m66592 *m66592 = dev_get_drvdata(&pdev->dev); del_timer_sync(&m66592->timer); iounmap(m66592->reg); free_irq(platform_get_irq(pdev, 0), m66592); + m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req); kfree(m66592); return 0; } +static void nop_completion(struct usb_ep *ep, struct usb_request *r) +{ +} + #define resource_len(r) (((r)->end - (r)->start) + 1) + static int __init m66592_probe(struct platform_device *pdev) { - struct resource *res = NULL; - int irq = -1; + struct resource *res; + int irq; void __iomem *reg = NULL; struct m66592 *m66592 = NULL; int ret = 0; int i; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - (char *)udc_name); + (char *)udc_name); if (!res) { ret = -ENODEV; printk(KERN_ERR "platform_get_resource_byname error.\n"); @@ -1548,7 +1553,7 @@ static int __init m66592_probe(struct platform_device *pdev) m66592->bi_bufnum = M66592_BASE_BUFNUM; ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED, - udc_name, m66592); + udc_name, m66592); if (ret < 0) { printk(KERN_ERR "request_irq error (%d)\n", ret); goto clean_up; @@ -1563,7 +1568,7 @@ static int __init m66592_probe(struct platform_device *pdev) if (i != 0) { INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list); list_add_tail(&m66592->ep[i].ep.ep_list, - &m66592->gadget.ep_list); + &m66592->gadget.ep_list); } ep->m66592 = m66592; INIT_LIST_HEAD(&ep->queue); @@ -1583,20 +1588,18 @@ static int __init m66592_probe(struct platform_device *pdev) the_controller = m66592; - /* AV: leaks */ m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL); if (m66592->ep0_req == NULL) - goto clean_up; - /* AV: leaks, and do we really need it separately allocated? */ - m66592->ep0_buf = kzalloc(2, GFP_KERNEL); - if (m66592->ep0_buf == NULL) - goto clean_up; + goto clean_up2; + m66592->ep0_req->complete = nop_completion; init_controller(m66592); - printk("driver %s, %s\n", udc_name, DRIVER_VERSION); + dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION); return 0; +clean_up2: + free_irq(irq, m66592); clean_up: if (m66592) { if (m66592->ep0_req) @@ -1611,10 +1614,7 @@ clean_up: /*-------------------------------------------------------------------------*/ static struct platform_driver m66592_driver = { - .probe = m66592_probe, - .remove = m66592_remove, - .suspend = m66592_suspend, - .resume = m66592_resume, + .remove = __exit_p(m66592_remove), .driver = { .name = (char *) udc_name, }, @@ -1622,7 +1622,7 @@ static struct platform_driver m66592_driver = { static int __init m66592_udc_init(void) { - return platform_driver_register(&m66592_driver); + return platform_driver_probe(&m66592_driver, m66592_probe); } module_init(m66592_udc_init); @@ -1631,4 +1631,3 @@ static void __exit m66592_udc_cleanup(void) platform_driver_unregister(&m66592_driver); } module_exit(m66592_udc_cleanup); - diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index 26b54f8b894..bfa0c645f22 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -24,73 +24,73 @@ #define __M66592_UDC_H__ #define M66592_SYSCFG 0x00 -#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */ -#define M66592_XTAL48 0x8000 /* 48MHz */ -#define M66592_XTAL24 0x4000 /* 24MHz */ -#define M66592_XTAL12 0x0000 /* 12MHz */ -#define M66592_XCKE 0x2000 /* b13: External clock enable */ -#define M66592_RCKE 0x1000 /* b12: Register clock enable */ -#define M66592_PLLC 0x0800 /* b11: PLL control */ -#define M66592_SCKE 0x0400 /* b10: USB clock enable */ -#define M66592_ATCKM 0x0100 /* b8: Automatic supply functional enable */ -#define M66592_HSE 0x0080 /* b7: Hi-speed enable */ -#define M66592_DCFM 0x0040 /* b6: Controller function select */ -#define M66592_DMRPD 0x0020 /* b5: D- pull down control */ -#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */ -#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */ -#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */ -#define M66592_USBE 0x0001 /* b0: USB module operation enable */ +#define M66592_XTAL 0xC000 /* b15-14: Crystal selection */ +#define M66592_XTAL48 0x8000 /* 48MHz */ +#define M66592_XTAL24 0x4000 /* 24MHz */ +#define M66592_XTAL12 0x0000 /* 12MHz */ +#define M66592_XCKE 0x2000 /* b13: External clock enable */ +#define M66592_RCKE 0x1000 /* b12: Register clock enable */ +#define M66592_PLLC 0x0800 /* b11: PLL control */ +#define M66592_SCKE 0x0400 /* b10: USB clock enable */ +#define M66592_ATCKM 0x0100 /* b8: Automatic clock supply */ +#define M66592_HSE 0x0080 /* b7: Hi-speed enable */ +#define M66592_DCFM 0x0040 /* b6: Controller function select */ +#define M66592_DMRPD 0x0020 /* b5: D- pull down control */ +#define M66592_DPRPU 0x0010 /* b4: D+ pull up control */ +#define M66592_FSRPC 0x0004 /* b2: Full-speed receiver enable */ +#define M66592_PCUT 0x0002 /* b1: Low power sleep enable */ +#define M66592_USBE 0x0001 /* b0: USB module operation enable */ #define M66592_SYSSTS 0x02 -#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */ -#define M66592_SE1 0x0003 /* SE1 */ -#define M66592_KSTS 0x0002 /* K State */ -#define M66592_JSTS 0x0001 /* J State */ -#define M66592_SE0 0x0000 /* SE0 */ +#define M66592_LNST 0x0003 /* b1-0: D+, D- line status */ +#define M66592_SE1 0x0003 /* SE1 */ +#define M66592_KSTS 0x0002 /* K State */ +#define M66592_JSTS 0x0001 /* J State */ +#define M66592_SE0 0x0000 /* SE0 */ #define M66592_DVSTCTR 0x04 -#define M66592_WKUP 0x0100 /* b8: Remote wakeup */ -#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */ -#define M66592_USBRST 0x0040 /* b6: USB reset enable */ -#define M66592_RESUME 0x0020 /* b5: Resume enable */ -#define M66592_UACT 0x0010 /* b4: USB bus enable */ -#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */ -#define M66592_HSMODE 0x0003 /* Hi-Speed mode */ -#define M66592_FSMODE 0x0002 /* Full-Speed mode */ -#define M66592_HSPROC 0x0001 /* HS handshake is processing */ +#define M66592_WKUP 0x0100 /* b8: Remote wakeup */ +#define M66592_RWUPE 0x0080 /* b7: Remote wakeup sense */ +#define M66592_USBRST 0x0040 /* b6: USB reset enable */ +#define M66592_RESUME 0x0020 /* b5: Resume enable */ +#define M66592_UACT 0x0010 /* b4: USB bus enable */ +#define M66592_RHST 0x0003 /* b1-0: Reset handshake status */ +#define M66592_HSMODE 0x0003 /* Hi-Speed mode */ +#define M66592_FSMODE 0x0002 /* Full-Speed mode */ +#define M66592_HSPROC 0x0001 /* HS handshake is processing */ #define M66592_TESTMODE 0x06 -#define M66592_UTST 0x000F /* b4-0: Test select */ -#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */ -#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */ -#define M66592_H_TST_K 0x000A /* HOST TEST K */ -#define M66592_H_TST_J 0x0009 /* HOST TEST J */ -#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */ -#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */ -#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */ -#define M66592_P_TST_K 0x0002 /* PERI TEST K */ -#define M66592_P_TST_J 0x0001 /* PERI TEST J */ -#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ +#define M66592_UTST 0x000F /* b4-0: Test select */ +#define M66592_H_TST_PACKET 0x000C /* HOST TEST Packet */ +#define M66592_H_TST_SE0_NAK 0x000B /* HOST TEST SE0 NAK */ +#define M66592_H_TST_K 0x000A /* HOST TEST K */ +#define M66592_H_TST_J 0x0009 /* HOST TEST J */ +#define M66592_H_TST_NORMAL 0x0000 /* HOST Normal Mode */ +#define M66592_P_TST_PACKET 0x0004 /* PERI TEST Packet */ +#define M66592_P_TST_SE0_NAK 0x0003 /* PERI TEST SE0 NAK */ +#define M66592_P_TST_K 0x0002 /* PERI TEST K */ +#define M66592_P_TST_J 0x0001 /* PERI TEST J */ +#define M66592_P_TST_NORMAL 0x0000 /* PERI Normal Mode */ #define M66592_PINCFG 0x0A -#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ -#define M66592_BIGEND 0x0100 /* b8: Big endian mode */ +#define M66592_LDRV 0x8000 /* b15: Drive Current Adjust */ +#define M66592_BIGEND 0x0100 /* b8: Big endian mode */ #define M66592_DMA0CFG 0x0C #define M66592_DMA1CFG 0x0E -#define M66592_DREQA 0x4000 /* b14: Dreq active select */ -#define M66592_BURST 0x2000 /* b13: Burst mode */ -#define M66592_DACKA 0x0400 /* b10: Dack active select */ -#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */ -#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */ -#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */ -#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */ -#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */ -#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */ -#define M66592_DENDA 0x0040 /* b6: Dend active select */ -#define M66592_PKTM 0x0020 /* b5: Packet mode */ -#define M66592_DENDE 0x0010 /* b4: Dend enable */ -#define M66592_OBUS 0x0004 /* b2: OUTbus mode */ +#define M66592_DREQA 0x4000 /* b14: Dreq active select */ +#define M66592_BURST 0x2000 /* b13: Burst mode */ +#define M66592_DACKA 0x0400 /* b10: Dack active select */ +#define M66592_DFORM 0x0380 /* b9-7: DMA mode select */ +#define M66592_CPU_ADR_RD_WR 0x0000 /* Address + RD/WR mode (CPU bus) */ +#define M66592_CPU_DACK_RD_WR 0x0100 /* DACK + RD/WR mode (CPU bus) */ +#define M66592_CPU_DACK_ONLY 0x0180 /* DACK only mode (CPU bus) */ +#define M66592_SPLIT_DACK_ONLY 0x0200 /* DACK only mode (SPLIT bus) */ +#define M66592_SPLIT_DACK_DSTB 0x0300 /* DACK + DSTB0 mode (SPLIT bus) */ +#define M66592_DENDA 0x0040 /* b6: Dend active select */ +#define M66592_PKTM 0x0020 /* b5: Packet mode */ +#define M66592_DENDE 0x0010 /* b4: Dend enable */ +#define M66592_OBUS 0x0004 /* b2: OUTbus mode */ #define M66592_CFIFO 0x10 #define M66592_D0FIFO 0x14 @@ -99,300 +99,300 @@ #define M66592_CFIFOSEL 0x1E #define M66592_D0FIFOSEL 0x24 #define M66592_D1FIFOSEL 0x2A -#define M66592_RCNT 0x8000 /* b15: Read count mode */ -#define M66592_REW 0x4000 /* b14: Buffer rewind */ -#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ -#define M66592_DREQE 0x1000 /* b12: DREQ output enable */ -#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO access */ -#define M66592_MBW_8 0x0000 /* 8bit */ -#define M66592_MBW_16 0x0400 /* 16bit */ -#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ -#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ -#define M66592_DEZPM 0x0080 /* b7: Zero-length packet additional mode */ -#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */ -#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */ +#define M66592_RCNT 0x8000 /* b15: Read count mode */ +#define M66592_REW 0x4000 /* b14: Buffer rewind */ +#define M66592_DCLRM 0x2000 /* b13: DMA buffer clear mode */ +#define M66592_DREQE 0x1000 /* b12: DREQ output enable */ +#define M66592_MBW 0x0400 /* b10: Maximum bit width for FIFO */ +#define M66592_MBW_8 0x0000 /* 8bit */ +#define M66592_MBW_16 0x0400 /* 16bit */ +#define M66592_TRENB 0x0200 /* b9: Transaction counter enable */ +#define M66592_TRCLR 0x0100 /* b8: Transaction counter clear */ +#define M66592_DEZPM 0x0080 /* b7: Zero-length packet mode */ +#define M66592_ISEL 0x0020 /* b5: DCP FIFO port direction select */ +#define M66592_CURPIPE 0x0007 /* b2-0: PIPE select */ #define M66592_CFIFOCTR 0x20 #define M66592_D0FIFOCTR 0x26 #define M66592_D1FIFOCTR 0x2c -#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */ -#define M66592_BCLR 0x4000 /* b14: Buffer clear */ -#define M66592_FRDY 0x2000 /* b13: FIFO ready */ -#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */ +#define M66592_BVAL 0x8000 /* b15: Buffer valid flag */ +#define M66592_BCLR 0x4000 /* b14: Buffer clear */ +#define M66592_FRDY 0x2000 /* b13: FIFO ready */ +#define M66592_DTLN 0x0FFF /* b11-0: FIFO received data length */ #define M66592_CFIFOSIE 0x22 -#define M66592_TGL 0x8000 /* b15: Buffer toggle */ -#define M66592_SCLR 0x4000 /* b14: Buffer clear */ -#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */ +#define M66592_TGL 0x8000 /* b15: Buffer toggle */ +#define M66592_SCLR 0x4000 /* b14: Buffer clear */ +#define M66592_SBUSY 0x2000 /* b13: SIE_FIFO busy */ #define M66592_D0FIFOTRN 0x28 #define M66592_D1FIFOTRN 0x2E -#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */ +#define M66592_TRNCNT 0xFFFF /* b15-0: Transaction counter */ #define M66592_INTENB0 0x30 -#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */ -#define M66592_RSME 0x4000 /* b14: Resume interrupt */ -#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */ -#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */ -#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition interrupt */ -#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */ -#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */ -#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */ -#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */ -#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */ -#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */ -#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */ -#define M66592_WDST 0x0008 /* b3: Control write data stage completed interrupt */ -#define M66592_RDST 0x0004 /* b2: Control read data stage completed interrupt */ -#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */ -#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */ +#define M66592_VBSE 0x8000 /* b15: VBUS interrupt */ +#define M66592_RSME 0x4000 /* b14: Resume interrupt */ +#define M66592_SOFE 0x2000 /* b13: Frame update interrupt */ +#define M66592_DVSE 0x1000 /* b12: Device state transition interrupt */ +#define M66592_CTRE 0x0800 /* b11: Control transfer stage transition irq */ +#define M66592_BEMPE 0x0400 /* b10: Buffer empty interrupt */ +#define M66592_NRDYE 0x0200 /* b9: Buffer not ready interrupt */ +#define M66592_BRDYE 0x0100 /* b8: Buffer ready interrupt */ +#define M66592_URST 0x0080 /* b7: USB reset detected interrupt */ +#define M66592_SADR 0x0040 /* b6: Set address executed interrupt */ +#define M66592_SCFG 0x0020 /* b5: Set configuration executed interrupt */ +#define M66592_SUSP 0x0010 /* b4: Suspend detected interrupt */ +#define M66592_WDST 0x0008 /* b3: Control write data stage completed irq */ +#define M66592_RDST 0x0004 /* b2: Control read data stage completed irq */ +#define M66592_CMPL 0x0002 /* b1: Control transfer complete interrupt */ +#define M66592_SERR 0x0001 /* b0: Sequence error interrupt */ #define M66592_INTENB1 0x32 -#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */ -#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */ -#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */ -#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */ -#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */ -#define M66592_INTL 0x0002 /* b1: Interrupt sense select */ -#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */ +#define M66592_BCHGE 0x4000 /* b14: USB us chenge interrupt */ +#define M66592_DTCHE 0x1000 /* b12: Detach sense interrupt */ +#define M66592_SIGNE 0x0020 /* b5: SETUP IGNORE interrupt */ +#define M66592_SACKE 0x0010 /* b4: SETUP ACK interrupt */ +#define M66592_BRDYM 0x0004 /* b2: BRDY clear timing */ +#define M66592_INTL 0x0002 /* b1: Interrupt sense select */ +#define M66592_PCSE 0x0001 /* b0: PCUT enable by CS assert */ #define M66592_BRDYENB 0x36 #define M66592_BRDYSTS 0x46 -#define M66592_BRDY7 0x0080 /* b7: PIPE7 */ -#define M66592_BRDY6 0x0040 /* b6: PIPE6 */ -#define M66592_BRDY5 0x0020 /* b5: PIPE5 */ -#define M66592_BRDY4 0x0010 /* b4: PIPE4 */ -#define M66592_BRDY3 0x0008 /* b3: PIPE3 */ -#define M66592_BRDY2 0x0004 /* b2: PIPE2 */ -#define M66592_BRDY1 0x0002 /* b1: PIPE1 */ -#define M66592_BRDY0 0x0001 /* b1: PIPE0 */ +#define M66592_BRDY7 0x0080 /* b7: PIPE7 */ +#define M66592_BRDY6 0x0040 /* b6: PIPE6 */ +#define M66592_BRDY5 0x0020 /* b5: PIPE5 */ +#define M66592_BRDY4 0x0010 /* b4: PIPE4 */ +#define M66592_BRDY3 0x0008 /* b3: PIPE3 */ +#define M66592_BRDY2 0x0004 /* b2: PIPE2 */ +#define M66592_BRDY1 0x0002 /* b1: PIPE1 */ +#define M66592_BRDY0 0x0001 /* b1: PIPE0 */ #define M66592_NRDYENB 0x38 #define M66592_NRDYSTS 0x48 -#define M66592_NRDY7 0x0080 /* b7: PIPE7 */ -#define M66592_NRDY6 0x0040 /* b6: PIPE6 */ -#define M66592_NRDY5 0x0020 /* b5: PIPE5 */ -#define M66592_NRDY4 0x0010 /* b4: PIPE4 */ -#define M66592_NRDY3 0x0008 /* b3: PIPE3 */ -#define M66592_NRDY2 0x0004 /* b2: PIPE2 */ -#define M66592_NRDY1 0x0002 /* b1: PIPE1 */ -#define M66592_NRDY0 0x0001 /* b1: PIPE0 */ +#define M66592_NRDY7 0x0080 /* b7: PIPE7 */ +#define M66592_NRDY6 0x0040 /* b6: PIPE6 */ +#define M66592_NRDY5 0x0020 /* b5: PIPE5 */ +#define M66592_NRDY4 0x0010 /* b4: PIPE4 */ +#define M66592_NRDY3 0x0008 /* b3: PIPE3 */ +#define M66592_NRDY2 0x0004 /* b2: PIPE2 */ +#define M66592_NRDY1 0x0002 /* b1: PIPE1 */ +#define M66592_NRDY0 0x0001 /* b1: PIPE0 */ #define M66592_BEMPENB 0x3A #define M66592_BEMPSTS 0x4A -#define M66592_BEMP7 0x0080 /* b7: PIPE7 */ -#define M66592_BEMP6 0x0040 /* b6: PIPE6 */ -#define M66592_BEMP5 0x0020 /* b5: PIPE5 */ -#define M66592_BEMP4 0x0010 /* b4: PIPE4 */ -#define M66592_BEMP3 0x0008 /* b3: PIPE3 */ -#define M66592_BEMP2 0x0004 /* b2: PIPE2 */ -#define M66592_BEMP1 0x0002 /* b1: PIPE1 */ -#define M66592_BEMP0 0x0001 /* b0: PIPE0 */ +#define M66592_BEMP7 0x0080 /* b7: PIPE7 */ +#define M66592_BEMP6 0x0040 /* b6: PIPE6 */ +#define M66592_BEMP5 0x0020 /* b5: PIPE5 */ +#define M66592_BEMP4 0x0010 /* b4: PIPE4 */ +#define M66592_BEMP3 0x0008 /* b3: PIPE3 */ +#define M66592_BEMP2 0x0004 /* b2: PIPE2 */ +#define M66592_BEMP1 0x0002 /* b1: PIPE1 */ +#define M66592_BEMP0 0x0001 /* b0: PIPE0 */ #define M66592_SOFCFG 0x3C -#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */ -#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */ -#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */ -#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */ +#define M66592_SOFM 0x000C /* b3-2: SOF palse mode */ +#define M66592_SOF_125US 0x0008 /* SOF OUT 125us uFrame Signal */ +#define M66592_SOF_1MS 0x0004 /* SOF OUT 1ms Frame Signal */ +#define M66592_SOF_DISABLE 0x0000 /* SOF OUT Disable */ #define M66592_INTSTS0 0x40 -#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */ -#define M66592_RESM 0x4000 /* b14: Resume interrupt */ -#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */ -#define M66592_DVST 0x1000 /* b12: Device state transition interrupt */ -#define M66592_CTRT 0x0800 /* b11: Control transfer stage transition interrupt */ -#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */ -#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */ -#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */ -#define M66592_VBSTS 0x0080 /* b7: VBUS input port */ -#define M66592_DVSQ 0x0070 /* b6-4: Device state */ -#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */ -#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */ -#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */ -#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */ -#define M66592_DS_SUSP 0x0040 /* Suspend */ -#define M66592_DS_CNFG 0x0030 /* Configured */ -#define M66592_DS_ADDS 0x0020 /* Address */ -#define M66592_DS_DFLT 0x0010 /* Default */ -#define M66592_DS_POWR 0x0000 /* Powered */ -#define M66592_DVSQS 0x0030 /* b5-4: Device state */ -#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */ -#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */ -#define M66592_CS_SQER 0x0006 /* Sequence error */ -#define M66592_CS_WRND 0x0005 /* Control write nodata status stage */ -#define M66592_CS_WRSS 0x0004 /* Control write status stage */ -#define M66592_CS_WRDS 0x0003 /* Control write data stage */ -#define M66592_CS_RDSS 0x0002 /* Control read status stage */ -#define M66592_CS_RDDS 0x0001 /* Control read data stage */ -#define M66592_CS_IDST 0x0000 /* Idle or setup stage */ +#define M66592_VBINT 0x8000 /* b15: VBUS interrupt */ +#define M66592_RESM 0x4000 /* b14: Resume interrupt */ +#define M66592_SOFR 0x2000 /* b13: SOF frame update interrupt */ +#define M66592_DVST 0x1000 /* b12: Device state transition */ +#define M66592_CTRT 0x0800 /* b11: Control stage transition */ +#define M66592_BEMP 0x0400 /* b10: Buffer empty interrupt */ +#define M66592_NRDY 0x0200 /* b9: Buffer not ready interrupt */ +#define M66592_BRDY 0x0100 /* b8: Buffer ready interrupt */ +#define M66592_VBSTS 0x0080 /* b7: VBUS input port */ +#define M66592_DVSQ 0x0070 /* b6-4: Device state */ +#define M66592_DS_SPD_CNFG 0x0070 /* Suspend Configured */ +#define M66592_DS_SPD_ADDR 0x0060 /* Suspend Address */ +#define M66592_DS_SPD_DFLT 0x0050 /* Suspend Default */ +#define M66592_DS_SPD_POWR 0x0040 /* Suspend Powered */ +#define M66592_DS_SUSP 0x0040 /* Suspend */ +#define M66592_DS_CNFG 0x0030 /* Configured */ +#define M66592_DS_ADDS 0x0020 /* Address */ +#define M66592_DS_DFLT 0x0010 /* Default */ +#define M66592_DS_POWR 0x0000 /* Powered */ +#define M66592_DVSQS 0x0030 /* b5-4: Device state */ +#define M66592_VALID 0x0008 /* b3: Setup packet detected flag */ +#define M66592_CTSQ 0x0007 /* b2-0: Control transfer stage */ +#define M66592_CS_SQER 0x0006 /* Sequence error */ +#define M66592_CS_WRND 0x0005 /* Control write nodata status */ +#define M66592_CS_WRSS 0x0004 /* Control write status stage */ +#define M66592_CS_WRDS 0x0003 /* Control write data stage */ +#define M66592_CS_RDSS 0x0002 /* Control read status stage */ +#define M66592_CS_RDDS 0x0001 /* Control read data stage */ +#define M66592_CS_IDST 0x0000 /* Idle or setup stage */ #define M66592_INTSTS1 0x42 -#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */ -#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */ -#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */ -#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */ +#define M66592_BCHG 0x4000 /* b14: USB bus chenge interrupt */ +#define M66592_DTCH 0x1000 /* b12: Detach sense interrupt */ +#define M66592_SIGN 0x0020 /* b5: SETUP IGNORE interrupt */ +#define M66592_SACK 0x0010 /* b4: SETUP ACK interrupt */ #define M66592_FRMNUM 0x4C -#define M66592_OVRN 0x8000 /* b15: Overrun error */ -#define M66592_CRCE 0x4000 /* b14: Received data error */ -#define M66592_SOFRM 0x0800 /* b11: SOF output mode */ -#define M66592_FRNM 0x07FF /* b10-0: Frame number */ +#define M66592_OVRN 0x8000 /* b15: Overrun error */ +#define M66592_CRCE 0x4000 /* b14: Received data error */ +#define M66592_SOFRM 0x0800 /* b11: SOF output mode */ +#define M66592_FRNM 0x07FF /* b10-0: Frame number */ #define M66592_UFRMNUM 0x4E -#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */ +#define M66592_UFRNM 0x0007 /* b2-0: Micro frame number */ #define M66592_RECOVER 0x50 -#define M66592_STSRECOV 0x0700 /* Status recovery */ -#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */ -#define M66592_STSR_DEFAULT 0x0100 /* Default state */ -#define M66592_STSR_ADDRESS 0x0200 /* Address state */ -#define M66592_STSR_CONFIG 0x0300 /* Configured state */ -#define M66592_USBADDR 0x007F /* b6-0: USB address */ +#define M66592_STSRECOV 0x0700 /* Status recovery */ +#define M66592_STSR_HI 0x0400 /* FULL(0) or HI(1) Speed */ +#define M66592_STSR_DEFAULT 0x0100 /* Default state */ +#define M66592_STSR_ADDRESS 0x0200 /* Address state */ +#define M66592_STSR_CONFIG 0x0300 /* Configured state */ +#define M66592_USBADDR 0x007F /* b6-0: USB address */ #define M66592_USBREQ 0x54 -#define M66592_bRequest 0xFF00 /* b15-8: bRequest */ -#define M66592_GET_STATUS 0x0000 -#define M66592_CLEAR_FEATURE 0x0100 -#define M66592_ReqRESERVED 0x0200 -#define M66592_SET_FEATURE 0x0300 -#define M66592_ReqRESERVED1 0x0400 -#define M66592_SET_ADDRESS 0x0500 -#define M66592_GET_DESCRIPTOR 0x0600 -#define M66592_SET_DESCRIPTOR 0x0700 -#define M66592_GET_CONFIGURATION 0x0800 -#define M66592_SET_CONFIGURATION 0x0900 -#define M66592_GET_INTERFACE 0x0A00 -#define M66592_SET_INTERFACE 0x0B00 -#define M66592_SYNCH_FRAME 0x0C00 -#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */ -#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data transfer direction */ -#define M66592_HOST_TO_DEVICE 0x0000 -#define M66592_DEVICE_TO_HOST 0x0080 -#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */ -#define M66592_STANDARD 0x0000 -#define M66592_CLASS 0x0020 -#define M66592_VENDOR 0x0040 -#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */ -#define M66592_DEVICE 0x0000 -#define M66592_INTERFACE 0x0001 -#define M66592_ENDPOINT 0x0002 +#define M66592_bRequest 0xFF00 /* b15-8: bRequest */ +#define M66592_GET_STATUS 0x0000 +#define M66592_CLEAR_FEATURE 0x0100 +#define M66592_ReqRESERVED 0x0200 +#define M66592_SET_FEATURE 0x0300 +#define M66592_ReqRESERVED1 0x0400 +#define M66592_SET_ADDRESS 0x0500 +#define M66592_GET_DESCRIPTOR 0x0600 +#define M66592_SET_DESCRIPTOR 0x0700 +#define M66592_GET_CONFIGURATION 0x0800 +#define M66592_SET_CONFIGURATION 0x0900 +#define M66592_GET_INTERFACE 0x0A00 +#define M66592_SET_INTERFACE 0x0B00 +#define M66592_SYNCH_FRAME 0x0C00 +#define M66592_bmRequestType 0x00FF /* b7-0: bmRequestType */ +#define M66592_bmRequestTypeDir 0x0080 /* b7 : Data direction */ +#define M66592_HOST_TO_DEVICE 0x0000 +#define M66592_DEVICE_TO_HOST 0x0080 +#define M66592_bmRequestTypeType 0x0060 /* b6-5: Type */ +#define M66592_STANDARD 0x0000 +#define M66592_CLASS 0x0020 +#define M66592_VENDOR 0x0040 +#define M66592_bmRequestTypeRecip 0x001F /* b4-0: Recipient */ +#define M66592_DEVICE 0x0000 +#define M66592_INTERFACE 0x0001 +#define M66592_ENDPOINT 0x0002 #define M66592_USBVAL 0x56 -#define M66592_wValue 0xFFFF /* b15-0: wValue */ +#define M66592_wValue 0xFFFF /* b15-0: wValue */ /* Standard Feature Selector */ -#define M66592_ENDPOINT_HALT 0x0000 -#define M66592_DEVICE_REMOTE_WAKEUP 0x0001 -#define M66592_TEST_MODE 0x0002 +#define M66592_ENDPOINT_HALT 0x0000 +#define M66592_DEVICE_REMOTE_WAKEUP 0x0001 +#define M66592_TEST_MODE 0x0002 /* Descriptor Types */ -#define M66592_DT_TYPE 0xFF00 -#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8) -#define M66592_DT_DEVICE 0x01 -#define M66592_DT_CONFIGURATION 0x02 -#define M66592_DT_STRING 0x03 -#define M66592_DT_INTERFACE 0x04 -#define M66592_DT_ENDPOINT 0x05 -#define M66592_DT_DEVICE_QUALIFIER 0x06 -#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07 -#define M66592_DT_INTERFACE_POWER 0x08 -#define M66592_DT_INDEX 0x00FF -#define M66592_CONF_NUM 0x00FF -#define M66592_ALT_SET 0x00FF +#define M66592_DT_TYPE 0xFF00 +#define M66592_GET_DT_TYPE(v) (((v) & DT_TYPE) >> 8) +#define M66592_DT_DEVICE 0x01 +#define M66592_DT_CONFIGURATION 0x02 +#define M66592_DT_STRING 0x03 +#define M66592_DT_INTERFACE 0x04 +#define M66592_DT_ENDPOINT 0x05 +#define M66592_DT_DEVICE_QUALIFIER 0x06 +#define M66592_DT_OTHER_SPEED_CONFIGURATION 0x07 +#define M66592_DT_INTERFACE_POWER 0x08 +#define M66592_DT_INDEX 0x00FF +#define M66592_CONF_NUM 0x00FF +#define M66592_ALT_SET 0x00FF #define M66592_USBINDEX 0x58 -#define M66592_wIndex 0xFFFF /* b15-0: wIndex */ -#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode Selectors */ -#define M66592_TEST_J 0x0100 /* Test_J */ -#define M66592_TEST_K 0x0200 /* Test_K */ -#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */ -#define M66592_TEST_PACKET 0x0400 /* Test_Packet */ -#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */ -#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */ -#define M66592_TEST_Reserved 0x4000 /* Reserved */ -#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific test modes */ -#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */ -#define M66592_EP_DIR_IN 0x0080 -#define M66592_EP_DIR_OUT 0x0000 +#define M66592_wIndex 0xFFFF /* b15-0: wIndex */ +#define M66592_TEST_SELECT 0xFF00 /* b15-b8: Test Mode */ +#define M66592_TEST_J 0x0100 /* Test_J */ +#define M66592_TEST_K 0x0200 /* Test_K */ +#define M66592_TEST_SE0_NAK 0x0300 /* Test_SE0_NAK */ +#define M66592_TEST_PACKET 0x0400 /* Test_Packet */ +#define M66592_TEST_FORCE_ENABLE 0x0500 /* Test_Force_Enable */ +#define M66592_TEST_STSelectors 0x0600 /* Standard test selectors */ +#define M66592_TEST_Reserved 0x4000 /* Reserved */ +#define M66592_TEST_VSTModes 0xC000 /* Vendor-specific tests */ +#define M66592_EP_DIR 0x0080 /* b7: Endpoint Direction */ +#define M66592_EP_DIR_IN 0x0080 +#define M66592_EP_DIR_OUT 0x0000 #define M66592_USBLENG 0x5A -#define M66592_wLength 0xFFFF /* b15-0: wLength */ +#define M66592_wLength 0xFFFF /* b15-0: wLength */ #define M66592_DCPCFG 0x5C -#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */ -#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */ +#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */ +#define M66592_DIR 0x0010 /* b4: Control transfer DIR select */ #define M66592_DCPMAXP 0x5E -#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */ -#define M66592_DEVICE_0 0x0000 /* Device address 0 */ -#define M66592_DEVICE_1 0x4000 /* Device address 1 */ -#define M66592_DEVICE_2 0x8000 /* Device address 2 */ -#define M66592_DEVICE_3 0xC000 /* Device address 3 */ -#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of default control pipe */ +#define M66592_DEVSEL 0xC000 /* b15-14: Device address select */ +#define M66592_DEVICE_0 0x0000 /* Device address 0 */ +#define M66592_DEVICE_1 0x4000 /* Device address 1 */ +#define M66592_DEVICE_2 0x8000 /* Device address 2 */ +#define M66592_DEVICE_3 0xC000 /* Device address 3 */ +#define M66592_MAXP 0x007F /* b6-0: Maxpacket size of ep0 */ #define M66592_DCPCTR 0x60 -#define M66592_BSTS 0x8000 /* b15: Buffer status */ -#define M66592_SUREQ 0x4000 /* b14: Send USB request */ -#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ -#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ -#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ -#define M66592_CCPL 0x0004 /* b2: Enable control transfer complete */ -#define M66592_PID 0x0003 /* b1-0: Response PID */ -#define M66592_PID_STALL 0x0002 /* STALL */ -#define M66592_PID_BUF 0x0001 /* BUF */ -#define M66592_PID_NAK 0x0000 /* NAK */ +#define M66592_BSTS 0x8000 /* b15: Buffer status */ +#define M66592_SUREQ 0x4000 /* b14: Send USB request */ +#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ +#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ +#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ +#define M66592_CCPL 0x0004 /* b2: control transfer complete */ +#define M66592_PID 0x0003 /* b1-0: Response PID */ +#define M66592_PID_STALL 0x0002 /* STALL */ +#define M66592_PID_BUF 0x0001 /* BUF */ +#define M66592_PID_NAK 0x0000 /* NAK */ #define M66592_PIPESEL 0x64 -#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */ -#define M66592_PIPE0 0x0000 /* PIPE 0 */ -#define M66592_PIPE1 0x0001 /* PIPE 1 */ -#define M66592_PIPE2 0x0002 /* PIPE 2 */ -#define M66592_PIPE3 0x0003 /* PIPE 3 */ -#define M66592_PIPE4 0x0004 /* PIPE 4 */ -#define M66592_PIPE5 0x0005 /* PIPE 5 */ -#define M66592_PIPE6 0x0006 /* PIPE 6 */ -#define M66592_PIPE7 0x0007 /* PIPE 7 */ +#define M66592_PIPENM 0x0007 /* b2-0: Pipe select */ +#define M66592_PIPE0 0x0000 /* PIPE 0 */ +#define M66592_PIPE1 0x0001 /* PIPE 1 */ +#define M66592_PIPE2 0x0002 /* PIPE 2 */ +#define M66592_PIPE3 0x0003 /* PIPE 3 */ +#define M66592_PIPE4 0x0004 /* PIPE 4 */ +#define M66592_PIPE5 0x0005 /* PIPE 5 */ +#define M66592_PIPE6 0x0006 /* PIPE 6 */ +#define M66592_PIPE7 0x0007 /* PIPE 7 */ #define M66592_PIPECFG 0x66 -#define M66592_TYP 0xC000 /* b15-14: Transfer type */ -#define M66592_ISO 0xC000 /* Isochronous */ -#define M66592_INT 0x8000 /* Interrupt */ -#define M66592_BULK 0x4000 /* Bulk */ -#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode select */ -#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */ -#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode select */ -#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */ -#define M66592_DIR 0x0010 /* b4: Transfer direction select */ -#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */ -#define M66592_DIR_P_IN 0x0010 /* PERI IN */ -#define M66592_DIR_H_IN 0x0000 /* HOST IN */ -#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */ -#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */ -#define M66592_EP1 0x0001 -#define M66592_EP2 0x0002 -#define M66592_EP3 0x0003 -#define M66592_EP4 0x0004 -#define M66592_EP5 0x0005 -#define M66592_EP6 0x0006 -#define M66592_EP7 0x0007 -#define M66592_EP8 0x0008 -#define M66592_EP9 0x0009 -#define M66592_EP10 0x000A -#define M66592_EP11 0x000B -#define M66592_EP12 0x000C -#define M66592_EP13 0x000D -#define M66592_EP14 0x000E -#define M66592_EP15 0x000F +#define M66592_TYP 0xC000 /* b15-14: Transfer type */ +#define M66592_ISO 0xC000 /* Isochronous */ +#define M66592_INT 0x8000 /* Interrupt */ +#define M66592_BULK 0x4000 /* Bulk */ +#define M66592_BFRE 0x0400 /* b10: Buffer ready interrupt mode */ +#define M66592_DBLB 0x0200 /* b9: Double buffer mode select */ +#define M66592_CNTMD 0x0100 /* b8: Continuous transfer mode */ +#define M66592_SHTNAK 0x0080 /* b7: Transfer end NAK */ +#define M66592_DIR 0x0010 /* b4: Transfer direction select */ +#define M66592_DIR_H_OUT 0x0010 /* HOST OUT */ +#define M66592_DIR_P_IN 0x0010 /* PERI IN */ +#define M66592_DIR_H_IN 0x0000 /* HOST IN */ +#define M66592_DIR_P_OUT 0x0000 /* PERI OUT */ +#define M66592_EPNUM 0x000F /* b3-0: Eendpoint number select */ +#define M66592_EP1 0x0001 +#define M66592_EP2 0x0002 +#define M66592_EP3 0x0003 +#define M66592_EP4 0x0004 +#define M66592_EP5 0x0005 +#define M66592_EP6 0x0006 +#define M66592_EP7 0x0007 +#define M66592_EP8 0x0008 +#define M66592_EP9 0x0009 +#define M66592_EP10 0x000A +#define M66592_EP11 0x000B +#define M66592_EP12 0x000C +#define M66592_EP13 0x000D +#define M66592_EP14 0x000E +#define M66592_EP15 0x000F #define M66592_PIPEBUF 0x68 -#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */ -#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10) -#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */ +#define M66592_BUFSIZE 0x7C00 /* b14-10: Pipe buffer size */ +#define M66592_BUF_SIZE(x) ((((x) / 64) - 1) << 10) +#define M66592_BUFNMB 0x00FF /* b7-0: Pipe buffer number */ #define M66592_PIPEMAXP 0x6A -#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */ +#define M66592_MXPS 0x07FF /* b10-0: Maxpacket size */ #define M66592_PIPEPERI 0x6C -#define M66592_IFIS 0x1000 /* b12: Isochronous in-buffer flush mode select */ -#define M66592_IITV 0x0007 /* b2-0: Isochronous interval */ +#define M66592_IFIS 0x1000 /* b12: ISO in-buffer flush mode */ +#define M66592_IITV 0x0007 /* b2-0: ISO interval */ #define M66592_PIPE1CTR 0x70 #define M66592_PIPE2CTR 0x72 @@ -401,19 +401,17 @@ #define M66592_PIPE5CTR 0x78 #define M66592_PIPE6CTR 0x7A #define M66592_PIPE7CTR 0x7C -#define M66592_BSTS 0x8000 /* b15: Buffer status */ -#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (Only for PIPE1 to 5) */ -#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */ -#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ -#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ -#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ -#define M66592_PID 0x0003 /* b1-0: Response PID */ +#define M66592_BSTS 0x8000 /* b15: Buffer status */ +#define M66592_INBUFM 0x4000 /* b14: IN buffer monitor (PIPE 1-5) */ +#define M66592_ACLRM 0x0200 /* b9: Out buffer auto clear mode */ +#define M66592_SQCLR 0x0100 /* b8: Sequence toggle bit clear */ +#define M66592_SQSET 0x0080 /* b7: Sequence toggle bit set */ +#define M66592_SQMON 0x0040 /* b6: Sequence toggle bit monitor */ +#define M66592_PID 0x0003 /* b1-0: Response PID */ #define M66592_INVALID_REG 0x7E -#define __iomem - #define get_pipectr_addr(pipenum) (M66592_PIPE1CTR + (pipenum - 1) * 2) #define M66592_MAX_SAMPLING 10 @@ -449,7 +447,7 @@ struct m66592_ep { struct m66592 *m66592; struct list_head queue; - unsigned busy:1; + unsigned busy:1; unsigned internal_ccpl:1; /* use only control */ /* this member can able to after m66592_enable */ @@ -477,7 +475,7 @@ struct m66592 { struct m66592_ep *epaddr2ep[16]; struct usb_request *ep0_req; /* for internal request */ - u16 *ep0_buf; /* for internal request */ + u16 ep0_data; /* for internal request */ struct timer_list timer; @@ -527,8 +525,8 @@ static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset) } static inline void m66592_read_fifo(struct m66592 *m66592, - unsigned long offset, - void *buf, unsigned long len) + unsigned long offset, + void *buf, unsigned long len) { unsigned long fifoaddr = (unsigned long)m66592->reg + offset; @@ -543,8 +541,8 @@ static inline void m66592_write(struct m66592 *m66592, u16 val, } static inline void m66592_write_fifo(struct m66592 *m66592, - unsigned long offset, - void *buf, unsigned long len) + unsigned long offset, + void *buf, unsigned long len) { unsigned long fifoaddr = (unsigned long)m66592->reg + offset; unsigned long odd = len & 0x0001; @@ -558,7 +556,7 @@ static inline void m66592_write_fifo(struct m66592 *m66592, } static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat, - unsigned long offset) + unsigned long offset) { u16 tmp; tmp = m66592_read(m66592, offset); diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c index 38138bb9ddb..9cd98e73dc1 100644 --- a/drivers/usb/gadget/serial.c +++ b/drivers/usb/gadget/serial.c @@ -33,6 +33,7 @@ #include <linux/device.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/mutex.h> #include <asm/byteorder.h> #include <asm/io.h> @@ -258,7 +259,7 @@ static const char *EP_IN_NAME; static const char *EP_OUT_NAME; static const char *EP_NOTIFY_NAME; -static struct semaphore gs_open_close_sem[GS_NUM_PORTS]; +static struct mutex gs_open_close_lock[GS_NUM_PORTS]; static unsigned int read_q_size = GS_DEFAULT_READ_Q_SIZE; static unsigned int write_q_size = GS_DEFAULT_WRITE_Q_SIZE; @@ -595,7 +596,7 @@ static int __init gs_module_init(void) tty_set_operations(gs_tty_driver, &gs_tty_ops); for (i=0; i < GS_NUM_PORTS; i++) - sema_init(&gs_open_close_sem[i], 1); + mutex_init(&gs_open_close_lock[i]); retval = tty_register_driver(gs_tty_driver); if (retval) { @@ -635,7 +636,7 @@ static int gs_open(struct tty_struct *tty, struct file *file) struct gs_port *port; struct gs_dev *dev; struct gs_buf *buf; - struct semaphore *sem; + struct mutex *mtx; int ret; port_num = tty->index; @@ -656,10 +657,10 @@ static int gs_open(struct tty_struct *tty, struct file *file) return -ENODEV; } - sem = &gs_open_close_sem[port_num]; - if (down_interruptible(sem)) { + mtx = &gs_open_close_lock[port_num]; + if (mutex_lock_interruptible(mtx)) { printk(KERN_ERR - "gs_open: (%d,%p,%p) interrupted waiting for semaphore\n", + "gs_open: (%d,%p,%p) interrupted waiting for mutex\n", port_num, tty, file); return -ERESTARTSYS; } @@ -754,12 +755,12 @@ static int gs_open(struct tty_struct *tty, struct file *file) exit_unlock_port: spin_unlock_irqrestore(&port->port_lock, flags); - up(sem); + mutex_unlock(mtx); return ret; exit_unlock_dev: spin_unlock_irqrestore(&dev->dev_lock, flags); - up(sem); + mutex_unlock(mtx); return ret; } @@ -781,7 +782,7 @@ exit_unlock_dev: static void gs_close(struct tty_struct *tty, struct file *file) { struct gs_port *port = tty->driver_data; - struct semaphore *sem; + struct mutex *mtx; if (port == NULL) { printk(KERN_ERR "gs_close: NULL port pointer\n"); @@ -790,8 +791,8 @@ static void gs_close(struct tty_struct *tty, struct file *file) gs_debug("gs_close: (%d,%p,%p)\n", port->port_num, tty, file); - sem = &gs_open_close_sem[port->port_num]; - down(sem); + mtx = &gs_open_close_lock[port->port_num]; + mutex_lock(mtx); spin_lock_irq(&port->port_lock); @@ -846,7 +847,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) exit: spin_unlock_irq(&port->port_lock); - up(sem); + mutex_unlock(mtx); } /* |