diff options
author | RajithaY <rajithax.yerrumsetty@intel.com> | 2017-04-25 03:31:15 -0700 |
---|---|---|
committer | Rajitha Yerrumchetty <rajithax.yerrumsetty@intel.com> | 2017-05-22 06:48:08 +0000 |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/roms/u-boot/drivers/usb/gadget | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/roms/u-boot/drivers/usb/gadget')
34 files changed, 0 insertions, 26252 deletions
diff --git a/qemu/roms/u-boot/drivers/usb/gadget/Makefile b/qemu/roms/u-boot/drivers/usb/gadget/Makefile deleted file mode 100644 index 896c8d407..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# -# (C) Copyright 2000-2007 -# Wolfgang Denk, DENX Software Engineering, wd@denx.de. -# -# SPDX-License-Identifier: GPL-2.0+ -# - -obj-$(CONFIG_USB_GADGET) += epautoconf.o config.o usbstring.o -obj-$(CONFIG_USB_ETHER) += epautoconf.o config.o usbstring.o - -# new USB gadget layer dependencies -ifdef CONFIG_USB_GADGET -obj-$(CONFIG_USB_GADGET_ATMEL_USBA) += atmel_usba_udc.o -obj-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o -obj-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o -obj-$(CONFIG_CI_UDC) += ci_udc.o -obj-$(CONFIG_THOR_FUNCTION) += f_thor.o -obj-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o -obj-$(CONFIG_DFU_FUNCTION) += f_dfu.o -obj-$(CONFIG_USB_GADGET_MASS_STORAGE) += f_mass_storage.o -endif -ifdef CONFIG_USB_ETHER -obj-y += ether.o -obj-$(CONFIG_USB_ETH_RNDIS) += rndis.o -obj-$(CONFIG_CI_UDC) += ci_udc.o -obj-$(CONFIG_CPU_PXA25X) += pxa25x_udc.o -else -# Devices not related to the new gadget layer depend on CONFIG_USB_DEVICE -ifdef CONFIG_USB_DEVICE -obj-y += core.o -obj-y += ep0.o -obj-$(CONFIG_DW_UDC) += designware_udc.o -obj-$(CONFIG_OMAP1510) += omap1510_udc.o -obj-$(CONFIG_OMAP1610) += omap1510_udc.o -obj-$(CONFIG_MPC885_FAMILY) += mpc8xx_udc.o -obj-$(CONFIG_CPU_PXA27X) += pxa27x_udc.o -endif -endif diff --git a/qemu/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.c b/qemu/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.c deleted file mode 100644 index c99208d10..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.c +++ /dev/null @@ -1,1306 +0,0 @@ -/* - * Driver for the Atmel USBA high speed USB device controller - * [Original from Linux kernel: drivers/usb/gadget/atmel_usba_udc.c] - * - * Copyright (C) 2005-2013 Atmel Corporation - * Bo Shen <voice.shen@atmel.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/errno.h> -#include <asm/gpio.h> -#include <asm/hardware.h> -#include <linux/list.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb/atmel_usba_udc.h> -#include <malloc.h> -#include <usb/lin_gadget_compat.h> - -#include "atmel_usba_udc.h" - -static int vbus_is_present(struct usba_udc *udc) -{ - /* No Vbus detection: Assume always present */ - return 1; -} - -static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req) -{ - unsigned int transaction_len; - - transaction_len = req->req.length - req->req.actual; - req->last_transaction = 1; - if (transaction_len > ep->ep.maxpacket) { - transaction_len = ep->ep.maxpacket; - req->last_transaction = 0; - } else if (transaction_len == ep->ep.maxpacket && req->req.zero) { - req->last_transaction = 0; - } - - DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n", - ep->ep.name, req, transaction_len, - req->last_transaction ? ", done" : ""); - - memcpy(ep->fifo, req->req.buf + req->req.actual, transaction_len); - usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); - req->req.actual += transaction_len; -} - -static void submit_request(struct usba_ep *ep, struct usba_request *req) -{ - DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d), dma: %d\n", - ep->ep.name, req, req->req.length, req->using_dma); - - req->req.actual = 0; - req->submitted = 1; - - next_fifo_transaction(ep, req); - if (req->last_transaction) { - usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); - } else { - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); - } -} - -static void submit_next_request(struct usba_ep *ep) -{ - struct usba_request *req; - - if (list_empty(&ep->queue)) { - usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY); - return; - } - - req = list_entry(ep->queue.next, struct usba_request, queue); - if (!req->submitted) - submit_request(ep, req); -} - -static void send_status(struct usba_udc *udc, struct usba_ep *ep) -{ - ep->state = STATUS_STAGE_IN; - usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); -} - -static void receive_data(struct usba_ep *ep) -{ - struct usba_udc *udc = ep->udc; - struct usba_request *req; - unsigned long status; - unsigned int bytecount, nr_busy; - int is_complete = 0; - - status = usba_ep_readl(ep, STA); - nr_busy = USBA_BFEXT(BUSY_BANKS, status); - - DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy); - - while (nr_busy > 0) { - if (list_empty(&ep->queue)) { - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - break; - } - req = list_entry(ep->queue.next, - struct usba_request, queue); - - bytecount = USBA_BFEXT(BYTE_COUNT, status); - - if (status & USBA_SHORT_PACKET) - is_complete = 1; - if (req->req.actual + bytecount >= req->req.length) { - is_complete = 1; - bytecount = req->req.length - req->req.actual; - } - - memcpy(req->req.buf + req->req.actual, ep->fifo, bytecount); - req->req.actual += bytecount; - - usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); - - if (is_complete) { - DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name); - req->req.status = 0; - list_del_init(&req->queue); - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - spin_lock(&udc->lock); - req->req.complete(&ep->ep, &req->req); - spin_unlock(&udc->lock); - } - - status = usba_ep_readl(ep, STA); - nr_busy = USBA_BFEXT(BUSY_BANKS, status); - - if (is_complete && ep_is_control(ep)) { - send_status(udc, ep); - break; - } - } -} - -static void -request_complete(struct usba_ep *ep, struct usba_request *req, int status) -{ - if (req->req.status == -EINPROGRESS) - req->req.status = status; - - DBG(DBG_GADGET | DBG_REQ, "%s: req %p complete: status %d, actual %u\n", - ep->ep.name, req, req->req.status, req->req.actual); - - req->req.complete(&ep->ep, &req->req); -} - -static void -request_complete_list(struct usba_ep *ep, struct list_head *list, int status) -{ - struct usba_request *req, *tmp_req; - - list_for_each_entry_safe(req, tmp_req, list, queue) { - list_del_init(&req->queue); - request_complete(ep, req, status); - } -} - -static int -usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) -{ - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - unsigned long flags, ept_cfg, maxpacket; - unsigned int nr_trans; - - DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc); - - maxpacket = usb_endpoint_maxp(desc) & 0x7ff; - - if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - != ep->index) || - ep->index == 0 || - desc->bDescriptorType != USB_DT_ENDPOINT || - maxpacket == 0 || - maxpacket > ep->fifo_size) { - DBG(DBG_ERR, "ep_enable: Invalid argument"); - return -EINVAL; - } - - ep->is_isoc = 0; - ep->is_in = 0; - - if (maxpacket <= 8) - ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8); - else - /* LSB is bit 1, not 0 */ - ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3); - - DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n", - ep->ep.name, ept_cfg, maxpacket); - - if (usb_endpoint_dir_in(desc)) { - ep->is_in = 1; - ept_cfg |= USBA_EPT_DIR_IN; - } - - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); - break; - case USB_ENDPOINT_XFER_ISOC: - if (!ep->can_isoc) { - DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n", - ep->ep.name); - return -EINVAL; - } - - /* - * Bits 11:12 specify number of _additional_ - * transactions per microframe. - */ - nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1; - if (nr_trans > 3) - return -EINVAL; - - ep->is_isoc = 1; - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO); - - /* - * Do triple-buffering on high-bandwidth iso endpoints. - */ - if (nr_trans > 1 && ep->nr_banks == 3) - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE); - else - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE); - ept_cfg |= USBA_BF(NB_TRANS, nr_trans); - break; - case USB_ENDPOINT_XFER_BULK: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); - break; - case USB_ENDPOINT_XFER_INT: - ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT); - ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE); - break; - } - - spin_lock_irqsave(&ep->udc->lock, flags); - - ep->desc = desc; - ep->ep.maxpacket = maxpacket; - - usba_ep_writel(ep, CFG, ept_cfg); - usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); - - usba_writel(udc, INT_ENB, - (usba_readl(udc, INT_ENB) - | USBA_BF(EPT_INT, 1 << ep->index))); - - spin_unlock_irqrestore(&udc->lock, flags); - - DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index, - (unsigned long)usba_ep_readl(ep, CFG)); - DBG(DBG_HW, "INT_ENB after init: %#08lx\n", - (unsigned long)usba_readl(udc, INT_ENB)); - - return 0; -} - -static int usba_ep_disable(struct usb_ep *_ep) -{ - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - LIST_HEAD(req_list); - unsigned long flags; - - DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name); - - spin_lock_irqsave(&udc->lock, flags); - - if (!ep->desc) { - spin_unlock_irqrestore(&udc->lock, flags); - /* REVISIT because this driver disables endpoints in - * reset_all_endpoints() before calling disconnect(), - * most gadget drivers would trigger this non-error ... - */ - if (udc->gadget.speed != USB_SPEED_UNKNOWN) - DBG(DBG_ERR, "ep_disable: %s not enabled\n", - ep->ep.name); - return -EINVAL; - } - ep->desc = NULL; - - list_splice_init(&ep->queue, &req_list); - usba_ep_writel(ep, CFG, 0); - usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE); - usba_writel(udc, INT_ENB, - usba_readl(udc, INT_ENB) & - ~USBA_BF(EPT_INT, 1 << ep->index)); - - request_complete_list(ep, &req_list, -ESHUTDOWN); - - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static struct usb_request * -usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct usba_request *req; - - DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags); - - req = malloc(sizeof(struct usba_request)); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void -usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct usba_request *req = to_usba_req(_req); - - DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req); - - free(req); -} - -static int -usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct usba_request *req = to_usba_req(_req); - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - unsigned long flags; - int ret; - - DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n", - ep->ep.name, req, _req->length); - - if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || - !ep->desc) - return -ESHUTDOWN; - - req->submitted = 0; - req->using_dma = 0; - req->last_transaction = 0; - - _req->status = -EINPROGRESS; - _req->actual = 0; - - /* May have received a reset since last time we checked */ - ret = -ESHUTDOWN; - spin_lock_irqsave(&udc->lock, flags); - if (ep->desc) { - list_add_tail(&req->queue, &ep->queue); - - if ((!ep_is_control(ep) && ep->is_in) || - (ep_is_control(ep) && (ep->state == DATA_STAGE_IN || - ep->state == STATUS_STAGE_IN))) - usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); - else - usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); - - ret = 0; - } - spin_unlock_irqrestore(&udc->lock, flags); - - return ret; -} - -static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_request *req = to_usba_req(_req); - - DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n", - ep->ep.name, req); - - /* - * Errors should stop the queue from advancing until the - * completion function returns. - */ - list_del_init(&req->queue); - - request_complete(ep, req, -ECONNRESET); - - /* Process the next request if any */ - submit_next_request(ep); - - return 0; -} - -static int usba_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct usba_ep *ep = to_usba_ep(_ep); - unsigned long flags; - int ret = 0; - - DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name, - value ? "set" : "clear"); - - if (!ep->desc) { - DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", - ep->ep.name); - return -ENODEV; - } - - if (ep->is_isoc) { - DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n", - ep->ep.name); - return -ENOTTY; - } - - spin_lock_irqsave(&udc->lock, flags); - - /* - * We can't halt IN endpoints while there are still data to be - * transferred - */ - if (!list_empty(&ep->queue) || - ((value && ep->is_in && (usba_ep_readl(ep, STA) & - USBA_BF(BUSY_BANKS, -1L))))) { - ret = -EAGAIN; - } else { - if (value) - usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); - else - usba_ep_writel(ep, CLR_STA, - USBA_FORCE_STALL | USBA_TOGGLE_CLR); - usba_ep_readl(ep, STA); - } - - spin_unlock_irqrestore(&udc->lock, flags); - - return ret; -} - -static int usba_ep_fifo_status(struct usb_ep *_ep) -{ - struct usba_ep *ep = to_usba_ep(_ep); - - return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); -} - -static void usba_ep_fifo_flush(struct usb_ep *_ep) -{ - struct usba_ep *ep = to_usba_ep(_ep); - struct usba_udc *udc = ep->udc; - - usba_writel(udc, EPT_RST, 1 << ep->index); -} - -static const struct usb_ep_ops usba_ep_ops = { - .enable = usba_ep_enable, - .disable = usba_ep_disable, - .alloc_request = usba_ep_alloc_request, - .free_request = usba_ep_free_request, - .queue = usba_ep_queue, - .dequeue = usba_ep_dequeue, - .set_halt = usba_ep_set_halt, - .fifo_status = usba_ep_fifo_status, - .fifo_flush = usba_ep_fifo_flush, -}; - -static int usba_udc_get_frame(struct usb_gadget *gadget) -{ - struct usba_udc *udc = to_usba_udc(gadget); - - return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM)); -} - -static int usba_udc_wakeup(struct usb_gadget *gadget) -{ - struct usba_udc *udc = to_usba_udc(gadget); - unsigned long flags; - u32 ctrl; - int ret = -EINVAL; - - spin_lock_irqsave(&udc->lock, flags); - if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) { - ctrl = usba_readl(udc, CTRL); - usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP); - ret = 0; - } - spin_unlock_irqrestore(&udc->lock, flags); - - return ret; -} - -static int -usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) -{ - struct usba_udc *udc = to_usba_udc(gadget); - unsigned long flags; - - spin_lock_irqsave(&udc->lock, flags); - if (is_selfpowered) - udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED; - else - udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED); - spin_unlock_irqrestore(&udc->lock, flags); - - return 0; -} - -static const struct usb_gadget_ops usba_udc_ops = { - .get_frame = usba_udc_get_frame, - .wakeup = usba_udc_wakeup, - .set_selfpowered = usba_udc_set_selfpowered, -}; - -static struct usb_endpoint_descriptor usba_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(64), - /* FIXME: I have no idea what to put here */ - .bInterval = 1, -}; - -/* - * Called with interrupts disabled and udc->lock held. - */ -static void reset_all_endpoints(struct usba_udc *udc) -{ - struct usba_ep *ep; - struct usba_request *req, *tmp_req; - - usba_writel(udc, EPT_RST, ~0UL); - - ep = to_usba_ep(udc->gadget.ep0); - list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) { - list_del_init(&req->queue); - request_complete(ep, req, -ECONNRESET); - } - - /* NOTE: normally, the next call to the gadget driver is in - * charge of disabling endpoints... usually disconnect(). - * The exception would be entering a high speed test mode. - * - * FIXME remove this code ... and retest thoroughly. - */ - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { - spin_unlock(&udc->lock); - usba_ep_disable(&ep->ep); - spin_lock(&udc->lock); - } - } -} - -static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) -{ - struct usba_ep *ep; - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) - return to_usba_ep(udc->gadget.ep0); - - list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - u8 bEndpointAddress; - - if (!ep->desc) - continue; - bEndpointAddress = ep->desc->bEndpointAddress; - if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) - continue; - if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) - == (wIndex & USB_ENDPOINT_NUMBER_MASK)) - return ep; - } - - return NULL; -} - -/* Called with interrupts disabled and udc->lock held */ -static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep) -{ - usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL); - ep->state = WAIT_FOR_SETUP; -} - -static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep) -{ - if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL) - return 1; - return 0; -} - -static inline void set_address(struct usba_udc *udc, unsigned int addr) -{ - u32 regval; - - DBG(DBG_BUS, "setting address %u...\n", addr); - regval = usba_readl(udc, CTRL); - regval = USBA_BFINS(DEV_ADDR, addr, regval); - usba_writel(udc, CTRL, regval); -} - -static int do_test_mode(struct usba_udc *udc) -{ - static const char test_packet_buffer[] = { - /* JKJKJKJK * 9 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* JJKKJJKK * 8 */ - 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, - /* JJKKJJKK * 8 */ - 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, - /* JJJJJJJKKKKKKK * 8 */ - 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - /* JJJJJJJK * 8 */ - 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, - /* {JKKKKKKK * 10}, JK */ - 0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E - }; - struct usba_ep *ep; - int test_mode; - - test_mode = udc->test_mode; - - /* Start from a clean slate */ - reset_all_endpoints(udc); - - switch (test_mode) { - case 0x0100: - /* Test_J */ - usba_writel(udc, TST, USBA_TST_J_MODE); - DBG(DBG_ALL, "Entering Test_J mode...\n"); - break; - case 0x0200: - /* Test_K */ - usba_writel(udc, TST, USBA_TST_K_MODE); - DBG(DBG_ALL, "Entering Test_K mode...\n"); - break; - case 0x0300: - /* - * Test_SE0_NAK: Force high-speed mode and set up ep0 - * for Bulk IN transfers - */ - ep = &udc->usba_ep[0]; - usba_writel(udc, TST, - USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH)); - usba_ep_writel(ep, CFG, - USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) - | USBA_EPT_DIR_IN - | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) - | USBA_BF(BK_NUMBER, 1)); - if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { - set_protocol_stall(udc, ep); - DBG(DBG_ALL, "Test_SE0_NAK: ep0 not mapped\n"); - } else { - usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); - DBG(DBG_ALL, "Entering Test_SE0_NAK mode...\n"); - } - break; - case 0x0400: - /* Test_Packet */ - ep = &udc->usba_ep[0]; - usba_ep_writel(ep, CFG, - USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64) - | USBA_EPT_DIR_IN - | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK) - | USBA_BF(BK_NUMBER, 1)); - if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) { - set_protocol_stall(udc, ep); - DBG(DBG_ALL, "Test_Packet: ep0 not mapped\n"); - } else { - usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE); - usba_writel(udc, TST, USBA_TST_PKT_MODE); - memcpy(ep->fifo, test_packet_buffer, - sizeof(test_packet_buffer)); - usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); - DBG(DBG_ALL, "Entering Test_Packet mode...\n"); - } - break; - default: - DBG(DBG_ERR, "Invalid test mode: 0x%04x\n", test_mode); - return -EINVAL; - } - - return 0; -} - -/* Avoid overly long expressions */ -static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq) -{ - if (crq->wValue == cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP)) - return true; - return false; -} - -static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq) -{ - if (crq->wValue == cpu_to_le16(USB_DEVICE_TEST_MODE)) - return true; - return false; -} - -static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq) -{ - if (crq->wValue == cpu_to_le16(USB_ENDPOINT_HALT)) - return true; - return false; -} - -static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep, - struct usb_ctrlrequest *crq) -{ - int retval = 0; - - switch (crq->bRequest) { - case USB_REQ_GET_STATUS: { - u16 status; - - if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) { - status = cpu_to_le16(udc->devstatus); - } else if (crq->bRequestType - == (USB_DIR_IN | USB_RECIP_INTERFACE)) { - status = cpu_to_le16(0); - } else if (crq->bRequestType - == (USB_DIR_IN | USB_RECIP_ENDPOINT)) { - struct usba_ep *target; - - target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); - if (!target) - goto stall; - - status = 0; - if (is_stalled(udc, target)) - status |= cpu_to_le16(1); - } else { - goto delegate; - } - - /* Write directly to the FIFO. No queueing is done. */ - if (crq->wLength != cpu_to_le16(sizeof(status))) - goto stall; - ep->state = DATA_STAGE_IN; - __raw_writew(status, ep->fifo); - usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY); - break; - } - - case USB_REQ_CLEAR_FEATURE: { - if (crq->bRequestType == USB_RECIP_DEVICE) { - if (feature_is_dev_remote_wakeup(crq)) - udc->devstatus - &= ~(1 << USB_DEVICE_REMOTE_WAKEUP); - else - /* Can't CLEAR_FEATURE TEST_MODE */ - goto stall; - } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { - struct usba_ep *target; - - if (crq->wLength != cpu_to_le16(0) || - !feature_is_ep_halt(crq)) - goto stall; - target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); - if (!target) - goto stall; - - usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL); - if (target->index != 0) - usba_ep_writel(target, CLR_STA, - USBA_TOGGLE_CLR); - } else { - goto delegate; - } - - send_status(udc, ep); - break; - } - - case USB_REQ_SET_FEATURE: { - if (crq->bRequestType == USB_RECIP_DEVICE) { - if (feature_is_dev_test_mode(crq)) { - send_status(udc, ep); - ep->state = STATUS_STAGE_TEST; - udc->test_mode = le16_to_cpu(crq->wIndex); - return 0; - } else if (feature_is_dev_remote_wakeup(crq)) { - udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP; - } else { - goto stall; - } - } else if (crq->bRequestType == USB_RECIP_ENDPOINT) { - struct usba_ep *target; - - if (crq->wLength != cpu_to_le16(0) || - !feature_is_ep_halt(crq)) - goto stall; - - target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex)); - if (!target) - goto stall; - - usba_ep_writel(target, SET_STA, USBA_FORCE_STALL); - } else { - goto delegate; - } - - send_status(udc, ep); - break; - } - - case USB_REQ_SET_ADDRESS: - if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) - goto delegate; - - set_address(udc, le16_to_cpu(crq->wValue)); - send_status(udc, ep); - ep->state = STATUS_STAGE_ADDR; - break; - - default: -delegate: - spin_unlock(&udc->lock); - retval = udc->driver->setup(&udc->gadget, crq); - spin_lock(&udc->lock); - } - - return retval; - -stall: - DBG(DBG_ALL, "%s: Invalid setup request: %02x.%02x v%04x i%04x l%d\n", - ep->ep.name, crq->bRequestType, crq->bRequest, - le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex), - le16_to_cpu(crq->wLength)); - set_protocol_stall(udc, ep); - - return -1; -} - -static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep) -{ - struct usba_request *req; - u32 epstatus; - u32 epctrl; - -restart: - epstatus = usba_ep_readl(ep, STA); - epctrl = usba_ep_readl(ep, CTL); - - DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n", - ep->ep.name, ep->state, epstatus, epctrl); - - req = NULL; - if (!list_empty(&ep->queue)) - req = list_entry(ep->queue.next, - struct usba_request, queue); - - if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { - if (req->submitted) - next_fifo_transaction(ep, req); - else - submit_request(ep, req); - - if (req->last_transaction) { - usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); - } - goto restart; - } - if ((epstatus & epctrl) & USBA_TX_COMPLETE) { - usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE); - - switch (ep->state) { - case DATA_STAGE_IN: - usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY); - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - ep->state = STATUS_STAGE_OUT; - break; - case STATUS_STAGE_ADDR: - /* Activate our new address */ - usba_writel(udc, CTRL, (usba_readl(udc, CTRL) - | USBA_FADDR_EN)); - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - ep->state = WAIT_FOR_SETUP; - break; - case STATUS_STAGE_IN: - if (req) { - list_del_init(&req->queue); - request_complete(ep, req, 0); - submit_next_request(ep); - } - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - ep->state = WAIT_FOR_SETUP; - break; - case STATUS_STAGE_TEST: - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); - ep->state = WAIT_FOR_SETUP; - if (do_test_mode(udc)) - set_protocol_stall(udc, ep); - break; - default: - DBG(DBG_ALL, "%s: TXCOMP: Invalid endpoint state %d\n", - ep->ep.name, ep->state); - set_protocol_stall(udc, ep); - break; - } - - goto restart; - } - if ((epstatus & epctrl) & USBA_RX_BK_RDY) { - switch (ep->state) { - case STATUS_STAGE_OUT: - usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - - if (req) { - list_del_init(&req->queue); - request_complete(ep, req, 0); - } - ep->state = WAIT_FOR_SETUP; - break; - - case DATA_STAGE_OUT: - receive_data(ep); - break; - - default: - usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - DBG(DBG_ALL, "%s: RXRDY: Invalid endpoint state %d\n", - ep->ep.name, ep->state); - set_protocol_stall(udc, ep); - break; - } - - goto restart; - } - if (epstatus & USBA_RX_SETUP) { - union { - struct usb_ctrlrequest crq; - unsigned long data[2]; - } crq; - unsigned int pkt_len; - int ret; - - if (ep->state != WAIT_FOR_SETUP) { - /* - * Didn't expect a SETUP packet at this - * point. Clean up any pending requests (which - * may be successful). - */ - int status = -EPROTO; - - /* - * RXRDY and TXCOMP are dropped when SETUP - * packets arrive. Just pretend we received - * the status packet. - */ - if (ep->state == STATUS_STAGE_OUT || - ep->state == STATUS_STAGE_IN) { - usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY); - status = 0; - } - - if (req) { - list_del_init(&req->queue); - request_complete(ep, req, status); - } - } - - pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA)); - DBG(DBG_HW, "Packet length: %u\n", pkt_len); - if (pkt_len != sizeof(crq)) { - DBG(DBG_ALL, "udc: Invalid length %u (expected %zu)\n", - pkt_len, sizeof(crq)); - set_protocol_stall(udc, ep); - return; - } - - DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo); - memcpy(crq.data, ep->fifo, sizeof(crq)); - - /* Free up one bank in the FIFO so that we can - * generate or receive a reply right away. */ - usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP); - - if (crq.crq.bRequestType & USB_DIR_IN) { - /* - * The USB 2.0 spec states that "if wLength is - * zero, there is no data transfer phase." - * However, testusb #14 seems to actually - * expect a data phase even if wLength = 0... - */ - ep->state = DATA_STAGE_IN; - } else { - if (crq.crq.wLength != cpu_to_le16(0)) - ep->state = DATA_STAGE_OUT; - else - ep->state = STATUS_STAGE_IN; - } - - ret = -1; - if (ep->index == 0) { - ret = handle_ep0_setup(udc, ep, &crq.crq); - } else { - spin_unlock(&udc->lock); - ret = udc->driver->setup(&udc->gadget, &crq.crq); - spin_lock(&udc->lock); - } - - DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n", - crq.crq.bRequestType, crq.crq.bRequest, - le16_to_cpu(crq.crq.wLength), ep->state, ret); - - if (ret < 0) { - /* Let the host know that we failed */ - set_protocol_stall(udc, ep); - } - } -} - -static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep) -{ - struct usba_request *req; - u32 epstatus; - u32 epctrl; - - epstatus = usba_ep_readl(ep, STA); - epctrl = usba_ep_readl(ep, CTL); - - DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus); - - while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) { - DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name); - - if (list_empty(&ep->queue)) { - DBG(DBG_INT, "ep_irq: queue empty\n"); - usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - return; - } - - req = list_entry(ep->queue.next, struct usba_request, queue); - - if (req->submitted) - next_fifo_transaction(ep, req); - else - submit_request(ep, req); - - if (req->last_transaction) { - list_del_init(&req->queue); - submit_next_request(ep); - request_complete(ep, req, 0); - } - - epstatus = usba_ep_readl(ep, STA); - epctrl = usba_ep_readl(ep, CTL); - } - - if ((epstatus & epctrl) & USBA_RX_BK_RDY) { - DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name); - receive_data(ep); - usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY); - } -} - -static int usba_udc_irq(struct usba_udc *udc) -{ - u32 status, ep_status; - - spin_lock(&udc->lock); - - status = usba_readl(udc, INT_STA); - DBG(DBG_INT, "irq, status=%#08x\n", status); - - if (status & USBA_DET_SUSPEND) { - usba_writel(udc, INT_CLR, USBA_DET_SUSPEND); - DBG(DBG_BUS, "Suspend detected\n"); - if (udc->gadget.speed != USB_SPEED_UNKNOWN && - udc->driver && udc->driver->suspend) { - spin_unlock(&udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(&udc->lock); - } - } - - if (status & USBA_WAKE_UP) { - usba_writel(udc, INT_CLR, USBA_WAKE_UP); - DBG(DBG_BUS, "Wake Up CPU detected\n"); - } - - if (status & USBA_END_OF_RESUME) { - usba_writel(udc, INT_CLR, USBA_END_OF_RESUME); - DBG(DBG_BUS, "Resume detected\n"); - if (udc->gadget.speed != USB_SPEED_UNKNOWN && - udc->driver && udc->driver->resume) { - spin_unlock(&udc->lock); - udc->driver->resume(&udc->gadget); - spin_lock(&udc->lock); - } - } - - ep_status = USBA_BFEXT(EPT_INT, status); - if (ep_status) { - int i; - - for (i = 0; i < USBA_NR_ENDPOINTS; i++) - if (ep_status & (1 << i)) { - if (ep_is_control(&udc->usba_ep[i])) - usba_control_irq(udc, &udc->usba_ep[i]); - else - usba_ep_irq(udc, &udc->usba_ep[i]); - } - } - - if (status & USBA_END_OF_RESET) { - struct usba_ep *ep0; - - usba_writel(udc, INT_CLR, USBA_END_OF_RESET); - reset_all_endpoints(udc); - - if (udc->gadget.speed != USB_SPEED_UNKNOWN && - udc->driver->disconnect) { - udc->gadget.speed = USB_SPEED_UNKNOWN; - spin_unlock(&udc->lock); - udc->driver->disconnect(&udc->gadget); - spin_lock(&udc->lock); - } - - if (status & USBA_HIGH_SPEED) - udc->gadget.speed = USB_SPEED_HIGH; - else - udc->gadget.speed = USB_SPEED_FULL; - - ep0 = &udc->usba_ep[0]; - ep0->desc = &usba_ep0_desc; - ep0->state = WAIT_FOR_SETUP; - usba_ep_writel(ep0, CFG, - (USBA_BF(EPT_SIZE, EP0_EPT_SIZE) - | USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL) - | USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE))); - usba_ep_writel(ep0, CTL_ENB, - USBA_EPT_ENABLE | USBA_RX_SETUP); - usba_writel(udc, INT_ENB, - (usba_readl(udc, INT_ENB) - | USBA_BF(EPT_INT, 1) - | USBA_DET_SUSPEND - | USBA_END_OF_RESUME)); - - /* - * Unclear why we hit this irregularly, e.g. in usbtest, - * but it's clearly harmless... - */ - if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED)) - DBG(DBG_ALL, "ODD: EP0 configuration is invalid!\n"); - } - - spin_unlock(&udc->lock); - - return 0; -} - -static int atmel_usba_start(struct usba_udc *udc) -{ - udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; - - udc->vbus_prev = 0; - - /* If Vbus is present, enable the controller and wait for reset */ - if (vbus_is_present(udc) && udc->vbus_prev == 0) { - usba_writel(udc, CTRL, USBA_ENABLE_MASK); - usba_writel(udc, INT_ENB, USBA_END_OF_RESET); - } - - return 0; -} - -static int atmel_usba_stop(struct usba_udc *udc) -{ - udc->gadget.speed = USB_SPEED_UNKNOWN; - reset_all_endpoints(udc); - - /* This will also disable the DP pullup */ - usba_writel(udc, CTRL, USBA_DISABLE_MASK); - - return 0; -} - -static struct usba_udc controller = { - .regs = (unsigned *)ATMEL_BASE_UDPHS, - .fifo = (unsigned *)ATMEL_BASE_UDPHS_FIFO, - .gadget = { - .ops = &usba_udc_ops, - .ep_list = LIST_HEAD_INIT(controller.gadget.ep_list), - .speed = USB_SPEED_HIGH, - .is_dualspeed = 1, - .name = "atmel_usba_udc", - }, -}; - -int usb_gadget_handle_interrupts(void) -{ - struct usba_udc *udc = &controller; - - return usba_udc_irq(udc); -} - - -int usb_gadget_register_driver(struct usb_gadget_driver *driver) -{ - struct usba_udc *udc = &controller; - int ret; - - if (!driver || !driver->bind || !driver->setup) { - printf("bad paramter\n"); - return -EINVAL; - } - - if (udc->driver) { - printf("UDC already has a gadget driver\n"); - return -EBUSY; - } - - atmel_usba_start(udc); - - udc->driver = driver; - - ret = driver->bind(&udc->gadget); - if (ret) { - error("driver->bind() returned %d\n", ret); - udc->driver = NULL; - } - - return ret; -} - -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct usba_udc *udc = &controller; - - if (!driver || !driver->unbind || !driver->disconnect) { - error("bad paramter\n"); - return -EINVAL; - } - - driver->disconnect(&udc->gadget); - driver->unbind(&udc->gadget); - udc->driver = NULL; - - atmel_usba_stop(udc); - - return 0; -} - -static struct usba_ep *usba_udc_pdata(struct usba_platform_data *pdata, - struct usba_udc *udc) -{ - struct usba_ep *eps; - int i; - - eps = malloc(sizeof(struct usba_ep) * pdata->num_ep); - if (!eps) { - error("failed to alloc eps\n"); - return NULL; - } - - udc->gadget.ep0 = &eps[0].ep; - - INIT_LIST_HEAD(&udc->gadget.ep_list); - INIT_LIST_HEAD(&eps[0].ep.ep_list); - - for (i = 0; i < pdata->num_ep; i++) { - struct usba_ep *ep = &eps[i]; - - ep->ep_regs = udc->regs + USBA_EPT_BASE(i); - ep->dma_regs = udc->regs + USBA_DMA_BASE(i); - ep->fifo = udc->fifo + USBA_FIFO_BASE(i); - ep->ep.ops = &usba_ep_ops; - ep->ep.name = pdata->ep[i].name; - ep->ep.maxpacket = pdata->ep[i].fifo_size; - ep->fifo_size = ep->ep.maxpacket; - ep->udc = udc; - INIT_LIST_HEAD(&ep->queue); - ep->nr_banks = pdata->ep[i].nr_banks; - ep->index = pdata->ep[i].index; - ep->can_dma = pdata->ep[i].can_dma; - ep->can_isoc = pdata->ep[i].can_isoc; - if (i) - list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - }; - - return eps; -} - -int usba_udc_probe(struct usba_platform_data *pdata) -{ - struct usba_udc *udc; - - udc = &controller; - - udc->usba_ep = usba_udc_pdata(pdata, udc); - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.h b/qemu/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.h deleted file mode 100644 index 92e462db6..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/atmel_usba_udc.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Register definition for Atmel USBA high speed USB device controller - * [Original from Linux kernel: drivers/usb/gadget/atmel_usba_udc.h] - * - * Copyright (C) 2005-2013 Atmel Corporation - * Bo Shen <voice.shen@atmel.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __LINUX_USB_GADGET_USBA_UDC_H__ -#define __LINUX_USB_GADGET_USBA_UDC_H__ - -/* USB register offsets */ -#define USBA_CTRL 0x0000 -#define USBA_FNUM 0x0004 -#define USBA_INT_ENB 0x0010 -#define USBA_INT_STA 0x0014 -#define USBA_INT_CLR 0x0018 -#define USBA_EPT_RST 0x001c -#define USBA_TST 0x00e0 - -/* USB endpoint register offsets */ -#define USBA_EPT_CFG 0x0000 -#define USBA_EPT_CTL_ENB 0x0004 -#define USBA_EPT_CTL_DIS 0x0008 -#define USBA_EPT_CTL 0x000c -#define USBA_EPT_SET_STA 0x0014 -#define USBA_EPT_CLR_STA 0x0018 -#define USBA_EPT_STA 0x001c - -/* USB DMA register offsets */ -#define USBA_DMA_NXT_DSC 0x0000 -#define USBA_DMA_ADDRESS 0x0004 -#define USBA_DMA_CONTROL 0x0008 -#define USBA_DMA_STATUS 0x000c - -/* Bitfields in CTRL */ -#define USBA_DEV_ADDR_OFFSET 0 -#define USBA_DEV_ADDR_SIZE 7 -#define USBA_FADDR_EN (1 << 7) -#define USBA_EN_USBA (1 << 8) -#define USBA_DETACH (1 << 9) -#define USBA_REMOTE_WAKE_UP (1 << 10) -#define USBA_PULLD_DIS (1 << 11) - -#if defined(CONFIG_AVR32) -#define USBA_ENABLE_MASK USBA_EN_USBA -#define USBA_DISABLE_MASK 0 -#elif defined(CONFIG_AT91FAMILY) -#define USBA_ENABLE_MASK (USBA_EN_USBA | USBA_PULLD_DIS) -#define USBA_DISABLE_MASK USBA_DETACH -#endif /* CONFIG_ARCH_AT91 */ - -/* Bitfields in FNUM */ -#define USBA_MICRO_FRAME_NUM_OFFSET 0 -#define USBA_MICRO_FRAME_NUM_SIZE 3 -#define USBA_FRAME_NUMBER_OFFSET 3 -#define USBA_FRAME_NUMBER_SIZE 11 -#define USBA_FRAME_NUM_ERROR (1 << 31) - -/* Bitfields in INT_ENB/INT_STA/INT_CLR */ -#define USBA_HIGH_SPEED (1 << 0) -#define USBA_DET_SUSPEND (1 << 1) -#define USBA_MICRO_SOF (1 << 2) -#define USBA_SOF (1 << 3) -#define USBA_END_OF_RESET (1 << 4) -#define USBA_WAKE_UP (1 << 5) -#define USBA_END_OF_RESUME (1 << 6) -#define USBA_UPSTREAM_RESUME (1 << 7) -#define USBA_EPT_INT_OFFSET 8 -#define USBA_EPT_INT_SIZE 16 -#define USBA_DMA_INT_OFFSET 24 -#define USBA_DMA_INT_SIZE 8 - -/* Bitfields in EPT_RST */ -#define USBA_RST_OFFSET 0 -#define USBA_RST_SIZE 16 - -/* Bitfields in USBA_TST */ -#define USBA_SPEED_CFG_OFFSET 0 -#define USBA_SPEED_CFG_SIZE 2 -#define USBA_TST_J_MODE (1 << 2) -#define USBA_TST_K_MODE (1 << 3) -#define USBA_TST_PKT_MODE (1 << 4) -#define USBA_OPMODE2 (1 << 5) - -/* Bitfields in EPT_CFG */ -#define USBA_EPT_SIZE_OFFSET 0 -#define USBA_EPT_SIZE_SIZE 3 -#define USBA_EPT_DIR_IN (1 << 3) -#define USBA_EPT_TYPE_OFFSET 4 -#define USBA_EPT_TYPE_SIZE 2 -#define USBA_BK_NUMBER_OFFSET 6 -#define USBA_BK_NUMBER_SIZE 2 -#define USBA_NB_TRANS_OFFSET 8 -#define USBA_NB_TRANS_SIZE 2 -#define USBA_EPT_MAPPED (1 << 31) - -/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */ -#define USBA_EPT_ENABLE (1 << 0) -#define USBA_AUTO_VALID (1 << 1) -#define USBA_INTDIS_DMA (1 << 3) -#define USBA_NYET_DIS (1 << 4) -#define USBA_DATAX_RX (1 << 6) -#define USBA_MDATA_RX (1 << 7) -/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */ -#define USBA_BUSY_BANK_IE (1 << 18) - -/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */ -#define USBA_FORCE_STALL (1 << 5) -#define USBA_TOGGLE_CLR (1 << 6) -#define USBA_TOGGLE_SEQ_OFFSET 6 -#define USBA_TOGGLE_SEQ_SIZE 2 -#define USBA_ERR_OVFLW (1 << 8) -#define USBA_RX_BK_RDY (1 << 9) -#define USBA_KILL_BANK (1 << 9) -#define USBA_TX_COMPLETE (1 << 10) -#define USBA_TX_PK_RDY (1 << 11) -#define USBA_ISO_ERR_TRANS (1 << 11) -#define USBA_RX_SETUP (1 << 12) -#define USBA_ISO_ERR_FLOW (1 << 12) -#define USBA_STALL_SENT (1 << 13) -#define USBA_ISO_ERR_CRC (1 << 13) -#define USBA_ISO_ERR_NBTRANS (1 << 13) -#define USBA_NAK_IN (1 << 14) -#define USBA_ISO_ERR_FLUSH (1 << 14) -#define USBA_NAK_OUT (1 << 15) -#define USBA_CURRENT_BANK_OFFSET 16 -#define USBA_CURRENT_BANK_SIZE 2 -#define USBA_BUSY_BANKS_OFFSET 18 -#define USBA_BUSY_BANKS_SIZE 2 -#define USBA_BYTE_COUNT_OFFSET 20 -#define USBA_BYTE_COUNT_SIZE 11 -#define USBA_SHORT_PACKET (1 << 31) - -/* Bitfields in DMA_CONTROL */ -#define USBA_DMA_CH_EN (1 << 0) -#define USBA_DMA_LINK (1 << 1) -#define USBA_DMA_END_TR_EN (1 << 2) -#define USBA_DMA_END_BUF_EN (1 << 3) -#define USBA_DMA_END_TR_IE (1 << 4) -#define USBA_DMA_END_BUF_IE (1 << 5) -#define USBA_DMA_DESC_LOAD_IE (1 << 6) -#define USBA_DMA_BURST_LOCK (1 << 7) -#define USBA_DMA_BUF_LEN_OFFSET 16 -#define USBA_DMA_BUF_LEN_SIZE 16 - -/* Bitfields in DMA_STATUS */ -#define USBA_DMA_CH_ACTIVE (1 << 1) -#define USBA_DMA_END_TR_ST (1 << 4) -#define USBA_DMA_END_BUF_ST (1 << 5) -#define USBA_DMA_DESC_LOAD_ST (1 << 6) - -/* Constants for SPEED_CFG */ -#define USBA_SPEED_CFG_NORMAL 0 -#define USBA_SPEED_CFG_FORCE_HIGH 2 -#define USBA_SPEED_CFG_FORCE_FULL 3 - -/* Constants for EPT_SIZE */ -#define USBA_EPT_SIZE_8 0 -#define USBA_EPT_SIZE_16 1 -#define USBA_EPT_SIZE_32 2 -#define USBA_EPT_SIZE_64 3 -#define USBA_EPT_SIZE_128 4 -#define USBA_EPT_SIZE_256 5 -#define USBA_EPT_SIZE_512 6 -#define USBA_EPT_SIZE_1024 7 - -/* Constants for EPT_TYPE */ -#define USBA_EPT_TYPE_CONTROL 0 -#define USBA_EPT_TYPE_ISO 1 -#define USBA_EPT_TYPE_BULK 2 -#define USBA_EPT_TYPE_INT 3 - -/* Constants for BK_NUMBER */ -#define USBA_BK_NUMBER_ZERO 0 -#define USBA_BK_NUMBER_ONE 1 -#define USBA_BK_NUMBER_DOUBLE 2 -#define USBA_BK_NUMBER_TRIPLE 3 - -/* Bit manipulation macros */ -#define USBA_BF(name, value) \ - (((value) & ((1 << USBA_##name##_SIZE) - 1)) \ - << USBA_##name##_OFFSET) -#define USBA_BFEXT(name, value) \ - (((value) >> USBA_##name##_OFFSET) \ - & ((1 << USBA_##name##_SIZE) - 1)) -#define USBA_BFINS(name, value, old) \ - (((old) & ~(((1 << USBA_##name##_SIZE) - 1) \ - << USBA_##name##_OFFSET)) \ - | USBA_BF(name, value)) - -/* Register access macros */ -#define usba_readl(udc, reg) \ - __raw_readl((udc)->regs + USBA_##reg) -#define usba_writel(udc, reg, value) \ - __raw_writel((value), (udc)->regs + USBA_##reg) -#define usba_ep_readl(ep, reg) \ - __raw_readl((ep)->ep_regs + USBA_EPT_##reg) -#define usba_ep_writel(ep, reg, value) \ - __raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg) -#define usba_dma_readl(ep, reg) \ - __raw_readl((ep)->dma_regs + USBA_DMA_##reg) -#define usba_dma_writel(ep, reg, value) \ - __raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg) - -/* Calculate base address for a given endpoint or DMA controller */ -#define USBA_EPT_BASE(x) (0x100 + (x) * 0x20) -#define USBA_DMA_BASE(x) (0x300 + (x) * 0x10) -#define USBA_FIFO_BASE(x) ((x) << 16) - -/* Synth parameters */ -#define USBA_NR_ENDPOINTS 7 - -#define EP0_FIFO_SIZE 64 -#define EP0_EPT_SIZE USBA_EPT_SIZE_64 -#define EP0_NR_BANKS 1 - -#define DBG_ERR 0x0001 /* report all error returns */ -#define DBG_HW 0x0002 /* debug hardware initialization */ -#define DBG_GADGET 0x0004 /* calls to/from gadget driver */ -#define DBG_INT 0x0008 /* interrupts */ -#define DBG_BUS 0x0010 /* report changes in bus state */ -#define DBG_QUEUE 0x0020 /* debug request queue processing */ -#define DBG_FIFO 0x0040 /* debug FIFO contents */ -#define DBG_DMA 0x0080 /* debug DMA handling */ -#define DBG_REQ 0x0100 /* print out queued request length */ -#define DBG_ALL 0xffff -#define DBG_NONE 0x0000 - -#define DEBUG_LEVEL (DBG_ERR) - -#define DBG(level, fmt, ...) \ - do { \ - if ((level) & DEBUG_LEVEL) \ - debug("udc: " fmt, ## __VA_ARGS__); \ - } while (0) - -enum usba_ctrl_state { - WAIT_FOR_SETUP, - DATA_STAGE_IN, - DATA_STAGE_OUT, - STATUS_STAGE_IN, - STATUS_STAGE_OUT, - STATUS_STAGE_ADDR, - STATUS_STAGE_TEST, -}; - -struct usba_dma_desc { - dma_addr_t next; - dma_addr_t addr; - u32 ctrl; -}; - -struct usba_ep { - int state; - void *ep_regs; - void *dma_regs; - void *fifo; - struct usb_ep ep; - struct usba_udc *udc; - - struct list_head queue; - - u16 fifo_size; - u8 nr_banks; - u8 index; - unsigned int can_dma:1; - unsigned int can_isoc:1; - unsigned int is_isoc:1; - unsigned int is_in:1; - - const struct usb_endpoint_descriptor *desc; -}; - -struct usba_request { - struct usb_request req; - struct list_head queue; - - u32 ctrl; - - unsigned int submitted:1; - unsigned int last_transaction:1; - unsigned int using_dma:1; - unsigned int mapped:1; -}; - -struct usba_udc { - void *regs; - void *fifo; - - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct platform_device *pdev; - int irq; - int vbus_pin; - int vbus_pin_inverted; - int num_ep; - struct usba_ep *usba_ep; - - u16 devstatus; - - u16 test_mode; - int vbus_prev; -}; - -static inline struct usba_ep *to_usba_ep(struct usb_ep *ep) -{ - return container_of(ep, struct usba_ep, ep); -} - -static inline struct usba_request *to_usba_req(struct usb_request *req) -{ - return container_of(req, struct usba_request, req); -} - -static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget) -{ - return container_of(gadget, struct usba_udc, gadget); -} - -#define ep_is_control(ep) ((ep)->index == 0) -#define ep_is_idle(ep) ((ep)->state == EP_STATE_IDLE) - -#endif /* __LINUX_USB_GADGET_USBA_UDC_H */ diff --git a/qemu/roms/u-boot/drivers/usb/gadget/ci_udc.c b/qemu/roms/u-boot/drivers/usb/gadget/ci_udc.c deleted file mode 100644 index 02d3fdade..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/ci_udc.c +++ /dev/null @@ -1,760 +0,0 @@ -/* - * Copyright 2011, Marvell Semiconductor Inc. - * Lei Wen <leiwen@marvell.com> - * - * SPDX-License-Identifier: GPL-2.0+ - * - * Back ported to the 8xx platform (from the 8260 platform) by - * Murray.Jensen@cmst.csiro.au, 27-Jan-01. - */ - -#include <common.h> -#include <command.h> -#include <config.h> -#include <net.h> -#include <malloc.h> -#include <asm/byteorder.h> -#include <asm/errno.h> -#include <asm/io.h> -#include <asm/unaligned.h> -#include <linux/types.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <usb/ci_udc.h> -#include "../host/ehci.h" -#include "ci_udc.h" - -/* - * Check if the system has too long cachelines. If the cachelines are - * longer then 128b, the driver will not be able flush/invalidate data - * cache over separate QH entries. We use 128b because one QH entry is - * 64b long and there are always two QH list entries for each endpoint. - */ -#if ARCH_DMA_MINALIGN > 128 -#error This driver can not work on systems with caches longer than 128b -#endif - -#ifndef DEBUG -#define DBG(x...) do {} while (0) -#else -#define DBG(x...) printf(x) -static const char *reqname(unsigned r) -{ - switch (r) { - case USB_REQ_GET_STATUS: return "GET_STATUS"; - case USB_REQ_CLEAR_FEATURE: return "CLEAR_FEATURE"; - case USB_REQ_SET_FEATURE: return "SET_FEATURE"; - case USB_REQ_SET_ADDRESS: return "SET_ADDRESS"; - case USB_REQ_GET_DESCRIPTOR: return "GET_DESCRIPTOR"; - case USB_REQ_SET_DESCRIPTOR: return "SET_DESCRIPTOR"; - case USB_REQ_GET_CONFIGURATION: return "GET_CONFIGURATION"; - case USB_REQ_SET_CONFIGURATION: return "SET_CONFIGURATION"; - case USB_REQ_GET_INTERFACE: return "GET_INTERFACE"; - case USB_REQ_SET_INTERFACE: return "SET_INTERFACE"; - default: return "*UNKNOWN*"; - } -} -#endif - -static struct usb_endpoint_descriptor ep0_out_desc = { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, -}; - -static struct usb_endpoint_descriptor ep0_in_desc = { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, -}; - -static int ci_pullup(struct usb_gadget *gadget, int is_on); -static int ci_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc); -static int ci_ep_disable(struct usb_ep *ep); -static int ci_ep_queue(struct usb_ep *ep, - struct usb_request *req, gfp_t gfp_flags); -static struct usb_request * -ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags); -static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req); - -static struct usb_gadget_ops ci_udc_ops = { - .pullup = ci_pullup, -}; - -static struct usb_ep_ops ci_ep_ops = { - .enable = ci_ep_enable, - .disable = ci_ep_disable, - .queue = ci_ep_queue, - .alloc_request = ci_ep_alloc_request, - .free_request = ci_ep_free_request, -}; - -/* Init values for USB endpoints. */ -static const struct usb_ep ci_ep_init[2] = { - [0] = { /* EP 0 */ - .maxpacket = 64, - .name = "ep0", - .ops = &ci_ep_ops, - }, - [1] = { /* EP 1..n */ - .maxpacket = 512, - .name = "ep-", - .ops = &ci_ep_ops, - }, -}; - -static struct ci_drv controller = { - .gadget = { - .name = "ci_udc", - .ops = &ci_udc_ops, - .is_dualspeed = 1, - }, -}; - -/** - * ci_get_qh() - return queue head for endpoint - * @ep_num: Endpoint number - * @dir_in: Direction of the endpoint (IN = 1, OUT = 0) - * - * This function returns the QH associated with particular endpoint - * and it's direction. - */ -static struct ept_queue_head *ci_get_qh(int ep_num, int dir_in) -{ - return &controller.epts[(ep_num * 2) + dir_in]; -} - -/** - * ci_get_qtd() - return queue item for endpoint - * @ep_num: Endpoint number - * @dir_in: Direction of the endpoint (IN = 1, OUT = 0) - * - * This function returns the QH associated with particular endpoint - * and it's direction. - */ -static struct ept_queue_item *ci_get_qtd(int ep_num, int dir_in) -{ - return controller.items[(ep_num * 2) + dir_in]; -} - -/** - * ci_flush_qh - flush cache over queue head - * @ep_num: Endpoint number - * - * This function flushes cache over QH for particular endpoint. - */ -static void ci_flush_qh(int ep_num) -{ - struct ept_queue_head *head = ci_get_qh(ep_num, 0); - const uint32_t start = (uint32_t)head; - const uint32_t end = start + 2 * sizeof(*head); - - flush_dcache_range(start, end); -} - -/** - * ci_invalidate_qh - invalidate cache over queue head - * @ep_num: Endpoint number - * - * This function invalidates cache over QH for particular endpoint. - */ -static void ci_invalidate_qh(int ep_num) -{ - struct ept_queue_head *head = ci_get_qh(ep_num, 0); - uint32_t start = (uint32_t)head; - uint32_t end = start + 2 * sizeof(*head); - - invalidate_dcache_range(start, end); -} - -/** - * ci_flush_qtd - flush cache over queue item - * @ep_num: Endpoint number - * - * This function flushes cache over qTD pair for particular endpoint. - */ -static void ci_flush_qtd(int ep_num) -{ - struct ept_queue_item *item = ci_get_qtd(ep_num, 0); - const uint32_t start = (uint32_t)item; - const uint32_t end_raw = start + 2 * sizeof(*item); - const uint32_t end = roundup(end_raw, ARCH_DMA_MINALIGN); - - flush_dcache_range(start, end); -} - -/** - * ci_invalidate_qtd - invalidate cache over queue item - * @ep_num: Endpoint number - * - * This function invalidates cache over qTD pair for particular endpoint. - */ -static void ci_invalidate_qtd(int ep_num) -{ - struct ept_queue_item *item = ci_get_qtd(ep_num, 0); - const uint32_t start = (uint32_t)item; - const uint32_t end_raw = start + 2 * sizeof(*item); - const uint32_t end = roundup(end_raw, ARCH_DMA_MINALIGN); - - invalidate_dcache_range(start, end); -} - -static struct usb_request * -ci_ep_alloc_request(struct usb_ep *ep, unsigned int gfp_flags) -{ - struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep); - return &ci_ep->req; -} - -static void ci_ep_free_request(struct usb_ep *ep, struct usb_request *_req) -{ - return; -} - -static void ep_enable(int num, int in, int maxpacket) -{ - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - unsigned n; - - n = readl(&udc->epctrl[num]); - if (in) - n |= (CTRL_TXE | CTRL_TXR | CTRL_TXT_BULK); - else - n |= (CTRL_RXE | CTRL_RXR | CTRL_RXT_BULK); - - if (num != 0) { - struct ept_queue_head *head = ci_get_qh(num, in); - - head->config = CONFIG_MAX_PKT(maxpacket) | CONFIG_ZLT; - ci_flush_qh(num); - } - writel(n, &udc->epctrl[num]); -} - -static int ci_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep); - int num, in; - num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - in = (desc->bEndpointAddress & USB_DIR_IN) != 0; - ci_ep->desc = desc; - - if (num) { - int max = get_unaligned_le16(&desc->wMaxPacketSize); - - if ((max > 64) && (controller.gadget.speed == USB_SPEED_FULL)) - max = 64; - if (ep->maxpacket != max) { - DBG("%s: from %d to %d\n", __func__, - ep->maxpacket, max); - ep->maxpacket = max; - } - } - ep_enable(num, in, ep->maxpacket); - DBG("%s: num=%d maxpacket=%d\n", __func__, num, ep->maxpacket); - return 0; -} - -static int ci_ep_disable(struct usb_ep *ep) -{ - struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep); - - ci_ep->desc = NULL; - return 0; -} - -static int ci_bounce(struct ci_ep *ep, int in) -{ - uint32_t addr = (uint32_t)ep->req.buf; - uint32_t ba; - - /* Input buffer address is not aligned. */ - if (addr & (ARCH_DMA_MINALIGN - 1)) - goto align; - - /* Input buffer length is not aligned. */ - if (ep->req.length & (ARCH_DMA_MINALIGN - 1)) - goto align; - - /* The buffer is well aligned, only flush cache. */ - ep->b_len = ep->req.length; - ep->b_buf = ep->req.buf; - goto flush; - -align: - /* Use internal buffer for small payloads. */ - if (ep->req.length <= 64) { - ep->b_len = 64; - ep->b_buf = ep->b_fast; - } else { - ep->b_len = roundup(ep->req.length, ARCH_DMA_MINALIGN); - ep->b_buf = memalign(ARCH_DMA_MINALIGN, ep->b_len); - if (!ep->b_buf) - return -ENOMEM; - } - if (in) - memcpy(ep->b_buf, ep->req.buf, ep->req.length); - -flush: - ba = (uint32_t)ep->b_buf; - flush_dcache_range(ba, ba + ep->b_len); - - return 0; -} - -static void ci_debounce(struct ci_ep *ep, int in) -{ - uint32_t addr = (uint32_t)ep->req.buf; - uint32_t ba = (uint32_t)ep->b_buf; - - if (in) { - if (addr == ba) - return; /* not a bounce */ - goto free; - } - invalidate_dcache_range(ba, ba + ep->b_len); - - if (addr == ba) - return; /* not a bounce */ - - memcpy(ep->req.buf, ep->b_buf, ep->req.actual); -free: - /* Large payloads use allocated buffer, free it. */ - if (ep->b_buf != ep->b_fast) - free(ep->b_buf); -} - -static int ci_ep_queue(struct usb_ep *ep, - struct usb_request *req, gfp_t gfp_flags) -{ - struct ci_ep *ci_ep = container_of(ep, struct ci_ep, ep); - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - struct ept_queue_item *item; - struct ept_queue_head *head; - int bit, num, len, in, ret; - num = ci_ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - in = (ci_ep->desc->bEndpointAddress & USB_DIR_IN) != 0; - item = ci_get_qtd(num, in); - head = ci_get_qh(num, in); - len = req->length; - - ret = ci_bounce(ci_ep, in); - if (ret) - return ret; - - item->next = TERMINATE; - item->info = INFO_BYTES(len) | INFO_IOC | INFO_ACTIVE; - item->page0 = (uint32_t)ci_ep->b_buf; - item->page1 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x1000; - item->page2 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x2000; - item->page3 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x3000; - item->page4 = ((uint32_t)ci_ep->b_buf & 0xfffff000) + 0x4000; - ci_flush_qtd(num); - - head->next = (unsigned) item; - head->info = 0; - - DBG("ept%d %s queue len %x, buffer %p\n", - num, in ? "in" : "out", len, ci_ep->b_buf); - ci_flush_qh(num); - - if (in) - bit = EPT_TX(num); - else - bit = EPT_RX(num); - - writel(bit, &udc->epprime); - - return 0; -} - -static void handle_ep_complete(struct ci_ep *ep) -{ - struct ept_queue_item *item; - int num, in, len; - num = ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - in = (ep->desc->bEndpointAddress & USB_DIR_IN) != 0; - if (num == 0) - ep->desc = &ep0_out_desc; - item = ci_get_qtd(num, in); - ci_invalidate_qtd(num); - - if (item->info & 0xff) - printf("EP%d/%s FAIL info=%x pg0=%x\n", - num, in ? "in" : "out", item->info, item->page0); - - len = (item->info >> 16) & 0x7fff; - ep->req.actual = ep->req.length - len; - ci_debounce(ep, in); - - DBG("ept%d %s complete %x\n", - num, in ? "in" : "out", len); - ep->req.complete(&ep->ep, &ep->req); - if (num == 0) { - ep->req.length = 0; - usb_ep_queue(&ep->ep, &ep->req, 0); - ep->desc = &ep0_in_desc; - } -} - -#define SETUP(type, request) (((type) << 8) | (request)) - -static void handle_setup(void) -{ - struct usb_request *req = &controller.ep[0].req; - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - struct ept_queue_head *head; - struct usb_ctrlrequest r; - int status = 0; - int num, in, _num, _in, i; - char *buf; - head = ci_get_qh(0, 0); /* EP0 OUT */ - - ci_invalidate_qh(0); - memcpy(&r, head->setup_data, sizeof(struct usb_ctrlrequest)); -#ifdef CONFIG_CI_UDC_HAS_HOSTPC - writel(EPT_RX(0), &udc->epsetupstat); -#else - writel(EPT_RX(0), &udc->epstat); -#endif - DBG("handle setup %s, %x, %x index %x value %x\n", reqname(r.bRequest), - r.bRequestType, r.bRequest, r.wIndex, r.wValue); - - switch (SETUP(r.bRequestType, r.bRequest)) { - case SETUP(USB_RECIP_ENDPOINT, USB_REQ_CLEAR_FEATURE): - _num = r.wIndex & 15; - _in = !!(r.wIndex & 0x80); - - if ((r.wValue == 0) && (r.wLength == 0)) { - req->length = 0; - for (i = 0; i < NUM_ENDPOINTS; i++) { - struct ci_ep *ep = &controller.ep[i]; - - if (!ep->desc) - continue; - num = ep->desc->bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK; - in = (ep->desc->bEndpointAddress - & USB_DIR_IN) != 0; - if ((num == _num) && (in == _in)) { - ep_enable(num, in, ep->ep.maxpacket); - usb_ep_queue(controller.gadget.ep0, - req, 0); - break; - } - } - } - return; - - case SETUP(USB_RECIP_DEVICE, USB_REQ_SET_ADDRESS): - /* - * write address delayed (will take effect - * after the next IN txn) - */ - writel((r.wValue << 25) | (1 << 24), &udc->devaddr); - req->length = 0; - usb_ep_queue(controller.gadget.ep0, req, 0); - return; - - case SETUP(USB_DIR_IN | USB_RECIP_DEVICE, USB_REQ_GET_STATUS): - req->length = 2; - buf = (char *)req->buf; - buf[0] = 1 << USB_DEVICE_SELF_POWERED; - buf[1] = 0; - usb_ep_queue(controller.gadget.ep0, req, 0); - return; - } - /* pass request up to the gadget driver */ - if (controller.driver) - status = controller.driver->setup(&controller.gadget, &r); - else - status = -ENODEV; - - if (!status) - return; - DBG("STALL reqname %s type %x value %x, index %x\n", - reqname(r.bRequest), r.bRequestType, r.wValue, r.wIndex); - writel((1<<16) | (1 << 0), &udc->epctrl[0]); -} - -static void stop_activity(void) -{ - int i, num, in; - struct ept_queue_head *head; - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - writel(readl(&udc->epcomp), &udc->epcomp); -#ifdef CONFIG_CI_UDC_HAS_HOSTPC - writel(readl(&udc->epsetupstat), &udc->epsetupstat); -#endif - writel(readl(&udc->epstat), &udc->epstat); - writel(0xffffffff, &udc->epflush); - - /* error out any pending reqs */ - for (i = 0; i < NUM_ENDPOINTS; i++) { - if (i != 0) - writel(0, &udc->epctrl[i]); - if (controller.ep[i].desc) { - num = controller.ep[i].desc->bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK; - in = (controller.ep[i].desc->bEndpointAddress - & USB_DIR_IN) != 0; - head = ci_get_qh(num, in); - head->info = INFO_ACTIVE; - ci_flush_qh(num); - } - } -} - -void udc_irq(void) -{ - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - unsigned n = readl(&udc->usbsts); - writel(n, &udc->usbsts); - int bit, i, num, in; - - n &= (STS_SLI | STS_URI | STS_PCI | STS_UI | STS_UEI); - if (n == 0) - return; - - if (n & STS_URI) { - DBG("-- reset --\n"); - stop_activity(); - } - if (n & STS_SLI) - DBG("-- suspend --\n"); - - if (n & STS_PCI) { - int max = 64; - int speed = USB_SPEED_FULL; - -#ifdef CONFIG_CI_UDC_HAS_HOSTPC - bit = (readl(&udc->hostpc1_devlc) >> 25) & 3; -#else - bit = (readl(&udc->portsc) >> 26) & 3; -#endif - DBG("-- portchange %x %s\n", bit, (bit == 2) ? "High" : "Full"); - if (bit == 2) { - speed = USB_SPEED_HIGH; - max = 512; - } - controller.gadget.speed = speed; - for (i = 1; i < NUM_ENDPOINTS; i++) { - if (controller.ep[i].ep.maxpacket > max) - controller.ep[i].ep.maxpacket = max; - } - } - - if (n & STS_UEI) - printf("<UEI %x>\n", readl(&udc->epcomp)); - - if ((n & STS_UI) || (n & STS_UEI)) { -#ifdef CONFIG_CI_UDC_HAS_HOSTPC - n = readl(&udc->epsetupstat); -#else - n = readl(&udc->epstat); -#endif - if (n & EPT_RX(0)) - handle_setup(); - - n = readl(&udc->epcomp); - if (n != 0) - writel(n, &udc->epcomp); - - for (i = 0; i < NUM_ENDPOINTS && n; i++) { - if (controller.ep[i].desc) { - num = controller.ep[i].desc->bEndpointAddress - & USB_ENDPOINT_NUMBER_MASK; - in = (controller.ep[i].desc->bEndpointAddress - & USB_DIR_IN) != 0; - bit = (in) ? EPT_TX(num) : EPT_RX(num); - if (n & bit) - handle_ep_complete(&controller.ep[i]); - } - } - } -} - -int usb_gadget_handle_interrupts(void) -{ - u32 value; - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - - value = readl(&udc->usbsts); - if (value) - udc_irq(); - - return value; -} - -static int ci_pullup(struct usb_gadget *gadget, int is_on) -{ - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - if (is_on) { - /* RESET */ - writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RST, &udc->usbcmd); - udelay(200); - - writel((unsigned)controller.epts, &udc->epinitaddr); - - /* select DEVICE mode */ - writel(USBMODE_DEVICE, &udc->usbmode); - - writel(0xffffffff, &udc->epflush); - - /* Turn on the USB connection by enabling the pullup resistor */ - writel(USBCMD_ITC(MICRO_8FRAME) | USBCMD_RUN, &udc->usbcmd); - } else { - stop_activity(); - writel(USBCMD_FS2, &udc->usbcmd); - udelay(800); - if (controller.driver) - controller.driver->disconnect(gadget); - } - - return 0; -} - -void udc_disconnect(void) -{ - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - /* disable pullup */ - stop_activity(); - writel(USBCMD_FS2, &udc->usbcmd); - udelay(800); - if (controller.driver) - controller.driver->disconnect(&controller.gadget); -} - -static int ci_udc_probe(void) -{ - struct ept_queue_head *head; - uint8_t *imem; - int i; - - const int num = 2 * NUM_ENDPOINTS; - - const int eplist_min_align = 4096; - const int eplist_align = roundup(eplist_min_align, ARCH_DMA_MINALIGN); - const int eplist_raw_sz = num * sizeof(struct ept_queue_head); - const int eplist_sz = roundup(eplist_raw_sz, ARCH_DMA_MINALIGN); - - const int ilist_align = roundup(ARCH_DMA_MINALIGN, 32); - const int ilist_ent_raw_sz = 2 * sizeof(struct ept_queue_item); - const int ilist_ent_sz = roundup(ilist_ent_raw_sz, ARCH_DMA_MINALIGN); - const int ilist_sz = NUM_ENDPOINTS * ilist_ent_sz; - - /* The QH list must be aligned to 4096 bytes. */ - controller.epts = memalign(eplist_align, eplist_sz); - if (!controller.epts) - return -ENOMEM; - memset(controller.epts, 0, eplist_sz); - - /* - * Each qTD item must be 32-byte aligned, each qTD touple must be - * cacheline aligned. There are two qTD items for each endpoint and - * only one of them is used for the endpoint at time, so we can group - * them together. - */ - controller.items_mem = memalign(ilist_align, ilist_sz); - if (!controller.items_mem) { - free(controller.epts); - return -ENOMEM; - } - memset(controller.items_mem, 0, ilist_sz); - - for (i = 0; i < 2 * NUM_ENDPOINTS; i++) { - /* - * Configure QH for each endpoint. The structure of the QH list - * is such that each two subsequent fields, N and N+1 where N is - * even, in the QH list represent QH for one endpoint. The Nth - * entry represents OUT configuration and the N+1th entry does - * represent IN configuration of the endpoint. - */ - head = controller.epts + i; - if (i < 2) - head->config = CONFIG_MAX_PKT(EP0_MAX_PACKET_SIZE) - | CONFIG_ZLT | CONFIG_IOS; - else - head->config = CONFIG_MAX_PKT(EP_MAX_PACKET_SIZE) - | CONFIG_ZLT; - head->next = TERMINATE; - head->info = 0; - - imem = controller.items_mem + ((i >> 1) * ilist_ent_sz); - if (i & 1) - imem += sizeof(struct ept_queue_item); - - controller.items[i] = (struct ept_queue_item *)imem; - - if (i & 1) { - ci_flush_qh(i - 1); - ci_flush_qtd(i - 1); - } - } - - INIT_LIST_HEAD(&controller.gadget.ep_list); - - /* Init EP 0 */ - memcpy(&controller.ep[0].ep, &ci_ep_init[0], sizeof(*ci_ep_init)); - controller.ep[0].desc = &ep0_in_desc; - controller.gadget.ep0 = &controller.ep[0].ep; - INIT_LIST_HEAD(&controller.gadget.ep0->ep_list); - - /* Init EP 1..n */ - for (i = 1; i < NUM_ENDPOINTS; i++) { - memcpy(&controller.ep[i].ep, &ci_ep_init[1], - sizeof(*ci_ep_init)); - list_add_tail(&controller.ep[i].ep.ep_list, - &controller.gadget.ep_list); - } - - return 0; -} - -int usb_gadget_register_driver(struct usb_gadget_driver *driver) -{ - int ret; - - if (!driver) - return -EINVAL; - if (!driver->bind || !driver->setup || !driver->disconnect) - return -EINVAL; - if (driver->speed != USB_SPEED_FULL && driver->speed != USB_SPEED_HIGH) - return -EINVAL; - - ret = usb_lowlevel_init(0, USB_INIT_DEVICE, (void **)&controller.ctrl); - if (ret) - return ret; - - ret = ci_udc_probe(); -#if defined(CONFIG_USB_EHCI_MX6) || defined(CONFIG_USB_EHCI_MXS) - /* - * FIXME: usb_lowlevel_init()->ehci_hcd_init() should be doing all - * HW-specific initialization, e.g. ULPI-vs-UTMI PHY selection - */ - if (!ret) { - struct ci_udc *udc = (struct ci_udc *)controller.ctrl->hcor; - - /* select ULPI phy */ - writel(PTS(PTS_ENABLE) | PFSC, &udc->portsc); - } -#endif - - ret = driver->bind(&controller.gadget); - if (ret) { - DBG("driver->bind() returned %d\n", ret); - return ret; - } - controller.driver = driver; - - return 0; -} - -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - return 0; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/ci_udc.h b/qemu/roms/u-boot/drivers/usb/gadget/ci_udc.h deleted file mode 100644 index 4425fd934..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/ci_udc.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2011, Marvell Semiconductor Inc. - * - * Licensed under the GPL-2 or later. - */ -#ifndef __GADGET__CI_UDC_H__ -#define __GADGET__CI_UDC_H__ - -#define NUM_ENDPOINTS 6 - -#ifdef CONFIG_CI_UDC_HAS_HOSTPC -struct ci_udc { - u32 usbcmd; /* 0x130 */ - u32 usbsts; /* 0x134 */ - u32 pad1[3]; - u32 devaddr; /* 0x144 */ - u32 epinitaddr; /* 0x148 */ - u32 pad2[10]; - u32 portsc; /* 0x174 */ - u32 pad178[(0x1b4 - (0x174 + 4)) / 4]; - u32 hostpc1_devlc; /* 0x1b4 */ - u32 pad1b8[(0x1f8 - (0x1b4 + 4)) / 4]; - u32 usbmode; /* 0x1f8 */ - u32 pad1fc[(0x208 - (0x1f8 + 4)) / 4]; - u32 epsetupstat; /* 0x208 */ - u32 epprime; /* 0x20c */ - u32 epflush; /* 0x210 */ - u32 epstat; /* 0x214 */ - u32 epcomp; /* 0x218 */ - u32 epctrl[16]; /* 0x21c */ -}; -#else -struct ci_udc { - u32 usbcmd; /* 0x140 */ - u32 usbsts; /* 0x144 */ - u32 pad1[3]; - u32 devaddr; /* 0x154 */ - u32 epinitaddr; /* 0x158 */ - u32 pad2[10]; - u32 portsc; /* 0x184 */ - u32 pad3[8]; - u32 usbmode; /* 0x1a8 */ - u32 epstat; /* 0x1ac */ - u32 epprime; /* 0x1b0 */ - u32 epflush; /* 0x1b4 */ - u32 pad4; - u32 epcomp; /* 0x1bc */ - u32 epctrl[16]; /* 0x1c0 */ -}; - -#define PTS_ENABLE 2 -#define PTS(x) (((x) & 0x3) << 30) -#define PFSC (1 << 24) -#endif - -#define MICRO_8FRAME 0x8 -#define USBCMD_ITC(x) ((((x) > 0xff) ? 0xff : x) << 16) -#define USBCMD_FS2 (1 << 15) -#define USBCMD_RST (1 << 1) -#define USBCMD_RUN (1) - -#define STS_SLI (1 << 8) -#define STS_URI (1 << 6) -#define STS_PCI (1 << 2) -#define STS_UEI (1 << 1) -#define STS_UI (1 << 0) - -#define USBMODE_DEVICE 2 - -#define EPT_TX(x) (1 << (((x) & 0xffff) + 16)) -#define EPT_RX(x) (1 << ((x) & 0xffff)) - -#define CTRL_TXE (1 << 23) -#define CTRL_TXR (1 << 22) -#define CTRL_RXE (1 << 7) -#define CTRL_RXR (1 << 6) -#define CTRL_TXT_BULK (2 << 18) -#define CTRL_RXT_BULK (2 << 2) - -struct ci_ep { - struct usb_ep ep; - struct list_head queue; - const struct usb_endpoint_descriptor *desc; - - struct usb_request req; - uint8_t *b_buf; - uint32_t b_len; - uint8_t b_fast[64] __aligned(ARCH_DMA_MINALIGN); -}; - -struct ci_drv { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct ehci_ctrl *ctrl; - struct ept_queue_head *epts; - struct ept_queue_item *items[2 * NUM_ENDPOINTS]; - uint8_t *items_mem; - struct ci_ep ep[NUM_ENDPOINTS]; -}; - -struct ept_queue_head { - unsigned config; - unsigned current; /* read-only */ - - unsigned next; - unsigned info; - unsigned page0; - unsigned page1; - unsigned page2; - unsigned page3; - unsigned page4; - unsigned reserved_0; - - unsigned char setup_data[8]; - - unsigned reserved_1; - unsigned reserved_2; - unsigned reserved_3; - unsigned reserved_4; -}; - -#define CONFIG_MAX_PKT(n) ((n) << 16) -#define CONFIG_ZLT (1 << 29) /* stop on zero-len xfer */ -#define CONFIG_IOS (1 << 15) /* IRQ on setup */ - -struct ept_queue_item { - unsigned next; - unsigned info; - unsigned page0; - unsigned page1; - unsigned page2; - unsigned page3; - unsigned page4; - unsigned reserved; -}; - -#define TERMINATE 1 -#define INFO_BYTES(n) ((n) << 16) -#define INFO_IOC (1 << 15) -#define INFO_ACTIVE (1 << 7) -#define INFO_HALTED (1 << 6) -#define INFO_BUFFER_ERROR (1 << 5) -#define INFO_TX_ERROR (1 << 3) -#endif diff --git a/qemu/roms/u-boot/drivers/usb/gadget/composite.c b/qemu/roms/u-boot/drivers/usb/gadget/composite.c deleted file mode 100644 index 7bd25629c..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/composite.c +++ /dev/null @@ -1,1091 +0,0 @@ -/* - * composite.c - infrastructure for Composite USB Gadgets - * - * Copyright (C) 2006-2008 David Brownell - * U-boot porting: Lukasz Majewski <l.majewski@samsung.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#undef DEBUG - -#include <linux/bitops.h> -#include <linux/usb/composite.h> - -#define USB_BUFSIZ 4096 - -static struct usb_composite_driver *composite; - -/** - * usb_add_function() - add a function to a configuration - * @config: the configuration - * @function: the function being added - * Context: single threaded during gadget setup - * - * After initialization, each configuration must have one or more - * functions added to it. Adding a function involves calling its @bind() - * method to allocate resources such as interface and string identifiers - * and endpoints. - * - * This function returns the value of the function's bind(), which is - * zero for success else a negative errno value. - */ -int usb_add_function(struct usb_configuration *config, - struct usb_function *function) -{ - int value = -EINVAL; - - debug("adding '%s'/%p to config '%s'/%p\n", - function->name, function, - config->label, config); - - if (!function->set_alt || !function->disable) - goto done; - - function->config = config; - list_add_tail(&function->list, &config->functions); - - if (function->bind) { - value = function->bind(config, function); - if (value < 0) { - list_del(&function->list); - function->config = NULL; - } - } else - value = 0; - - if (!config->fullspeed && function->descriptors) - config->fullspeed = 1; - if (!config->highspeed && function->hs_descriptors) - config->highspeed = 1; - -done: - if (value) - debug("adding '%s'/%p --> %d\n", - function->name, function, value); - return value; -} - -/** - * usb_function_deactivate - prevent function and gadget enumeration - * @function: the function that isn't yet ready to respond - * - * Blocks response of the gadget driver to host enumeration by - * preventing the data line pullup from being activated. This is - * normally called during @bind() processing to change from the - * initial "ready to respond" state, or when a required resource - * becomes available. - * - * For example, drivers that serve as a passthrough to a userspace - * daemon can block enumeration unless that daemon (such as an OBEX, - * MTP, or print server) is ready to handle host requests. - * - * Not all systems support software control of their USB peripheral - * data pullups. - * - * Returns zero on success, else negative errno. - */ -int usb_function_deactivate(struct usb_function *function) -{ - struct usb_composite_dev *cdev = function->config->cdev; - int status = 0; - - if (cdev->deactivations == 0) - status = usb_gadget_disconnect(cdev->gadget); - if (status == 0) - cdev->deactivations++; - - return status; -} - -/** - * usb_function_activate - allow function and gadget enumeration - * @function: function on which usb_function_activate() was called - * - * Reverses effect of usb_function_deactivate(). If no more functions - * are delaying their activation, the gadget driver will respond to - * host enumeration procedures. - * - * Returns zero on success, else negative errno. - */ -int usb_function_activate(struct usb_function *function) -{ - struct usb_composite_dev *cdev = function->config->cdev; - int status = 0; - - if (cdev->deactivations == 0) - status = -EINVAL; - else { - cdev->deactivations--; - if (cdev->deactivations == 0) - status = usb_gadget_connect(cdev->gadget); - } - - return status; -} - -/** - * usb_interface_id() - allocate an unused interface ID - * @config: configuration associated with the interface - * @function: function handling the interface - * Context: single threaded during gadget setup - * - * usb_interface_id() is called from usb_function.bind() callbacks to - * allocate new interface IDs. The function driver will then store that - * ID in interface, association, CDC union, and other descriptors. It - * will also handle any control requests targetted at that interface, - * particularly changing its altsetting via set_alt(). There may - * also be class-specific or vendor-specific requests to handle. - * - * All interface identifier should be allocated using this routine, to - * ensure that for example different functions don't wrongly assign - * different meanings to the same identifier. Note that since interface - * identifers are configuration-specific, functions used in more than - * one configuration (or more than once in a given configuration) need - * multiple versions of the relevant descriptors. - * - * Returns the interface ID which was allocated; or -ENODEV if no - * more interface IDs can be allocated. - */ -int usb_interface_id(struct usb_configuration *config, - struct usb_function *function) -{ - unsigned char id = config->next_interface_id; - - if (id < MAX_CONFIG_INTERFACES) { - config->interface[id] = function; - config->next_interface_id = id + 1; - return id; - } - return -ENODEV; -} - -static int config_buf(struct usb_configuration *config, - enum usb_device_speed speed, void *buf, u8 type) -{ - int len = USB_BUFSIZ - USB_DT_CONFIG_SIZE; - void *next = buf + USB_DT_CONFIG_SIZE; - struct usb_descriptor_header **descriptors; - struct usb_config_descriptor *c = buf; - int status; - struct usb_function *f; - - /* write the config descriptor */ - c = buf; - c->bLength = USB_DT_CONFIG_SIZE; - c->bDescriptorType = type; - - c->bNumInterfaces = config->next_interface_id; - c->bConfigurationValue = config->bConfigurationValue; - c->iConfiguration = config->iConfiguration; - c->bmAttributes = USB_CONFIG_ATT_ONE | config->bmAttributes; - c->bMaxPower = config->bMaxPower ? : (CONFIG_USB_GADGET_VBUS_DRAW / 2); - - /* There may be e.g. OTG descriptors */ - if (config->descriptors) { - status = usb_descriptor_fillbuf(next, len, - config->descriptors); - if (status < 0) - return status; - len -= status; - next += status; - } - - /* add each function's descriptors */ - list_for_each_entry(f, &config->functions, list) { - if (speed == USB_SPEED_HIGH) - descriptors = f->hs_descriptors; - else - descriptors = f->descriptors; - if (!descriptors) - continue; - status = usb_descriptor_fillbuf(next, len, - (const struct usb_descriptor_header **) descriptors); - if (status < 0) - return status; - len -= status; - next += status; - } - - len = next - buf; - c->wTotalLength = cpu_to_le16(len); - return len; -} - -static int config_desc(struct usb_composite_dev *cdev, unsigned w_value) -{ - enum usb_device_speed speed = USB_SPEED_UNKNOWN; - struct usb_gadget *gadget = cdev->gadget; - u8 type = w_value >> 8; - int hs = 0; - struct usb_configuration *c; - - if (gadget_is_dualspeed(gadget)) { - if (gadget->speed == USB_SPEED_HIGH) - hs = 1; - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - if (hs) - speed = USB_SPEED_HIGH; - } - - w_value &= 0xff; - list_for_each_entry(c, &cdev->configs, list) { - if (speed == USB_SPEED_HIGH) { - if (!c->highspeed) - continue; - } else { - if (!c->fullspeed) - continue; - } - if (w_value == 0) - return config_buf(c, speed, cdev->req->buf, type); - w_value--; - } - return -EINVAL; -} - -static int count_configs(struct usb_composite_dev *cdev, unsigned type) -{ - struct usb_gadget *gadget = cdev->gadget; - unsigned count = 0; - int hs = 0; - struct usb_configuration *c; - - if (gadget_is_dualspeed(gadget)) { - if (gadget->speed == USB_SPEED_HIGH) - hs = 1; - if (type == USB_DT_DEVICE_QUALIFIER) - hs = !hs; - } - list_for_each_entry(c, &cdev->configs, list) { - /* ignore configs that won't work at this speed */ - if (hs) { - if (!c->highspeed) - continue; - } else { - if (!c->fullspeed) - continue; - } - count++; - } - return count; -} - -static void device_qual(struct usb_composite_dev *cdev) -{ - struct usb_qualifier_descriptor *qual = cdev->req->buf; - - qual->bLength = sizeof(*qual); - qual->bDescriptorType = USB_DT_DEVICE_QUALIFIER; - /* POLICY: same bcdUSB and device type info at both speeds */ - qual->bcdUSB = cdev->desc.bcdUSB; - qual->bDeviceClass = cdev->desc.bDeviceClass; - qual->bDeviceSubClass = cdev->desc.bDeviceSubClass; - qual->bDeviceProtocol = cdev->desc.bDeviceProtocol; - /* ASSUME same EP0 fifo size at both speeds */ - qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0; - qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER); - qual->bRESERVED = 0; -} - -static void reset_config(struct usb_composite_dev *cdev) -{ - struct usb_function *f; - - debug("%s:\n", __func__); - - list_for_each_entry(f, &cdev->config->functions, list) { - if (f->disable) - f->disable(f); - - bitmap_zero(f->endpoints, 32); - } - cdev->config = NULL; -} - -static int set_config(struct usb_composite_dev *cdev, - const struct usb_ctrlrequest *ctrl, unsigned number) -{ - struct usb_gadget *gadget = cdev->gadget; - unsigned power = gadget_is_otg(gadget) ? 8 : 100; - struct usb_descriptor_header **descriptors; - int result = -EINVAL; - struct usb_endpoint_descriptor *ep; - struct usb_configuration *c = NULL; - int addr; - int tmp; - struct usb_function *f; - - if (cdev->config) - reset_config(cdev); - - if (number) { - list_for_each_entry(c, &cdev->configs, list) { - if (c->bConfigurationValue == number) { - result = 0; - break; - } - } - if (result < 0) - goto done; - } else - result = 0; - - debug("%s: %s speed config #%d: %s\n", __func__, - ({ char *speed; - switch (gadget->speed) { - case USB_SPEED_LOW: - speed = "low"; - break; - case USB_SPEED_FULL: - speed = "full"; - break; - case USB_SPEED_HIGH: - speed = "high"; - break; - default: - speed = "?"; - break; - }; - speed; - }), number, c ? c->label : "unconfigured"); - - if (!c) - goto done; - - cdev->config = c; - - /* Initialize all interfaces by setting them to altsetting zero. */ - for (tmp = 0; tmp < MAX_CONFIG_INTERFACES; tmp++) { - f = c->interface[tmp]; - if (!f) - break; - - /* - * Record which endpoints are used by the function. This is used - * to dispatch control requests targeted at that endpoint to the - * function's setup callback instead of the current - * configuration's setup callback. - */ - if (gadget->speed == USB_SPEED_HIGH) - descriptors = f->hs_descriptors; - else - descriptors = f->descriptors; - - for (; *descriptors; ++descriptors) { - if ((*descriptors)->bDescriptorType != USB_DT_ENDPOINT) - continue; - - ep = (struct usb_endpoint_descriptor *)*descriptors; - addr = ((ep->bEndpointAddress & 0x80) >> 3) - | (ep->bEndpointAddress & 0x0f); - __set_bit(addr, f->endpoints); - } - - result = f->set_alt(f, tmp, 0); - if (result < 0) { - debug("interface %d (%s/%p) alt 0 --> %d\n", - tmp, f->name, f, result); - - reset_config(cdev); - goto done; - } - } - - /* when we return, be sure our power usage is valid */ - power = c->bMaxPower ? (2 * c->bMaxPower) : CONFIG_USB_GADGET_VBUS_DRAW; -done: - usb_gadget_vbus_draw(gadget, power); - return result; -} - -/** - * usb_add_config() - add a configuration to a device. - * @cdev: wraps the USB gadget - * @config: the configuration, with bConfigurationValue assigned - * Context: single threaded during gadget setup - * - * One of the main tasks of a composite driver's bind() routine is to - * add each of the configurations it supports, using this routine. - * - * This function returns the value of the configuration's bind(), which - * is zero for success else a negative errno value. Binding configurations - * assigns global resources including string IDs, and per-configuration - * resources such as interface IDs and endpoints. - */ -int usb_add_config(struct usb_composite_dev *cdev, - struct usb_configuration *config) -{ - int status = -EINVAL; - struct usb_configuration *c; - struct usb_function *f; - unsigned int i; - - debug("%s: adding config #%u '%s'/%p\n", __func__, - config->bConfigurationValue, - config->label, config); - - if (!config->bConfigurationValue || !config->bind) - goto done; - - /* Prevent duplicate configuration identifiers */ - list_for_each_entry(c, &cdev->configs, list) { - if (c->bConfigurationValue == config->bConfigurationValue) { - status = -EBUSY; - goto done; - } - } - - config->cdev = cdev; - list_add_tail(&config->list, &cdev->configs); - - INIT_LIST_HEAD(&config->functions); - config->next_interface_id = 0; - - status = config->bind(config); - if (status < 0) { - list_del(&config->list); - config->cdev = NULL; - } else { - debug("cfg %d/%p speeds:%s%s\n", - config->bConfigurationValue, config, - config->highspeed ? " high" : "", - config->fullspeed - ? (gadget_is_dualspeed(cdev->gadget) - ? " full" - : " full/low") - : ""); - - for (i = 0; i < MAX_CONFIG_INTERFACES; i++) { - f = config->interface[i]; - if (!f) - continue; - debug("%s: interface %d = %s/%p\n", - __func__, i, f->name, f); - } - } - - usb_ep_autoconfig_reset(cdev->gadget); - -done: - if (status) - debug("added config '%s'/%u --> %d\n", config->label, - config->bConfigurationValue, status); - return status; -} - -/* - * We support strings in multiple languages ... string descriptor zero - * says which languages are supported. The typical case will be that - * only one language (probably English) is used, with I18N handled on - * the host side. - */ - -static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf) -{ - const struct usb_gadget_strings *s; - u16 language; - __le16 *tmp; - - while (*sp) { - s = *sp; - language = cpu_to_le16(s->language); - for (tmp = buf; *tmp && tmp < &buf[126]; tmp++) { - if (*tmp == language) - goto repeat; - } - *tmp++ = language; -repeat: - sp++; - } -} - -static int lookup_string( - struct usb_gadget_strings **sp, - void *buf, - u16 language, - int id -) -{ - int value; - struct usb_gadget_strings *s; - - while (*sp) { - s = *sp++; - if (s->language != language) - continue; - value = usb_gadget_get_string(s, id, buf); - if (value > 0) - return value; - } - return -EINVAL; -} - -static int get_string(struct usb_composite_dev *cdev, - void *buf, u16 language, int id) -{ - struct usb_string_descriptor *s = buf; - struct usb_gadget_strings **sp; - int len; - struct usb_configuration *c; - struct usb_function *f; - - /* - * Yes, not only is USB's I18N support probably more than most - * folk will ever care about ... also, it's all supported here. - * (Except for UTF8 support for Unicode's "Astral Planes".) - */ - - /* 0 == report all available language codes */ - if (id == 0) { - memset(s, 0, 256); - s->bDescriptorType = USB_DT_STRING; - - sp = composite->strings; - if (sp) - collect_langs(sp, s->wData); - - list_for_each_entry(c, &cdev->configs, list) { - sp = c->strings; - if (sp) - collect_langs(sp, s->wData); - - list_for_each_entry(f, &c->functions, list) { - sp = f->strings; - if (sp) - collect_langs(sp, s->wData); - } - } - - for (len = 0; len <= 126 && s->wData[len]; len++) - continue; - if (!len) - return -EINVAL; - - s->bLength = 2 * (len + 1); - return s->bLength; - } - - /* - * Otherwise, look up and return a specified string. String IDs - * are device-scoped, so we look up each string table we're told - * about. These lookups are infrequent; simpler-is-better here. - */ - if (composite->strings) { - len = lookup_string(composite->strings, buf, language, id); - if (len > 0) - return len; - } - list_for_each_entry(c, &cdev->configs, list) { - if (c->strings) { - len = lookup_string(c->strings, buf, language, id); - if (len > 0) - return len; - } - list_for_each_entry(f, &c->functions, list) { - if (!f->strings) - continue; - len = lookup_string(f->strings, buf, language, id); - if (len > 0) - return len; - } - } - return -EINVAL; -} - -/** - * usb_string_id() - allocate an unused string ID - * @cdev: the device whose string descriptor IDs are being allocated - * Context: single threaded during gadget setup - * - * @usb_string_id() is called from bind() callbacks to allocate - * string IDs. Drivers for functions, configurations, or gadgets will - * then store that ID in the appropriate descriptors and string table. - * - * All string identifier should be allocated using this, - * @usb_string_ids_tab() or @usb_string_ids_n() routine, to ensure - * that for example different functions don't wrongly assign different - * meanings to the same identifier. - */ -int usb_string_id(struct usb_composite_dev *cdev) -{ - if (cdev->next_string_id < 254) { - /* - * string id 0 is reserved by USB spec for list of - * supported languages - * 255 reserved as well? -- mina86 - */ - cdev->next_string_id++; - return cdev->next_string_id; - } - return -ENODEV; -} - -/** - * usb_string_ids() - allocate unused string IDs in batch - * @cdev: the device whose string descriptor IDs are being allocated - * @str: an array of usb_string objects to assign numbers to - * Context: single threaded during gadget setup - * - * @usb_string_ids() is called from bind() callbacks to allocate - * string IDs. Drivers for functions, configurations, or gadgets will - * then copy IDs from the string table to the appropriate descriptors - * and string table for other languages. - * - * All string identifier should be allocated using this, - * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for - * example different functions don't wrongly assign different meanings - * to the same identifier. - */ -int usb_string_ids_tab(struct usb_composite_dev *cdev, struct usb_string *str) -{ - u8 next = cdev->next_string_id; - - for (; str->s; ++str) { - if (next >= 254) - return -ENODEV; - str->id = ++next; - } - - cdev->next_string_id = next; - - return 0; -} - -/** - * usb_string_ids_n() - allocate unused string IDs in batch - * @c: the device whose string descriptor IDs are being allocated - * @n: number of string IDs to allocate - * Context: single threaded during gadget setup - * - * Returns the first requested ID. This ID and next @n-1 IDs are now - * valid IDs. At least provided that @n is non-zero because if it - * is, returns last requested ID which is now very useful information. - * - * @usb_string_ids_n() is called from bind() callbacks to allocate - * string IDs. Drivers for functions, configurations, or gadgets will - * then store that ID in the appropriate descriptors and string table. - * - * All string identifier should be allocated using this, - * @usb_string_id() or @usb_string_ids_n() routine, to ensure that for - * example different functions don't wrongly assign different meanings - * to the same identifier. - */ -int usb_string_ids_n(struct usb_composite_dev *c, unsigned n) -{ - u8 next = c->next_string_id; - - if (n > 254 || next + n > 254) - return -ENODEV; - - c->next_string_id += n; - return next + 1; -} - -static void composite_setup_complete(struct usb_ep *ep, struct usb_request *req) -{ - if (req->status || req->actual != req->length) - debug("%s: setup complete --> %d, %d/%d\n", __func__, - req->status, req->actual, req->length); -} - -/* - * The setup() callback implements all the ep0 functionality that's - * not handled lower down, in hardware or the hardware driver(like - * device and endpoint feature flags, and their status). It's all - * housekeeping for the gadget function we're implementing. Most of - * the work is in config and function specific setup. - */ -static int -composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) -{ - u16 w_length = le16_to_cpu(ctrl->wLength); - u16 w_index = le16_to_cpu(ctrl->wIndex); - u16 w_value = le16_to_cpu(ctrl->wValue); - struct usb_composite_dev *cdev = get_gadget_data(gadget); - u8 intf = w_index & 0xFF; - int value = -EOPNOTSUPP; - struct usb_request *req = cdev->req; - struct usb_function *f = NULL; - int standard; - u8 endp; - struct usb_configuration *c; - - /* - * partial re-init of the response message; the function or the - * gadget might need to intercept e.g. a control-OUT completion - * when we delegate to it. - */ - req->zero = 0; - req->complete = composite_setup_complete; - req->length = USB_BUFSIZ; - gadget->ep0->driver_data = cdev; - standard = (ctrl->bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD; - if (!standard) - goto unknown; - - switch (ctrl->bRequest) { - - /* we handle all standard USB descriptors */ - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != USB_DIR_IN) - goto unknown; - switch (w_value >> 8) { - - case USB_DT_DEVICE: - cdev->desc.bNumConfigurations = - count_configs(cdev, USB_DT_DEVICE); - value = min(w_length, (u16) sizeof cdev->desc); - memcpy(req->buf, &cdev->desc, value); - break; - case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget)) - break; - device_qual(cdev); - value = min(w_length, - sizeof(struct usb_qualifier_descriptor)); - break; - case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget_is_dualspeed(gadget)) - break; - - case USB_DT_CONFIG: - value = config_desc(cdev, w_value); - if (value >= 0) - value = min(w_length, (u16) value); - break; - case USB_DT_STRING: - value = get_string(cdev, req->buf, - w_index, w_value & 0xff); - if (value >= 0) - value = min(w_length, (u16) value); - break; - default: - goto unknown; - } - break; - - /* any number of configs can work */ - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != 0) - goto unknown; - if (gadget_is_otg(gadget)) { - if (gadget->a_hnp_support) - debug("HNP available\n"); - else if (gadget->a_alt_hnp_support) - debug("HNP on another port\n"); - else - debug("HNP inactive\n"); - } - - value = set_config(cdev, ctrl, w_value); - break; - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != USB_DIR_IN) - goto unknown; - if (cdev->config) - *(u8 *)req->buf = cdev->config->bConfigurationValue; - else - *(u8 *)req->buf = 0; - value = min(w_length, (u16) 1); - break; - - /* - * function drivers must handle get/set altsetting; if there's - * no get() method, we know only altsetting zero works. - */ - case USB_REQ_SET_INTERFACE: - if (ctrl->bRequestType != USB_RECIP_INTERFACE) - goto unknown; - if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) - break; - f = cdev->config->interface[intf]; - if (!f) - break; - if (w_value && !f->set_alt) - break; - value = f->set_alt(f, w_index, w_value); - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) - goto unknown; - if (!cdev->config || w_index >= MAX_CONFIG_INTERFACES) - break; - f = cdev->config->interface[intf]; - if (!f) - break; - /* lots of interfaces only need altsetting zero... */ - value = f->get_alt ? f->get_alt(f, w_index) : 0; - if (value < 0) - break; - *((u8 *)req->buf) = value; - value = min(w_length, (u16) 1); - break; - default: -unknown: - debug("non-core control req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, - w_value, w_index, w_length); - - /* - * functions always handle their interfaces and endpoints... - * punt other recipients (other, WUSB, ...) to the current - * configuration code. - */ - switch (ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_INTERFACE: - f = cdev->config->interface[intf]; - break; - - case USB_RECIP_ENDPOINT: - endp = ((w_index & 0x80) >> 3) | (w_index & 0x0f); - list_for_each_entry(f, &cdev->config->functions, list) { - if (test_bit(endp, f->endpoints)) - break; - } - if (&f->list == &cdev->config->functions) - f = NULL; - break; - /* - * dfu-util (version 0.5) sets bmRequestType.Receipent = Device - * for non-standard request (w_value = 0x21, - * bRequest = GET_DESCRIPTOR in this case). - * When only one interface is registered (as it is done now), - * then this request shall be handled as it was requested for - * interface. - * - * In the below code it is checked if only one interface is - * present and proper function for it is extracted. Due to that - * function's setup (f->setup) is called to handle this - * special non-standard request. - */ - case USB_RECIP_DEVICE: - debug("cdev->config->next_interface_id: %d intf: %d\n", - cdev->config->next_interface_id, intf); - if (cdev->config->next_interface_id == 1) - f = cdev->config->interface[intf]; - break; - } - - if (f && f->setup) - value = f->setup(f, ctrl); - else { - c = cdev->config; - if (c && c->setup) - value = c->setup(c, ctrl); - } - - goto done; - } - - /* respond with data transfer before status phase? */ - if (value >= 0) { - req->length = value; - req->zero = value < w_length; - value = usb_ep_queue(gadget->ep0, req, GFP_KERNEL); - if (value < 0) { - debug("ep_queue --> %d\n", value); - req->status = 0; - composite_setup_complete(gadget->ep0, req); - } - } - -done: - /* device either stalls (value < 0) or reports success */ - return value; -} - -static void composite_disconnect(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - - if (cdev->config) - reset_config(cdev); - if (composite->disconnect) - composite->disconnect(cdev); -} - -static void composite_unbind(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct usb_configuration *c; - struct usb_function *f; - - /* - * composite_disconnect() must already have been called - * by the underlying peripheral controller driver! - * so there's no i/o concurrency that could affect the - * state protected by cdev->lock. - */ - BUG_ON(cdev->config); - - while (!list_empty(&cdev->configs)) { - c = list_first_entry(&cdev->configs, - struct usb_configuration, list); - while (!list_empty(&c->functions)) { - f = list_first_entry(&c->functions, - struct usb_function, list); - list_del(&f->list); - if (f->unbind) { - debug("unbind function '%s'/%p\n", - f->name, f); - f->unbind(c, f); - } - } - list_del(&c->list); - if (c->unbind) { - debug("unbind config '%s'/%p\n", c->label, c); - c->unbind(c); - } - } - if (composite->unbind) - composite->unbind(cdev); - - if (cdev->req) { - kfree(cdev->req->buf); - usb_ep_free_request(gadget->ep0, cdev->req); - } - kfree(cdev); - set_gadget_data(gadget, NULL); - - composite = NULL; -} - -static int composite_bind(struct usb_gadget *gadget) -{ - int status = -ENOMEM; - struct usb_composite_dev *cdev; - - cdev = calloc(sizeof *cdev, 1); - if (!cdev) - return status; - - cdev->gadget = gadget; - set_gadget_data(gadget, cdev); - INIT_LIST_HEAD(&cdev->configs); - - /* preallocate control response and buffer */ - cdev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); - if (!cdev->req) - goto fail; - cdev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, USB_BUFSIZ); - if (!cdev->req->buf) - goto fail; - cdev->req->complete = composite_setup_complete; - gadget->ep0->driver_data = cdev; - - cdev->bufsiz = USB_BUFSIZ; - cdev->driver = composite; - - usb_gadget_set_selfpowered(gadget); - usb_ep_autoconfig_reset(cdev->gadget); - - status = composite->bind(cdev); - if (status < 0) - goto fail; - - memcpy(&cdev->desc, composite->dev, - sizeof(struct usb_device_descriptor)); - cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - - debug("%s: ready\n", composite->name); - return 0; - -fail: - composite_unbind(gadget); - return status; -} - -static void -composite_suspend(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct usb_function *f; - - debug("%s: suspend\n", __func__); - if (cdev->config) { - list_for_each_entry(f, &cdev->config->functions, list) { - if (f->suspend) - f->suspend(f); - } - } - if (composite->suspend) - composite->suspend(cdev); - - cdev->suspended = 1; -} - -static void -composite_resume(struct usb_gadget *gadget) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct usb_function *f; - - debug("%s: resume\n", __func__); - if (composite->resume) - composite->resume(cdev); - if (cdev->config) { - list_for_each_entry(f, &cdev->config->functions, list) { - if (f->resume) - f->resume(f); - } - } - - cdev->suspended = 0; -} - -static struct usb_gadget_driver composite_driver = { - .speed = USB_SPEED_HIGH, - - .bind = composite_bind, - .unbind = composite_unbind, - - .setup = composite_setup, - .disconnect = composite_disconnect, - - .suspend = composite_suspend, - .resume = composite_resume, -}; - -/** - * usb_composite_register() - register a composite driver - * @driver: the driver to register - * Context: single threaded during gadget setup - * - * This function is used to register drivers using the composite driver - * framework. The return value is zero, or a negative errno value. - * Those values normally come from the driver's @bind method, which does - * all the work of setting up the driver to match the hardware. - * - * On successful return, the gadget is ready to respond to requests from - * the host, unless one of its components invokes usb_gadget_disconnect() - * while it was binding. That would usually be done in order to wait for - * some userspace participation. - */ -int usb_composite_register(struct usb_composite_driver *driver) -{ - if (!driver || !driver->dev || !driver->bind || composite) - return -EINVAL; - - if (!driver->name) - driver->name = "composite"; - composite = driver; - - return usb_gadget_register_driver(&composite_driver); -} - -/** - * usb_composite_unregister() - unregister a composite driver - * @driver: the driver to unregister - * - * This function is used to unregister drivers using the composite - * driver framework. - */ -void usb_composite_unregister(struct usb_composite_driver *driver) -{ - if (composite != driver) - return; - usb_gadget_unregister_driver(&composite_driver); - composite = NULL; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/config.c b/qemu/roms/u-boot/drivers/usb/gadget/config.c deleted file mode 100644 index 014a6791c..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/config.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * usb/gadget/config.c -- simplify building config descriptors - * - * Copyright (C) 2003 David Brownell - * - * SPDX-License-Identifier: GPL-2.0+ - * - * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and - * Remy Bohmer <linux@bohmer.net> - */ - -#include <common.h> -#include <asm/unaligned.h> -#include <asm/errno.h> -#include <linux/list.h> -#include <linux/string.h> - -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - - -/** - * usb_descriptor_fillbuf - fill buffer with descriptors - * @buf: Buffer to be filled - * @buflen: Size of buf - * @src: Array of descriptor pointers, terminated by null pointer. - * - * Copies descriptors into the buffer, returning the length or a - * negative error code if they can't all be copied. Useful when - * assembling descriptors for an associated set of interfaces used - * as part of configuring a composite device; or in other cases where - * sets of descriptors need to be marshaled. - */ -int -usb_descriptor_fillbuf(void *buf, unsigned buflen, - const struct usb_descriptor_header **src) -{ - u8 *dest = buf; - - if (!src) - return -EINVAL; - - /* fill buffer from src[] until null descriptor ptr */ - for (; NULL != *src; src++) { - unsigned len = (*src)->bLength; - - if (len > buflen) - return -EINVAL; - memcpy(dest, *src, len); - buflen -= len; - dest += len; - } - return dest - (u8 *)buf; -} - - -/** - * usb_gadget_config_buf - builts a complete configuration descriptor - * @config: Header for the descriptor, including characteristics such - * as power requirements and number of interfaces. - * @desc: Null-terminated vector of pointers to the descriptors (interface, - * endpoint, etc) defining all functions in this device configuration. - * @buf: Buffer for the resulting configuration descriptor. - * @length: Length of buffer. If this is not big enough to hold the - * entire configuration descriptor, an error code will be returned. - * - * This copies descriptors into the response buffer, building a descriptor - * for that configuration. It returns the buffer length or a negative - * status code. The config.wTotalLength field is set to match the length - * of the result, but other descriptor fields (including power usage and - * interface count) must be set by the caller. - * - * Gadget drivers could use this when constructing a config descriptor - * in response to USB_REQ_GET_DESCRIPTOR. They will need to patch the - * resulting bDescriptorType value if USB_DT_OTHER_SPEED_CONFIG is needed. - */ -int usb_gadget_config_buf( - const struct usb_config_descriptor *config, - void *buf, - unsigned length, - const struct usb_descriptor_header **desc -) -{ - struct usb_config_descriptor *cp = buf; - int len; - - /* config descriptor first */ - if (length < USB_DT_CONFIG_SIZE || !desc) - return -EINVAL; - /* config need not be aligned */ - memcpy(cp, config, sizeof(*cp)); - - /* then interface/endpoint/class/vendor/... */ - len = usb_descriptor_fillbuf(USB_DT_CONFIG_SIZE + (u8 *)buf, - length - USB_DT_CONFIG_SIZE, desc); - if (len < 0) - return len; - len += USB_DT_CONFIG_SIZE; - if (len > 0xffff) - return -EINVAL; - - /* patch up the config descriptor */ - cp->bLength = USB_DT_CONFIG_SIZE; - cp->bDescriptorType = USB_DT_CONFIG; - put_unaligned_le16(len, &cp->wTotalLength); - cp->bmAttributes |= USB_CONFIG_ATT_ONE; - return len; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/core.c b/qemu/roms/u-boot/drivers/usb/gadget/core.c deleted file mode 100644 index 30d55a49a..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/core.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * (C) Copyright 2003 - * Gerry Hamel, geh@ti.com, Texas Instruments - * - * Based on - * linux/drivers/usbd/usbd.c.c - USB Device Core Layer - * - * Copyright (c) 2000, 2001, 2002 Lineo - * Copyright (c) 2001 Hewlett Packard - * - * By: - * Stuart Lynne <sl@lineo.com>, - * Tom Rushworth <tbr@lineo.com>, - * Bruce Balden <balden@lineo.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <malloc.h> -#include <usbdevice.h> - -#define MAX_INTERFACES 2 - - -int maxstrings = 20; - -/* Global variables ************************************************************************** */ - -struct usb_string_descriptor **usb_strings; - -int usb_devices; - -extern struct usb_function_driver ep0_driver; - -int registered_functions; -int registered_devices; - -char *usbd_device_events[] = { - "DEVICE_UNKNOWN", - "DEVICE_INIT", - "DEVICE_CREATE", - "DEVICE_HUB_CONFIGURED", - "DEVICE_RESET", - "DEVICE_ADDRESS_ASSIGNED", - "DEVICE_CONFIGURED", - "DEVICE_SET_INTERFACE", - "DEVICE_SET_FEATURE", - "DEVICE_CLEAR_FEATURE", - "DEVICE_DE_CONFIGURED", - "DEVICE_BUS_INACTIVE", - "DEVICE_BUS_ACTIVITY", - "DEVICE_POWER_INTERRUPTION", - "DEVICE_HUB_RESET", - "DEVICE_DESTROY", - "DEVICE_FUNCTION_PRIVATE", -}; - -char *usbd_device_states[] = { - "STATE_INIT", - "STATE_CREATED", - "STATE_ATTACHED", - "STATE_POWERED", - "STATE_DEFAULT", - "STATE_ADDRESSED", - "STATE_CONFIGURED", - "STATE_UNKNOWN", -}; - -char *usbd_device_requests[] = { - "GET STATUS", /* 0 */ - "CLEAR FEATURE", /* 1 */ - "RESERVED", /* 2 */ - "SET FEATURE", /* 3 */ - "RESERVED", /* 4 */ - "SET ADDRESS", /* 5 */ - "GET DESCRIPTOR", /* 6 */ - "SET DESCRIPTOR", /* 7 */ - "GET CONFIGURATION", /* 8 */ - "SET CONFIGURATION", /* 9 */ - "GET INTERFACE", /* 10 */ - "SET INTERFACE", /* 11 */ - "SYNC FRAME", /* 12 */ -}; - -char *usbd_device_descriptors[] = { - "UNKNOWN", /* 0 */ - "DEVICE", /* 1 */ - "CONFIG", /* 2 */ - "STRING", /* 3 */ - "INTERFACE", /* 4 */ - "ENDPOINT", /* 5 */ - "DEVICE QUALIFIER", /* 6 */ - "OTHER SPEED", /* 7 */ - "INTERFACE POWER", /* 8 */ -}; - -char *usbd_device_status[] = { - "USBD_OPENING", - "USBD_OK", - "USBD_SUSPENDED", - "USBD_CLOSING", -}; - - -/* Descriptor support functions ************************************************************** */ - - -/** - * usbd_get_string - find and return a string descriptor - * @index: string index to return - * - * Find an indexed string and return a pointer to a it. - */ -struct usb_string_descriptor *usbd_get_string (__u8 index) -{ - if (index >= maxstrings) { - return NULL; - } - return usb_strings[index]; -} - - -/* Access to device descriptor functions ***************************************************** */ - - -/* * - * usbd_device_configuration_instance - find a configuration instance for this device - * @device: - * @configuration: index to configuration, 0 - N-1 - * - * Get specifed device configuration. Index should be bConfigurationValue-1. - */ -static struct usb_configuration_instance *usbd_device_configuration_instance (struct usb_device_instance *device, - unsigned int port, unsigned int configuration) -{ - if (configuration >= device->configurations) - return NULL; - - return device->configuration_instance_array + configuration; -} - - -/* * - * usbd_device_interface_instance - * @device: - * @configuration: index to configuration, 0 - N-1 - * @interface: index to interface - * - * Return the specified interface descriptor for the specified device. - */ -struct usb_interface_instance *usbd_device_interface_instance (struct usb_device_instance *device, int port, int configuration, int interface) -{ - struct usb_configuration_instance *configuration_instance; - - if ((configuration_instance = usbd_device_configuration_instance (device, port, configuration)) == NULL) { - return NULL; - } - if (interface >= configuration_instance->interfaces) { - return NULL; - } - return configuration_instance->interface_instance_array + interface; -} - -/* * - * usbd_device_alternate_descriptor_list - * @device: - * @configuration: index to configuration, 0 - N-1 - * @interface: index to interface - * @alternate: alternate setting - * - * Return the specified alternate descriptor for the specified device. - */ -struct usb_alternate_instance *usbd_device_alternate_instance (struct usb_device_instance *device, int port, int configuration, int interface, int alternate) -{ - struct usb_interface_instance *interface_instance; - - if ((interface_instance = usbd_device_interface_instance (device, port, configuration, interface)) == NULL) { - return NULL; - } - - if (alternate >= interface_instance->alternates) { - return NULL; - } - - return interface_instance->alternates_instance_array + alternate; -} - - -/* * - * usbd_device_device_descriptor - * @device: which device - * @configuration: index to configuration, 0 - N-1 - * @port: which port - * - * Return the specified configuration descriptor for the specified device. - */ -struct usb_device_descriptor *usbd_device_device_descriptor (struct usb_device_instance *device, int port) -{ - return (device->device_descriptor); -} - -/** - * usbd_device_configuration_descriptor - * @device: which device - * @port: which port - * @configuration: index to configuration, 0 - N-1 - * - * Return the specified configuration descriptor for the specified device. - */ -struct usb_configuration_descriptor *usbd_device_configuration_descriptor (struct - usb_device_instance - *device, int port, int configuration) -{ - struct usb_configuration_instance *configuration_instance; - if (!(configuration_instance = usbd_device_configuration_instance (device, port, configuration))) { - return NULL; - } - return (configuration_instance->configuration_descriptor); -} - - -/** - * usbd_device_interface_descriptor - * @device: which device - * @port: which port - * @configuration: index to configuration, 0 - N-1 - * @interface: index to interface - * @alternate: alternate setting - * - * Return the specified interface descriptor for the specified device. - */ -struct usb_interface_descriptor *usbd_device_interface_descriptor (struct usb_device_instance - *device, int port, int configuration, int interface, int alternate) -{ - struct usb_interface_instance *interface_instance; - if (!(interface_instance = usbd_device_interface_instance (device, port, configuration, interface))) { - return NULL; - } - if ((alternate < 0) || (alternate >= interface_instance->alternates)) { - return NULL; - } - return (interface_instance->alternates_instance_array[alternate].interface_descriptor); -} - -/** - * usbd_device_endpoint_descriptor_index - * @device: which device - * @port: which port - * @configuration: index to configuration, 0 - N-1 - * @interface: index to interface - * @alternate: index setting - * @index: which index - * - * Return the specified endpoint descriptor for the specified device. - */ -struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor_index (struct usb_device_instance - *device, int port, int configuration, int interface, int alternate, int index) -{ - struct usb_alternate_instance *alternate_instance; - - if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) { - return NULL; - } - if (index >= alternate_instance->endpoints) { - return NULL; - } - return *(alternate_instance->endpoints_descriptor_array + index); -} - - -/** - * usbd_device_endpoint_transfersize - * @device: which device - * @port: which port - * @configuration: index to configuration, 0 - N-1 - * @interface: index to interface - * @index: which index - * - * Return the specified endpoint transfer size; - */ -int usbd_device_endpoint_transfersize (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int index) -{ - struct usb_alternate_instance *alternate_instance; - - if (!(alternate_instance = usbd_device_alternate_instance (device, port, configuration, interface, alternate))) { - return 0; - } - if (index >= alternate_instance->endpoints) { - return 0; - } - return *(alternate_instance->endpoint_transfersize_array + index); -} - - -/** - * usbd_device_endpoint_descriptor - * @device: which device - * @port: which port - * @configuration: index to configuration, 0 - N-1 - * @interface: index to interface - * @alternate: alternate setting - * @endpoint: which endpoint - * - * Return the specified endpoint descriptor for the specified device. - */ -struct usb_endpoint_descriptor *usbd_device_endpoint_descriptor (struct usb_device_instance *device, int port, int configuration, int interface, int alternate, int endpoint) -{ - struct usb_endpoint_descriptor *endpoint_descriptor; - int i; - - for (i = 0; !(endpoint_descriptor = usbd_device_endpoint_descriptor_index (device, port, configuration, interface, alternate, i)); i++) { - if (endpoint_descriptor->bEndpointAddress == endpoint) { - return endpoint_descriptor; - } - } - return NULL; -} - -/** - * usbd_endpoint_halted - * @device: point to struct usb_device_instance - * @endpoint: endpoint to check - * - * Return non-zero if endpoint is halted. - */ -int usbd_endpoint_halted (struct usb_device_instance *device, int endpoint) -{ - return (device->status == USB_STATUS_HALT); -} - - -/** - * usbd_rcv_complete - complete a receive - * @endpoint: - * @len: - * @urb_bad: - * - * Called from rcv interrupt to complete. - */ -void usbd_rcv_complete(struct usb_endpoint_instance *endpoint, int len, int urb_bad) -{ - if (endpoint) { - struct urb *rcv_urb; - - /*usbdbg("len: %d urb: %p\n", len, endpoint->rcv_urb); */ - - /* if we had an urb then update actual_length, dispatch if neccessary */ - if ((rcv_urb = endpoint->rcv_urb)) { - - /*usbdbg("actual: %d buffer: %d\n", */ - /*rcv_urb->actual_length, rcv_urb->buffer_length); */ - - /* check the urb is ok, are we adding data less than the packetsize */ - if (!urb_bad && (len <= endpoint->rcv_packetSize)) { - /*usbdbg("updating actual_length by %d\n",len); */ - - /* increment the received data size */ - rcv_urb->actual_length += len; - - } else { - usberr(" RECV_ERROR actual: %d buffer: %d urb_bad: %d\n", - rcv_urb->actual_length, rcv_urb->buffer_length, urb_bad); - - rcv_urb->actual_length = 0; - rcv_urb->status = RECV_ERROR; - } - } else { - usberr("no rcv_urb!"); - } - } else { - usberr("no endpoint!"); - } - -} - -/** - * usbd_tx_complete - complete a transmit - * @endpoint: - * @resetart: - * - * Called from tx interrupt to complete. - */ -void usbd_tx_complete (struct usb_endpoint_instance *endpoint) -{ - if (endpoint) { - struct urb *tx_urb; - - /* if we have a tx_urb advance or reset, finish if complete */ - if ((tx_urb = endpoint->tx_urb)) { - int sent = endpoint->last; - endpoint->sent += sent; - endpoint->last -= sent; - - if( (endpoint->tx_urb->actual_length - endpoint->sent) <= 0 ) { - tx_urb->actual_length = 0; - endpoint->sent = 0; - endpoint->last = 0; - - /* Remove from active, save for re-use */ - urb_detach(tx_urb); - urb_append(&endpoint->done, tx_urb); - /*usbdbg("done->next %p, tx_urb %p, done %p", */ - /* endpoint->done.next, tx_urb, &endpoint->done); */ - - endpoint->tx_urb = first_urb_detached(&endpoint->tx); - if( endpoint->tx_urb ) { - endpoint->tx_queue--; - usbdbg("got urb from tx list"); - } - if( !endpoint->tx_urb ) { - /*usbdbg("taking urb from done list"); */ - endpoint->tx_urb = first_urb_detached(&endpoint->done); - } - if( !endpoint->tx_urb ) { - usbdbg("allocating new urb for tx_urb"); - endpoint->tx_urb = usbd_alloc_urb(tx_urb->device, endpoint); - } - } - } - } -} - -/* URB linked list functions ***************************************************** */ - -/* - * Initialize an urb_link to be a single element list. - * If the urb_link is being used as a distinguished list head - * the list is empty when the head is the only link in the list. - */ -void urb_link_init (urb_link * ul) -{ - if (ul) { - ul->prev = ul->next = ul; - } -} - -/* - * Detach an urb_link from a list, and set it - * up as a single element list, so no dangling - * pointers can be followed, and so it can be - * joined to another list if so desired. - */ -void urb_detach (struct urb *urb) -{ - if (urb) { - urb_link *ul = &urb->link; - ul->next->prev = ul->prev; - ul->prev->next = ul->next; - urb_link_init (ul); - } -} - -/* - * Return the first urb_link in a list with a distinguished - * head "hd", or NULL if the list is empty. This will also - * work as a predicate, returning NULL if empty, and non-NULL - * otherwise. - */ -urb_link *first_urb_link (urb_link * hd) -{ - urb_link *nx; - if (NULL != hd && NULL != (nx = hd->next) && nx != hd) { - /* There is at least one element in the list */ - /* (besides the distinguished head). */ - return (nx); - } - /* The list is empty */ - return (NULL); -} - -/* - * Return the first urb in a list with a distinguished - * head "hd", or NULL if the list is empty. - */ -struct urb *first_urb (urb_link * hd) -{ - urb_link *nx; - if (NULL == (nx = first_urb_link (hd))) { - /* The list is empty */ - return (NULL); - } - return (p2surround (struct urb, link, nx)); -} - -/* - * Detach and return the first urb in a list with a distinguished - * head "hd", or NULL if the list is empty. - * - */ -struct urb *first_urb_detached (urb_link * hd) -{ - struct urb *urb; - if ((urb = first_urb (hd))) { - urb_detach (urb); - } - return urb; -} - - -/* - * Append an urb_link (or a whole list of - * urb_links) to the tail of another list - * of urb_links. - */ -void urb_append (urb_link * hd, struct urb *urb) -{ - if (hd && urb) { - urb_link *new = &urb->link; - - /* This allows the new urb to be a list of urbs, */ - /* with new pointing at the first, but the link */ - /* must be initialized. */ - /* Order is important here... */ - urb_link *pul = hd->prev; - new->prev->next = hd; - hd->prev = new->prev; - new->prev = pul; - pul->next = new; - } -} - -/* URB create/destroy functions ***************************************************** */ - -/** - * usbd_alloc_urb - allocate an URB appropriate for specified endpoint - * @device: device instance - * @endpoint: endpoint - * - * Allocate an urb structure. The usb device urb structure is used to - * contain all data associated with a transfer, including a setup packet for - * control transfers. - * - * NOTE: endpoint_address MUST contain a direction flag. - */ -struct urb *usbd_alloc_urb (struct usb_device_instance *device, - struct usb_endpoint_instance *endpoint) -{ - struct urb *urb; - - if (!(urb = (struct urb *) malloc (sizeof (struct urb)))) { - usberr (" F A T A L: malloc(%zu) FAILED!!!!", - sizeof (struct urb)); - return NULL; - } - - /* Fill in known fields */ - memset (urb, 0, sizeof (struct urb)); - urb->endpoint = endpoint; - urb->device = device; - urb->buffer = (u8 *) urb->buffer_data; - urb->buffer_length = sizeof (urb->buffer_data); - - urb_link_init (&urb->link); - - return urb; -} - -/** - * usbd_dealloc_urb - deallocate an URB and associated buffer - * @urb: pointer to an urb structure - * - * Deallocate an urb structure and associated data. - */ -void usbd_dealloc_urb (struct urb *urb) -{ - if (urb) { - free (urb); - } -} - -/* Event signaling functions ***************************************************** */ - -/** - * usbd_device_event - called to respond to various usb events - * @device: pointer to struct device - * @event: event to respond to - * - * Used by a Bus driver to indicate an event. - */ -void usbd_device_event_irq (struct usb_device_instance *device, usb_device_event_t event, int data) -{ - usb_device_state_t state; - - if (!device || !device->bus) { - usberr("(%p,%d) NULL device or device->bus", device, event); - return; - } - - state = device->device_state; - - usbinfo("%s", usbd_device_events[event]); - - switch (event) { - case DEVICE_UNKNOWN: - break; - case DEVICE_INIT: - device->device_state = STATE_INIT; - break; - - case DEVICE_CREATE: - device->device_state = STATE_ATTACHED; - break; - - case DEVICE_HUB_CONFIGURED: - device->device_state = STATE_POWERED; - break; - - case DEVICE_RESET: - device->device_state = STATE_DEFAULT; - device->address = 0; - break; - - case DEVICE_ADDRESS_ASSIGNED: - device->device_state = STATE_ADDRESSED; - break; - - case DEVICE_CONFIGURED: - device->device_state = STATE_CONFIGURED; - break; - - case DEVICE_DE_CONFIGURED: - device->device_state = STATE_ADDRESSED; - break; - - case DEVICE_BUS_INACTIVE: - if (device->status != USBD_CLOSING) { - device->status = USBD_SUSPENDED; - } - break; - case DEVICE_BUS_ACTIVITY: - if (device->status != USBD_CLOSING) { - device->status = USBD_OK; - } - break; - - case DEVICE_SET_INTERFACE: - break; - case DEVICE_SET_FEATURE: - break; - case DEVICE_CLEAR_FEATURE: - break; - - case DEVICE_POWER_INTERRUPTION: - device->device_state = STATE_POWERED; - break; - case DEVICE_HUB_RESET: - device->device_state = STATE_ATTACHED; - break; - case DEVICE_DESTROY: - device->device_state = STATE_UNKNOWN; - break; - - case DEVICE_FUNCTION_PRIVATE: - break; - - default: - usbdbg("event %d - not handled",event); - break; - } - debug("%s event: %d oldstate: %d newstate: %d status: %d address: %d", - device->name, event, state, - device->device_state, device->status, device->address); - - /* tell the bus interface driver */ - if( device->event ) { - /* usbdbg("calling device->event"); */ - device->event(device, event, data); - } -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/designware_udc.c b/qemu/roms/u-boot/drivers/usb/gadget/designware_udc.c deleted file mode 100644 index b7c10384a..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/designware_udc.c +++ /dev/null @@ -1,1019 +0,0 @@ -/* - * Based on drivers/usb/gadget/omap1510_udc.c - * TI OMAP1510 USB bus interface driver - * - * (C) Copyright 2009 - * Vipin Kumar, ST Micoelectronics, vipin.kumar@st.com. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> - -#include <usbdevice.h> -#include "ep0.h" -#include <usb/designware_udc.h> -#include <usb/udc.h> -#include <asm/arch/hardware.h> - -#define UDC_INIT_MDELAY 80 /* Device settle delay */ - -/* Some kind of debugging output... */ -#ifndef DEBUG_DWUSBTTY -#define UDCDBG(str) -#define UDCDBGA(fmt, args...) -#else -#define UDCDBG(str) serial_printf(str "\n") -#define UDCDBGA(fmt, args...) serial_printf(fmt "\n", ##args) -#endif - -static struct urb *ep0_urb; -static struct usb_device_instance *udc_device; - -static struct plug_regs *const plug_regs_p = - (struct plug_regs * const)CONFIG_SYS_PLUG_BASE; -static struct udc_regs *const udc_regs_p = - (struct udc_regs * const)CONFIG_SYS_USBD_BASE; -static struct udc_endp_regs *const outep_regs_p = - &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->out_regs[0]; -static struct udc_endp_regs *const inep_regs_p = - &((struct udc_regs * const)CONFIG_SYS_USBD_BASE)->in_regs[0]; - -/* - * udc_state_transition - Write the next packet to TxFIFO. - * @initial: Initial state. - * @final: Final state. - * - * Helper function to implement device state changes. The device states and - * the events that transition between them are: - * - * STATE_ATTACHED - * || /\ - * \/ || - * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET - * || /\ - * \/ || - * STATE_POWERED - * || /\ - * \/ || - * DEVICE_RESET DEVICE_POWER_INTERRUPTION - * || /\ - * \/ || - * STATE_DEFAULT - * || /\ - * \/ || - * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET - * || /\ - * \/ || - * STATE_ADDRESSED - * || /\ - * \/ || - * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED - * || /\ - * \/ || - * STATE_CONFIGURED - * - * udc_state_transition transitions up (in the direction from STATE_ATTACHED - * to STATE_CONFIGURED) from the specified initial state to the specified final - * state, passing through each intermediate state on the way. If the initial - * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then - * no state transitions will take place. - * - * udc_state_transition also transitions down (in the direction from - * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the - * specified final state, passing through each intermediate state on the way. - * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final - * state, then no state transitions will take place. - * - * This function must only be called with interrupts disabled. - */ -static void udc_state_transition(usb_device_state_t initial, - usb_device_state_t final) -{ - if (initial < final) { - switch (initial) { - case STATE_ATTACHED: - usbd_device_event_irq(udc_device, - DEVICE_HUB_CONFIGURED, 0); - if (final == STATE_POWERED) - break; - case STATE_POWERED: - usbd_device_event_irq(udc_device, DEVICE_RESET, 0); - if (final == STATE_DEFAULT) - break; - case STATE_DEFAULT: - usbd_device_event_irq(udc_device, - DEVICE_ADDRESS_ASSIGNED, 0); - if (final == STATE_ADDRESSED) - break; - case STATE_ADDRESSED: - usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); - case STATE_CONFIGURED: - break; - default: - break; - } - } else if (initial > final) { - switch (initial) { - case STATE_CONFIGURED: - usbd_device_event_irq(udc_device, - DEVICE_DE_CONFIGURED, 0); - if (final == STATE_ADDRESSED) - break; - case STATE_ADDRESSED: - usbd_device_event_irq(udc_device, DEVICE_RESET, 0); - if (final == STATE_DEFAULT) - break; - case STATE_DEFAULT: - usbd_device_event_irq(udc_device, - DEVICE_POWER_INTERRUPTION, 0); - if (final == STATE_POWERED) - break; - case STATE_POWERED: - usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0); - case STATE_ATTACHED: - break; - default: - break; - } - } -} - -/* Stall endpoint */ -static void udc_stall_ep(u32 ep_num) -{ - writel(readl(&inep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, - &inep_regs_p[ep_num].endp_cntl); - - writel(readl(&outep_regs_p[ep_num].endp_cntl) | ENDP_CNTL_STALL, - &outep_regs_p[ep_num].endp_cntl); -} - -static void *get_fifo(int ep_num, int in) -{ - u32 *fifo_ptr = (u32 *)CONFIG_SYS_FIFO_BASE; - - switch (ep_num) { - case UDC_EP3: - fifo_ptr += readl(&inep_regs_p[1].endp_bsorfn); - /* break intentionally left out */ - - case UDC_EP1: - fifo_ptr += readl(&inep_regs_p[0].endp_bsorfn); - /* break intentionally left out */ - - case UDC_EP0: - default: - if (in) { - fifo_ptr += - readl(&outep_regs_p[2].endp_maxpacksize) >> 16; - /* break intentionally left out */ - } else { - break; - } - - case UDC_EP2: - fifo_ptr += readl(&outep_regs_p[0].endp_maxpacksize) >> 16; - /* break intentionally left out */ - } - - return (void *)fifo_ptr; -} - -static int usbgetpckfromfifo(int epNum, u8 *bufp, u32 len) -{ - u8 *fifo_ptr = (u8 *)get_fifo(epNum, 0); - u32 i, nw, nb; - u32 *wrdp; - u8 *bytp; - u32 tmp[128]; - - if (readl(&udc_regs_p->dev_stat) & DEV_STAT_RXFIFO_EMPTY) - return -1; - - nw = len / sizeof(u32); - nb = len % sizeof(u32); - - /* use tmp buf if bufp is not word aligned */ - if ((int)bufp & 0x3) - wrdp = (u32 *)&tmp[0]; - else - wrdp = (u32 *)bufp; - - for (i = 0; i < nw; i++) { - writel(readl(fifo_ptr), wrdp); - wrdp++; - } - - bytp = (u8 *)wrdp; - for (i = 0; i < nb; i++) { - writeb(readb(fifo_ptr), bytp); - fifo_ptr++; - bytp++; - } - readl(&outep_regs_p[epNum].write_done); - - /* copy back tmp buffer to bufp if bufp is not word aligned */ - if ((int)bufp & 0x3) - memcpy(bufp, tmp, len); - - return 0; -} - -static void usbputpcktofifo(int epNum, u8 *bufp, u32 len) -{ - u32 i, nw, nb; - u32 *wrdp; - u8 *bytp; - u8 *fifo_ptr = get_fifo(epNum, 1); - - nw = len / sizeof(int); - nb = len % sizeof(int); - wrdp = (u32 *)bufp; - for (i = 0; i < nw; i++) { - writel(*wrdp, fifo_ptr); - wrdp++; - } - - bytp = (u8 *)wrdp; - for (i = 0; i < nb; i++) { - writeb(*bytp, fifo_ptr); - fifo_ptr++; - bytp++; - } -} - -/* - * dw_write_noniso_tx_fifo - Write the next packet to TxFIFO. - * @endpoint: Endpoint pointer. - * - * If the endpoint has an active tx_urb, then the next packet of data from the - * URB is written to the tx FIFO. The total amount of data in the urb is given - * by urb->actual_length. The maximum amount of data that can be sent in any - * one packet is given by endpoint->tx_packetSize. The number of data bytes - * from this URB that have already been transmitted is given by endpoint->sent. - * endpoint->last is updated by this routine with the number of data bytes - * transmitted in this packet. - * - */ -static void dw_write_noniso_tx_fifo(struct usb_endpoint_instance - *endpoint) -{ - struct urb *urb = endpoint->tx_urb; - int align; - - if (urb) { - u32 last; - - UDCDBGA("urb->buffer %p, buffer_length %d, actual_length %d", - urb->buffer, urb->buffer_length, urb->actual_length); - - last = MIN(urb->actual_length - endpoint->sent, - endpoint->tx_packetSize); - - if (last) { - u8 *cp = urb->buffer + endpoint->sent; - - /* - * This ensures that USBD packet fifo is accessed - * - through word aligned pointer or - * - through non word aligned pointer but only - * with a max length to make the next packet - * word aligned - */ - - align = ((ulong)cp % sizeof(int)); - if (align) - last = MIN(last, sizeof(int) - align); - - UDCDBGA("endpoint->sent %d, tx_packetSize %d, last %d", - endpoint->sent, endpoint->tx_packetSize, last); - - usbputpcktofifo(endpoint->endpoint_address & - USB_ENDPOINT_NUMBER_MASK, cp, last); - } - endpoint->last = last; - } -} - -/* - * Handle SETUP USB interrupt. - * This function implements TRM Figure 14-14. - */ -static void dw_udc_setup(struct usb_endpoint_instance *endpoint) -{ - u8 *datap = (u8 *)&ep0_urb->device_request; - int ep_addr = endpoint->endpoint_address; - - UDCDBG("-> Entering device setup"); - usbgetpckfromfifo(ep_addr, datap, 8); - - /* Try to process setup packet */ - if (ep0_recv_setup(ep0_urb)) { - /* Not a setup packet, stall next EP0 transaction */ - udc_stall_ep(0); - UDCDBG("can't parse setup packet, still waiting for setup"); - return; - } - - /* Check direction */ - if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) - == USB_REQ_HOST2DEVICE) { - UDCDBG("control write on EP0"); - if (le16_to_cpu(ep0_urb->device_request.wLength)) { - /* Stall this request */ - UDCDBG("Stalling unsupported EP0 control write data " - "stage."); - udc_stall_ep(0); - } - } else { - - UDCDBG("control read on EP0"); - /* - * The ep0_recv_setup function has already placed our response - * packet data in ep0_urb->buffer and the packet length in - * ep0_urb->actual_length. - */ - endpoint->tx_urb = ep0_urb; - endpoint->sent = 0; - /* - * Write packet data to the FIFO. dw_write_noniso_tx_fifo - * will update endpoint->last with the number of bytes written - * to the FIFO. - */ - dw_write_noniso_tx_fifo(endpoint); - - writel(0x0, &inep_regs_p[ep_addr].write_done); - } - - udc_unset_nak(endpoint->endpoint_address); - - UDCDBG("<- Leaving device setup"); -} - -/* - * Handle endpoint 0 RX interrupt - */ -static void dw_udc_ep0_rx(struct usb_endpoint_instance *endpoint) -{ - u8 dummy[64]; - - UDCDBG("RX on EP0"); - - /* Check direction */ - if ((ep0_urb->device_request.bmRequestType - & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { - /* - * This rx interrupt must be for a control write data - * stage packet. - * - * We don't support control write data stages. - * We should never end up here. - */ - - UDCDBG("Stalling unexpected EP0 control write " - "data stage packet"); - udc_stall_ep(0); - } else { - /* - * This rx interrupt must be for a control read status - * stage packet. - */ - UDCDBG("ACK on EP0 control read status stage packet"); - u32 len = (readl(&outep_regs_p[0].endp_status) >> 11) & 0xfff; - usbgetpckfromfifo(0, dummy, len); - } -} - -/* - * Handle endpoint 0 TX interrupt - */ -static void dw_udc_ep0_tx(struct usb_endpoint_instance *endpoint) -{ - struct usb_device_request *request = &ep0_urb->device_request; - int ep_addr; - - UDCDBG("TX on EP0"); - - /* Check direction */ - if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) == - USB_REQ_HOST2DEVICE) { - /* - * This tx interrupt must be for a control write status - * stage packet. - */ - UDCDBG("ACK on EP0 control write status stage packet"); - } else { - /* - * This tx interrupt must be for a control read data - * stage packet. - */ - int wLength = le16_to_cpu(request->wLength); - - /* - * Update our count of bytes sent so far in this - * transfer. - */ - endpoint->sent += endpoint->last; - - /* - * We are finished with this transfer if we have sent - * all of the bytes in our tx urb (urb->actual_length) - * unless we need a zero-length terminating packet. We - * need a zero-length terminating packet if we returned - * fewer bytes than were requested (wLength) by the host, - * and the number of bytes we returned is an exact - * multiple of the packet size endpoint->tx_packetSize. - */ - if ((endpoint->sent == ep0_urb->actual_length) && - ((ep0_urb->actual_length == wLength) || - (endpoint->last != endpoint->tx_packetSize))) { - /* Done with control read data stage. */ - UDCDBG("control read data stage complete"); - } else { - /* - * We still have another packet of data to send - * in this control read data stage or else we - * need a zero-length terminating packet. - */ - UDCDBG("ACK control read data stage packet"); - dw_write_noniso_tx_fifo(endpoint); - - ep_addr = endpoint->endpoint_address; - writel(0x0, &inep_regs_p[ep_addr].write_done); - } - } -} - -static struct usb_endpoint_instance *dw_find_ep(int ep) -{ - int i; - - for (i = 0; i < udc_device->bus->max_endpoints; i++) { - if ((udc_device->bus->endpoint_array[i].endpoint_address & - USB_ENDPOINT_NUMBER_MASK) == ep) - return &udc_device->bus->endpoint_array[i]; - } - return NULL; -} - -/* - * Handle RX transaction on non-ISO endpoint. - * The ep argument is a physical endpoint number for a non-ISO IN endpoint - * in the range 1 to 15. - */ -static void dw_udc_epn_rx(int ep) -{ - int nbytes = 0; - struct urb *urb; - struct usb_endpoint_instance *endpoint = dw_find_ep(ep); - - if (endpoint) { - urb = endpoint->rcv_urb; - - if (urb) { - u8 *cp = urb->buffer + urb->actual_length; - - nbytes = (readl(&outep_regs_p[ep].endp_status) >> 11) & - 0xfff; - usbgetpckfromfifo(ep, cp, nbytes); - usbd_rcv_complete(endpoint, nbytes, 0); - } - } -} - -/* - * Handle TX transaction on non-ISO endpoint. - * The ep argument is a physical endpoint number for a non-ISO IN endpoint - * in the range 16 to 30. - */ -static void dw_udc_epn_tx(int ep) -{ - struct usb_endpoint_instance *endpoint = dw_find_ep(ep); - - if (!endpoint) - return; - - /* - * We need to transmit a terminating zero-length packet now if - * we have sent all of the data in this URB and the transfer - * size was an exact multiple of the packet size. - */ - if (endpoint->tx_urb && - (endpoint->last == endpoint->tx_packetSize) && - (endpoint->tx_urb->actual_length - endpoint->sent - - endpoint->last == 0)) { - /* handle zero length packet here */ - writel(0x0, &inep_regs_p[ep].write_done); - - } - - if (endpoint->tx_urb && endpoint->tx_urb->actual_length) { - /* retire the data that was just sent */ - usbd_tx_complete(endpoint); - /* - * Check to see if we have more data ready to transmit - * now. - */ - if (endpoint->tx_urb && endpoint->tx_urb->actual_length) { - /* write data to FIFO */ - dw_write_noniso_tx_fifo(endpoint); - writel(0x0, &inep_regs_p[ep].write_done); - - } else if (endpoint->tx_urb - && (endpoint->tx_urb->actual_length == 0)) { - /* udc_set_nak(ep); */ - } - } -} - -/* - * Start of public functions. - */ - -/* Called to start packet transmission. */ -int udc_endpoint_write(struct usb_endpoint_instance *endpoint) -{ - udc_unset_nak(endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK); - return 0; -} - -/* Start to initialize h/w stuff */ -int udc_init(void) -{ - int i; - u32 plug_st; - - udc_device = NULL; - - UDCDBG("starting"); - - readl(&plug_regs_p->plug_pending); - - for (i = 0; i < UDC_INIT_MDELAY; i++) - udelay(1000); - - plug_st = readl(&plug_regs_p->plug_state); - writel(plug_st | PLUG_STATUS_EN, &plug_regs_p->plug_state); - - writel(~0x0, &udc_regs_p->endp_int); - writel(~0x0, &udc_regs_p->dev_int_mask); - writel(~0x0, &udc_regs_p->endp_int_mask); - -#ifndef CONFIG_USBD_HS - writel(DEV_CONF_FS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW | - DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf); -#else - writel(DEV_CONF_HS_SPEED | DEV_CONF_REMWAKEUP | DEV_CONF_SELFPOW | - DEV_CONF_PHYINT_16, &udc_regs_p->dev_conf); -#endif - - writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl); - - /* Clear all interrupts pending */ - writel(DEV_INT_MSK, &udc_regs_p->dev_int); - - return 0; -} - -int is_usbd_high_speed(void) -{ - return (readl(&udc_regs_p->dev_stat) & DEV_STAT_ENUM) ? 0 : 1; -} - -/* - * udc_setup_ep - setup endpoint - * Associate a physical endpoint with endpoint_instance - */ -void udc_setup_ep(struct usb_device_instance *device, - u32 ep, struct usb_endpoint_instance *endpoint) -{ - UDCDBGA("setting up endpoint addr %x", endpoint->endpoint_address); - int ep_addr; - int ep_num, ep_type; - int packet_size; - int buffer_size; - int attributes; - char *tt; - u32 endp_intmask; - - if ((ep != 0) && (udc_device->device_state < STATE_ADDRESSED)) - return; - - tt = getenv("usbtty"); - if (!tt) - tt = "generic"; - - ep_addr = endpoint->endpoint_address; - ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; - - if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - /* IN endpoint */ - packet_size = endpoint->tx_packetSize; - buffer_size = packet_size * 2; - attributes = endpoint->tx_attributes; - } else { - /* OUT endpoint */ - packet_size = endpoint->rcv_packetSize; - buffer_size = packet_size * 2; - attributes = endpoint->rcv_attributes; - } - - switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_CONTROL: - ep_type = ENDP_EPTYPE_CNTL; - break; - case USB_ENDPOINT_XFER_BULK: - default: - ep_type = ENDP_EPTYPE_BULK; - break; - case USB_ENDPOINT_XFER_INT: - ep_type = ENDP_EPTYPE_INT; - break; - case USB_ENDPOINT_XFER_ISOC: - ep_type = ENDP_EPTYPE_ISO; - break; - } - - struct udc_endp_regs *out_p = &outep_regs_p[ep_num]; - struct udc_endp_regs *in_p = &inep_regs_p[ep_num]; - - if (!ep_addr) { - /* Setup endpoint 0 */ - buffer_size = packet_size; - - writel(readl(&in_p->endp_cntl) | ENDP_CNTL_CNAK, - &in_p->endp_cntl); - - writel(readl(&out_p->endp_cntl) | ENDP_CNTL_CNAK, - &out_p->endp_cntl); - - writel(ENDP_CNTL_CONTROL | ENDP_CNTL_FLUSH, &in_p->endp_cntl); - - writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); - - writel(packet_size, &in_p->endp_maxpacksize); - - writel(ENDP_CNTL_CONTROL | ENDP_CNTL_RRDY, &out_p->endp_cntl); - - writel(packet_size | ((buffer_size / sizeof(int)) << 16), - &out_p->endp_maxpacksize); - - } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - /* Setup the IN endpoint */ - writel(0x0, &in_p->endp_status); - writel((ep_type << 4) | ENDP_CNTL_RRDY, &in_p->endp_cntl); - writel(buffer_size / sizeof(int), &in_p->endp_bsorfn); - writel(packet_size, &in_p->endp_maxpacksize); - - if (!strcmp(tt, "cdc_acm")) { - if (ep_type == ENDP_EPTYPE_INT) { - /* Conf no. 1 Interface no. 0 */ - writel((packet_size << 19) | - ENDP_EPDIR_IN | (1 << 7) | - (0 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } else { - /* Conf no. 1 Interface no. 1 */ - writel((packet_size << 19) | - ENDP_EPDIR_IN | (1 << 7) | - (1 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } - } else { - /* Conf no. 1 Interface no. 0 */ - writel((packet_size << 19) | - ENDP_EPDIR_IN | (1 << 7) | - (0 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } - - } else { - /* Setup the OUT endpoint */ - writel(0x0, &out_p->endp_status); - writel((ep_type << 4) | ENDP_CNTL_RRDY, &out_p->endp_cntl); - writel(packet_size | ((buffer_size / sizeof(int)) << 16), - &out_p->endp_maxpacksize); - - if (!strcmp(tt, "cdc_acm")) { - writel((packet_size << 19) | - ENDP_EPDIR_OUT | (1 << 7) | - (1 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } else { - writel((packet_size << 19) | - ENDP_EPDIR_OUT | (1 << 7) | - (0 << 11) | (ep_type << 5) | ep_num, - &udc_regs_p->udc_endp_reg[ep_num]); - } - - } - - endp_intmask = readl(&udc_regs_p->endp_int_mask); - endp_intmask &= ~((1 << ep_num) | 0x10000 << ep_num); - writel(endp_intmask, &udc_regs_p->endp_int_mask); -} - -/* Turn on the USB connection by enabling the pullup resistor */ -void udc_connect(void) -{ - u32 plug_st, dev_cntl; - - dev_cntl = readl(&udc_regs_p->dev_cntl); - dev_cntl |= DEV_CNTL_SOFTDISCONNECT; - writel(dev_cntl, &udc_regs_p->dev_cntl); - - udelay(1000); - - dev_cntl = readl(&udc_regs_p->dev_cntl); - dev_cntl &= ~DEV_CNTL_SOFTDISCONNECT; - writel(dev_cntl, &udc_regs_p->dev_cntl); - - plug_st = readl(&plug_regs_p->plug_state); - plug_st &= ~(PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); - writel(plug_st, &plug_regs_p->plug_state); -} - -/* Turn off the USB connection by disabling the pullup resistor */ -void udc_disconnect(void) -{ - u32 plug_st; - - writel(DEV_CNTL_SOFTDISCONNECT, &udc_regs_p->dev_cntl); - - plug_st = readl(&plug_regs_p->plug_state); - plug_st |= (PLUG_STATUS_PHY_RESET | PLUG_STATUS_PHY_MODE); - writel(plug_st, &plug_regs_p->plug_state); -} - -/* Switch on the UDC */ -void udc_enable(struct usb_device_instance *device) -{ - UDCDBGA("enable device %p, status %d", device, device->status); - - /* Save the device structure pointer */ - udc_device = device; - - /* Setup ep0 urb */ - if (!ep0_urb) { - ep0_urb = - usbd_alloc_urb(udc_device, udc_device->bus->endpoint_array); - } else { - serial_printf("udc_enable: ep0_urb already allocated %p\n", - ep0_urb); - } - - writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); -} - -/** - * udc_startup - allow udc code to do any additional startup - */ -void udc_startup_events(struct usb_device_instance *device) -{ - /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ - usbd_device_event_irq(device, DEVICE_INIT, 0); - - /* - * The DEVICE_CREATE event puts the USB device in the state - * STATE_ATTACHED. - */ - usbd_device_event_irq(device, DEVICE_CREATE, 0); - - /* - * Some USB controller driver implementations signal - * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. - * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, - * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. - * The DW USB client controller has the capability to detect when the - * USB cable is connected to a powered USB bus, so we will defer the - * DEVICE_HUB_CONFIGURED and DEVICE_RESET events until later. - */ - - udc_enable(device); -} - -/* - * Plug detection interrupt handling - */ -static void dw_udc_plug_irq(void) -{ - if (readl(&plug_regs_p->plug_state) & PLUG_STATUS_ATTACHED) { - /* - * USB cable attached - * Turn off PHY reset bit (PLUG detect). - * Switch PHY opmode to normal operation (PLUG detect). - */ - udc_connect(); - writel(DEV_INT_SOF, &udc_regs_p->dev_int_mask); - - UDCDBG("device attached and powered"); - udc_state_transition(udc_device->device_state, STATE_POWERED); - } else { - writel(~0x0, &udc_regs_p->dev_int_mask); - - UDCDBG("device detached or unpowered"); - udc_state_transition(udc_device->device_state, STATE_ATTACHED); - } -} - -/* - * Device interrupt handling - */ -static void dw_udc_dev_irq(void) -{ - if (readl(&udc_regs_p->dev_int) & DEV_INT_USBRESET) { - writel(~0x0, &udc_regs_p->endp_int_mask); - - writel(readl(&inep_regs_p[0].endp_cntl) | ENDP_CNTL_FLUSH, - &inep_regs_p[0].endp_cntl); - - writel(DEV_INT_USBRESET, &udc_regs_p->dev_int); - - /* - * This endpoint0 specific register can be programmed only - * after the phy clock is initialized - */ - writel((EP0_MAX_PACKET_SIZE << 19) | ENDP_EPTYPE_CNTL, - &udc_regs_p->udc_endp_reg[0]); - - UDCDBG("device reset in progess"); - udc_state_transition(udc_device->device_state, STATE_DEFAULT); - } - - /* Device Enumeration completed */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_ENUM) { - writel(DEV_INT_ENUM, &udc_regs_p->dev_int); - - /* Endpoint interrupt enabled for Ctrl IN & Ctrl OUT */ - writel(readl(&udc_regs_p->endp_int_mask) & ~0x10001, - &udc_regs_p->endp_int_mask); - - UDCDBG("default -> addressed"); - udc_state_transition(udc_device->device_state, STATE_ADDRESSED); - } - - /* The USB will be in SUSPEND in 3 ms */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_INACTIVE) { - writel(DEV_INT_INACTIVE, &udc_regs_p->dev_int); - - UDCDBG("entering inactive state"); - /* usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); */ - } - - /* SetConfiguration command received */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_SETCFG) { - writel(DEV_INT_SETCFG, &udc_regs_p->dev_int); - - UDCDBG("entering configured state"); - udc_state_transition(udc_device->device_state, - STATE_CONFIGURED); - } - - /* SetInterface command received */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_SETINTF) - writel(DEV_INT_SETINTF, &udc_regs_p->dev_int); - - /* USB Suspend detected on cable */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_SUSPUSB) { - writel(DEV_INT_SUSPUSB, &udc_regs_p->dev_int); - - UDCDBG("entering suspended state"); - usbd_device_event_irq(udc_device, DEVICE_BUS_INACTIVE, 0); - } - - /* USB Start-Of-Frame detected on cable */ - if (readl(&udc_regs_p->dev_int) & DEV_INT_SOF) - writel(DEV_INT_SOF, &udc_regs_p->dev_int); -} - -/* - * Endpoint interrupt handling - */ -static void dw_udc_endpoint_irq(void) -{ - while (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLOUT) { - - writel(ENDP0_INT_CTRLOUT, &udc_regs_p->endp_int); - - if ((readl(&outep_regs_p[0].endp_status) & ENDP_STATUS_OUTMSK) - == ENDP_STATUS_OUT_SETUP) { - dw_udc_setup(udc_device->bus->endpoint_array + 0); - writel(ENDP_STATUS_OUT_SETUP, - &outep_regs_p[0].endp_status); - - } else if ((readl(&outep_regs_p[0].endp_status) & - ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { - dw_udc_ep0_rx(udc_device->bus->endpoint_array + 0); - writel(ENDP_STATUS_OUT_DATA, - &outep_regs_p[0].endp_status); - - } else if ((readl(&outep_regs_p[0].endp_status) & - ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { - /* NONE received */ - } - - writel(0x0, &outep_regs_p[0].endp_status); - } - - if (readl(&udc_regs_p->endp_int) & ENDP0_INT_CTRLIN) { - dw_udc_ep0_tx(udc_device->bus->endpoint_array + 0); - - writel(ENDP_STATUS_IN, &inep_regs_p[0].endp_status); - writel(ENDP0_INT_CTRLIN, &udc_regs_p->endp_int); - } - - if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOOUT_MSK) { - u32 epnum = 0; - u32 ep_int = readl(&udc_regs_p->endp_int) & - ENDP_INT_NONISOOUT_MSK; - - ep_int >>= 16; - while (0x0 == (ep_int & 0x1)) { - ep_int >>= 1; - epnum++; - } - - writel((1 << 16) << epnum, &udc_regs_p->endp_int); - - if ((readl(&outep_regs_p[epnum].endp_status) & - ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_DATA) { - - dw_udc_epn_rx(epnum); - writel(ENDP_STATUS_OUT_DATA, - &outep_regs_p[epnum].endp_status); - } else if ((readl(&outep_regs_p[epnum].endp_status) & - ENDP_STATUS_OUTMSK) == ENDP_STATUS_OUT_NONE) { - writel(0x0, &outep_regs_p[epnum].endp_status); - } - } - - if (readl(&udc_regs_p->endp_int) & ENDP_INT_NONISOIN_MSK) { - u32 epnum = 0; - u32 ep_int = readl(&udc_regs_p->endp_int) & - ENDP_INT_NONISOIN_MSK; - - while (0x0 == (ep_int & 0x1)) { - ep_int >>= 1; - epnum++; - } - - if (readl(&inep_regs_p[epnum].endp_status) & ENDP_STATUS_IN) { - writel(ENDP_STATUS_IN, - &outep_regs_p[epnum].endp_status); - dw_udc_epn_tx(epnum); - - writel(ENDP_STATUS_IN, - &outep_regs_p[epnum].endp_status); - } - - writel((1 << epnum), &udc_regs_p->endp_int); - } -} - -/* - * UDC interrupts - */ -void udc_irq(void) -{ - /* - * Loop while we have interrupts. - * If we don't do this, the input chain - * polling delay is likely to miss - * host requests. - */ - while (readl(&plug_regs_p->plug_pending)) - dw_udc_plug_irq(); - - while (readl(&udc_regs_p->dev_int)) - dw_udc_dev_irq(); - - if (readl(&udc_regs_p->endp_int)) - dw_udc_endpoint_irq(); -} - -/* Flow control */ -void udc_set_nak(int epid) -{ - writel(readl(&inep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, - &inep_regs_p[epid].endp_cntl); - - writel(readl(&outep_regs_p[epid].endp_cntl) | ENDP_CNTL_SNAK, - &outep_regs_p[epid].endp_cntl); -} - -void udc_unset_nak(int epid) -{ - u32 val; - - val = readl(&inep_regs_p[epid].endp_cntl); - val &= ~ENDP_CNTL_SNAK; - val |= ENDP_CNTL_CNAK; - writel(val, &inep_regs_p[epid].endp_cntl); - - val = readl(&outep_regs_p[epid].endp_cntl); - val &= ~ENDP_CNTL_SNAK; - val |= ENDP_CNTL_CNAK; - writel(val, &outep_regs_p[epid].endp_cntl); -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/ep0.c b/qemu/roms/u-boot/drivers/usb/gadget/ep0.c deleted file mode 100644 index b3214882f..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/ep0.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * (C) Copyright 2003 - * Gerry Hamel, geh@ti.com, Texas Instruments - * - * (C) Copyright 2006 - * Bryan O'Donoghue, deckard@CodeHermit.ie - * - * Based on - * linux/drivers/usbd/ep0.c - * - * Copyright (c) 2000, 2001, 2002 Lineo - * Copyright (c) 2001 Hewlett Packard - * - * By: - * Stuart Lynne <sl@lineo.com>, - * Tom Rushworth <tbr@lineo.com>, - * Bruce Balden <balden@lineo.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -/* - * This is the builtin ep0 control function. It implements all required functionality - * for responding to control requests (SETUP packets). - * - * XXX - * - * Currently we do not pass any SETUP packets (or other) to the configured - * function driver. This may need to change. - * - * XXX - * - * As alluded to above, a simple callback cdc_recv_setup has been implemented - * in the usb_device data structure to facilicate passing - * Common Device Class packets to a function driver. - * - * XXX - */ - -#include <common.h> -#include <usbdevice.h> - -#if 0 -#define dbg_ep0(lvl,fmt,args...) serial_printf("[%s] %s:%d: "fmt"\n",__FILE__,__FUNCTION__,__LINE__,##args) -#else -#define dbg_ep0(lvl,fmt,args...) -#endif - -/* EP0 Configuration Set ********************************************************************* */ - - -/** - * ep0_get_status - fill in URB data with appropriate status - * @device: - * @urb: - * @index: - * @requesttype: - * - */ -static int ep0_get_status (struct usb_device_instance *device, - struct urb *urb, int index, int requesttype) -{ - char *cp; - - urb->actual_length = 2; - cp = (char*)urb->buffer; - cp[0] = cp[1] = 0; - - switch (requesttype) { - case USB_REQ_RECIPIENT_DEVICE: - cp[0] = USB_STATUS_SELFPOWERED; - break; - case USB_REQ_RECIPIENT_INTERFACE: - break; - case USB_REQ_RECIPIENT_ENDPOINT: - cp[0] = usbd_endpoint_halted (device, index); - break; - case USB_REQ_RECIPIENT_OTHER: - urb->actual_length = 0; - default: - break; - } - dbg_ep0 (2, "%02x %02x", cp[0], cp[1]); - return 0; -} - -/** - * ep0_get_one - * @device: - * @urb: - * @result: - * - * Set a single byte value in the urb send buffer. Return non-zero to signal - * a request error. - */ -static int ep0_get_one (struct usb_device_instance *device, struct urb *urb, - __u8 result) -{ - urb->actual_length = 1; /* XXX 2? */ - ((char *) urb->buffer)[0] = result; - return 0; -} - -/** - * copy_config - * @urb: pointer to urb - * @data: pointer to configuration data - * @length: length of data - * - * Copy configuration data to urb transfer buffer if there is room for it. - */ -void copy_config (struct urb *urb, void *data, int max_length, - int max_buf) -{ - int available; - int length; - - /*dbg_ep0(3, "-> actual: %d buf: %d max_buf: %d max_length: %d data: %p", */ - /* urb->actual_length, urb->buffer_length, max_buf, max_length, data); */ - - if (!data) { - dbg_ep0 (1, "data is NULL"); - return; - } - length = max_length; - - if (length > max_length) { - dbg_ep0 (1, "length: %d >= max_length: %d", length, - max_length); - return; - } - /*dbg_ep0(1, " actual: %d buf: %d max_buf: %d max_length: %d length: %d", */ - /* urb->actual_length, urb->buffer_length, max_buf, max_length, length); */ - - if ((available = - /*urb->buffer_length */ max_buf - urb->actual_length) <= 0) { - return; - } - /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */ - /* urb->actual_length, urb->buffer_length, max_buf, length, available); */ - - if (length > available) { - length = available; - } - /*dbg_ep0(1, "actual: %d buf: %d max_buf: %d length: %d available: %d", */ - /* urb->actual_length, urb->buffer_length, max_buf, length, available); */ - - memcpy (urb->buffer + urb->actual_length, data, length); - urb->actual_length += length; - - dbg_ep0 (3, - "copy_config: <- actual: %d buf: %d max_buf: %d max_length: %d available: %d", - urb->actual_length, urb->buffer_length, max_buf, max_length, - available); -} - -/** - * ep0_get_descriptor - * @device: - * @urb: - * @max: - * @descriptor_type: - * @index: - * - * Called by ep0_rx_process for a get descriptor device command. Determine what - * descriptor is being requested, copy to send buffer. Return zero if ok to send, - * return non-zero to signal a request error. - */ -static int ep0_get_descriptor (struct usb_device_instance *device, - struct urb *urb, int max, int descriptor_type, - int index) -{ - int port = 0; /* XXX compound device */ - - /*dbg_ep0(3, "max: %x type: %x index: %x", max, descriptor_type, index); */ - - if (!urb || !urb->buffer || !urb->buffer_length - || (urb->buffer_length < 255)) { - dbg_ep0 (2, "invalid urb %p", urb); - return -1L; - } - - /* setup tx urb */ - urb->actual_length = 0; - - dbg_ep0 (2, "%s", USBD_DEVICE_DESCRIPTORS (descriptor_type)); - - switch (descriptor_type) { - case USB_DESCRIPTOR_TYPE_DEVICE: - { - struct usb_device_descriptor *device_descriptor; - if (! - (device_descriptor = - usbd_device_device_descriptor (device, port))) { - return -1; - } - /* copy descriptor for this device */ - copy_config (urb, device_descriptor, - sizeof (struct usb_device_descriptor), - max); - - /* correct the correct control endpoint 0 max packet size into the descriptor */ - device_descriptor = - (struct usb_device_descriptor *) urb->buffer; - - } - dbg_ep0(3, "copied device configuration, actual_length: 0x%x", urb->actual_length); - break; - - case USB_DESCRIPTOR_TYPE_CONFIGURATION: - { - struct usb_configuration_descriptor - *configuration_descriptor; - struct usb_device_descriptor *device_descriptor; - if (! - (device_descriptor = - usbd_device_device_descriptor (device, port))) { - return -1; - } - /*dbg_ep0(2, "%d %d", index, device_descriptor->bNumConfigurations); */ - if (index >= device_descriptor->bNumConfigurations) { - dbg_ep0 (0, "index too large: %d >= %d", index, - device_descriptor-> - bNumConfigurations); - return -1; - } - - if (! - (configuration_descriptor = - usbd_device_configuration_descriptor (device, - port, - index))) { - dbg_ep0 (0, - "usbd_device_configuration_descriptor failed: %d", - index); - return -1; - } - dbg_ep0(0, "attempt to copy %d bytes to urb\n",cpu_to_le16(configuration_descriptor->wTotalLength)); - copy_config (urb, configuration_descriptor, - - cpu_to_le16(configuration_descriptor->wTotalLength), - max); - } - - break; - - case USB_DESCRIPTOR_TYPE_STRING: - { - struct usb_string_descriptor *string_descriptor; - if (!(string_descriptor = usbd_get_string (index))) { - serial_printf("Invalid string index %d\n", index); - return -1; - } - dbg_ep0(3, "string_descriptor: %p length %d", string_descriptor, string_descriptor->bLength); - copy_config (urb, string_descriptor, string_descriptor->bLength, max); - } - break; - case USB_DESCRIPTOR_TYPE_INTERFACE: - serial_printf("USB_DESCRIPTOR_TYPE_INTERFACE - error not implemented\n"); - return -1; - case USB_DESCRIPTOR_TYPE_ENDPOINT: - serial_printf("USB_DESCRIPTOR_TYPE_ENDPOINT - error not implemented\n"); - return -1; - case USB_DESCRIPTOR_TYPE_HID: - { - serial_printf("USB_DESCRIPTOR_TYPE_HID - error not implemented\n"); - return -1; /* unsupported at this time */ -#if 0 - int bNumInterface = - le16_to_cpu (urb->device_request.wIndex); - int bAlternateSetting = 0; - int class = 0; - struct usb_class_descriptor *class_descriptor; - - if (!(class_descriptor = - usbd_device_class_descriptor_index (device, - port, 0, - bNumInterface, - bAlternateSetting, - class)) - || class_descriptor->descriptor.hid.bDescriptorType != USB_DT_HID) { - dbg_ep0 (3, "[%d] interface is not HID", - bNumInterface); - return -1; - } - /* copy descriptor for this class */ - copy_config (urb, class_descriptor, - class_descriptor->descriptor.hid.bLength, - max); -#endif - } - break; - case USB_DESCRIPTOR_TYPE_REPORT: - { - serial_printf("USB_DESCRIPTOR_TYPE_REPORT - error not implemented\n"); - return -1; /* unsupported at this time */ -#if 0 - int bNumInterface = - le16_to_cpu (urb->device_request.wIndex); - int bAlternateSetting = 0; - int class = 0; - struct usb_class_report_descriptor *report_descriptor; - - if (!(report_descriptor = - usbd_device_class_report_descriptor_index - (device, port, 0, bNumInterface, - bAlternateSetting, class)) - || report_descriptor->bDescriptorType != - USB_DT_REPORT) { - dbg_ep0 (3, "[%d] descriptor is not REPORT", - bNumInterface); - return -1; - } - /* copy report descriptor for this class */ - /*copy_config(urb, &report_descriptor->bData[0], report_descriptor->wLength, max); */ - if (max - urb->actual_length > 0) { - int length = - MIN (report_descriptor->wLength, - max - urb->actual_length); - memcpy (urb->buffer + urb->actual_length, - &report_descriptor->bData[0], length); - urb->actual_length += length; - } -#endif - } - break; - case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: -#if defined(CONFIG_USBD_HS) - { - struct usb_qualifier_descriptor *qualifier_descriptor = - device->qualifier_descriptor; - - if (!qualifier_descriptor) - return -1; - - /* copy descriptor for this device */ - copy_config(urb, qualifier_descriptor, - sizeof(struct usb_qualifier_descriptor), - max); - - } - dbg_ep0(3, "copied qualifier descriptor, actual_length: 0x%x", - urb->actual_length); -#else - return -1; -#endif - break; - - default: - return -1; - } - - - dbg_ep0 (1, "urb: buffer: %p buffer_length: %2d actual_length: %2d tx_packetSize: %2d", - urb->buffer, urb->buffer_length, urb->actual_length, - device->bus->endpoint_array[0].tx_packetSize); -/* - if ((urb->actual_length < max) && !(urb->actual_length % device->bus->endpoint_array[0].tx_packetSize)) { - dbg_ep0(0, "adding null byte"); - urb->buffer[urb->actual_length++] = 0; - dbg_ep0(0, "urb: buffer_length: %2d actual_length: %2d packet size: %2d", - urb->buffer_length, urb->actual_length device->bus->endpoint_array[0].tx_packetSize); - } -*/ - return 0; - -} - -/** - * ep0_recv_setup - called to indicate URB has been received - * @urb: pointer to struct urb - * - * Check if this is a setup packet, process the device request, put results - * back into the urb and return zero or non-zero to indicate success (DATA) - * or failure (STALL). - * - */ -int ep0_recv_setup (struct urb *urb) -{ - /*struct usb_device_request *request = urb->buffer; */ - /*struct usb_device_instance *device = urb->device; */ - - struct usb_device_request *request; - struct usb_device_instance *device; - int address; - - dbg_ep0 (0, "entering ep0_recv_setup()"); - if (!urb || !urb->device) { - dbg_ep0 (3, "invalid URB %p", urb); - return -1; - } - - request = &urb->device_request; - device = urb->device; - - dbg_ep0 (3, "urb: %p device: %p", urb, urb->device); - - - /*dbg_ep0(2, "- - - - - - - - - -"); */ - - dbg_ep0 (2, - "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x %s", - request->bmRequestType, request->bRequest, - le16_to_cpu (request->wValue), le16_to_cpu (request->wIndex), - le16_to_cpu (request->wLength), - USBD_DEVICE_REQUESTS (request->bRequest)); - - /* handle USB Standard Request (c.f. USB Spec table 9-2) */ - if ((request->bmRequestType & USB_REQ_TYPE_MASK) != 0) { - if(device->device_state <= STATE_CONFIGURED){ - /* Attempt to handle a CDC specific request if we are - * in the configured state. - */ - return device->cdc_recv_setup(request,urb); - } - dbg_ep0 (1, "non standard request: %x", - request->bmRequestType & USB_REQ_TYPE_MASK); - return -1; /* Stall here */ - } - - switch (device->device_state) { - case STATE_CREATED: - case STATE_ATTACHED: - case STATE_POWERED: - /* It actually is important to allow requests in these states, - * Windows will request descriptors before assigning an - * address to the client. - */ - - /*dbg_ep0 (1, "request %s not allowed in this state: %s", */ - /* USBD_DEVICE_REQUESTS(request->bRequest), */ - /* usbd_device_states[device->device_state]); */ - /*return -1; */ - break; - - case STATE_INIT: - case STATE_DEFAULT: - switch (request->bRequest) { - case USB_REQ_GET_STATUS: - case USB_REQ_GET_INTERFACE: - case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */ - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - case USB_REQ_SET_DESCRIPTOR: - /* case USB_REQ_SET_CONFIGURATION: */ - case USB_REQ_SET_INTERFACE: - dbg_ep0 (1, - "request %s not allowed in DEFAULT state: %s", - USBD_DEVICE_REQUESTS (request->bRequest), - usbd_device_states[device->device_state]); - return -1; - - case USB_REQ_SET_CONFIGURATION: - case USB_REQ_SET_ADDRESS: - case USB_REQ_GET_DESCRIPTOR: - case USB_REQ_GET_CONFIGURATION: - break; - } - case STATE_ADDRESSED: - case STATE_CONFIGURED: - break; - case STATE_UNKNOWN: - dbg_ep0 (1, "request %s not allowed in UNKNOWN state: %s", - USBD_DEVICE_REQUESTS (request->bRequest), - usbd_device_states[device->device_state]); - return -1; - } - - /* handle all requests that return data (direction bit set on bm RequestType) */ - if ((request->bmRequestType & USB_REQ_DIRECTION_MASK)) { - - dbg_ep0 (3, "Device-to-Host"); - - switch (request->bRequest) { - - case USB_REQ_GET_STATUS: - return ep0_get_status (device, urb, request->wIndex, - request->bmRequestType & - USB_REQ_RECIPIENT_MASK); - - case USB_REQ_GET_DESCRIPTOR: - return ep0_get_descriptor (device, urb, - le16_to_cpu (request->wLength), - le16_to_cpu (request->wValue) >> 8, - le16_to_cpu (request->wValue) & 0xff); - - case USB_REQ_GET_CONFIGURATION: - serial_printf("get config %d\n", device->configuration); - return ep0_get_one (device, urb, - device->configuration); - - case USB_REQ_GET_INTERFACE: - return ep0_get_one (device, urb, device->alternate); - - case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */ - return -1; - - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - case USB_REQ_SET_ADDRESS: - case USB_REQ_SET_DESCRIPTOR: - case USB_REQ_SET_CONFIGURATION: - case USB_REQ_SET_INTERFACE: - return -1; - } - } - /* handle the requests that do not return data */ - else { - - - /*dbg_ep0(3, "Host-to-Device"); */ - switch (request->bRequest) { - - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - dbg_ep0 (0, "Host-to-Device"); - switch (request-> - bmRequestType & USB_REQ_RECIPIENT_MASK) { - case USB_REQ_RECIPIENT_DEVICE: - /* XXX DEVICE_REMOTE_WAKEUP or TEST_MODE would be added here */ - /* XXX fall through for now as we do not support either */ - case USB_REQ_RECIPIENT_INTERFACE: - case USB_REQ_RECIPIENT_OTHER: - dbg_ep0 (0, "request %s not", - USBD_DEVICE_REQUESTS (request->bRequest)); - default: - return -1; - - case USB_REQ_RECIPIENT_ENDPOINT: - dbg_ep0 (0, "ENDPOINT: %x", le16_to_cpu (request->wValue)); - if (le16_to_cpu (request->wValue) == USB_ENDPOINT_HALT) { - /*return usbd_device_feature (device, le16_to_cpu (request->wIndex), */ - /* request->bRequest == USB_REQ_SET_FEATURE); */ - /* NEED TO IMPLEMENT THIS!!! */ - return -1; - } else { - dbg_ep0 (1, "request %s bad wValue: %04x", - USBD_DEVICE_REQUESTS - (request->bRequest), - le16_to_cpu (request->wValue)); - return -1; - } - } - - case USB_REQ_SET_ADDRESS: - /* check if this is a re-address, reset first if it is (this shouldn't be possible) */ - if (device->device_state != STATE_DEFAULT) { - dbg_ep0 (1, "set_address: %02x state: %s", - le16_to_cpu (request->wValue), - usbd_device_states[device->device_state]); - return -1; - } - address = le16_to_cpu (request->wValue); - if ((address & 0x7f) != address) { - dbg_ep0 (1, "invalid address %04x %04x", - address, address & 0x7f); - return -1; - } - device->address = address; - - /*dbg_ep0(2, "address: %d %d %d", */ - /* request->wValue, le16_to_cpu(request->wValue), device->address); */ - - return 0; - - case USB_REQ_SET_DESCRIPTOR: /* XXX should we support this? */ - dbg_ep0 (0, "set descriptor: NOT SUPPORTED"); - return -1; - - case USB_REQ_SET_CONFIGURATION: - /* c.f. 9.4.7 - the top half of wValue is reserved */ - device->configuration = le16_to_cpu(request->wValue) & 0xff; - - /* reset interface and alternate settings */ - device->interface = device->alternate = 0; - - /*dbg_ep0(2, "set configuration: %d", device->configuration); */ - /*serial_printf("DEVICE_CONFIGURED.. event?\n"); */ - return 0; - - case USB_REQ_SET_INTERFACE: - device->interface = le16_to_cpu (request->wIndex); - device->alternate = le16_to_cpu (request->wValue); - /*dbg_ep0(2, "set interface: %d alternate: %d", device->interface, device->alternate); */ - serial_printf ("DEVICE_SET_INTERFACE.. event?\n"); - return 0; - - case USB_REQ_GET_STATUS: - case USB_REQ_GET_DESCRIPTOR: - case USB_REQ_GET_CONFIGURATION: - case USB_REQ_GET_INTERFACE: - case USB_REQ_SYNCH_FRAME: /* XXX should never see this (?) */ - return -1; - } - } - return -1; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/ep0.h b/qemu/roms/u-boot/drivers/usb/gadget/ep0.h deleted file mode 100644 index 6042e7562..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/ep0.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * (C) Copyright 2003 - * Gerry Hamel, geh@ti.com, Texas Instruments - * - * Based on - * linux/drivers/usbd/ep0.c - * - * Copyright (c) 2000, 2001, 2002 Lineo - * Copyright (c) 2001 Hewlett Packard - * - * By: - * Stuart Lynne <sl@lineo.com>, - * Tom Rushworth <tbr@lineo.com>, - * Bruce Balden <balden@lineo.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __USBDCORE_EP0_H__ -#define __USBDCORE_EP0_H__ - - -int ep0_recv_setup (struct urb *urb); - - -#endif diff --git a/qemu/roms/u-boot/drivers/usb/gadget/epautoconf.c b/qemu/roms/u-boot/drivers/usb/gadget/epautoconf.c deleted file mode 100644 index 0df4b2a10..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/epautoconf.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * epautoconf.c -- endpoint autoconfiguration for usb gadget drivers - * - * Copyright (C) 2004 David Brownell - * - * SPDX-License-Identifier: GPL-2.0+ - * - * SPDX-License-Identifier: GPL-2.0+ - * - * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and - * Remy Bohmer <linux@bohmer.net> - */ - -#include <common.h> -#include <linux/usb/ch9.h> -#include <asm/errno.h> -#include <linux/usb/gadget.h> -#include <asm/unaligned.h> -#include "gadget_chips.h" - -#define isdigit(c) ('0' <= (c) && (c) <= '9') - -/* we must assign addresses for configurable endpoints (like net2280) */ -static unsigned epnum; - -/* #define MANY_ENDPOINTS */ -#ifdef MANY_ENDPOINTS -/* more than 15 configurable endpoints */ -static unsigned in_epnum; -#endif - - -/* - * This should work with endpoints from controller drivers sharing the - * same endpoint naming convention. By example: - * - * - ep1, ep2, ... address is fixed, not direction or type - * - ep1in, ep2out, ... address and direction are fixed, not type - * - ep1-bulk, ep2-bulk, ... address and type are fixed, not direction - * - ep1in-bulk, ep2out-iso, ... all three are fixed - * - ep-* ... no functionality restrictions - * - * Type suffixes are "-bulk", "-iso", or "-int". Numbers are decimal. - * Less common restrictions are implied by gadget_is_*(). - * - * NOTE: each endpoint is unidirectional, as specified by its USB - * descriptor; and isn't specific to a configuration or altsetting. - */ -static int ep_matches( - struct usb_gadget *gadget, - struct usb_ep *ep, - struct usb_endpoint_descriptor *desc -) -{ - u8 type; - const char *tmp; - u16 max; - - /* endpoint already claimed? */ - if (NULL != ep->driver_data) - return 0; - - /* only support ep0 for portable CONTROL traffic */ - type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - if (USB_ENDPOINT_XFER_CONTROL == type) - return 0; - - /* some other naming convention */ - if ('e' != ep->name[0]) - return 0; - - /* type-restriction: "-iso", "-bulk", or "-int". - * direction-restriction: "in", "out". - */ - if ('-' != ep->name[2]) { - tmp = strrchr(ep->name, '-'); - if (tmp) { - switch (type) { - case USB_ENDPOINT_XFER_INT: - /* bulk endpoints handle interrupt transfers, - * except the toggle-quirky iso-synch kind - */ - if ('s' == tmp[2]) /* == "-iso" */ - return 0; - /* for now, avoid PXA "interrupt-in"; - * it's documented as never using DATA1. - */ - if (gadget_is_pxa(gadget) - && 'i' == tmp[1]) - return 0; - break; - case USB_ENDPOINT_XFER_BULK: - if ('b' != tmp[1]) /* != "-bulk" */ - return 0; - break; - case USB_ENDPOINT_XFER_ISOC: - if ('s' != tmp[2]) /* != "-iso" */ - return 0; - } - } else { - tmp = ep->name + strlen(ep->name); - } - - /* direction-restriction: "..in-..", "out-.." */ - tmp--; - if (!isdigit(*tmp)) { - if (desc->bEndpointAddress & USB_DIR_IN) { - if ('n' != *tmp) - return 0; - } else { - if ('t' != *tmp) - return 0; - } - } - } - - /* endpoint maxpacket size is an input parameter, except for bulk - * where it's an output parameter representing the full speed limit. - * the usb spec fixes high speed bulk maxpacket at 512 bytes. - */ - max = 0x7ff & le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); - switch (type) { - case USB_ENDPOINT_XFER_INT: - /* INT: limit 64 bytes full speed, 1024 high speed */ - if (!gadget->is_dualspeed && max > 64) - return 0; - /* FALLTHROUGH */ - - case USB_ENDPOINT_XFER_ISOC: - /* ISO: limit 1023 bytes full speed, 1024 high speed */ - if (ep->maxpacket < max) - return 0; - if (!gadget->is_dualspeed && max > 1023) - return 0; - - /* BOTH: "high bandwidth" works only at high speed */ - if ((get_unaligned(&desc->wMaxPacketSize) & - __constant_cpu_to_le16(3<<11))) { - if (!gadget->is_dualspeed) - return 0; - /* configure your hardware with enough buffering!! */ - } - break; - } - - /* MATCH!! */ - - /* report address */ - if (isdigit(ep->name[2])) { - u8 num = simple_strtoul(&ep->name[2], NULL, 10); - desc->bEndpointAddress |= num; -#ifdef MANY_ENDPOINTS - } else if (desc->bEndpointAddress & USB_DIR_IN) { - if (++in_epnum > 15) - return 0; - desc->bEndpointAddress = USB_DIR_IN | in_epnum; -#endif - } else { - if (++epnum > 15) - return 0; - desc->bEndpointAddress |= epnum; - } - - /* report (variable) full speed bulk maxpacket */ - if (USB_ENDPOINT_XFER_BULK == type) { - int size = ep->maxpacket; - - /* min() doesn't work on bitfields with gcc-3.5 */ - if (size > 64) - size = 64; - put_unaligned(cpu_to_le16(size), &desc->wMaxPacketSize); - } - return 1; -} - -static struct usb_ep * -find_ep(struct usb_gadget *gadget, const char *name) -{ - struct usb_ep *ep; - - list_for_each_entry(ep, &gadget->ep_list, ep_list) { - if (0 == strcmp(ep->name, name)) - return ep; - } - return NULL; -} - -/** - * usb_ep_autoconfig - choose an endpoint matching the descriptor - * @gadget: The device to which the endpoint must belong. - * @desc: Endpoint descriptor, with endpoint direction and transfer mode - * initialized. For periodic transfers, the maximum packet - * size must also be initialized. This is modified on success. - * - * By choosing an endpoint to use with the specified descriptor, this - * routine simplifies writing gadget drivers that work with multiple - * USB device controllers. The endpoint would be passed later to - * usb_ep_enable(), along with some descriptor. - * - * That second descriptor won't always be the same as the first one. - * For example, isochronous endpoints can be autoconfigured for high - * bandwidth, and then used in several lower bandwidth altsettings. - * Also, high and full speed descriptors will be different. - * - * Be sure to examine and test the results of autoconfiguration on your - * hardware. This code may not make the best choices about how to use the - * USB controller, and it can't know all the restrictions that may apply. - * Some combinations of driver and hardware won't be able to autoconfigure. - * - * On success, this returns an un-claimed usb_ep, and modifies the endpoint - * descriptor bEndpointAddress. For bulk endpoints, the wMaxPacket value - * is initialized as if the endpoint were used at full speed. To prevent - * the endpoint from being returned by a later autoconfig call, claim it - * by assigning ep->driver_data to some non-null value. - * - * On failure, this returns a null endpoint descriptor. - */ -struct usb_ep *usb_ep_autoconfig( - struct usb_gadget *gadget, - struct usb_endpoint_descriptor *desc -) -{ - struct usb_ep *ep; - u8 type; - - type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; - - /* First, apply chip-specific "best usage" knowledge. - * This might make a good usb_gadget_ops hook ... - */ - if (gadget_is_net2280(gadget) && type == USB_ENDPOINT_XFER_INT) { - /* ep-e, ep-f are PIO with only 64 byte fifos */ - ep = find_ep(gadget, "ep-e"); - if (ep && ep_matches(gadget, ep, desc)) - return ep; - ep = find_ep(gadget, "ep-f"); - if (ep && ep_matches(gadget, ep, desc)) - return ep; - - } else if (gadget_is_goku(gadget)) { - if (USB_ENDPOINT_XFER_INT == type) { - /* single buffering is enough */ - ep = find_ep(gadget, "ep3-bulk"); - if (ep && ep_matches(gadget, ep, desc)) - return ep; - } else if (USB_ENDPOINT_XFER_BULK == type - && (USB_DIR_IN & desc->bEndpointAddress)) { - /* DMA may be available */ - ep = find_ep(gadget, "ep2-bulk"); - if (ep && ep_matches(gadget, ep, desc)) - return ep; - } - - } else if (gadget_is_sh(gadget) && USB_ENDPOINT_XFER_INT == type) { - /* single buffering is enough; maybe 8 byte fifo is too */ - ep = find_ep(gadget, "ep3in-bulk"); - if (ep && ep_matches(gadget, ep, desc)) - return ep; - - } else if (gadget_is_mq11xx(gadget) && USB_ENDPOINT_XFER_INT == type) { - ep = find_ep(gadget, "ep1-bulk"); - if (ep && ep_matches(gadget, ep, desc)) - return ep; - } - - /* Second, look at endpoints until an unclaimed one looks usable */ - list_for_each_entry(ep, &gadget->ep_list, ep_list) { - if (ep_matches(gadget, ep, desc)) - return ep; - } - - /* Fail */ - return NULL; -} - -/** - * usb_ep_autoconfig_reset - reset endpoint autoconfig state - * @gadget: device for which autoconfig state will be reset - * - * Use this for devices where one configuration may need to assign - * endpoint resources very differently from the next one. It clears - * state such as ep->driver_data and the record of assigned endpoints - * used by usb_ep_autoconfig(). - */ -void usb_ep_autoconfig_reset(struct usb_gadget *gadget) -{ - struct usb_ep *ep; - - list_for_each_entry(ep, &gadget->ep_list, ep_list) { - ep->driver_data = NULL; - } -#ifdef MANY_ENDPOINTS - in_epnum = 0; -#endif - epnum = 0; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/ether.c b/qemu/roms/u-boot/drivers/usb/gadget/ether.c deleted file mode 100644 index cc6cc1f32..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/ether.c +++ /dev/null @@ -1,2555 +0,0 @@ -/* - * ether.c -- Ethernet gadget driver, with CDC and non-CDC options - * - * Copyright (C) 2003-2005,2008 David Brownell - * Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger - * Copyright (C) 2008 Nokia Corporation - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/errno.h> -#include <linux/netdevice.h> -#include <linux/usb/ch9.h> -#include <linux/usb/cdc.h> -#include <linux/usb/gadget.h> -#include <net.h> -#include <malloc.h> -#include <linux/ctype.h> - -#include "gadget_chips.h" -#include "rndis.h" - -#define USB_NET_NAME "usb_ether" - -#define atomic_read -extern struct platform_data brd; -#define spin_lock(x) -#define spin_unlock(x) - - -unsigned packet_received, packet_sent; - -#define GFP_ATOMIC ((gfp_t) 0) -#define GFP_KERNEL ((gfp_t) 0) - -/* - * Ethernet gadget driver -- with CDC and non-CDC options - * Builds on hardware support for a full duplex link. - * - * CDC Ethernet is the standard USB solution for sending Ethernet frames - * using USB. Real hardware tends to use the same framing protocol but look - * different for control features. This driver strongly prefers to use - * this USB-IF standard as its open-systems interoperability solution; - * most host side USB stacks (except from Microsoft) support it. - * - * This is sometimes called "CDC ECM" (Ethernet Control Model) to support - * TLA-soup. "CDC ACM" (Abstract Control Model) is for modems, and a new - * "CDC EEM" (Ethernet Emulation Model) is starting to spread. - * - * There's some hardware that can't talk CDC ECM. We make that hardware - * implement a "minimalist" vendor-agnostic CDC core: same framing, but - * link-level setup only requires activating the configuration. Only the - * endpoint descriptors, and product/vendor IDs, are relevant; no control - * operations are available. Linux supports it, but other host operating - * systems may not. (This is a subset of CDC Ethernet.) - * - * It turns out that if you add a few descriptors to that "CDC Subset", - * (Windows) host side drivers from MCCI can treat it as one submode of - * a proprietary scheme called "SAFE" ... without needing to know about - * specific product/vendor IDs. So we do that, making it easier to use - * those MS-Windows drivers. Those added descriptors make it resemble a - * CDC MDLM device, but they don't change device behavior at all. (See - * MCCI Engineering report 950198 "SAFE Networking Functions".) - * - * A third option is also in use. Rather than CDC Ethernet, or something - * simpler, Microsoft pushes their own approach: RNDIS. The published - * RNDIS specs are ambiguous and appear to be incomplete, and are also - * needlessly complex. They borrow more from CDC ACM than CDC ECM. - */ -#define ETH_ALEN 6 /* Octets in one ethernet addr */ -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */ -#define ETH_FCS_LEN 4 /* Octets in the FCS */ - -#define DRIVER_DESC "Ethernet Gadget" -/* Based on linux 2.6.27 version */ -#define DRIVER_VERSION "May Day 2005" - -static const char shortname[] = "ether"; -static const char driver_desc[] = DRIVER_DESC; - -#define RX_EXTRA 20 /* guard against rx overflows */ - -#ifndef CONFIG_USB_ETH_RNDIS -#define rndis_uninit(x) do {} while (0) -#define rndis_deregister(c) do {} while (0) -#define rndis_exit() do {} while (0) -#endif - -/* CDC and RNDIS support the same host-chosen outgoing packet filters. */ -#define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ - |USB_CDC_PACKET_TYPE_ALL_MULTICAST \ - |USB_CDC_PACKET_TYPE_PROMISCUOUS \ - |USB_CDC_PACKET_TYPE_DIRECTED) - -#define USB_CONNECT_TIMEOUT (3 * CONFIG_SYS_HZ) - -/*-------------------------------------------------------------------------*/ - -struct eth_dev { - struct usb_gadget *gadget; - struct usb_request *req; /* for control responses */ - struct usb_request *stat_req; /* for cdc & rndis status */ - - u8 config; - struct usb_ep *in_ep, *out_ep, *status_ep; - const struct usb_endpoint_descriptor - *in, *out, *status; - - struct usb_request *tx_req, *rx_req; - - struct eth_device *net; - struct net_device_stats stats; - unsigned int tx_qlen; - - unsigned zlp:1; - unsigned cdc:1; - unsigned rndis:1; - unsigned suspended:1; - unsigned network_started:1; - u16 cdc_filter; - unsigned long todo; - int mtu; -#define WORK_RX_MEMORY 0 - int rndis_config; - u8 host_mac[ETH_ALEN]; -}; - -/* - * This version autoconfigures as much as possible at run-time. - * - * It also ASSUMES a self-powered device, without remote wakeup, - * although remote wakeup support would make sense. - */ - -/*-------------------------------------------------------------------------*/ -static struct eth_dev l_ethdev; -static struct eth_device l_netdev; -static struct usb_gadget_driver eth_driver; - -/*-------------------------------------------------------------------------*/ - -/* "main" config is either CDC, or its simple subset */ -static inline int is_cdc(struct eth_dev *dev) -{ -#if !defined(CONFIG_USB_ETH_SUBSET) - return 1; /* only cdc possible */ -#elif !defined(CONFIG_USB_ETH_CDC) - return 0; /* only subset possible */ -#else - return dev->cdc; /* depends on what hardware we found */ -#endif -} - -/* "secondary" RNDIS config may sometimes be activated */ -static inline int rndis_active(struct eth_dev *dev) -{ -#ifdef CONFIG_USB_ETH_RNDIS - return dev->rndis; -#else - return 0; -#endif -} - -#define subset_active(dev) (!is_cdc(dev) && !rndis_active(dev)) -#define cdc_active(dev) (is_cdc(dev) && !rndis_active(dev)) - -#define DEFAULT_QLEN 2 /* double buffering by default */ - -/* peak bulk transfer bits-per-second */ -#define HS_BPS (13 * 512 * 8 * 1000 * 8) -#define FS_BPS (19 * 64 * 1 * 1000 * 8) - -#ifdef CONFIG_USB_GADGET_DUALSPEED -#define DEVSPEED USB_SPEED_HIGH - -#ifdef CONFIG_USB_ETH_QMULT -#define qmult CONFIG_USB_ETH_QMULT -#else -#define qmult 5 -#endif - -/* for dual-speed hardware, use deeper queues at highspeed */ -#define qlen(gadget) \ - (DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1)) - -static inline int BITRATE(struct usb_gadget *g) -{ - return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS; -} - -#else /* full speed (low speed doesn't do bulk) */ - -#define qmult 1 - -#define DEVSPEED USB_SPEED_FULL - -#define qlen(gadget) DEFAULT_QLEN - -static inline int BITRATE(struct usb_gadget *g) -{ - return FS_BPS; -} -#endif - -/*-------------------------------------------------------------------------*/ - -/* - * DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! - * Instead: allocate your own, using normal USB-IF procedures. - */ - -/* - * Thanks to NetChip Technologies for donating this product ID. - * It's for devices with only CDC Ethernet configurations. - */ -#define CDC_VENDOR_NUM 0x0525 /* NetChip */ -#define CDC_PRODUCT_NUM 0xa4a1 /* Linux-USB Ethernet Gadget */ - -/* - * For hardware that can't talk CDC, we use the same vendor ID that - * ARM Linux has used for ethernet-over-usb, both with sa1100 and - * with pxa250. We're protocol-compatible, if the host-side drivers - * use the endpoint descriptors. bcdDevice (version) is nonzero, so - * drivers that need to hard-wire endpoint numbers have a hook. - * - * The protocol is a minimal subset of CDC Ether, which works on any bulk - * hardware that's not deeply broken ... even on hardware that can't talk - * RNDIS (like SA-1100, with no interrupt endpoint, or anything that - * doesn't handle control-OUT). - */ -#define SIMPLE_VENDOR_NUM 0x049f /* Compaq Computer Corp. */ -#define SIMPLE_PRODUCT_NUM 0x505a /* Linux-USB "CDC Subset" Device */ - -/* - * For hardware that can talk RNDIS and either of the above protocols, - * use this ID ... the windows INF files will know it. Unless it's - * used with CDC Ethernet, Linux 2.4 hosts will need updates to choose - * the non-RNDIS configuration. - */ -#define RNDIS_VENDOR_NUM 0x0525 /* NetChip */ -#define RNDIS_PRODUCT_NUM 0xa4a2 /* Ethernet/RNDIS Gadget */ - -/* - * Some systems will want different product identifers published in the - * device descriptor, either numbers or strings or both. These string - * parameters are in UTF-8 (superset of ASCII's 7 bit characters). - */ - -/* - * Emulating them in eth_bind: - * static ushort idVendor; - * static ushort idProduct; - */ - -#if defined(CONFIG_USBNET_MANUFACTURER) -static char *iManufacturer = CONFIG_USBNET_MANUFACTURER; -#else -static char *iManufacturer = "U-boot"; -#endif - -/* These probably need to be configurable. */ -static ushort bcdDevice; -static char *iProduct; -static char *iSerialNumber; - -static char dev_addr[18]; - -static char host_addr[18]; - - -/*-------------------------------------------------------------------------*/ - -/* - * USB DRIVER HOOKUP (to the hardware driver, below us), mostly - * ep0 implementation: descriptors, config management, setup(). - * also optional class-specific notification interrupt transfer. - */ - -/* - * DESCRIPTORS ... most are static, but strings and (full) configuration - * descriptors are built on demand. For now we do either full CDC, or - * our simple subset, with RNDIS as an optional second configuration. - * - * RNDIS includes some CDC ACM descriptors ... like CDC Ethernet. But - * the class descriptors match a modem (they're ignored; it's really just - * Ethernet functionality), they don't need the NOP altsetting, and the - * status transfer endpoint isn't optional. - */ - -#define STRING_MANUFACTURER 1 -#define STRING_PRODUCT 2 -#define STRING_ETHADDR 3 -#define STRING_DATA 4 -#define STRING_CONTROL 5 -#define STRING_RNDIS_CONTROL 6 -#define STRING_CDC 7 -#define STRING_SUBSET 8 -#define STRING_RNDIS 9 -#define STRING_SERIALNUMBER 10 - -/* holds our biggest descriptor (or RNDIS response) */ -#define USB_BUFSIZ 256 - -/* - * This device advertises one configuration, eth_config, unless RNDIS - * is enabled (rndis_config) on hardware supporting at least two configs. - * - * NOTE: Controllers like superh_udc should probably be able to use - * an RNDIS-only configuration. - * - * FIXME define some higher-powered configurations to make it easier - * to recharge batteries ... - */ - -#define DEV_CONFIG_VALUE 1 /* cdc or subset */ -#define DEV_RNDIS_CONFIG_VALUE 2 /* rndis; optional */ - -static struct usb_device_descriptor -device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = __constant_cpu_to_le16(0x0200), - - .bDeviceClass = USB_CLASS_COMM, - .bDeviceSubClass = 0, - .bDeviceProtocol = 0, - - .idVendor = __constant_cpu_to_le16(CDC_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16(CDC_PRODUCT_NUM), - .iManufacturer = STRING_MANUFACTURER, - .iProduct = STRING_PRODUCT, - .bNumConfigurations = 1, -}; - -static struct usb_otg_descriptor -otg_descriptor = { - .bLength = sizeof otg_descriptor, - .bDescriptorType = USB_DT_OTG, - - .bmAttributes = USB_OTG_SRP, -}; - -static struct usb_config_descriptor -eth_config = { - .bLength = sizeof eth_config, - .bDescriptorType = USB_DT_CONFIG, - - /* compute wTotalLength on the fly */ - .bNumInterfaces = 2, - .bConfigurationValue = DEV_CONFIG_VALUE, - .iConfiguration = STRING_CDC, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 1, -}; - -#ifdef CONFIG_USB_ETH_RNDIS -static struct usb_config_descriptor -rndis_config = { - .bLength = sizeof rndis_config, - .bDescriptorType = USB_DT_CONFIG, - - /* compute wTotalLength on the fly */ - .bNumInterfaces = 2, - .bConfigurationValue = DEV_RNDIS_CONFIG_VALUE, - .iConfiguration = STRING_RNDIS, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = 1, -}; -#endif - -/* - * Compared to the simple CDC subset, the full CDC Ethernet model adds - * three class descriptors, two interface descriptors, optional status - * endpoint. Both have a "data" interface and two bulk endpoints. - * There are also differences in how control requests are handled. - * - * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the - * CDC-ACM (modem) spec. Unfortunately MSFT's RNDIS driver is buggy; it - * may hang or oops. Since bugfixes (or accurate specs, letting Linux - * work around those bugs) are unlikely to ever come from MSFT, you may - * wish to avoid using RNDIS. - * - * MCCI offers an alternative to RNDIS if you need to connect to Windows - * but have hardware that can't support CDC Ethernet. We add descriptors - * to present the CDC Subset as a (nonconformant) CDC MDLM variant called - * "SAFE". That borrows from both CDC Ethernet and CDC MDLM. You can - * get those drivers from MCCI, or bundled with various products. - */ - -#ifdef CONFIG_USB_ETH_CDC -static struct usb_interface_descriptor -control_intf = { - .bLength = sizeof control_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 0, - /* status endpoint is optional; this may be patched later */ - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ETHERNET, - .bInterfaceProtocol = USB_CDC_PROTO_NONE, - .iInterface = STRING_CONTROL, -}; -#endif - -#ifdef CONFIG_USB_ETH_RNDIS -static const struct usb_interface_descriptor -rndis_control_intf = { - .bLength = sizeof rndis_control_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 0, - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - .bInterfaceProtocol = USB_CDC_ACM_PROTO_VENDOR, - .iInterface = STRING_RNDIS_CONTROL, -}; -#endif - -static const struct usb_cdc_header_desc header_desc = { - .bLength = sizeof header_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_HEADER_TYPE, - - .bcdCDC = __constant_cpu_to_le16(0x0110), -}; - -#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) - -static const struct usb_cdc_union_desc union_desc = { - .bLength = sizeof union_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_UNION_TYPE, - - .bMasterInterface0 = 0, /* index of control interface */ - .bSlaveInterface0 = 1, /* index of DATA interface */ -}; - -#endif /* CDC || RNDIS */ - -#ifdef CONFIG_USB_ETH_RNDIS - -static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = { - .bLength = sizeof call_mgmt_descriptor, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, - - .bmCapabilities = 0x00, - .bDataInterface = 0x01, -}; - -static const struct usb_cdc_acm_descriptor acm_descriptor = { - .bLength = sizeof acm_descriptor, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ACM_TYPE, - - .bmCapabilities = 0x00, -}; - -#endif - -#ifndef CONFIG_USB_ETH_CDC - -/* - * "SAFE" loosely follows CDC WMC MDLM, violating the spec in various - * ways: data endpoints live in the control interface, there's no data - * interface, and it's not used to talk to a cell phone radio. - */ - -static const struct usb_cdc_mdlm_desc mdlm_desc = { - .bLength = sizeof mdlm_desc, - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_MDLM_TYPE, - - .bcdVersion = __constant_cpu_to_le16(0x0100), - .bGUID = { - 0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6, - 0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f, - }, -}; - -/* - * since "usb_cdc_mdlm_detail_desc" is a variable length structure, we - * can't really use its struct. All we do here is say that we're using - * the submode of "SAFE" which directly matches the CDC Subset. - */ -static const u8 mdlm_detail_desc[] = { - 6, - USB_DT_CS_INTERFACE, - USB_CDC_MDLM_DETAIL_TYPE, - - 0, /* "SAFE" */ - 0, /* network control capabilities (none) */ - 0, /* network data capabilities ("raw" encapsulation) */ -}; - -#endif - -static const struct usb_cdc_ether_desc ether_desc = { - .bLength = sizeof(ether_desc), - .bDescriptorType = USB_DT_CS_INTERFACE, - .bDescriptorSubType = USB_CDC_ETHERNET_TYPE, - - /* this descriptor actually adds value, surprise! */ - .iMACAddress = STRING_ETHADDR, - .bmEthernetStatistics = __constant_cpu_to_le32(0), /* no statistics */ - .wMaxSegmentSize = __constant_cpu_to_le16(ETH_FRAME_LEN), - .wNumberMCFilters = __constant_cpu_to_le16(0), - .bNumberPowerFilters = 0, -}; - -#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) - -/* - * include the status endpoint if we can, even where it's optional. - * use wMaxPacketSize big enough to fit CDC_NOTIFY_SPEED_CHANGE in one - * packet, to simplify cancellation; and a big transfer interval, to - * waste less bandwidth. - * - * some drivers (like Linux 2.4 cdc-ether!) "need" it to exist even - * if they ignore the connect/disconnect notifications that real aether - * can provide. more advanced cdc configurations might want to support - * encapsulated commands (vendor-specific, using control-OUT). - * - * RNDIS requires the status endpoint, since it uses that encapsulation - * mechanism for its funky RPC scheme. - */ - -#define LOG2_STATUS_INTERVAL_MSEC 5 /* 1 << 5 == 32 msec */ -#define STATUS_BYTECOUNT 16 /* 8 byte header + data */ - -static struct usb_endpoint_descriptor -fs_status_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = 1 << LOG2_STATUS_INTERVAL_MSEC, -}; -#endif - -#ifdef CONFIG_USB_ETH_CDC - -/* the default data interface has no endpoints ... */ - -static const struct usb_interface_descriptor -data_nop_intf = { - .bLength = sizeof data_nop_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 1, - .bAlternateSetting = 0, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, -}; - -/* ... but the "real" data interface has two bulk endpoints */ - -static const struct usb_interface_descriptor -data_intf = { - .bLength = sizeof data_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 1, - .bAlternateSetting = 1, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = STRING_DATA, -}; - -#endif - -#ifdef CONFIG_USB_ETH_RNDIS - -/* RNDIS doesn't activate by changing to the "real" altsetting */ - -static const struct usb_interface_descriptor -rndis_data_intf = { - .bLength = sizeof rndis_data_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 1, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, - .bInterfaceSubClass = 0, - .bInterfaceProtocol = 0, - .iInterface = STRING_DATA, -}; - -#endif - -#ifdef CONFIG_USB_ETH_SUBSET - -/* - * "Simple" CDC-subset option is a simple vendor-neutral model that most - * full speed controllers can handle: one interface, two bulk endpoints. - * - * To assist host side drivers, we fancy it up a bit, and add descriptors - * so some host side drivers will understand it as a "SAFE" variant. - */ - -static const struct usb_interface_descriptor -subset_data_intf = { - .bLength = sizeof subset_data_intf, - .bDescriptorType = USB_DT_INTERFACE, - - .bInterfaceNumber = 0, - .bAlternateSetting = 0, - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_COMM, - .bInterfaceSubClass = USB_CDC_SUBCLASS_MDLM, - .bInterfaceProtocol = 0, - .iInterface = STRING_DATA, -}; - -#endif /* SUBSET */ - -static struct usb_endpoint_descriptor -fs_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(64), -}; - -static struct usb_endpoint_descriptor -fs_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(64), -}; - -static const struct usb_descriptor_header *fs_eth_function[11] = { - (struct usb_descriptor_header *) &otg_descriptor, -#ifdef CONFIG_USB_ETH_CDC - /* "cdc" mode descriptors */ - (struct usb_descriptor_header *) &control_intf, - (struct usb_descriptor_header *) &header_desc, - (struct usb_descriptor_header *) &union_desc, - (struct usb_descriptor_header *) ðer_desc, - /* NOTE: status endpoint may need to be removed */ - (struct usb_descriptor_header *) &fs_status_desc, - /* data interface, with altsetting */ - (struct usb_descriptor_header *) &data_nop_intf, - (struct usb_descriptor_header *) &data_intf, - (struct usb_descriptor_header *) &fs_source_desc, - (struct usb_descriptor_header *) &fs_sink_desc, - NULL, -#endif /* CONFIG_USB_ETH_CDC */ -}; - -static inline void fs_subset_descriptors(void) -{ -#ifdef CONFIG_USB_ETH_SUBSET - /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ - fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; - fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; - fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; - fs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; - fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc; - fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc; - fs_eth_function[8] = NULL; -#else - fs_eth_function[1] = NULL; -#endif -} - -#ifdef CONFIG_USB_ETH_RNDIS -static const struct usb_descriptor_header *fs_rndis_function[] = { - (struct usb_descriptor_header *) &otg_descriptor, - /* control interface matches ACM, not Ethernet */ - (struct usb_descriptor_header *) &rndis_control_intf, - (struct usb_descriptor_header *) &header_desc, - (struct usb_descriptor_header *) &call_mgmt_descriptor, - (struct usb_descriptor_header *) &acm_descriptor, - (struct usb_descriptor_header *) &union_desc, - (struct usb_descriptor_header *) &fs_status_desc, - /* data interface has no altsetting */ - (struct usb_descriptor_header *) &rndis_data_intf, - (struct usb_descriptor_header *) &fs_source_desc, - (struct usb_descriptor_header *) &fs_sink_desc, - NULL, -}; -#endif - -/* - * usb 2.0 devices need to expose both high speed and full speed - * descriptors, unless they only run at full speed. - */ - -#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) -static struct usb_endpoint_descriptor -hs_status_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(STATUS_BYTECOUNT), - .bInterval = LOG2_STATUS_INTERVAL_MSEC + 4, -}; -#endif /* CONFIG_USB_ETH_CDC */ - -static struct usb_endpoint_descriptor -hs_source_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor -hs_sink_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_qualifier_descriptor -dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_COMM, - - .bNumConfigurations = 1, -}; - -static const struct usb_descriptor_header *hs_eth_function[11] = { - (struct usb_descriptor_header *) &otg_descriptor, -#ifdef CONFIG_USB_ETH_CDC - /* "cdc" mode descriptors */ - (struct usb_descriptor_header *) &control_intf, - (struct usb_descriptor_header *) &header_desc, - (struct usb_descriptor_header *) &union_desc, - (struct usb_descriptor_header *) ðer_desc, - /* NOTE: status endpoint may need to be removed */ - (struct usb_descriptor_header *) &hs_status_desc, - /* data interface, with altsetting */ - (struct usb_descriptor_header *) &data_nop_intf, - (struct usb_descriptor_header *) &data_intf, - (struct usb_descriptor_header *) &hs_source_desc, - (struct usb_descriptor_header *) &hs_sink_desc, - NULL, -#endif /* CONFIG_USB_ETH_CDC */ -}; - -static inline void hs_subset_descriptors(void) -{ -#ifdef CONFIG_USB_ETH_SUBSET - /* behavior is "CDC Subset"; extra descriptors say "SAFE" */ - hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf; - hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc; - hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc; - hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc; - hs_eth_function[5] = (struct usb_descriptor_header *) ðer_desc; - hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc; - hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc; - hs_eth_function[8] = NULL; -#else - hs_eth_function[1] = NULL; -#endif -} - -#ifdef CONFIG_USB_ETH_RNDIS -static const struct usb_descriptor_header *hs_rndis_function[] = { - (struct usb_descriptor_header *) &otg_descriptor, - /* control interface matches ACM, not Ethernet */ - (struct usb_descriptor_header *) &rndis_control_intf, - (struct usb_descriptor_header *) &header_desc, - (struct usb_descriptor_header *) &call_mgmt_descriptor, - (struct usb_descriptor_header *) &acm_descriptor, - (struct usb_descriptor_header *) &union_desc, - (struct usb_descriptor_header *) &hs_status_desc, - /* data interface has no altsetting */ - (struct usb_descriptor_header *) &rndis_data_intf, - (struct usb_descriptor_header *) &hs_source_desc, - (struct usb_descriptor_header *) &hs_sink_desc, - NULL, -}; -#endif - - -/* maxpacket and other transfer characteristics vary by speed. */ -static inline struct usb_endpoint_descriptor * -ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, - struct usb_endpoint_descriptor *fs) -{ - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; -} - -/*-------------------------------------------------------------------------*/ - -/* descriptors that are built on-demand */ - -static char manufacturer[50]; -static char product_desc[40] = DRIVER_DESC; -static char serial_number[20]; - -/* address that the host will use ... usually assigned at random */ -static char ethaddr[2 * ETH_ALEN + 1]; - -/* static strings, in UTF-8 */ -static struct usb_string strings[] = { - { STRING_MANUFACTURER, manufacturer, }, - { STRING_PRODUCT, product_desc, }, - { STRING_SERIALNUMBER, serial_number, }, - { STRING_DATA, "Ethernet Data", }, - { STRING_ETHADDR, ethaddr, }, -#ifdef CONFIG_USB_ETH_CDC - { STRING_CDC, "CDC Ethernet", }, - { STRING_CONTROL, "CDC Communications Control", }, -#endif -#ifdef CONFIG_USB_ETH_SUBSET - { STRING_SUBSET, "CDC Ethernet Subset", }, -#endif -#ifdef CONFIG_USB_ETH_RNDIS - { STRING_RNDIS, "RNDIS", }, - { STRING_RNDIS_CONTROL, "RNDIS Communications Control", }, -#endif - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab = { - .language = 0x0409, /* en-us */ - .strings = strings, -}; - -/*============================================================================*/ -DEFINE_CACHE_ALIGN_BUFFER(u8, control_req, USB_BUFSIZ); - -#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) -DEFINE_CACHE_ALIGN_BUFFER(u8, status_req, STATUS_BYTECOUNT); -#endif - - -/** - * strlcpy - Copy a %NUL terminated string into a sized buffer - * @dest: Where to copy the string to - * @src: Where to copy the string from - * @size: size of destination buffer - * - * Compatible with *BSD: the result is always a valid - * NUL-terminated string that fits in the buffer (unless, - * of course, the buffer size is zero). It does not pad - * out the result like strncpy() does. - */ -size_t strlcpy(char *dest, const char *src, size_t size) -{ - size_t ret = strlen(src); - - if (size) { - size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dest, src, len); - dest[len] = '\0'; - } - return ret; -} - -/*============================================================================*/ - -/* - * one config, two interfaces: control, data. - * complications: class descriptors, and an altsetting. - */ -static int -config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg) -{ - int len; - const struct usb_config_descriptor *config; - const struct usb_descriptor_header **function; - int hs = 0; - - if (gadget_is_dualspeed(g)) { - hs = (g->speed == USB_SPEED_HIGH); - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - } -#define which_fn(t) (hs ? hs_ ## t ## _function : fs_ ## t ## _function) - - if (index >= device_desc.bNumConfigurations) - return -EINVAL; - -#ifdef CONFIG_USB_ETH_RNDIS - /* - * list the RNDIS config first, to make Microsoft's drivers - * happy. DOCSIS 1.0 needs this too. - */ - if (device_desc.bNumConfigurations == 2 && index == 0) { - config = &rndis_config; - function = which_fn(rndis); - } else -#endif - { - config = ð_config; - function = which_fn(eth); - } - - /* for now, don't advertise srp-only devices */ - if (!is_otg) - function++; - - len = usb_gadget_config_buf(config, buf, USB_BUFSIZ, function); - if (len < 0) - return len; - ((struct usb_config_descriptor *) buf)->bDescriptorType = type; - return len; -} - -/*-------------------------------------------------------------------------*/ - -static void eth_start(struct eth_dev *dev, gfp_t gfp_flags); -static int alloc_requests(struct eth_dev *dev, unsigned n, gfp_t gfp_flags); - -static int -set_ether_config(struct eth_dev *dev, gfp_t gfp_flags) -{ - int result = 0; - struct usb_gadget *gadget = dev->gadget; - -#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) - /* status endpoint used for RNDIS and (optionally) CDC */ - if (!subset_active(dev) && dev->status_ep) { - dev->status = ep_desc(gadget, &hs_status_desc, - &fs_status_desc); - dev->status_ep->driver_data = dev; - - result = usb_ep_enable(dev->status_ep, dev->status); - if (result != 0) { - debug("enable %s --> %d\n", - dev->status_ep->name, result); - goto done; - } - } -#endif - - dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc); - dev->in_ep->driver_data = dev; - - dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc); - dev->out_ep->driver_data = dev; - - /* - * With CDC, the host isn't allowed to use these two data - * endpoints in the default altsetting for the interface. - * so we don't activate them yet. Reset from SET_INTERFACE. - * - * Strictly speaking RNDIS should work the same: activation is - * a side effect of setting a packet filter. Deactivation is - * from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG. - */ - if (!cdc_active(dev)) { - result = usb_ep_enable(dev->in_ep, dev->in); - if (result != 0) { - debug("enable %s --> %d\n", - dev->in_ep->name, result); - goto done; - } - - result = usb_ep_enable(dev->out_ep, dev->out); - if (result != 0) { - debug("enable %s --> %d\n", - dev->out_ep->name, result); - goto done; - } - } - -done: - if (result == 0) - result = alloc_requests(dev, qlen(gadget), gfp_flags); - - /* on error, disable any endpoints */ - if (result < 0) { - if (!subset_active(dev) && dev->status_ep) - (void) usb_ep_disable(dev->status_ep); - dev->status = NULL; - (void) usb_ep_disable(dev->in_ep); - (void) usb_ep_disable(dev->out_ep); - dev->in = NULL; - dev->out = NULL; - } else if (!cdc_active(dev)) { - /* - * activate non-CDC configs right away - * this isn't strictly according to the RNDIS spec - */ - eth_start(dev, GFP_ATOMIC); - } - - /* caller is responsible for cleanup on error */ - return result; -} - -static void eth_reset_config(struct eth_dev *dev) -{ - if (dev->config == 0) - return; - - debug("%s\n", __func__); - - rndis_uninit(dev->rndis_config); - - /* - * disable endpoints, forcing (synchronous) completion of - * pending i/o. then free the requests. - */ - - if (dev->in) { - usb_ep_disable(dev->in_ep); - if (dev->tx_req) { - usb_ep_free_request(dev->in_ep, dev->tx_req); - dev->tx_req = NULL; - } - } - if (dev->out) { - usb_ep_disable(dev->out_ep); - if (dev->rx_req) { - usb_ep_free_request(dev->out_ep, dev->rx_req); - dev->rx_req = NULL; - } - } - if (dev->status) - usb_ep_disable(dev->status_ep); - - dev->rndis = 0; - dev->cdc_filter = 0; - dev->config = 0; -} - -/* - * change our operational config. must agree with the code - * that returns config descriptors, and altsetting code. - */ -static int eth_set_config(struct eth_dev *dev, unsigned number, - gfp_t gfp_flags) -{ - int result = 0; - struct usb_gadget *gadget = dev->gadget; - - if (gadget_is_sa1100(gadget) - && dev->config - && dev->tx_qlen != 0) { - /* tx fifo is full, but we can't clear it...*/ - error("can't change configurations"); - return -ESPIPE; - } - eth_reset_config(dev); - - switch (number) { - case DEV_CONFIG_VALUE: - result = set_ether_config(dev, gfp_flags); - break; -#ifdef CONFIG_USB_ETH_RNDIS - case DEV_RNDIS_CONFIG_VALUE: - dev->rndis = 1; - result = set_ether_config(dev, gfp_flags); - break; -#endif - default: - result = -EINVAL; - /* FALL THROUGH */ - case 0: - break; - } - - if (result) { - if (number) - eth_reset_config(dev); - usb_gadget_vbus_draw(dev->gadget, - gadget_is_otg(dev->gadget) ? 8 : 100); - } else { - char *speed; - unsigned power; - - power = 2 * eth_config.bMaxPower; - usb_gadget_vbus_draw(dev->gadget, power); - - switch (gadget->speed) { - case USB_SPEED_FULL: - speed = "full"; break; -#ifdef CONFIG_USB_GADGET_DUALSPEED - case USB_SPEED_HIGH: - speed = "high"; break; -#endif - default: - speed = "?"; break; - } - - dev->config = number; - printf("%s speed config #%d: %d mA, %s, using %s\n", - speed, number, power, driver_desc, - rndis_active(dev) - ? "RNDIS" - : (cdc_active(dev) - ? "CDC Ethernet" - : "CDC Ethernet Subset")); - } - return result; -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_ETH_CDC - -/* - * The interrupt endpoint is used in CDC networking models (Ethernet, ATM) - * only to notify the host about link status changes (which we support) or - * report completion of some encapsulated command (as used in RNDIS). Since - * we want this CDC Ethernet code to be vendor-neutral, we don't use that - * command mechanism; and only one status request is ever queued. - */ -static void eth_status_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct usb_cdc_notification *event = req->buf; - int value = req->status; - struct eth_dev *dev = ep->driver_data; - - /* issue the second notification if host reads the first */ - if (event->bNotificationType == USB_CDC_NOTIFY_NETWORK_CONNECTION - && value == 0) { - __le32 *data = req->buf + sizeof *event; - - event->bmRequestType = 0xA1; - event->bNotificationType = USB_CDC_NOTIFY_SPEED_CHANGE; - event->wValue = __constant_cpu_to_le16(0); - event->wIndex = __constant_cpu_to_le16(1); - event->wLength = __constant_cpu_to_le16(8); - - /* SPEED_CHANGE data is up/down speeds in bits/sec */ - data[0] = data[1] = cpu_to_le32(BITRATE(dev->gadget)); - - req->length = STATUS_BYTECOUNT; - value = usb_ep_queue(ep, req, GFP_ATOMIC); - debug("send SPEED_CHANGE --> %d\n", value); - if (value == 0) - return; - } else if (value != -ECONNRESET) { - debug("event %02x --> %d\n", - event->bNotificationType, value); - if (event->bNotificationType == - USB_CDC_NOTIFY_SPEED_CHANGE) { - l_ethdev.network_started = 1; - printf("USB network up!\n"); - } - } - req->context = NULL; -} - -static void issue_start_status(struct eth_dev *dev) -{ - struct usb_request *req = dev->stat_req; - struct usb_cdc_notification *event; - int value; - - /* - * flush old status - * - * FIXME ugly idiom, maybe we'd be better with just - * a "cancel the whole queue" primitive since any - * unlink-one primitive has way too many error modes. - * here, we "know" toggle is already clear... - * - * FIXME iff req->context != null just dequeue it - */ - usb_ep_disable(dev->status_ep); - usb_ep_enable(dev->status_ep, dev->status); - - /* - * 3.8.1 says to issue first NETWORK_CONNECTION, then - * a SPEED_CHANGE. could be useful in some configs. - */ - event = req->buf; - event->bmRequestType = 0xA1; - event->bNotificationType = USB_CDC_NOTIFY_NETWORK_CONNECTION; - event->wValue = __constant_cpu_to_le16(1); /* connected */ - event->wIndex = __constant_cpu_to_le16(1); - event->wLength = 0; - - req->length = sizeof *event; - req->complete = eth_status_complete; - req->context = dev; - - value = usb_ep_queue(dev->status_ep, req, GFP_ATOMIC); - if (value < 0) - debug("status buf queue --> %d\n", value); -} - -#endif - -/*-------------------------------------------------------------------------*/ - -static void eth_setup_complete(struct usb_ep *ep, struct usb_request *req) -{ - if (req->status || req->actual != req->length) - debug("setup complete --> %d, %d/%d\n", - req->status, req->actual, req->length); -} - -#ifdef CONFIG_USB_ETH_RNDIS - -static void rndis_response_complete(struct usb_ep *ep, struct usb_request *req) -{ - if (req->status || req->actual != req->length) - debug("rndis response complete --> %d, %d/%d\n", - req->status, req->actual, req->length); - - /* done sending after USB_CDC_GET_ENCAPSULATED_RESPONSE */ -} - -static void rndis_command_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct eth_dev *dev = ep->driver_data; - int status; - - /* received RNDIS command from USB_CDC_SEND_ENCAPSULATED_COMMAND */ - status = rndis_msg_parser(dev->rndis_config, (u8 *) req->buf); - if (status < 0) - error("%s: rndis parse error %d", __func__, status); -} - -#endif /* RNDIS */ - -/* - * The setup() callback implements all the ep0 functionality that's not - * handled lower down. CDC has a number of less-common features: - * - * - two interfaces: control, and ethernet data - * - Ethernet data interface has two altsettings: default, and active - * - class-specific descriptors for the control interface - * - class-specific control requests - */ -static int -eth_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) -{ - struct eth_dev *dev = get_gadget_data(gadget); - struct usb_request *req = dev->req; - int value = -EOPNOTSUPP; - u16 wIndex = le16_to_cpu(ctrl->wIndex); - u16 wValue = le16_to_cpu(ctrl->wValue); - u16 wLength = le16_to_cpu(ctrl->wLength); - - /* - * descriptors just go into the pre-allocated ep0 buffer, - * while config change events may enable network traffic. - */ - - debug("%s\n", __func__); - - req->complete = eth_setup_complete; - switch (ctrl->bRequest) { - - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != USB_DIR_IN) - break; - switch (wValue >> 8) { - - case USB_DT_DEVICE: - value = min(wLength, (u16) sizeof device_desc); - memcpy(req->buf, &device_desc, value); - break; - case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget)) - break; - value = min(wLength, (u16) sizeof dev_qualifier); - memcpy(req->buf, &dev_qualifier, value); - break; - - case USB_DT_OTHER_SPEED_CONFIG: - if (!gadget_is_dualspeed(gadget)) - break; - /* FALLTHROUGH */ - case USB_DT_CONFIG: - value = config_buf(gadget, req->buf, - wValue >> 8, - wValue & 0xff, - gadget_is_otg(gadget)); - if (value >= 0) - value = min(wLength, (u16) value); - break; - - case USB_DT_STRING: - value = usb_gadget_get_string(&stringtab, - wValue & 0xff, req->buf); - - if (value >= 0) - value = min(wLength, (u16) value); - - break; - } - break; - - case USB_REQ_SET_CONFIGURATION: - if (ctrl->bRequestType != 0) - break; - if (gadget->a_hnp_support) - debug("HNP available\n"); - else if (gadget->a_alt_hnp_support) - debug("HNP needs a different root port\n"); - value = eth_set_config(dev, wValue, GFP_ATOMIC); - break; - case USB_REQ_GET_CONFIGURATION: - if (ctrl->bRequestType != USB_DIR_IN) - break; - *(u8 *)req->buf = dev->config; - value = min(wLength, (u16) 1); - break; - - case USB_REQ_SET_INTERFACE: - if (ctrl->bRequestType != USB_RECIP_INTERFACE - || !dev->config - || wIndex > 1) - break; - if (!cdc_active(dev) && wIndex != 0) - break; - - /* - * PXA hardware partially handles SET_INTERFACE; - * we need to kluge around that interference. - */ - if (gadget_is_pxa(gadget)) { - value = eth_set_config(dev, DEV_CONFIG_VALUE, - GFP_ATOMIC); - /* - * PXA25x driver use non-CDC ethernet gadget. - * But only _CDC and _RNDIS code can signalize - * that network is working. So we signalize it - * here. - */ - l_ethdev.network_started = 1; - debug("USB network up!\n"); - goto done_set_intf; - } - -#ifdef CONFIG_USB_ETH_CDC - switch (wIndex) { - case 0: /* control/master intf */ - if (wValue != 0) - break; - if (dev->status) { - usb_ep_disable(dev->status_ep); - usb_ep_enable(dev->status_ep, dev->status); - } - - value = 0; - break; - case 1: /* data intf */ - if (wValue > 1) - break; - usb_ep_disable(dev->in_ep); - usb_ep_disable(dev->out_ep); - - /* - * CDC requires the data transfers not be done from - * the default interface setting ... also, setting - * the non-default interface resets filters etc. - */ - if (wValue == 1) { - if (!cdc_active(dev)) - break; - usb_ep_enable(dev->in_ep, dev->in); - usb_ep_enable(dev->out_ep, dev->out); - dev->cdc_filter = DEFAULT_FILTER; - if (dev->status) - issue_start_status(dev); - eth_start(dev, GFP_ATOMIC); - } - value = 0; - break; - } -#else - /* - * FIXME this is wrong, as is the assumption that - * all non-PXA hardware talks real CDC ... - */ - debug("set_interface ignored!\n"); -#endif /* CONFIG_USB_ETH_CDC */ - -done_set_intf: - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE) - || !dev->config - || wIndex > 1) - break; - if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0) - break; - - /* for CDC, iff carrier is on, data interface is active. */ - if (rndis_active(dev) || wIndex != 1) - *(u8 *)req->buf = 0; - else { - /* *(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0; */ - /* carrier always ok ...*/ - *(u8 *)req->buf = 1 ; - } - value = min(wLength, (u16) 1); - break; - -#ifdef CONFIG_USB_ETH_CDC - case USB_CDC_SET_ETHERNET_PACKET_FILTER: - /* - * see 6.2.30: no data, wIndex = interface, - * wValue = packet filter bitmap - */ - if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) - || !cdc_active(dev) - || wLength != 0 - || wIndex > 1) - break; - debug("packet filter %02x\n", wValue); - dev->cdc_filter = wValue; - value = 0; - break; - - /* - * and potentially: - * case USB_CDC_SET_ETHERNET_MULTICAST_FILTERS: - * case USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER: - * case USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER: - * case USB_CDC_GET_ETHERNET_STATISTIC: - */ - -#endif /* CONFIG_USB_ETH_CDC */ - -#ifdef CONFIG_USB_ETH_RNDIS - /* - * RNDIS uses the CDC command encapsulation mechanism to implement - * an RPC scheme, with much getting/setting of attributes by OID. - */ - case USB_CDC_SEND_ENCAPSULATED_COMMAND: - if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE) - || !rndis_active(dev) - || wLength > USB_BUFSIZ - || wValue - || rndis_control_intf.bInterfaceNumber - != wIndex) - break; - /* read the request, then process it */ - value = wLength; - req->complete = rndis_command_complete; - /* later, rndis_control_ack () sends a notification */ - break; - - case USB_CDC_GET_ENCAPSULATED_RESPONSE: - if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE) - == ctrl->bRequestType - && rndis_active(dev) - /* && wLength >= 0x0400 */ - && !wValue - && rndis_control_intf.bInterfaceNumber - == wIndex) { - u8 *buf; - u32 n; - - /* return the result */ - buf = rndis_get_next_response(dev->rndis_config, &n); - if (buf) { - memcpy(req->buf, buf, n); - req->complete = rndis_response_complete; - rndis_free_response(dev->rndis_config, buf); - value = n; - } - /* else stalls ... spec says to avoid that */ - } - break; -#endif /* RNDIS */ - - default: - debug("unknown control req%02x.%02x v%04x i%04x l%d\n", - ctrl->bRequestType, ctrl->bRequest, - wValue, wIndex, wLength); - } - - /* respond with data transfer before status phase? */ - if (value >= 0) { - debug("respond with data transfer before status phase\n"); - req->length = value; - req->zero = value < wLength - && (value % gadget->ep0->maxpacket) == 0; - value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); - if (value < 0) { - debug("ep_queue --> %d\n", value); - req->status = 0; - eth_setup_complete(gadget->ep0, req); - } - } - - /* host either stalls (value < 0) or reports success */ - return value; -} - -/*-------------------------------------------------------------------------*/ - -static void rx_complete(struct usb_ep *ep, struct usb_request *req); - -static int rx_submit(struct eth_dev *dev, struct usb_request *req, - gfp_t gfp_flags) -{ - int retval = -ENOMEM; - size_t size; - - /* - * Padding up to RX_EXTRA handles minor disagreements with host. - * Normally we use the USB "terminate on short read" convention; - * so allow up to (N*maxpacket), since that memory is normally - * already allocated. Some hardware doesn't deal well with short - * reads (e.g. DMA must be N*maxpacket), so for now don't trim a - * byte off the end (to force hardware errors on overflow). - * - * RNDIS uses internal framing, and explicitly allows senders to - * pad to end-of-packet. That's potentially nice for speed, - * but means receivers can't recover synch on their own. - */ - - debug("%s\n", __func__); - if (!req) - return -EINVAL; - - size = (ETHER_HDR_SIZE + dev->mtu + RX_EXTRA); - size += dev->out_ep->maxpacket - 1; - if (rndis_active(dev)) - size += sizeof(struct rndis_packet_msg_type); - size -= size % dev->out_ep->maxpacket; - - /* - * Some platforms perform better when IP packets are aligned, - * but on at least one, checksumming fails otherwise. Note: - * RNDIS headers involve variable numbers of LE32 values. - */ - - req->buf = (u8 *) NetRxPackets[0]; - req->length = size; - req->complete = rx_complete; - - retval = usb_ep_queue(dev->out_ep, req, gfp_flags); - - if (retval) - error("rx submit --> %d", retval); - - return retval; -} - -static void rx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct eth_dev *dev = ep->driver_data; - - debug("%s: status %d\n", __func__, req->status); - switch (req->status) { - /* normal completion */ - case 0: - if (rndis_active(dev)) { - /* we know MaxPacketsPerTransfer == 1 here */ - int length = rndis_rm_hdr(req->buf, req->actual); - if (length < 0) - goto length_err; - req->length -= length; - req->actual -= length; - } - if (req->actual < ETH_HLEN || ETH_FRAME_LEN < req->actual) { -length_err: - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - debug("rx length %d\n", req->length); - break; - } - - dev->stats.rx_packets++; - dev->stats.rx_bytes += req->length; - break; - - /* software-driven interface shutdown */ - case -ECONNRESET: /* unlink */ - case -ESHUTDOWN: /* disconnect etc */ - /* for hardware automagic (such as pxa) */ - case -ECONNABORTED: /* endpoint reset */ - break; - - /* data overrun */ - case -EOVERFLOW: - dev->stats.rx_over_errors++; - /* FALLTHROUGH */ - default: - dev->stats.rx_errors++; - break; - } - - packet_received = 1; -} - -static int alloc_requests(struct eth_dev *dev, unsigned n, gfp_t gfp_flags) -{ - - dev->tx_req = usb_ep_alloc_request(dev->in_ep, 0); - - if (!dev->tx_req) - goto fail1; - - dev->rx_req = usb_ep_alloc_request(dev->out_ep, 0); - - if (!dev->rx_req) - goto fail2; - - return 0; - -fail2: - usb_ep_free_request(dev->in_ep, dev->tx_req); -fail1: - error("can't alloc requests"); - return -1; -} - -static void tx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct eth_dev *dev = ep->driver_data; - - debug("%s: status %s\n", __func__, (req->status) ? "failed" : "ok"); - switch (req->status) { - default: - dev->stats.tx_errors++; - debug("tx err %d\n", req->status); - /* FALLTHROUGH */ - case -ECONNRESET: /* unlink */ - case -ESHUTDOWN: /* disconnect etc */ - break; - case 0: - dev->stats.tx_bytes += req->length; - } - dev->stats.tx_packets++; - - packet_sent = 1; -} - -static inline int eth_is_promisc(struct eth_dev *dev) -{ - /* no filters for the CDC subset; always promisc */ - if (subset_active(dev)) - return 1; - return dev->cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; -} - -#if 0 -static int eth_start_xmit (struct sk_buff *skb, struct net_device *net) -{ - struct eth_dev *dev = netdev_priv(net); - int length = skb->len; - int retval; - struct usb_request *req = NULL; - unsigned long flags; - - /* apply outgoing CDC or RNDIS filters */ - if (!eth_is_promisc (dev)) { - u8 *dest = skb->data; - - if (is_multicast_ether_addr(dest)) { - u16 type; - - /* ignores USB_CDC_PACKET_TYPE_MULTICAST and host - * SET_ETHERNET_MULTICAST_FILTERS requests - */ - if (is_broadcast_ether_addr(dest)) - type = USB_CDC_PACKET_TYPE_BROADCAST; - else - type = USB_CDC_PACKET_TYPE_ALL_MULTICAST; - if (!(dev->cdc_filter & type)) { - dev_kfree_skb_any (skb); - return 0; - } - } - /* ignores USB_CDC_PACKET_TYPE_DIRECTED */ - } - - spin_lock_irqsave(&dev->req_lock, flags); - /* - * this freelist can be empty if an interrupt triggered disconnect() - * and reconfigured the gadget (shutting down this queue) after the - * network stack decided to xmit but before we got the spinlock. - */ - if (list_empty(&dev->tx_reqs)) { - spin_unlock_irqrestore(&dev->req_lock, flags); - return 1; - } - - req = container_of (dev->tx_reqs.next, struct usb_request, list); - list_del (&req->list); - - /* temporarily stop TX queue when the freelist empties */ - if (list_empty (&dev->tx_reqs)) - netif_stop_queue (net); - spin_unlock_irqrestore(&dev->req_lock, flags); - - /* no buffer copies needed, unless the network stack did it - * or the hardware can't use skb buffers. - * or there's not enough space for any RNDIS headers we need - */ - if (rndis_active(dev)) { - struct sk_buff *skb_rndis; - - skb_rndis = skb_realloc_headroom (skb, - sizeof (struct rndis_packet_msg_type)); - if (!skb_rndis) - goto drop; - - dev_kfree_skb_any (skb); - skb = skb_rndis; - rndis_add_hdr (skb); - length = skb->len; - } - req->buf = skb->data; - req->context = skb; - req->complete = tx_complete; - - /* use zlp framing on tx for strict CDC-Ether conformance, - * though any robust network rx path ignores extra padding. - * and some hardware doesn't like to write zlps. - */ - req->zero = 1; - if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0) - length++; - - req->length = length; - - /* throttle highspeed IRQ rate back slightly */ - if (gadget_is_dualspeed(dev->gadget)) - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) - ? ((atomic_read(&dev->tx_qlen) % qmult) != 0) - : 0; - - retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC); - switch (retval) { - default: - DEBUG (dev, "tx queue err %d\n", retval); - break; - case 0: - net->trans_start = jiffies; - atomic_inc (&dev->tx_qlen); - } - - if (retval) { -drop: - dev->stats.tx_dropped++; - dev_kfree_skb_any (skb); - spin_lock_irqsave(&dev->req_lock, flags); - if (list_empty (&dev->tx_reqs)) - netif_start_queue (net); - list_add (&req->list, &dev->tx_reqs); - spin_unlock_irqrestore(&dev->req_lock, flags); - } - return 0; -} - -/*-------------------------------------------------------------------------*/ -#endif - -static void eth_unbind(struct usb_gadget *gadget) -{ - struct eth_dev *dev = get_gadget_data(gadget); - - debug("%s...\n", __func__); - rndis_deregister(dev->rndis_config); - rndis_exit(); - - /* we've already been disconnected ... no i/o is active */ - if (dev->req) { - usb_ep_free_request(gadget->ep0, dev->req); - dev->req = NULL; - } - if (dev->stat_req) { - usb_ep_free_request(dev->status_ep, dev->stat_req); - dev->stat_req = NULL; - } - - if (dev->tx_req) { - usb_ep_free_request(dev->in_ep, dev->tx_req); - dev->tx_req = NULL; - } - - if (dev->rx_req) { - usb_ep_free_request(dev->out_ep, dev->rx_req); - dev->rx_req = NULL; - } - -/* unregister_netdev (dev->net);*/ -/* free_netdev(dev->net);*/ - - dev->gadget = NULL; - set_gadget_data(gadget, NULL); -} - -static void eth_disconnect(struct usb_gadget *gadget) -{ - eth_reset_config(get_gadget_data(gadget)); - /* FIXME RNDIS should enter RNDIS_UNINITIALIZED */ -} - -static void eth_suspend(struct usb_gadget *gadget) -{ - /* Not used */ -} - -static void eth_resume(struct usb_gadget *gadget) -{ - /* Not used */ -} - -/*-------------------------------------------------------------------------*/ - -#ifdef CONFIG_USB_ETH_RNDIS - -/* - * The interrupt endpoint is used in RNDIS to notify the host when messages - * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT - * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even - * REMOTE_NDIS_KEEPALIVE_MSG. - * - * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and - * normally just one notification will be queued. - */ - -static void rndis_control_ack_complete(struct usb_ep *ep, - struct usb_request *req) -{ - struct eth_dev *dev = ep->driver_data; - - debug("%s...\n", __func__); - if (req->status || req->actual != req->length) - debug("rndis control ack complete --> %d, %d/%d\n", - req->status, req->actual, req->length); - - if (!l_ethdev.network_started) { - if (rndis_get_state(dev->rndis_config) - == RNDIS_DATA_INITIALIZED) { - l_ethdev.network_started = 1; - printf("USB RNDIS network up!\n"); - } - } - - req->context = NULL; - - if (req != dev->stat_req) - usb_ep_free_request(ep, req); -} - -static char rndis_resp_buf[8] __attribute__((aligned(sizeof(__le32)))); - -static int rndis_control_ack(struct eth_device *net) -{ - struct eth_dev *dev = &l_ethdev; - int length; - struct usb_request *resp = dev->stat_req; - - /* in case RNDIS calls this after disconnect */ - if (!dev->status) { - debug("status ENODEV\n"); - return -ENODEV; - } - - /* in case queue length > 1 */ - if (resp->context) { - resp = usb_ep_alloc_request(dev->status_ep, GFP_ATOMIC); - if (!resp) - return -ENOMEM; - resp->buf = rndis_resp_buf; - } - - /* - * Send RNDIS RESPONSE_AVAILABLE notification; - * USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too - */ - resp->length = 8; - resp->complete = rndis_control_ack_complete; - resp->context = dev; - - *((__le32 *) resp->buf) = __constant_cpu_to_le32(1); - *((__le32 *) (resp->buf + 4)) = __constant_cpu_to_le32(0); - - length = usb_ep_queue(dev->status_ep, resp, GFP_ATOMIC); - if (length < 0) { - resp->status = 0; - rndis_control_ack_complete(dev->status_ep, resp); - } - - return 0; -} - -#else - -#define rndis_control_ack NULL - -#endif /* RNDIS */ - -static void eth_start(struct eth_dev *dev, gfp_t gfp_flags) -{ - if (rndis_active(dev)) { - rndis_set_param_medium(dev->rndis_config, - NDIS_MEDIUM_802_3, - BITRATE(dev->gadget)/100); - rndis_signal_connect(dev->rndis_config); - } -} - -static int eth_stop(struct eth_dev *dev) -{ -#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT - unsigned long ts; - unsigned long timeout = CONFIG_SYS_HZ; /* 1 sec to stop RNDIS */ -#endif - - if (rndis_active(dev)) { - rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0); - rndis_signal_disconnect(dev->rndis_config); - -#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT - /* Wait until host receives OID_GEN_MEDIA_CONNECT_STATUS */ - ts = get_timer(0); - while (get_timer(ts) < timeout) - usb_gadget_handle_interrupts(); -#endif - - rndis_uninit(dev->rndis_config); - dev->rndis = 0; - } - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int is_eth_addr_valid(char *str) -{ - if (strlen(str) == 17) { - int i; - char *p, *q; - uchar ea[6]; - - /* see if it looks like an ethernet address */ - - p = str; - - for (i = 0; i < 6; i++) { - char term = (i == 5 ? '\0' : ':'); - - ea[i] = simple_strtol(p, &q, 16); - - if ((q - p) != 2 || *q++ != term) - break; - - p = q; - } - - /* Now check the contents. */ - return is_valid_ether_addr(ea); - } - return 0; -} - -static u8 nibble(unsigned char c) -{ - if (likely(isdigit(c))) - return c - '0'; - c = toupper(c); - if (likely(isxdigit(c))) - return 10 + c - 'A'; - return 0; -} - -static int get_ether_addr(const char *str, u8 *dev_addr) -{ - if (str) { - unsigned i; - - for (i = 0; i < 6; i++) { - unsigned char num; - - if ((*str == '.') || (*str == ':')) - str++; - num = nibble(*str++) << 4; - num |= (nibble(*str++)); - dev_addr[i] = num; - } - if (is_valid_ether_addr(dev_addr)) - return 0; - } - return 1; -} - -static int eth_bind(struct usb_gadget *gadget) -{ - struct eth_dev *dev = &l_ethdev; - u8 cdc = 1, zlp = 1, rndis = 1; - struct usb_ep *in_ep, *out_ep, *status_ep = NULL; - int status = -ENOMEM; - int gcnum; - u8 tmp[7]; - - /* these flags are only ever cleared; compiler take note */ -#ifndef CONFIG_USB_ETH_CDC - cdc = 0; -#endif -#ifndef CONFIG_USB_ETH_RNDIS - rndis = 0; -#endif - /* - * Because most host side USB stacks handle CDC Ethernet, that - * standard protocol is _strongly_ preferred for interop purposes. - * (By everyone except Microsoft.) - */ - if (gadget_is_pxa(gadget)) { - /* pxa doesn't support altsettings */ - cdc = 0; - } else if (gadget_is_musbhdrc(gadget)) { - /* reduce tx dma overhead by avoiding special cases */ - zlp = 0; - } else if (gadget_is_sh(gadget)) { - /* sh doesn't support multiple interfaces or configs */ - cdc = 0; - rndis = 0; - } else if (gadget_is_sa1100(gadget)) { - /* hardware can't write zlps */ - zlp = 0; - /* - * sa1100 CAN do CDC, without status endpoint ... we use - * non-CDC to be compatible with ARM Linux-2.4 "usb-eth". - */ - cdc = 0; - } - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(0x0300 + gcnum); - else { - /* - * can't assume CDC works. don't want to default to - * anything less functional on CDC-capable hardware, - * so we fail in this case. - */ - error("controller '%s' not recognized", - gadget->name); - return -ENODEV; - } - - /* - * If there's an RNDIS configuration, that's what Windows wants to - * be using ... so use these product IDs here and in the "linux.inf" - * needed to install MSFT drivers. Current Linux kernels will use - * the second configuration if it's CDC Ethernet, and need some help - * to choose the right configuration otherwise. - */ - if (rndis) { -#if defined(CONFIG_USB_RNDIS_VENDOR_ID) && defined(CONFIG_USB_RNDIS_PRODUCT_ID) - device_desc.idVendor = - __constant_cpu_to_le16(CONFIG_USB_RNDIS_VENDOR_ID); - device_desc.idProduct = - __constant_cpu_to_le16(CONFIG_USB_RNDIS_PRODUCT_ID); -#else - device_desc.idVendor = - __constant_cpu_to_le16(RNDIS_VENDOR_NUM); - device_desc.idProduct = - __constant_cpu_to_le16(RNDIS_PRODUCT_NUM); -#endif - sprintf(product_desc, "RNDIS/%s", driver_desc); - - /* - * CDC subset ... recognized by Linux since 2.4.10, but Windows - * drivers aren't widely available. (That may be improved by - * supporting one submode of the "SAFE" variant of MDLM.) - */ - } else { -#if defined(CONFIG_USB_CDC_VENDOR_ID) && defined(CONFIG_USB_CDC_PRODUCT_ID) - device_desc.idVendor = cpu_to_le16(CONFIG_USB_CDC_VENDOR_ID); - device_desc.idProduct = cpu_to_le16(CONFIG_USB_CDC_PRODUCT_ID); -#else - if (!cdc) { - device_desc.idVendor = - __constant_cpu_to_le16(SIMPLE_VENDOR_NUM); - device_desc.idProduct = - __constant_cpu_to_le16(SIMPLE_PRODUCT_NUM); - } -#endif - } - /* support optional vendor/distro customization */ - if (bcdDevice) - device_desc.bcdDevice = cpu_to_le16(bcdDevice); - if (iManufacturer) - strlcpy(manufacturer, iManufacturer, sizeof manufacturer); - if (iProduct) - strlcpy(product_desc, iProduct, sizeof product_desc); - if (iSerialNumber) { - device_desc.iSerialNumber = STRING_SERIALNUMBER, - strlcpy(serial_number, iSerialNumber, sizeof serial_number); - } - - /* all we really need is bulk IN/OUT */ - usb_ep_autoconfig_reset(gadget); - in_ep = usb_ep_autoconfig(gadget, &fs_source_desc); - if (!in_ep) { -autoconf_fail: - error("can't autoconfigure on %s\n", - gadget->name); - return -ENODEV; - } - in_ep->driver_data = in_ep; /* claim */ - - out_ep = usb_ep_autoconfig(gadget, &fs_sink_desc); - if (!out_ep) - goto autoconf_fail; - out_ep->driver_data = out_ep; /* claim */ - -#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) - /* - * CDC Ethernet control interface doesn't require a status endpoint. - * Since some hosts expect one, try to allocate one anyway. - */ - if (cdc || rndis) { - status_ep = usb_ep_autoconfig(gadget, &fs_status_desc); - if (status_ep) { - status_ep->driver_data = status_ep; /* claim */ - } else if (rndis) { - error("can't run RNDIS on %s", gadget->name); - return -ENODEV; -#ifdef CONFIG_USB_ETH_CDC - } else if (cdc) { - control_intf.bNumEndpoints = 0; - /* FIXME remove endpoint from descriptor list */ -#endif - } - } -#endif - - /* one config: cdc, else minimal subset */ - if (!cdc) { - eth_config.bNumInterfaces = 1; - eth_config.iConfiguration = STRING_SUBSET; - - /* - * use functions to set these up, in case we're built to work - * with multiple controllers and must override CDC Ethernet. - */ - fs_subset_descriptors(); - hs_subset_descriptors(); - } - - device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket; - usb_gadget_set_selfpowered(gadget); - - /* For now RNDIS is always a second config */ - if (rndis) - device_desc.bNumConfigurations = 2; - - if (gadget_is_dualspeed(gadget)) { - if (rndis) - dev_qualifier.bNumConfigurations = 2; - else if (!cdc) - dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC; - - /* assumes ep0 uses the same value for both speeds ... */ - dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0; - - /* and that all endpoints are dual-speed */ - hs_source_desc.bEndpointAddress = - fs_source_desc.bEndpointAddress; - hs_sink_desc.bEndpointAddress = - fs_sink_desc.bEndpointAddress; -#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (status_ep) - hs_status_desc.bEndpointAddress = - fs_status_desc.bEndpointAddress; -#endif - } - - if (gadget_is_otg(gadget)) { - otg_descriptor.bmAttributes |= USB_OTG_HNP, - eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - eth_config.bMaxPower = 4; -#ifdef CONFIG_USB_ETH_RNDIS - rndis_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP; - rndis_config.bMaxPower = 4; -#endif - } - - - /* network device setup */ - dev->net = &l_netdev; - - dev->cdc = cdc; - dev->zlp = zlp; - - dev->in_ep = in_ep; - dev->out_ep = out_ep; - dev->status_ep = status_ep; - - /* - * Module params for these addresses should come from ID proms. - * The host side address is used with CDC and RNDIS, and commonly - * ends up in a persistent config database. It's not clear if - * host side code for the SAFE thing cares -- its original BLAN - * thing didn't, Sharp never assigned those addresses on Zaurii. - */ - get_ether_addr(dev_addr, dev->net->enetaddr); - - memset(tmp, 0, sizeof(tmp)); - memcpy(tmp, dev->net->enetaddr, sizeof(dev->net->enetaddr)); - - get_ether_addr(host_addr, dev->host_mac); - - sprintf(ethaddr, "%02X%02X%02X%02X%02X%02X", - dev->host_mac[0], dev->host_mac[1], - dev->host_mac[2], dev->host_mac[3], - dev->host_mac[4], dev->host_mac[5]); - - if (rndis) { - status = rndis_init(); - if (status < 0) { - error("can't init RNDIS, %d", status); - goto fail; - } - } - - /* - * use PKTSIZE (or aligned... from u-boot) and set - * wMaxSegmentSize accordingly - */ - dev->mtu = PKTSIZE_ALIGN; /* RNDIS does not like this, only 1514, TODO*/ - - /* preallocate control message data and buffer */ - dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL); - if (!dev->req) - goto fail; - dev->req->buf = control_req; - dev->req->complete = eth_setup_complete; - - /* ... and maybe likewise for status transfer */ -#if defined(CONFIG_USB_ETH_CDC) || defined(CONFIG_USB_ETH_RNDIS) - if (dev->status_ep) { - dev->stat_req = usb_ep_alloc_request(dev->status_ep, - GFP_KERNEL); - if (!dev->stat_req) { - usb_ep_free_request(dev->status_ep, dev->req); - - goto fail; - } - dev->stat_req->buf = status_req; - dev->stat_req->context = NULL; - } -#endif - - /* finish hookup to lower layer ... */ - dev->gadget = gadget; - set_gadget_data(gadget, dev); - gadget->ep0->driver_data = dev; - - /* - * two kinds of host-initiated state changes: - * - iff DATA transfer is active, carrier is "on" - * - tx queueing enabled if open *and* carrier is "on" - */ - - printf("using %s, OUT %s IN %s%s%s\n", gadget->name, - out_ep->name, in_ep->name, - status_ep ? " STATUS " : "", - status_ep ? status_ep->name : "" - ); - printf("MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->net->enetaddr[0], dev->net->enetaddr[1], - dev->net->enetaddr[2], dev->net->enetaddr[3], - dev->net->enetaddr[4], dev->net->enetaddr[5]); - - if (cdc || rndis) - printf("HOST MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - dev->host_mac[0], dev->host_mac[1], - dev->host_mac[2], dev->host_mac[3], - dev->host_mac[4], dev->host_mac[5]); - - if (rndis) { - u32 vendorID = 0; - - /* FIXME RNDIS vendor id == "vendor NIC code" == ? */ - - dev->rndis_config = rndis_register(rndis_control_ack); - if (dev->rndis_config < 0) { -fail0: - eth_unbind(gadget); - debug("RNDIS setup failed\n"); - status = -ENODEV; - goto fail; - } - - /* these set up a lot of the OIDs that RNDIS needs */ - rndis_set_host_mac(dev->rndis_config, dev->host_mac); - if (rndis_set_param_dev(dev->rndis_config, dev->net, dev->mtu, - &dev->stats, &dev->cdc_filter)) - goto fail0; - if (rndis_set_param_vendor(dev->rndis_config, vendorID, - manufacturer)) - goto fail0; - if (rndis_set_param_medium(dev->rndis_config, - NDIS_MEDIUM_802_3, 0)) - goto fail0; - printf("RNDIS ready\n"); - } - return 0; - -fail: - error("%s failed, status = %d", __func__, status); - eth_unbind(gadget); - return status; -} - -/*-------------------------------------------------------------------------*/ - -static int usb_eth_init(struct eth_device *netdev, bd_t *bd) -{ - struct eth_dev *dev = &l_ethdev; - struct usb_gadget *gadget; - unsigned long ts; - unsigned long timeout = USB_CONNECT_TIMEOUT; - - if (!netdev) { - error("received NULL ptr"); - goto fail; - } - - /* Configure default mac-addresses for the USB ethernet device */ -#ifdef CONFIG_USBNET_DEV_ADDR - strlcpy(dev_addr, CONFIG_USBNET_DEV_ADDR, sizeof(dev_addr)); -#endif -#ifdef CONFIG_USBNET_HOST_ADDR - strlcpy(host_addr, CONFIG_USBNET_HOST_ADDR, sizeof(host_addr)); -#endif - /* Check if the user overruled the MAC addresses */ - if (getenv("usbnet_devaddr")) - strlcpy(dev_addr, getenv("usbnet_devaddr"), - sizeof(dev_addr)); - - if (getenv("usbnet_hostaddr")) - strlcpy(host_addr, getenv("usbnet_hostaddr"), - sizeof(host_addr)); - - if (!is_eth_addr_valid(dev_addr)) { - error("Need valid 'usbnet_devaddr' to be set"); - goto fail; - } - if (!is_eth_addr_valid(host_addr)) { - error("Need valid 'usbnet_hostaddr' to be set"); - goto fail; - } - - if (usb_gadget_register_driver(ð_driver) < 0) - goto fail; - - dev->network_started = 0; - - packet_received = 0; - packet_sent = 0; - - gadget = dev->gadget; - usb_gadget_connect(gadget); - - if (getenv("cdc_connect_timeout")) - timeout = simple_strtoul(getenv("cdc_connect_timeout"), - NULL, 10) * CONFIG_SYS_HZ; - ts = get_timer(0); - while (!l_ethdev.network_started) { - /* Handle control-c and timeouts */ - if (ctrlc() || (get_timer(ts) > timeout)) { - error("The remote end did not respond in time."); - goto fail; - } - usb_gadget_handle_interrupts(); - } - - packet_received = 0; - rx_submit(dev, dev->rx_req, 0); - return 0; -fail: - return -1; -} - -static int usb_eth_send(struct eth_device *netdev, void *packet, int length) -{ - int retval; - void *rndis_pkt = NULL; - struct eth_dev *dev = &l_ethdev; - struct usb_request *req = dev->tx_req; - unsigned long ts; - unsigned long timeout = USB_CONNECT_TIMEOUT; - - debug("%s:...\n", __func__); - - /* new buffer is needed to include RNDIS header */ - if (rndis_active(dev)) { - rndis_pkt = malloc(length + - sizeof(struct rndis_packet_msg_type)); - if (!rndis_pkt) { - error("No memory to alloc RNDIS packet"); - goto drop; - } - rndis_add_hdr(rndis_pkt, length); - memcpy(rndis_pkt + sizeof(struct rndis_packet_msg_type), - packet, length); - packet = rndis_pkt; - length += sizeof(struct rndis_packet_msg_type); - } - req->buf = packet; - req->context = NULL; - req->complete = tx_complete; - - /* - * use zlp framing on tx for strict CDC-Ether conformance, - * though any robust network rx path ignores extra padding. - * and some hardware doesn't like to write zlps. - */ - req->zero = 1; - if (!dev->zlp && (length % dev->in_ep->maxpacket) == 0) - length++; - - req->length = length; -#if 0 - /* throttle highspeed IRQ rate back slightly */ - if (gadget_is_dualspeed(dev->gadget)) - req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH) - ? ((dev->tx_qlen % qmult) != 0) : 0; -#endif - dev->tx_qlen = 1; - ts = get_timer(0); - packet_sent = 0; - - retval = usb_ep_queue(dev->in_ep, req, GFP_ATOMIC); - - if (!retval) - debug("%s: packet queued\n", __func__); - while (!packet_sent) { - if (get_timer(ts) > timeout) { - printf("timeout sending packets to usb ethernet\n"); - return -1; - } - usb_gadget_handle_interrupts(); - } - if (rndis_pkt) - free(rndis_pkt); - - return 0; -drop: - dev->stats.tx_dropped++; - return -ENOMEM; -} - -static int usb_eth_recv(struct eth_device *netdev) -{ - struct eth_dev *dev = &l_ethdev; - - usb_gadget_handle_interrupts(); - - if (packet_received) { - debug("%s: packet received\n", __func__); - if (dev->rx_req) { - NetReceive(NetRxPackets[0], dev->rx_req->length); - packet_received = 0; - - rx_submit(dev, dev->rx_req, 0); - } else - error("dev->rx_req invalid"); - } - return 0; -} - -void usb_eth_halt(struct eth_device *netdev) -{ - struct eth_dev *dev = &l_ethdev; - - if (!netdev) { - error("received NULL ptr"); - return; - } - - /* If the gadget not registered, simple return */ - if (!dev->gadget) - return; - - /* - * Some USB controllers may need additional deinitialization here - * before dropping pull-up (also due to hardware issues). - * For example: unhandled interrupt with status stage started may - * bring the controller to fully broken state (until board reset). - * There are some variants to debug and fix such cases: - * 1) In the case of RNDIS connection eth_stop can perform additional - * interrupt handling. See RNDIS_COMPLETE_SIGNAL_DISCONNECT definition. - * 2) 'pullup' callback in your UDC driver can be improved to perform - * this deinitialization. - */ - eth_stop(dev); - - usb_gadget_disconnect(dev->gadget); - - /* Clear pending interrupt */ - if (dev->network_started) { - usb_gadget_handle_interrupts(); - dev->network_started = 0; - } - - usb_gadget_unregister_driver(ð_driver); -} - -static struct usb_gadget_driver eth_driver = { - .speed = DEVSPEED, - - .bind = eth_bind, - .unbind = eth_unbind, - - .setup = eth_setup, - .disconnect = eth_disconnect, - - .suspend = eth_suspend, - .resume = eth_resume, -}; - -int usb_eth_initialize(bd_t *bi) -{ - struct eth_device *netdev = &l_netdev; - - strlcpy(netdev->name, USB_NET_NAME, sizeof(netdev->name)); - - netdev->init = usb_eth_init; - netdev->send = usb_eth_send; - netdev->recv = usb_eth_recv; - netdev->halt = usb_eth_halt; - -#ifdef CONFIG_MCAST_TFTP - #error not supported -#endif - eth_register(netdev); - return 0; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/f_dfu.c b/qemu/roms/u-boot/drivers/usb/gadget/f_dfu.c deleted file mode 100644 index 1b1e1793d..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/f_dfu.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * f_dfu.c -- Device Firmware Update USB function - * - * Copyright (C) 2012 Samsung Electronics - * authors: Andrzej Pietrasiewicz <andrzej.p@samsung.com> - * Lukasz Majewski <l.majewski@samsung.com> - * - * Based on OpenMoko u-boot: drivers/usb/usbdfu.c - * (C) 2007 by OpenMoko, Inc. - * Author: Harald Welte <laforge@openmoko.org> - * - * based on existing SAM7DFU code from OpenPCD: - * (C) Copyright 2006 by Harald Welte <hwelte at hmw-consulting.de> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <errno.h> -#include <common.h> -#include <malloc.h> - -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb/composite.h> - -#include <dfu.h> -#include <g_dnl.h> -#include "f_dfu.h" - -struct f_dfu { - struct usb_function usb_function; - - struct usb_descriptor_header **function; - struct usb_string *strings; - - /* when configured, we have one config */ - u8 config; - u8 altsetting; - enum dfu_state dfu_state; - unsigned int dfu_status; - - /* Send/received block number is handy for data integrity check */ - int blk_seq_num; - unsigned int poll_timeout; -}; - -typedef int (*dfu_state_fn) (struct f_dfu *, - const struct usb_ctrlrequest *, - struct usb_gadget *, - struct usb_request *); - -static inline struct f_dfu *func_to_dfu(struct usb_function *f) -{ - return container_of(f, struct f_dfu, usb_function); -} - -static const struct dfu_function_descriptor dfu_func = { - .bLength = sizeof dfu_func, - .bDescriptorType = DFU_DT_FUNC, - .bmAttributes = DFU_BIT_WILL_DETACH | - DFU_BIT_MANIFESTATION_TOLERANT | - DFU_BIT_CAN_UPLOAD | - DFU_BIT_CAN_DNLOAD, - .wDetachTimeOut = 0, - .wTransferSize = DFU_USB_BUFSIZ, - .bcdDFUVersion = __constant_cpu_to_le16(0x0110), -}; - -static struct usb_interface_descriptor dfu_intf_runtime = { - .bLength = sizeof dfu_intf_runtime, - .bDescriptorType = USB_DT_INTERFACE, - .bNumEndpoints = 0, - .bInterfaceClass = USB_CLASS_APP_SPEC, - .bInterfaceSubClass = 1, - .bInterfaceProtocol = 1, - /* .iInterface = DYNAMIC */ -}; - -static struct usb_descriptor_header *dfu_runtime_descs[] = { - (struct usb_descriptor_header *) &dfu_intf_runtime, - NULL, -}; - -static const struct usb_qualifier_descriptor dev_qualifier = { - .bLength = sizeof dev_qualifier, - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_VENDOR_SPEC, - .bNumConfigurations = 1, -}; - -static const char dfu_name[] = "Device Firmware Upgrade"; - -/* - * static strings, in UTF-8 - * - * dfu_generic configuration - */ -static struct usb_string strings_dfu_generic[] = { - [0].s = dfu_name, - { } /* end of list */ -}; - -static struct usb_gadget_strings stringtab_dfu_generic = { - .language = 0x0409, /* en-us */ - .strings = strings_dfu_generic, -}; - -static struct usb_gadget_strings *dfu_generic_strings[] = { - &stringtab_dfu_generic, - NULL, -}; - -/* - * usb_function specific - */ -static struct usb_gadget_strings stringtab_dfu = { - .language = 0x0409, /* en-us */ - /* - * .strings - * - * assigned during initialization, - * depends on number of flash entities - * - */ -}; - -static struct usb_gadget_strings *dfu_strings[] = { - &stringtab_dfu, - NULL, -}; - -static void dfu_set_poll_timeout(struct dfu_status *dstat, unsigned int ms) -{ - /* - * The bwPollTimeout DFU_GETSTATUS request payload provides information - * about minimum time, in milliseconds, that the host should wait before - * sending a subsequent DFU_GETSTATUS request - * - * This permits the device to vary the delay depending on its need to - * erase or program the memory - * - */ - - unsigned char *p = (unsigned char *)&ms; - - if (!ms || (ms & ~DFU_POLL_TIMEOUT_MASK)) { - dstat->bwPollTimeout[0] = 0; - dstat->bwPollTimeout[1] = 0; - dstat->bwPollTimeout[2] = 0; - - return; - } - - dstat->bwPollTimeout[0] = *p++; - dstat->bwPollTimeout[1] = *p++; - dstat->bwPollTimeout[2] = *p; -} - -/*-------------------------------------------------------------------------*/ - -static void dnload_request_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct f_dfu *f_dfu = req->context; - - dfu_write(dfu_get_entity(f_dfu->altsetting), req->buf, - req->length, f_dfu->blk_seq_num); -} - -static void dnload_request_flush(struct usb_ep *ep, struct usb_request *req) -{ - struct f_dfu *f_dfu = req->context; - - dfu_flush(dfu_get_entity(f_dfu->altsetting), req->buf, - req->length, f_dfu->blk_seq_num); -} - -static void handle_getstatus(struct usb_request *req) -{ - struct dfu_status *dstat = (struct dfu_status *)req->buf; - struct f_dfu *f_dfu = req->context; - - dfu_set_poll_timeout(dstat, 0); - - switch (f_dfu->dfu_state) { - case DFU_STATE_dfuDNLOAD_SYNC: - case DFU_STATE_dfuDNBUSY: - f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_IDLE; - break; - case DFU_STATE_dfuMANIFEST_SYNC: - f_dfu->dfu_state = DFU_STATE_dfuMANIFEST; - break; - case DFU_STATE_dfuMANIFEST: - dfu_set_poll_timeout(dstat, DFU_MANIFEST_POLL_TIMEOUT); - default: - break; - } - - if (f_dfu->poll_timeout) - if (!(f_dfu->blk_seq_num % - (dfu_get_buf_size() / DFU_USB_BUFSIZ))) - dfu_set_poll_timeout(dstat, f_dfu->poll_timeout); - - /* send status response */ - dstat->bStatus = f_dfu->dfu_status; - dstat->bState = f_dfu->dfu_state; - dstat->iString = 0; -} - -static void handle_getstate(struct usb_request *req) -{ - struct f_dfu *f_dfu = req->context; - - ((u8 *)req->buf)[0] = f_dfu->dfu_state; - req->actual = sizeof(u8); -} - -static inline void to_dfu_mode(struct f_dfu *f_dfu) -{ - f_dfu->usb_function.strings = dfu_strings; - f_dfu->usb_function.hs_descriptors = f_dfu->function; - f_dfu->dfu_state = DFU_STATE_dfuIDLE; -} - -static inline void to_runtime_mode(struct f_dfu *f_dfu) -{ - f_dfu->usb_function.strings = NULL; - f_dfu->usb_function.hs_descriptors = dfu_runtime_descs; -} - -static int handle_upload(struct usb_request *req, u16 len) -{ - struct f_dfu *f_dfu = req->context; - - return dfu_read(dfu_get_entity(f_dfu->altsetting), req->buf, - req->length, f_dfu->blk_seq_num); -} - -static int handle_dnload(struct usb_gadget *gadget, u16 len) -{ - struct usb_composite_dev *cdev = get_gadget_data(gadget); - struct usb_request *req = cdev->req; - struct f_dfu *f_dfu = req->context; - - if (len == 0) - f_dfu->dfu_state = DFU_STATE_dfuMANIFEST_SYNC; - - req->complete = dnload_request_complete; - - return len; -} - -/*-------------------------------------------------------------------------*/ -/* DFU state machine */ -static int state_app_idle(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(req); - value = RET_STAT_LEN; - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(req); - break; - case USB_REQ_DFU_DETACH: - f_dfu->dfu_state = DFU_STATE_appDETACH; - to_dfu_mode(f_dfu); - value = RET_ZLP; - break; - default: - value = RET_STALL; - break; - } - - return value; -} - -static int state_app_detach(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(req); - value = RET_STAT_LEN; - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(req); - break; - default: - f_dfu->dfu_state = DFU_STATE_appIDLE; - value = RET_STALL; - break; - } - - return value; -} - -static int state_dfu_idle(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 len = le16_to_cpu(ctrl->wLength); - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_DNLOAD: - if (len == 0) { - f_dfu->dfu_state = DFU_STATE_dfuERROR; - value = RET_STALL; - break; - } - f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC; - f_dfu->blk_seq_num = w_value; - value = handle_dnload(gadget, len); - break; - case USB_REQ_DFU_UPLOAD: - f_dfu->dfu_state = DFU_STATE_dfuUPLOAD_IDLE; - f_dfu->blk_seq_num = 0; - value = handle_upload(req, len); - break; - case USB_REQ_DFU_ABORT: - /* no zlp? */ - value = RET_ZLP; - break; - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(req); - value = RET_STAT_LEN; - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(req); - break; - case USB_REQ_DFU_DETACH: - /* - * Proprietary extension: 'detach' from idle mode and - * get back to runtime mode in case of USB Reset. As - * much as I dislike this, we just can't use every USB - * bus reset to switch back to runtime mode, since at - * least the Linux USB stack likes to send a number of - * resets in a row :( - */ - f_dfu->dfu_state = - DFU_STATE_dfuMANIFEST_WAIT_RST; - to_runtime_mode(f_dfu); - f_dfu->dfu_state = DFU_STATE_appIDLE; - - dfu_trigger_reset(); - break; - default: - f_dfu->dfu_state = DFU_STATE_dfuERROR; - value = RET_STALL; - break; - } - - return value; -} - -static int state_dfu_dnload_sync(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(req); - value = RET_STAT_LEN; - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(req); - break; - default: - f_dfu->dfu_state = DFU_STATE_dfuERROR; - value = RET_STALL; - break; - } - - return value; -} - -static int state_dfu_dnbusy(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(req); - value = RET_STAT_LEN; - break; - default: - f_dfu->dfu_state = DFU_STATE_dfuERROR; - value = RET_STALL; - break; - } - - return value; -} - -static int state_dfu_dnload_idle(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 len = le16_to_cpu(ctrl->wLength); - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_DNLOAD: - f_dfu->dfu_state = DFU_STATE_dfuDNLOAD_SYNC; - f_dfu->blk_seq_num = w_value; - value = handle_dnload(gadget, len); - break; - case USB_REQ_DFU_ABORT: - f_dfu->dfu_state = DFU_STATE_dfuIDLE; - value = RET_ZLP; - break; - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(req); - value = RET_STAT_LEN; - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(req); - break; - default: - f_dfu->dfu_state = DFU_STATE_dfuERROR; - value = RET_STALL; - break; - } - - return value; -} - -static int state_dfu_manifest_sync(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_GETSTATUS: - /* We're MainfestationTolerant */ - f_dfu->dfu_state = DFU_STATE_dfuMANIFEST; - handle_getstatus(req); - f_dfu->blk_seq_num = 0; - value = RET_STAT_LEN; - req->complete = dnload_request_flush; - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(req); - break; - default: - f_dfu->dfu_state = DFU_STATE_dfuERROR; - value = RET_STALL; - break; - } - - return value; -} - -static int state_dfu_manifest(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_GETSTATUS: - /* We're MainfestationTolerant */ - f_dfu->dfu_state = DFU_STATE_dfuIDLE; - handle_getstatus(req); - f_dfu->blk_seq_num = 0; - value = RET_STAT_LEN; - puts("DOWNLOAD ... OK\nCtrl+C to exit ...\n"); - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(req); - break; - default: - f_dfu->dfu_state = DFU_STATE_dfuERROR; - value = RET_STALL; - break; - } - return value; -} - -static int state_dfu_upload_idle(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - u16 w_value = le16_to_cpu(ctrl->wValue); - u16 len = le16_to_cpu(ctrl->wLength); - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_UPLOAD: - /* state transition if less data then requested */ - f_dfu->blk_seq_num = w_value; - value = handle_upload(req, len); - if (value >= 0 && value < len) - f_dfu->dfu_state = DFU_STATE_dfuIDLE; - break; - case USB_REQ_DFU_ABORT: - f_dfu->dfu_state = DFU_STATE_dfuIDLE; - /* no zlp? */ - value = RET_ZLP; - break; - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(req); - value = RET_STAT_LEN; - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(req); - break; - default: - f_dfu->dfu_state = DFU_STATE_dfuERROR; - value = RET_STALL; - break; - } - - return value; -} - -static int state_dfu_error(struct f_dfu *f_dfu, - const struct usb_ctrlrequest *ctrl, - struct usb_gadget *gadget, - struct usb_request *req) -{ - int value = 0; - - switch (ctrl->bRequest) { - case USB_REQ_DFU_GETSTATUS: - handle_getstatus(req); - value = RET_STAT_LEN; - break; - case USB_REQ_DFU_GETSTATE: - handle_getstate(req); - break; - case USB_REQ_DFU_CLRSTATUS: - f_dfu->dfu_state = DFU_STATE_dfuIDLE; - f_dfu->dfu_status = DFU_STATUS_OK; - /* no zlp? */ - value = RET_ZLP; - break; - default: - f_dfu->dfu_state = DFU_STATE_dfuERROR; - value = RET_STALL; - break; - } - - return value; -} - -static dfu_state_fn dfu_state[] = { - state_app_idle, /* DFU_STATE_appIDLE */ - state_app_detach, /* DFU_STATE_appDETACH */ - state_dfu_idle, /* DFU_STATE_dfuIDLE */ - state_dfu_dnload_sync, /* DFU_STATE_dfuDNLOAD_SYNC */ - state_dfu_dnbusy, /* DFU_STATE_dfuDNBUSY */ - state_dfu_dnload_idle, /* DFU_STATE_dfuDNLOAD_IDLE */ - state_dfu_manifest_sync, /* DFU_STATE_dfuMANIFEST_SYNC */ - state_dfu_manifest, /* DFU_STATE_dfuMANIFEST */ - NULL, /* DFU_STATE_dfuMANIFEST_WAIT_RST */ - state_dfu_upload_idle, /* DFU_STATE_dfuUPLOAD_IDLE */ - state_dfu_error /* DFU_STATE_dfuERROR */ -}; - -static int -dfu_handle(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -{ - struct usb_gadget *gadget = f->config->cdev->gadget; - struct usb_request *req = f->config->cdev->req; - struct f_dfu *f_dfu = f->config->cdev->req->context; - u16 len = le16_to_cpu(ctrl->wLength); - u16 w_value = le16_to_cpu(ctrl->wValue); - int value = 0; - u8 req_type = ctrl->bRequestType & USB_TYPE_MASK; - - debug("w_value: 0x%x len: 0x%x\n", w_value, len); - debug("req_type: 0x%x ctrl->bRequest: 0x%x f_dfu->dfu_state: 0x%x\n", - req_type, ctrl->bRequest, f_dfu->dfu_state); - - if (req_type == USB_TYPE_STANDARD) { - if (ctrl->bRequest == USB_REQ_GET_DESCRIPTOR && - (w_value >> 8) == DFU_DT_FUNC) { - value = min(len, (u16) sizeof(dfu_func)); - memcpy(req->buf, &dfu_func, value); - } - } else /* DFU specific request */ - value = dfu_state[f_dfu->dfu_state] (f_dfu, ctrl, gadget, req); - - if (value >= 0) { - req->length = value; - req->zero = value < len; - value = usb_ep_queue(gadget->ep0, req, 0); - if (value < 0) { - debug("ep_queue --> %d\n", value); - req->status = 0; - } - } - - return value; -} - -/*-------------------------------------------------------------------------*/ - -static int -dfu_prepare_strings(struct f_dfu *f_dfu, int n) -{ - struct dfu_entity *de = NULL; - int i = 0; - - f_dfu->strings = calloc(sizeof(struct usb_string), n + 1); - if (!f_dfu->strings) - goto enomem; - - for (i = 0; i < n; ++i) { - de = dfu_get_entity(i); - f_dfu->strings[i].s = de->name; - } - - f_dfu->strings[i].id = 0; - f_dfu->strings[i].s = NULL; - - return 0; - -enomem: - while (i) - f_dfu->strings[--i].s = NULL; - - free(f_dfu->strings); - - return -ENOMEM; -} - -static int dfu_prepare_function(struct f_dfu *f_dfu, int n) -{ - struct usb_interface_descriptor *d; - int i = 0; - - f_dfu->function = calloc(sizeof(struct usb_descriptor_header *), n + 1); - if (!f_dfu->function) - goto enomem; - - for (i = 0; i < n; ++i) { - d = calloc(sizeof(*d), 1); - if (!d) - goto enomem; - - d->bLength = sizeof(*d); - d->bDescriptorType = USB_DT_INTERFACE; - d->bAlternateSetting = i; - d->bNumEndpoints = 0; - d->bInterfaceClass = USB_CLASS_APP_SPEC; - d->bInterfaceSubClass = 1; - d->bInterfaceProtocol = 2; - - f_dfu->function[i] = (struct usb_descriptor_header *)d; - } - f_dfu->function[i] = NULL; - - return 0; - -enomem: - while (i) { - free(f_dfu->function[--i]); - f_dfu->function[i] = NULL; - } - free(f_dfu->function); - - return -ENOMEM; -} - -static int dfu_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_composite_dev *cdev = c->cdev; - struct f_dfu *f_dfu = func_to_dfu(f); - int alt_num = dfu_get_alt_number(); - int rv, id, i; - - id = usb_interface_id(c, f); - if (id < 0) - return id; - dfu_intf_runtime.bInterfaceNumber = id; - - f_dfu->dfu_state = DFU_STATE_appIDLE; - f_dfu->dfu_status = DFU_STATUS_OK; - - rv = dfu_prepare_function(f_dfu, alt_num); - if (rv) - goto error; - - rv = dfu_prepare_strings(f_dfu, alt_num); - if (rv) - goto error; - for (i = 0; i < alt_num; i++) { - id = usb_string_id(cdev); - if (id < 0) - return id; - f_dfu->strings[i].id = id; - ((struct usb_interface_descriptor *)f_dfu->function[i]) - ->iInterface = id; - } - - to_dfu_mode(f_dfu); - - stringtab_dfu.strings = f_dfu->strings; - - cdev->req->context = f_dfu; - -error: - return rv; -} - -static void dfu_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_dfu *f_dfu = func_to_dfu(f); - int alt_num = dfu_get_alt_number(); - int i; - - if (f_dfu->strings) { - i = alt_num; - while (i) - f_dfu->strings[--i].s = NULL; - - free(f_dfu->strings); - } - - if (f_dfu->function) { - i = alt_num; - while (i) { - free(f_dfu->function[--i]); - f_dfu->function[i] = NULL; - } - free(f_dfu->function); - } - - free(f_dfu); -} - -static int dfu_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct f_dfu *f_dfu = func_to_dfu(f); - - debug("%s: intf:%d alt:%d\n", __func__, intf, alt); - - f_dfu->altsetting = alt; - - return 0; -} - -/* TODO: is this really what we need here? */ -static void dfu_disable(struct usb_function *f) -{ - struct f_dfu *f_dfu = func_to_dfu(f); - if (f_dfu->config == 0) - return; - - debug("%s: reset config\n", __func__); - - f_dfu->config = 0; -} - -static int dfu_bind_config(struct usb_configuration *c) -{ - struct f_dfu *f_dfu; - int status; - - f_dfu = calloc(sizeof(*f_dfu), 1); - if (!f_dfu) - return -ENOMEM; - f_dfu->usb_function.name = "dfu"; - f_dfu->usb_function.hs_descriptors = dfu_runtime_descs; - f_dfu->usb_function.bind = dfu_bind; - f_dfu->usb_function.unbind = dfu_unbind; - f_dfu->usb_function.set_alt = dfu_set_alt; - f_dfu->usb_function.disable = dfu_disable; - f_dfu->usb_function.strings = dfu_generic_strings; - f_dfu->usb_function.setup = dfu_handle; - f_dfu->poll_timeout = DFU_DEFAULT_POLL_TIMEOUT; - - status = usb_add_function(c, &f_dfu->usb_function); - if (status) - free(f_dfu); - - return status; -} - -int dfu_add(struct usb_configuration *c) -{ - int id; - - id = usb_string_id(c->cdev); - if (id < 0) - return id; - strings_dfu_generic[0].id = id; - dfu_intf_runtime.iInterface = id; - - debug("%s: cdev: 0x%p gadget:0x%p gadget->ep0: 0x%p\n", __func__, - c->cdev, c->cdev->gadget, c->cdev->gadget->ep0); - - return dfu_bind_config(c); -} - -DECLARE_GADGET_BIND_CALLBACK(usb_dnl_dfu, dfu_add); diff --git a/qemu/roms/u-boot/drivers/usb/gadget/f_dfu.h b/qemu/roms/u-boot/drivers/usb/gadget/f_dfu.h deleted file mode 100644 index 0c29954ad..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/f_dfu.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * f_dfu.h -- Device Firmware Update gadget - * - * Copyright (C) 2011-2012 Samsung Electronics - * author: Andrzej Pietrasiewicz <andrzej.p@samsung.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __F_DFU_H_ -#define __F_DFU_H_ - -#include <linux/compiler.h> -#include <linux/usb/composite.h> - -#define DFU_CONFIG_VAL 1 -#define DFU_DT_FUNC 0x21 - -#define DFU_BIT_WILL_DETACH (0x1 << 3) -#define DFU_BIT_MANIFESTATION_TOLERANT (0x1 << 2) -#define DFU_BIT_CAN_UPLOAD (0x1 << 1) -#define DFU_BIT_CAN_DNLOAD 0x1 - -/* big enough to hold our biggest descriptor */ -#define DFU_USB_BUFSIZ 4096 - -#define USB_REQ_DFU_DETACH 0x00 -#define USB_REQ_DFU_DNLOAD 0x01 -#define USB_REQ_DFU_UPLOAD 0x02 -#define USB_REQ_DFU_GETSTATUS 0x03 -#define USB_REQ_DFU_CLRSTATUS 0x04 -#define USB_REQ_DFU_GETSTATE 0x05 -#define USB_REQ_DFU_ABORT 0x06 - -#define DFU_STATUS_OK 0x00 -#define DFU_STATUS_errTARGET 0x01 -#define DFU_STATUS_errFILE 0x02 -#define DFU_STATUS_errWRITE 0x03 -#define DFU_STATUS_errERASE 0x04 -#define DFU_STATUS_errCHECK_ERASED 0x05 -#define DFU_STATUS_errPROG 0x06 -#define DFU_STATUS_errVERIFY 0x07 -#define DFU_STATUS_errADDRESS 0x08 -#define DFU_STATUS_errNOTDONE 0x09 -#define DFU_STATUS_errFIRMWARE 0x0a -#define DFU_STATUS_errVENDOR 0x0b -#define DFU_STATUS_errUSBR 0x0c -#define DFU_STATUS_errPOR 0x0d -#define DFU_STATUS_errUNKNOWN 0x0e -#define DFU_STATUS_errSTALLEDPKT 0x0f - -#define RET_STALL -1 -#define RET_ZLP 0 -#define RET_STAT_LEN 6 - -enum dfu_state { - DFU_STATE_appIDLE = 0, - DFU_STATE_appDETACH = 1, - DFU_STATE_dfuIDLE = 2, - DFU_STATE_dfuDNLOAD_SYNC = 3, - DFU_STATE_dfuDNBUSY = 4, - DFU_STATE_dfuDNLOAD_IDLE = 5, - DFU_STATE_dfuMANIFEST_SYNC = 6, - DFU_STATE_dfuMANIFEST = 7, - DFU_STATE_dfuMANIFEST_WAIT_RST = 8, - DFU_STATE_dfuUPLOAD_IDLE = 9, - DFU_STATE_dfuERROR = 10, -}; - -struct dfu_status { - __u8 bStatus; - __u8 bwPollTimeout[3]; - __u8 bState; - __u8 iString; -} __packed; - -struct dfu_function_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bmAttributes; - __le16 wDetachTimeOut; - __le16 wTransferSize; - __le16 bcdDFUVersion; -} __packed; - -#define DFU_POLL_TIMEOUT_MASK (0xFFFFFFUL) -#endif /* __F_DFU_H_ */ diff --git a/qemu/roms/u-boot/drivers/usb/gadget/f_mass_storage.c b/qemu/roms/u-boot/drivers/usb/gadget/f_mass_storage.c deleted file mode 100644 index 6374bb953..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/f_mass_storage.c +++ /dev/null @@ -1,2783 +0,0 @@ -/* - * f_mass_storage.c -- Mass Storage USB Composite Function - * - * Copyright (C) 2003-2008 Alan Stern - * Copyright (C) 2009 Samsung Electronics - * Author: Michal Nazarewicz <m.nazarewicz@samsung.com> - * All rights reserved. - * - * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause - */ - -/* - * The Mass Storage Function acts as a USB Mass Storage device, - * appearing to the host as a disk drive or as a CD-ROM drive. In - * addition to providing an example of a genuinely useful composite - * function for a USB device, it also illustrates a technique of - * double-buffering for increased throughput. - * - * Function supports multiple logical units (LUNs). Backing storage - * for each LUN is provided by a regular file or a block device. - * Access for each LUN can be limited to read-only. Moreover, the - * function can indicate that LUN is removable and/or CD-ROM. (The - * later implies read-only access.) - * - * MSF is configured by specifying a fsg_config structure. It has the - * following fields: - * - * nluns Number of LUNs function have (anywhere from 1 - * to FSG_MAX_LUNS which is 8). - * luns An array of LUN configuration values. This - * should be filled for each LUN that - * function will include (ie. for "nluns" - * LUNs). Each element of the array has - * the following fields: - * ->filename The path to the backing file for the LUN. - * Required if LUN is not marked as - * removable. - * ->ro Flag specifying access to the LUN shall be - * read-only. This is implied if CD-ROM - * emulation is enabled as well as when - * it was impossible to open "filename" - * in R/W mode. - * ->removable Flag specifying that LUN shall be indicated as - * being removable. - * ->cdrom Flag specifying that LUN shall be reported as - * being a CD-ROM. - * - * lun_name_format A printf-like format for names of the LUN - * devices. This determines how the - * directory in sysfs will be named. - * Unless you are using several MSFs in - * a single gadget (as opposed to single - * MSF in many configurations) you may - * leave it as NULL (in which case - * "lun%d" will be used). In the format - * you can use "%d" to index LUNs for - * MSF's with more than one LUN. (Beware - * that there is only one integer given - * as an argument for the format and - * specifying invalid format may cause - * unspecified behaviour.) - * thread_name Name of the kernel thread process used by the - * MSF. You can safely set it to NULL - * (in which case default "file-storage" - * will be used). - * - * vendor_name - * product_name - * release Information used as a reply to INQUIRY - * request. To use default set to NULL, - * NULL, 0xffff respectively. The first - * field should be 8 and the second 16 - * characters or less. - * - * can_stall Set to permit function to halt bulk endpoints. - * Disabled on some USB devices known not - * to work correctly. You should set it - * to true. - * - * If "removable" is not set for a LUN then a backing file must be - * specified. If it is set, then NULL filename means the LUN's medium - * is not loaded (an empty string as "filename" in the fsg_config - * structure causes error). The CD-ROM emulation includes a single - * data track and no audio tracks; hence there need be only one - * backing file per LUN. Note also that the CD-ROM block length is - * set to 512 rather than the more common value 2048. - * - * - * MSF includes support for module parameters. If gadget using it - * decides to use it, the following module parameters will be - * available: - * - * file=filename[,filename...] - * Names of the files or block devices used for - * backing storage. - * ro=b[,b...] Default false, boolean for read-only access. - * removable=b[,b...] - * Default true, boolean for removable media. - * cdrom=b[,b...] Default false, boolean for whether to emulate - * a CD-ROM drive. - * luns=N Default N = number of filenames, number of - * LUNs to support. - * stall Default determined according to the type of - * USB device controller (usually true), - * boolean to permit the driver to halt - * bulk endpoints. - * - * The module parameters may be prefixed with some string. You need - * to consult gadget's documentation or source to verify whether it is - * using those module parameters and if it does what are the prefixes - * (look for FSG_MODULE_PARAMETERS() macro usage, what's inside it is - * the prefix). - * - * - * Requirements are modest; only a bulk-in and a bulk-out endpoint are - * needed. The memory requirement amounts to two 16K buffers, size - * configurable by a parameter. Support is included for both - * full-speed and high-speed operation. - * - * Note that the driver is slightly non-portable in that it assumes a - * single memory/DMA buffer will be useable for bulk-in, bulk-out, and - * interrupt-in endpoints. With most device controllers this isn't an - * issue, but there may be some with hardware restrictions that prevent - * a buffer from being used by more than one endpoint. - * - * - * The pathnames of the backing files and the ro settings are - * available in the attribute files "file" and "ro" in the lun<n> (or - * to be more precise in a directory which name comes from - * "lun_name_format" option!) subdirectory of the gadget's sysfs - * directory. If the "removable" option is set, writing to these - * files will simulate ejecting/loading the medium (writing an empty - * line means eject) and adjusting a write-enable tab. Changes to the - * ro setting are not allowed when the medium is loaded or if CD-ROM - * emulation is being used. - * - * When a LUN receive an "eject" SCSI request (Start/Stop Unit), - * if the LUN is removable, the backing file is released to simulate - * ejection. - * - * - * This function is heavily based on "File-backed Storage Gadget" by - * Alan Stern which in turn is heavily based on "Gadget Zero" by David - * Brownell. The driver's SCSI command interface was based on the - * "Information technology - Small Computer System Interface - 2" - * document from X3T9.2 Project 375D, Revision 10L, 7-SEP-93, - * available at <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. - * The single exception is opcode 0x23 (READ FORMAT CAPACITIES), which - * was based on the "Universal Serial Bus Mass Storage Class UFI - * Command Specification" document, Revision 1.0, December 14, 1998, - * available at - * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>. - */ - -/* - * Driver Design - * - * The MSF is fairly straightforward. There is a main kernel - * thread that handles most of the work. Interrupt routines field - * callbacks from the controller driver: bulk- and interrupt-request - * completion notifications, endpoint-0 events, and disconnect events. - * Completion events are passed to the main thread by wakeup calls. Many - * ep0 requests are handled at interrupt time, but SetInterface, - * SetConfiguration, and device reset requests are forwarded to the - * thread in the form of "exceptions" using SIGUSR1 signals (since they - * should interrupt any ongoing file I/O operations). - * - * The thread's main routine implements the standard command/data/status - * parts of a SCSI interaction. It and its subroutines are full of tests - * for pending signals/exceptions -- all this polling is necessary since - * the kernel has no setjmp/longjmp equivalents. (Maybe this is an - * indication that the driver really wants to be running in userspace.) - * An important point is that so long as the thread is alive it keeps an - * open reference to the backing file. This will prevent unmounting - * the backing file's underlying filesystem and could cause problems - * during system shutdown, for example. To prevent such problems, the - * thread catches INT, TERM, and KILL signals and converts them into - * an EXIT exception. - * - * In normal operation the main thread is started during the gadget's - * fsg_bind() callback and stopped during fsg_unbind(). But it can - * also exit when it receives a signal, and there's no point leaving - * the gadget running when the thread is dead. At of this moment, MSF - * provides no way to deregister the gadget when thread dies -- maybe - * a callback functions is needed. - * - * To provide maximum throughput, the driver uses a circular pipeline of - * buffer heads (struct fsg_buffhd). In principle the pipeline can be - * arbitrarily long; in practice the benefits don't justify having more - * than 2 stages (i.e., double buffering). But it helps to think of the - * pipeline as being a long one. Each buffer head contains a bulk-in and - * a bulk-out request pointer (since the buffer can be used for both - * output and input -- directions always are given from the host's - * point of view) as well as a pointer to the buffer and various state - * variables. - * - * Use of the pipeline follows a simple protocol. There is a variable - * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. - * At any time that buffer head may still be in use from an earlier - * request, so each buffer head has a state variable indicating whether - * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the - * buffer head to be EMPTY, filling the buffer either by file I/O or by - * USB I/O (during which the buffer head is BUSY), and marking the buffer - * head FULL when the I/O is complete. Then the buffer will be emptied - * (again possibly by USB I/O, during which it is marked BUSY) and - * finally marked EMPTY again (possibly by a completion routine). - * - * A module parameter tells the driver to avoid stalling the bulk - * endpoints wherever the transport specification allows. This is - * necessary for some UDCs like the SuperH, which cannot reliably clear a - * halt on a bulk endpoint. However, under certain circumstances the - * Bulk-only specification requires a stall. In such cases the driver - * will halt the endpoint and set a flag indicating that it should clear - * the halt in software during the next device reset. Hopefully this - * will permit everything to work correctly. Furthermore, although the - * specification allows the bulk-out endpoint to halt when the host sends - * too much data, implementing this would cause an unavoidable race. - * The driver will always use the "no-stall" approach for OUT transfers. - * - * One subtle point concerns sending status-stage responses for ep0 - * requests. Some of these requests, such as device reset, can involve - * interrupting an ongoing file I/O operation, which might take an - * arbitrarily long time. During that delay the host might give up on - * the original ep0 request and issue a new one. When that happens the - * driver should not notify the host about completion of the original - * request, as the host will no longer be waiting for it. So the driver - * assigns to each ep0 request a unique tag, and it keeps track of the - * tag value of the request associated with a long-running exception - * (device-reset, interface-change, or configuration-change). When the - * exception handler is finished, the status-stage response is submitted - * only if the current ep0 request tag is equal to the exception request - * tag. Thus only the most recently received ep0 request will get a - * status-stage response. - * - * Warning: This driver source file is too long. It ought to be split up - * into a header file plus about 3 separate .c files, to handle the details - * of the Gadget, USB Mass Storage, and SCSI protocols. - */ - -/* #define VERBOSE_DEBUG */ -/* #define DUMP_MSGS */ - -#include <config.h> -#include <malloc.h> -#include <common.h> -#include <g_dnl.h> - -#include <linux/err.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <usb_mass_storage.h> - -#include <asm/unaligned.h> -#include <linux/usb/gadget.h> -#include <linux/usb/gadget.h> -#include <linux/usb/composite.h> -#include <usb/lin_gadget_compat.h> -#include <g_dnl.h> - -/*------------------------------------------------------------------------*/ - -#define FSG_DRIVER_DESC "Mass Storage Function" -#define FSG_DRIVER_VERSION "2012/06/5" - -static const char fsg_string_interface[] = "Mass Storage"; - -#define FSG_NO_INTR_EP 1 -#define FSG_NO_DEVICE_STRINGS 1 -#define FSG_NO_OTG 1 -#define FSG_NO_INTR_EP 1 - -#include "storage_common.c" - -/*-------------------------------------------------------------------------*/ - -#define GFP_ATOMIC ((gfp_t) 0) -#define PAGE_CACHE_SHIFT 12 -#define PAGE_CACHE_SIZE (1 << PAGE_CACHE_SHIFT) -#define kthread_create(...) __builtin_return_address(0) -#define wait_for_completion(...) do {} while (0) - -struct kref {int x; }; -struct completion {int x; }; - -inline void set_bit(int nr, volatile void *addr) -{ - int mask; - unsigned int *a = (unsigned int *) addr; - - a += nr >> 5; - mask = 1 << (nr & 0x1f); - *a |= mask; -} - -inline void clear_bit(int nr, volatile void *addr) -{ - int mask; - unsigned int *a = (unsigned int *) addr; - - a += nr >> 5; - mask = 1 << (nr & 0x1f); - *a &= ~mask; -} - -struct fsg_dev; -struct fsg_common; - -/* Data shared by all the FSG instances. */ -struct fsg_common { - struct usb_gadget *gadget; - struct fsg_dev *fsg, *new_fsg; - - struct usb_ep *ep0; /* Copy of gadget->ep0 */ - struct usb_request *ep0req; /* Copy of cdev->req */ - unsigned int ep0_req_tag; - - struct fsg_buffhd *next_buffhd_to_fill; - struct fsg_buffhd *next_buffhd_to_drain; - struct fsg_buffhd buffhds[FSG_NUM_BUFFERS]; - - int cmnd_size; - u8 cmnd[MAX_COMMAND_SIZE]; - - unsigned int nluns; - unsigned int lun; - struct fsg_lun luns[FSG_MAX_LUNS]; - - unsigned int bulk_out_maxpacket; - enum fsg_state state; /* For exception handling */ - unsigned int exception_req_tag; - - enum data_direction data_dir; - u32 data_size; - u32 data_size_from_cmnd; - u32 tag; - u32 residue; - u32 usb_amount_left; - - unsigned int can_stall:1; - unsigned int free_storage_on_release:1; - unsigned int phase_error:1; - unsigned int short_packet_received:1; - unsigned int bad_lun_okay:1; - unsigned int running:1; - - int thread_wakeup_needed; - struct completion thread_notifier; - struct task_struct *thread_task; - - /* Callback functions. */ - const struct fsg_operations *ops; - /* Gadget's private data. */ - void *private_data; - - const char *vendor_name; /* 8 characters or less */ - const char *product_name; /* 16 characters or less */ - u16 release; - - /* Vendor (8 chars), product (16 chars), release (4 - * hexadecimal digits) and NUL byte */ - char inquiry_string[8 + 16 + 4 + 1]; - - struct kref ref; -}; - -struct fsg_config { - unsigned nluns; - struct fsg_lun_config { - const char *filename; - char ro; - char removable; - char cdrom; - char nofua; - } luns[FSG_MAX_LUNS]; - - /* Callback functions. */ - const struct fsg_operations *ops; - /* Gadget's private data. */ - void *private_data; - - const char *vendor_name; /* 8 characters or less */ - const char *product_name; /* 16 characters or less */ - - char can_stall; -}; - -struct fsg_dev { - struct usb_function function; - struct usb_gadget *gadget; /* Copy of cdev->gadget */ - struct fsg_common *common; - - u16 interface_number; - - unsigned int bulk_in_enabled:1; - unsigned int bulk_out_enabled:1; - - unsigned long atomic_bitflags; -#define IGNORE_BULK_OUT 0 - - struct usb_ep *bulk_in; - struct usb_ep *bulk_out; -}; - - -static inline int __fsg_is_set(struct fsg_common *common, - const char *func, unsigned line) -{ - if (common->fsg) - return 1; - ERROR(common, "common->fsg is NULL in %s at %u\n", func, line); - WARN_ON(1); - return 0; -} - -#define fsg_is_set(common) likely(__fsg_is_set(common, __func__, __LINE__)) - - -static inline struct fsg_dev *fsg_from_func(struct usb_function *f) -{ - return container_of(f, struct fsg_dev, function); -} - - -typedef void (*fsg_routine_t)(struct fsg_dev *); - -static int exception_in_progress(struct fsg_common *common) -{ - return common->state > FSG_STATE_IDLE; -} - -/* Make bulk-out requests be divisible by the maxpacket size */ -static void set_bulk_out_req_length(struct fsg_common *common, - struct fsg_buffhd *bh, unsigned int length) -{ - unsigned int rem; - - bh->bulk_out_intended_length = length; - rem = length % common->bulk_out_maxpacket; - if (rem > 0) - length += common->bulk_out_maxpacket - rem; - bh->outreq->length = length; -} - -/*-------------------------------------------------------------------------*/ - -struct ums *ums; -struct fsg_common *the_fsg_common; - -static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) -{ - const char *name; - - if (ep == fsg->bulk_in) - name = "bulk-in"; - else if (ep == fsg->bulk_out) - name = "bulk-out"; - else - name = ep->name; - DBG(fsg, "%s set halt\n", name); - return usb_ep_set_halt(ep); -} - -/*-------------------------------------------------------------------------*/ - -/* These routines may be called in process context or in_irq */ - -/* Caller must hold fsg->lock */ -static void wakeup_thread(struct fsg_common *common) -{ - common->thread_wakeup_needed = 1; -} - -static void raise_exception(struct fsg_common *common, enum fsg_state new_state) -{ - /* Do nothing if a higher-priority exception is already in progress. - * If a lower-or-equal priority exception is in progress, preempt it - * and notify the main thread by sending it a signal. */ - if (common->state <= new_state) { - common->exception_req_tag = common->ep0_req_tag; - common->state = new_state; - common->thread_wakeup_needed = 1; - } -} - -/*-------------------------------------------------------------------------*/ - -static int ep0_queue(struct fsg_common *common) -{ - int rc; - - rc = usb_ep_queue(common->ep0, common->ep0req, GFP_ATOMIC); - common->ep0->driver_data = common; - if (rc != 0 && rc != -ESHUTDOWN) { - /* We can't do much more than wait for a reset */ - WARNING(common, "error in submission: %s --> %d\n", - common->ep0->name, rc); - } - return rc; -} - -/*-------------------------------------------------------------------------*/ - -/* Bulk and interrupt endpoint completion handlers. - * These always run in_irq. */ - -static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_common *common = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - if (req->status || req->actual != req->length) - DBG(common, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, req->length); - if (req->status == -ECONNRESET) /* Request was cancelled */ - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - bh->inreq_busy = 0; - bh->state = BUF_STATE_EMPTY; - wakeup_thread(common); -} - -static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct fsg_common *common = ep->driver_data; - struct fsg_buffhd *bh = req->context; - - dump_msg(common, "bulk-out", req->buf, req->actual); - if (req->status || req->actual != bh->bulk_out_intended_length) - DBG(common, "%s --> %d, %u/%u\n", __func__, - req->status, req->actual, - bh->bulk_out_intended_length); - if (req->status == -ECONNRESET) /* Request was cancelled */ - usb_ep_fifo_flush(ep); - - /* Hold the lock while we update the request and buffer states */ - bh->outreq_busy = 0; - bh->state = BUF_STATE_FULL; - wakeup_thread(common); -} - -/*-------------------------------------------------------------------------*/ - -/* Ep0 class-specific handlers. These always run in_irq. */ - -static int fsg_setup(struct usb_function *f, - const struct usb_ctrlrequest *ctrl) -{ - struct fsg_dev *fsg = fsg_from_func(f); - struct usb_request *req = fsg->common->ep0req; - u16 w_index = get_unaligned_le16(&ctrl->wIndex); - u16 w_value = get_unaligned_le16(&ctrl->wValue); - u16 w_length = get_unaligned_le16(&ctrl->wLength); - - if (!fsg_is_set(fsg->common)) - return -EOPNOTSUPP; - - switch (ctrl->bRequest) { - - case USB_BULK_RESET_REQUEST: - if (ctrl->bRequestType != - (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != fsg->interface_number || w_value != 0) - return -EDOM; - - /* Raise an exception to stop the current operation - * and reinitialize our state. */ - DBG(fsg, "bulk reset request\n"); - raise_exception(fsg->common, FSG_STATE_RESET); - return DELAYED_STATUS; - - case USB_BULK_GET_MAX_LUN_REQUEST: - if (ctrl->bRequestType != - (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE)) - break; - if (w_index != fsg->interface_number || w_value != 0) - return -EDOM; - VDBG(fsg, "get max LUN\n"); - *(u8 *) req->buf = fsg->common->nluns - 1; - - /* Respond with data/status */ - req->length = min((u16)1, w_length); - return ep0_queue(fsg->common); - } - - VDBG(fsg, - "unknown class-specific control req " - "%02x.%02x v%04x i%04x l%u\n", - ctrl->bRequestType, ctrl->bRequest, - get_unaligned_le16(&ctrl->wValue), w_index, w_length); - return -EOPNOTSUPP; -} - -/*-------------------------------------------------------------------------*/ - -/* All the following routines run in process context */ - -/* Use this for bulk or interrupt transfers, not ep0 */ -static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, - struct usb_request *req, int *pbusy, - enum fsg_buffer_state *state) -{ - int rc; - - if (ep == fsg->bulk_in) - dump_msg(fsg, "bulk-in", req->buf, req->length); - - *pbusy = 1; - *state = BUF_STATE_BUSY; - rc = usb_ep_queue(ep, req, GFP_KERNEL); - if (rc != 0) { - *pbusy = 0; - *state = BUF_STATE_EMPTY; - - /* We can't do much more than wait for a reset */ - - /* Note: currently the net2280 driver fails zero-length - * submissions if DMA is enabled. */ - if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && - req->length == 0)) - WARNING(fsg, "error in submission: %s --> %d\n", - ep->name, rc); - } -} - -#define START_TRANSFER_OR(common, ep_name, req, pbusy, state) \ - if (fsg_is_set(common)) \ - start_transfer((common)->fsg, (common)->fsg->ep_name, \ - req, pbusy, state); \ - else - -#define START_TRANSFER(common, ep_name, req, pbusy, state) \ - START_TRANSFER_OR(common, ep_name, req, pbusy, state) (void)0 - -static void busy_indicator(void) -{ - static int state; - - switch (state) { - case 0: - puts("\r|"); break; - case 1: - puts("\r/"); break; - case 2: - puts("\r-"); break; - case 3: - puts("\r\\"); break; - case 4: - puts("\r|"); break; - case 5: - puts("\r/"); break; - case 6: - puts("\r-"); break; - case 7: - puts("\r\\"); break; - default: - state = 0; - } - if (state++ == 8) - state = 0; -} - -static int sleep_thread(struct fsg_common *common) -{ - int rc = 0; - int i = 0, k = 0; - - /* Wait until a signal arrives or we are woken up */ - for (;;) { - if (common->thread_wakeup_needed) - break; - - if (++i == 50000) { - busy_indicator(); - i = 0; - k++; - } - - if (k == 10) { - /* Handle CTRL+C */ - if (ctrlc()) - return -EPIPE; - - /* Check cable connection */ - if (!g_dnl_board_usb_cable_connected()) - return -EIO; - - k = 0; - } - - usb_gadget_handle_interrupts(); - } - common->thread_wakeup_needed = 0; - return rc; -} - -/*-------------------------------------------------------------------------*/ - -static int do_read(struct fsg_common *common) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - u32 lba; - struct fsg_buffhd *bh; - int rc; - u32 amount_left; - loff_t file_offset; - unsigned int amount; - unsigned int partial_page; - ssize_t nread; - - /* Get the starting Logical Block Address and check that it's - * not too big */ - if (common->cmnd[0] == SC_READ_6) - lba = get_unaligned_be24(&common->cmnd[1]); - else { - lba = get_unaligned_be32(&common->cmnd[2]); - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) and FUA (Force Unit Access = don't read from the - * cache), but we don't implement them. */ - if ((common->cmnd[1] & ~0x18) != 0) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - file_offset = ((loff_t) lba) << 9; - - /* Carry out the file reads */ - amount_left = common->data_size_from_cmnd; - if (unlikely(amount_left == 0)) - return -EIO; /* No default reply */ - - for (;;) { - - /* Figure out how much we need to read: - * Try to read the remaining amount. - * But don't read more than the buffer size. - * And don't try to read past the end of the file. - * Finally, if we're not at a page boundary, don't read past - * the next page. - * If this means reading 0 then we were asked to read past - * the end of file. */ - amount = min(amount_left, FSG_BUFLEN); - partial_page = file_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, (unsigned int) PAGE_CACHE_SIZE - - partial_page); - - /* Wait for the next buffer to become available */ - bh = common->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); - if (rc) - return rc; - } - - /* If we were asked to read past the end of file, - * end with an empty buffer. */ - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->info_valid = 1; - bh->inreq->length = 0; - bh->state = BUF_STATE_FULL; - break; - } - - /* Perform the read */ - rc = ums->read_sector(ums, - file_offset / SECTOR_SIZE, - amount / SECTOR_SIZE, - (char __user *)bh->buf); - if (!rc) - return -EIO; - - nread = rc * SECTOR_SIZE; - - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); - - if (nread < 0) { - LDBG(curlun, "error in file read: %d\n", - (int) nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file read: %d/%u\n", - (int) nread, amount); - nread -= (nread & 511); /* Round down to a block */ - } - file_offset += nread; - amount_left -= nread; - common->residue -= nread; - bh->inreq->length = nread; - bh->state = BUF_STATE_FULL; - - /* If an error occurred, report it and its position */ - if (nread < amount) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->info_valid = 1; - break; - } - - if (amount_left == 0) - break; /* No more left to read */ - - /* Send this buffer and go read some more */ - bh->inreq->zero = 0; - START_TRANSFER_OR(common, bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state) - /* Don't know what to do if - * common->fsg is NULL */ - return -EIO; - common->next_buffhd_to_fill = bh->next; - } - - return -EIO; /* No default reply */ -} - -/*-------------------------------------------------------------------------*/ - -static int do_write(struct fsg_common *common) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - u32 lba; - struct fsg_buffhd *bh; - int get_some_more; - u32 amount_left_to_req, amount_left_to_write; - loff_t usb_offset, file_offset; - unsigned int amount; - unsigned int partial_page; - ssize_t nwritten; - int rc; - - if (curlun->ro) { - curlun->sense_data = SS_WRITE_PROTECTED; - return -EINVAL; - } - - /* Get the starting Logical Block Address and check that it's - * not too big */ - if (common->cmnd[0] == SC_WRITE_6) - lba = get_unaligned_be24(&common->cmnd[1]); - else { - lba = get_unaligned_be32(&common->cmnd[2]); - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) and FUA (Force Unit Access = write directly to the - * medium). We don't implement DPO; we implement FUA by - * performing synchronous output. */ - if (common->cmnd[1] & ~0x18) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* Carry out the file writes */ - get_some_more = 1; - file_offset = usb_offset = ((loff_t) lba) << 9; - amount_left_to_req = common->data_size_from_cmnd; - amount_left_to_write = common->data_size_from_cmnd; - - while (amount_left_to_write > 0) { - - /* Queue a request for more data from the host */ - bh = common->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY && get_some_more) { - - /* Figure out how much we want to get: - * Try to get the remaining amount. - * But don't get more than the buffer size. - * And don't try to go past the end of the file. - * If we're not at a page boundary, - * don't go past the next page. - * If this means getting 0, then we were asked - * to write past the end of file. - * Finally, round down to a block boundary. */ - amount = min(amount_left_to_req, FSG_BUFLEN); - partial_page = usb_offset & (PAGE_CACHE_SIZE - 1); - if (partial_page > 0) - amount = min(amount, - (unsigned int) PAGE_CACHE_SIZE - partial_page); - - if (amount == 0) { - get_some_more = 0; - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->info_valid = 1; - continue; - } - amount -= (amount & 511); - if (amount == 0) { - - /* Why were we were asked to transfer a - * partial block? */ - get_some_more = 0; - continue; - } - - /* Get the next buffer */ - usb_offset += amount; - common->usb_amount_left -= amount; - amount_left_to_req -= amount; - if (amount_left_to_req == 0) - get_some_more = 0; - - /* amount is always divisible by 512, hence by - * the bulk-out maxpacket size */ - bh->outreq->length = amount; - bh->bulk_out_intended_length = amount; - bh->outreq->short_not_ok = 1; - START_TRANSFER_OR(common, bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state) - /* Don't know what to do if - * common->fsg is NULL */ - return -EIO; - common->next_buffhd_to_fill = bh->next; - continue; - } - - /* Write the received data to the backing file */ - bh = common->next_buffhd_to_drain; - if (bh->state == BUF_STATE_EMPTY && !get_some_more) - break; /* We stopped early */ - if (bh->state == BUF_STATE_FULL) { - common->next_buffhd_to_drain = bh->next; - bh->state = BUF_STATE_EMPTY; - - /* Did something go wrong with the transfer? */ - if (bh->outreq->status != 0) { - curlun->sense_data = SS_COMMUNICATION_FAILURE; - curlun->info_valid = 1; - break; - } - - amount = bh->outreq->actual; - - /* Perform the write */ - rc = ums->write_sector(ums, - file_offset / SECTOR_SIZE, - amount / SECTOR_SIZE, - (char __user *)bh->buf); - if (!rc) - return -EIO; - nwritten = rc * SECTOR_SIZE; - - VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nwritten); - - if (nwritten < 0) { - LDBG(curlun, "error in file write: %d\n", - (int) nwritten); - nwritten = 0; - } else if (nwritten < amount) { - LDBG(curlun, "partial file write: %d/%u\n", - (int) nwritten, amount); - nwritten -= (nwritten & 511); - /* Round down to a block */ - } - file_offset += nwritten; - amount_left_to_write -= nwritten; - common->residue -= nwritten; - - /* If an error occurred, report it and its position */ - if (nwritten < amount) { - printf("nwritten:%d amount:%d\n", nwritten, - amount); - curlun->sense_data = SS_WRITE_ERROR; - curlun->info_valid = 1; - break; - } - - /* Did the host decide to stop early? */ - if (bh->outreq->actual != bh->outreq->length) { - common->short_packet_received = 1; - break; - } - continue; - } - - /* Wait for something to happen */ - rc = sleep_thread(common); - if (rc) - return rc; - } - - return -EIO; /* No default reply */ -} - -/*-------------------------------------------------------------------------*/ - -static int do_synchronize_cache(struct fsg_common *common) -{ - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int do_verify(struct fsg_common *common) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - u32 lba; - u32 verification_length; - struct fsg_buffhd *bh = common->next_buffhd_to_fill; - loff_t file_offset; - u32 amount_left; - unsigned int amount; - ssize_t nread; - int rc; - - /* Get the starting Logical Block Address and check that it's - * not too big */ - lba = get_unaligned_be32(&common->cmnd[2]); - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - /* We allow DPO (Disable Page Out = don't save data in the - * cache) but we don't implement it. */ - if (common->cmnd[1] & ~0x10) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - verification_length = get_unaligned_be16(&common->cmnd[7]); - if (unlikely(verification_length == 0)) - return -EIO; /* No default reply */ - - /* Prepare to carry out the file verify */ - amount_left = verification_length << 9; - file_offset = ((loff_t) lba) << 9; - - /* Write out all the dirty buffers before invalidating them */ - - /* Just try to read the requested blocks */ - while (amount_left > 0) { - - /* Figure out how much we need to read: - * Try to read the remaining amount, but not more than - * the buffer size. - * And don't try to read past the end of the file. - * If this means reading 0 then we were asked to read - * past the end of file. */ - amount = min(amount_left, FSG_BUFLEN); - if (amount == 0) { - curlun->sense_data = - SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - curlun->info_valid = 1; - break; - } - - /* Perform the read */ - rc = ums->read_sector(ums, - file_offset / SECTOR_SIZE, - amount / SECTOR_SIZE, - (char __user *)bh->buf); - if (!rc) - return -EIO; - nread = rc * SECTOR_SIZE; - - VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, - (unsigned long long) file_offset, - (int) nread); - if (nread < 0) { - LDBG(curlun, "error in file verify: %d\n", - (int) nread); - nread = 0; - } else if (nread < amount) { - LDBG(curlun, "partial file verify: %d/%u\n", - (int) nread, amount); - nread -= (nread & 511); /* Round down to a sector */ - } - if (nread == 0) { - curlun->sense_data = SS_UNRECOVERED_READ_ERROR; - curlun->info_valid = 1; - break; - } - file_offset += nread; - amount_left -= nread; - } - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int do_inquiry(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - static const char vendor_id[] = "Linux "; - u8 *buf = (u8 *) bh->buf; - - if (!curlun) { /* Unsupported LUNs are okay */ - common->bad_lun_okay = 1; - memset(buf, 0, 36); - buf[0] = 0x7f; /* Unsupported, no device-type */ - buf[4] = 31; /* Additional length */ - return 36; - } - - memset(buf, 0, 8); - buf[0] = TYPE_DISK; - buf[2] = 2; /* ANSI SCSI level 2 */ - buf[3] = 2; /* SCSI-2 INQUIRY data format */ - buf[4] = 31; /* Additional length */ - /* No special options */ - sprintf((char *) (buf + 8), "%-8s%-16s%04x", (char*) vendor_id , - ums->name, (u16) 0xffff); - - return 36; -} - - -static int do_request_sense(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - u8 *buf = (u8 *) bh->buf; - u32 sd, sdinfo; - int valid; - - /* - * From the SCSI-2 spec., section 7.9 (Unit attention condition): - * - * If a REQUEST SENSE command is received from an initiator - * with a pending unit attention condition (before the target - * generates the contingent allegiance condition), then the - * target shall either: - * a) report any pending sense data and preserve the unit - * attention condition on the logical unit, or, - * b) report the unit attention condition, may discard any - * pending sense data, and clear the unit attention - * condition on the logical unit for that initiator. - * - * FSG normally uses option a); enable this code to use option b). - */ -#if 0 - if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - } -#endif - - if (!curlun) { /* Unsupported LUNs are okay */ - common->bad_lun_okay = 1; - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - sdinfo = 0; - valid = 0; - } else { - sd = curlun->sense_data; - valid = curlun->info_valid << 7; - curlun->sense_data = SS_NO_SENSE; - curlun->info_valid = 0; - } - - memset(buf, 0, 18); - buf[0] = valid | 0x70; /* Valid, current error */ - buf[2] = SK(sd); - put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ - buf[7] = 18 - 8; /* Additional sense length */ - buf[12] = ASC(sd); - buf[13] = ASCQ(sd); - return 18; -} - -static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - u32 lba = get_unaligned_be32(&common->cmnd[2]); - int pmi = common->cmnd[8]; - u8 *buf = (u8 *) bh->buf; - - /* Check the PMI and LBA fields */ - if (pmi > 1 || (pmi == 0 && lba != 0)) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); - /* Max logical block */ - put_unaligned_be32(512, &buf[4]); /* Block length */ - return 8; -} - -static int do_read_header(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - int msf = common->cmnd[1] & 0x02; - u32 lba = get_unaligned_be32(&common->cmnd[2]); - u8 *buf = (u8 *) bh->buf; - - if (common->cmnd[1] & ~0x02) { /* Mask away MSF */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - if (lba >= curlun->num_sectors) { - curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; - return -EINVAL; - } - - memset(buf, 0, 8); - buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ - store_cdrom_address(&buf[4], msf, lba); - return 8; -} - - -static int do_read_toc(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - int msf = common->cmnd[1] & 0x02; - int start_track = common->cmnd[6]; - u8 *buf = (u8 *) bh->buf; - - if ((common->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ - start_track > 1) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - memset(buf, 0, 20); - buf[1] = (20-2); /* TOC data length */ - buf[2] = 1; /* First track number */ - buf[3] = 1; /* Last track number */ - buf[5] = 0x16; /* Data track, copying allowed */ - buf[6] = 0x01; /* Only track is number 1 */ - store_cdrom_address(&buf[8], msf, 0); - - buf[13] = 0x16; /* Lead-out track is data */ - buf[14] = 0xAA; /* Lead-out track number */ - store_cdrom_address(&buf[16], msf, curlun->num_sectors); - - return 20; -} - -static int do_mode_sense(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - int mscmnd = common->cmnd[0]; - u8 *buf = (u8 *) bh->buf; - u8 *buf0 = buf; - int pc, page_code; - int changeable_values, all_pages; - int valid_page = 0; - int len, limit; - - if ((common->cmnd[1] & ~0x08) != 0) { /* Mask away DBD */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - pc = common->cmnd[2] >> 6; - page_code = common->cmnd[2] & 0x3f; - if (pc == 3) { - curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; - return -EINVAL; - } - changeable_values = (pc == 1); - all_pages = (page_code == 0x3f); - - /* Write the mode parameter header. Fixed values are: default - * medium type, no cache control (DPOFUA), and no block descriptors. - * The only variable value is the WriteProtect bit. We will fill in - * the mode data length later. */ - memset(buf, 0, 8); - if (mscmnd == SC_MODE_SENSE_6) { - buf[2] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ - buf += 4; - limit = 255; - } else { /* SC_MODE_SENSE_10 */ - buf[3] = (curlun->ro ? 0x80 : 0x00); /* WP, DPOFUA */ - buf += 8; - limit = 65535; /* Should really be FSG_BUFLEN */ - } - - /* No block descriptors */ - - /* The mode pages, in numerical order. The only page we support - * is the Caching page. */ - if (page_code == 0x08 || all_pages) { - valid_page = 1; - buf[0] = 0x08; /* Page code */ - buf[1] = 10; /* Page length */ - memset(buf+2, 0, 10); /* None of the fields are changeable */ - - if (!changeable_values) { - buf[2] = 0x04; /* Write cache enable, */ - /* Read cache not disabled */ - /* No cache retention priorities */ - put_unaligned_be16(0xffff, &buf[4]); - /* Don't disable prefetch */ - /* Minimum prefetch = 0 */ - put_unaligned_be16(0xffff, &buf[8]); - /* Maximum prefetch */ - put_unaligned_be16(0xffff, &buf[10]); - /* Maximum prefetch ceiling */ - } - buf += 12; - } - - /* Check that a valid page was requested and the mode data length - * isn't too long. */ - len = buf - buf0; - if (!valid_page || len > limit) { - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - /* Store the mode data length */ - if (mscmnd == SC_MODE_SENSE_6) - buf0[0] = len - 1; - else - put_unaligned_be16(len - 2, buf0); - return len; -} - - -static int do_start_stop(struct fsg_common *common) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - - if (!curlun) { - return -EINVAL; - } else if (!curlun->removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } - - return 0; -} - -static int do_prevent_allow(struct fsg_common *common) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - int prevent; - - if (!curlun->removable) { - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; - } - - prevent = common->cmnd[4] & 0x01; - if ((common->cmnd[4] & ~0x01) != 0) { /* Mask away Prevent */ - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - - if (curlun->prevent_medium_removal && !prevent) - fsg_lun_fsync_sub(curlun); - curlun->prevent_medium_removal = prevent; - return 0; -} - - -static int do_read_format_capacities(struct fsg_common *common, - struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - u8 *buf = (u8 *) bh->buf; - - buf[0] = buf[1] = buf[2] = 0; - buf[3] = 8; /* Only the Current/Maximum Capacity Descriptor */ - buf += 4; - - put_unaligned_be32(curlun->num_sectors, &buf[0]); - /* Number of blocks */ - put_unaligned_be32(512, &buf[4]); /* Block length */ - buf[4] = 0x02; /* Current capacity */ - return 12; -} - - -static int do_mode_select(struct fsg_common *common, struct fsg_buffhd *bh) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - - /* We don't support MODE SELECT */ - if (curlun) - curlun->sense_data = SS_INVALID_COMMAND; - return -EINVAL; -} - - -/*-------------------------------------------------------------------------*/ - -static int halt_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - rc = fsg_set_halt(fsg, fsg->bulk_in); - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint halt\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_halt -> %d\n", rc); - rc = 0; - break; - } - - rc = usb_ep_set_halt(fsg->bulk_in); - } - return rc; -} - -static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) -{ - int rc; - - DBG(fsg, "bulk-in set wedge\n"); - rc = 0; /* usb_ep_set_wedge(fsg->bulk_in); */ - if (rc == -EAGAIN) - VDBG(fsg, "delayed bulk-in endpoint wedge\n"); - while (rc != 0) { - if (rc != -EAGAIN) { - WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc); - rc = 0; - break; - } - } - return rc; -} - -static int pad_with_zeros(struct fsg_dev *fsg) -{ - struct fsg_buffhd *bh = fsg->common->next_buffhd_to_fill; - u32 nkeep = bh->inreq->length; - u32 nsend; - int rc; - - bh->state = BUF_STATE_EMPTY; /* For the first iteration */ - fsg->common->usb_amount_left = nkeep + fsg->common->residue; - while (fsg->common->usb_amount_left > 0) { - - /* Wait for the next buffer to be free */ - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(fsg->common); - if (rc) - return rc; - } - - nsend = min(fsg->common->usb_amount_left, FSG_BUFLEN); - memset(bh->buf + nkeep, 0, nsend - nkeep); - bh->inreq->length = nsend; - bh->inreq->zero = 0; - start_transfer(fsg, fsg->bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state); - bh = fsg->common->next_buffhd_to_fill = bh->next; - fsg->common->usb_amount_left -= nsend; - nkeep = 0; - } - return 0; -} - -static int throw_away_data(struct fsg_common *common) -{ - struct fsg_buffhd *bh; - u32 amount; - int rc; - - for (bh = common->next_buffhd_to_drain; - bh->state != BUF_STATE_EMPTY || common->usb_amount_left > 0; - bh = common->next_buffhd_to_drain) { - - /* Throw away the data in a filled buffer */ - if (bh->state == BUF_STATE_FULL) { - bh->state = BUF_STATE_EMPTY; - common->next_buffhd_to_drain = bh->next; - - /* A short packet or an error ends everything */ - if (bh->outreq->actual != bh->outreq->length || - bh->outreq->status != 0) { - raise_exception(common, - FSG_STATE_ABORT_BULK_OUT); - return -EINTR; - } - continue; - } - - /* Try to submit another request if we need one */ - bh = common->next_buffhd_to_fill; - if (bh->state == BUF_STATE_EMPTY - && common->usb_amount_left > 0) { - amount = min(common->usb_amount_left, FSG_BUFLEN); - - /* amount is always divisible by 512, hence by - * the bulk-out maxpacket size */ - bh->outreq->length = amount; - bh->bulk_out_intended_length = amount; - bh->outreq->short_not_ok = 1; - START_TRANSFER_OR(common, bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state) - /* Don't know what to do if - * common->fsg is NULL */ - return -EIO; - common->next_buffhd_to_fill = bh->next; - common->usb_amount_left -= amount; - continue; - } - - /* Otherwise wait for something to happen */ - rc = sleep_thread(common); - if (rc) - return rc; - } - return 0; -} - - -static int finish_reply(struct fsg_common *common) -{ - struct fsg_buffhd *bh = common->next_buffhd_to_fill; - int rc = 0; - - switch (common->data_dir) { - case DATA_DIR_NONE: - break; /* Nothing to send */ - - /* If we don't know whether the host wants to read or write, - * this must be CB or CBI with an unknown command. We mustn't - * try to send or receive any data. So stall both bulk pipes - * if we can and wait for a reset. */ - case DATA_DIR_UNKNOWN: - if (!common->can_stall) { - /* Nothing */ - } else if (fsg_is_set(common)) { - fsg_set_halt(common->fsg, common->fsg->bulk_out); - rc = halt_bulk_in_endpoint(common->fsg); - } else { - /* Don't know what to do if common->fsg is NULL */ - rc = -EIO; - } - break; - - /* All but the last buffer of data must have already been sent */ - case DATA_DIR_TO_HOST: - if (common->data_size == 0) { - /* Nothing to send */ - - /* If there's no residue, simply send the last buffer */ - } else if (common->residue == 0) { - bh->inreq->zero = 0; - START_TRANSFER_OR(common, bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state) - return -EIO; - common->next_buffhd_to_fill = bh->next; - - /* For Bulk-only, if we're allowed to stall then send the - * short packet and halt the bulk-in endpoint. If we can't - * stall, pad out the remaining data with 0's. */ - } else if (common->can_stall) { - bh->inreq->zero = 1; - START_TRANSFER_OR(common, bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state) - /* Don't know what to do if - * common->fsg is NULL */ - rc = -EIO; - common->next_buffhd_to_fill = bh->next; - if (common->fsg) - rc = halt_bulk_in_endpoint(common->fsg); - } else if (fsg_is_set(common)) { - rc = pad_with_zeros(common->fsg); - } else { - /* Don't know what to do if common->fsg is NULL */ - rc = -EIO; - } - break; - - /* We have processed all we want from the data the host has sent. - * There may still be outstanding bulk-out requests. */ - case DATA_DIR_FROM_HOST: - if (common->residue == 0) { - /* Nothing to receive */ - - /* Did the host stop sending unexpectedly early? */ - } else if (common->short_packet_received) { - raise_exception(common, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; - - /* We haven't processed all the incoming data. Even though - * we may be allowed to stall, doing so would cause a race. - * The controller may already have ACK'ed all the remaining - * bulk-out packets, in which case the host wouldn't see a - * STALL. Not realizing the endpoint was halted, it wouldn't - * clear the halt -- leading to problems later on. */ -#if 0 - } else if (common->can_stall) { - if (fsg_is_set(common)) - fsg_set_halt(common->fsg, - common->fsg->bulk_out); - raise_exception(common, FSG_STATE_ABORT_BULK_OUT); - rc = -EINTR; -#endif - - /* We can't stall. Read in the excess data and throw it - * all away. */ - } else { - rc = throw_away_data(common); - } - break; - } - return rc; -} - - -static int send_status(struct fsg_common *common) -{ - struct fsg_lun *curlun = &common->luns[common->lun]; - struct fsg_buffhd *bh; - struct bulk_cs_wrap *csw; - int rc; - u8 status = USB_STATUS_PASS; - u32 sd, sdinfo = 0; - - /* Wait for the next buffer to become available */ - bh = common->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); - if (rc) - return rc; - } - - if (curlun) - sd = curlun->sense_data; - else if (common->bad_lun_okay) - sd = SS_NO_SENSE; - else - sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; - - if (common->phase_error) { - DBG(common, "sending phase-error status\n"); - status = USB_STATUS_PHASE_ERROR; - sd = SS_INVALID_COMMAND; - } else if (sd != SS_NO_SENSE) { - DBG(common, "sending command-failure status\n"); - status = USB_STATUS_FAIL; - VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" - " info x%x\n", - SK(sd), ASC(sd), ASCQ(sd), sdinfo); - } - - /* Store and send the Bulk-only CSW */ - csw = (void *)bh->buf; - - csw->Signature = cpu_to_le32(USB_BULK_CS_SIG); - csw->Tag = common->tag; - csw->Residue = cpu_to_le32(common->residue); - csw->Status = status; - - bh->inreq->length = USB_BULK_CS_WRAP_LEN; - bh->inreq->zero = 0; - START_TRANSFER_OR(common, bulk_in, bh->inreq, - &bh->inreq_busy, &bh->state) - /* Don't know what to do if common->fsg is NULL */ - return -EIO; - - common->next_buffhd_to_fill = bh->next; - return 0; -} - - -/*-------------------------------------------------------------------------*/ - -/* Check whether the command is properly formed and whether its data size - * and direction agree with the values we already have. */ -static int check_command(struct fsg_common *common, int cmnd_size, - enum data_direction data_dir, unsigned int mask, - int needs_medium, const char *name) -{ - int i; - int lun = common->cmnd[1] >> 5; - static const char dirletter[4] = {'u', 'o', 'i', 'n'}; - char hdlen[20]; - struct fsg_lun *curlun; - - hdlen[0] = 0; - if (common->data_dir != DATA_DIR_UNKNOWN) - sprintf(hdlen, ", H%c=%u", dirletter[(int) common->data_dir], - common->data_size); - VDBG(common, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", - name, cmnd_size, dirletter[(int) data_dir], - common->data_size_from_cmnd, common->cmnd_size, hdlen); - - /* We can't reply at all until we know the correct data direction - * and size. */ - if (common->data_size_from_cmnd == 0) - data_dir = DATA_DIR_NONE; - if (common->data_size < common->data_size_from_cmnd) { - /* Host data size < Device data size is a phase error. - * Carry out the command, but only transfer as much as - * we are allowed. */ - common->data_size_from_cmnd = common->data_size; - common->phase_error = 1; - } - common->residue = common->data_size; - common->usb_amount_left = common->data_size; - - /* Conflicting data directions is a phase error */ - if (common->data_dir != data_dir - && common->data_size_from_cmnd > 0) { - common->phase_error = 1; - return -EINVAL; - } - - /* Verify the length of the command itself */ - if (cmnd_size != common->cmnd_size) { - - /* Special case workaround: There are plenty of buggy SCSI - * implementations. Many have issues with cbw->Length - * field passing a wrong command size. For those cases we - * always try to work around the problem by using the length - * sent by the host side provided it is at least as large - * as the correct command length. - * Examples of such cases would be MS-Windows, which issues - * REQUEST SENSE with cbw->Length == 12 where it should - * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and - * REQUEST SENSE with cbw->Length == 10 where it should - * be 6 as well. - */ - if (cmnd_size <= common->cmnd_size) { - DBG(common, "%s is buggy! Expected length %d " - "but we got %d\n", name, - cmnd_size, common->cmnd_size); - cmnd_size = common->cmnd_size; - } else { - common->phase_error = 1; - return -EINVAL; - } - } - - /* Check that the LUN values are consistent */ - if (common->lun != lun) - DBG(common, "using LUN %d from CBW, not LUN %d from CDB\n", - common->lun, lun); - - /* Check the LUN */ - if (common->lun >= 0 && common->lun < common->nluns) { - curlun = &common->luns[common->lun]; - if (common->cmnd[0] != SC_REQUEST_SENSE) { - curlun->sense_data = SS_NO_SENSE; - curlun->info_valid = 0; - } - } else { - curlun = NULL; - common->bad_lun_okay = 0; - - /* INQUIRY and REQUEST SENSE commands are explicitly allowed - * to use unsupported LUNs; all others may not. */ - if (common->cmnd[0] != SC_INQUIRY && - common->cmnd[0] != SC_REQUEST_SENSE) { - DBG(common, "unsupported LUN %d\n", common->lun); - return -EINVAL; - } - } -#if 0 - /* If a unit attention condition exists, only INQUIRY and - * REQUEST SENSE commands are allowed; anything else must fail. */ - if (curlun && curlun->unit_attention_data != SS_NO_SENSE && - common->cmnd[0] != SC_INQUIRY && - common->cmnd[0] != SC_REQUEST_SENSE) { - curlun->sense_data = curlun->unit_attention_data; - curlun->unit_attention_data = SS_NO_SENSE; - return -EINVAL; - } -#endif - /* Check that only command bytes listed in the mask are non-zero */ - common->cmnd[1] &= 0x1f; /* Mask away the LUN */ - for (i = 1; i < cmnd_size; ++i) { - if (common->cmnd[i] && !(mask & (1 << i))) { - if (curlun) - curlun->sense_data = SS_INVALID_FIELD_IN_CDB; - return -EINVAL; - } - } - - return 0; -} - - -static int do_scsi_command(struct fsg_common *common) -{ - struct fsg_buffhd *bh; - int rc; - int reply = -EINVAL; - int i; - static char unknown[16]; - struct fsg_lun *curlun = &common->luns[common->lun]; - - dump_cdb(common); - - /* Wait for the next buffer to become available for data or status */ - bh = common->next_buffhd_to_fill; - common->next_buffhd_to_drain = bh; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); - if (rc) - return rc; - } - common->phase_error = 0; - common->short_packet_received = 0; - - down_read(&common->filesem); /* We're using the backing file */ - switch (common->cmnd[0]) { - - case SC_INQUIRY: - common->data_size_from_cmnd = common->cmnd[4]; - reply = check_command(common, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "INQUIRY"); - if (reply == 0) - reply = do_inquiry(common, bh); - break; - - case SC_MODE_SELECT_6: - common->data_size_from_cmnd = common->cmnd[4]; - reply = check_command(common, 6, DATA_DIR_FROM_HOST, - (1<<1) | (1<<4), 0, - "MODE SELECT(6)"); - if (reply == 0) - reply = do_mode_select(common, bh); - break; - - case SC_MODE_SELECT_10: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_FROM_HOST, - (1<<1) | (3<<7), 0, - "MODE SELECT(10)"); - if (reply == 0) - reply = do_mode_select(common, bh); - break; - - case SC_MODE_SENSE_6: - common->data_size_from_cmnd = common->cmnd[4]; - reply = check_command(common, 6, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (1<<4), 0, - "MODE SENSE(6)"); - if (reply == 0) - reply = do_mode_sense(common, bh); - break; - - case SC_MODE_SENSE_10: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (1<<1) | (1<<2) | (3<<7), 0, - "MODE SENSE(10)"); - if (reply == 0) - reply = do_mode_sense(common, bh); - break; - - case SC_PREVENT_ALLOW_MEDIUM_REMOVAL: - common->data_size_from_cmnd = 0; - reply = check_command(common, 6, DATA_DIR_NONE, - (1<<4), 0, - "PREVENT-ALLOW MEDIUM REMOVAL"); - if (reply == 0) - reply = do_prevent_allow(common); - break; - - case SC_READ_6: - i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; - reply = check_command(common, 6, DATA_DIR_TO_HOST, - (7<<1) | (1<<4), 1, - "READ(6)"); - if (reply == 0) - reply = do_read(common); - break; - - case SC_READ_10: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << 9; - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "READ(10)"); - if (reply == 0) - reply = do_read(common); - break; - - case SC_READ_12: - common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << 9; - reply = check_command(common, 12, DATA_DIR_TO_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "READ(12)"); - if (reply == 0) - reply = do_read(common); - break; - - case SC_READ_CAPACITY: - common->data_size_from_cmnd = 8; - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (0xf<<2) | (1<<8), 1, - "READ CAPACITY"); - if (reply == 0) - reply = do_read_capacity(common, bh); - break; - - case SC_READ_HEADER: - if (!common->luns[common->lun].cdrom) - goto unknown_cmnd; - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (3<<7) | (0x1f<<1), 1, - "READ HEADER"); - if (reply == 0) - reply = do_read_header(common, bh); - break; - - case SC_READ_TOC: - if (!common->luns[common->lun].cdrom) - goto unknown_cmnd; - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (7<<6) | (1<<1), 1, - "READ TOC"); - if (reply == 0) - reply = do_read_toc(common, bh); - break; - - case SC_READ_FORMAT_CAPACITIES: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command(common, 10, DATA_DIR_TO_HOST, - (3<<7), 1, - "READ FORMAT CAPACITIES"); - if (reply == 0) - reply = do_read_format_capacities(common, bh); - break; - - case SC_REQUEST_SENSE: - common->data_size_from_cmnd = common->cmnd[4]; - reply = check_command(common, 6, DATA_DIR_TO_HOST, - (1<<4), 0, - "REQUEST SENSE"); - if (reply == 0) - reply = do_request_sense(common, bh); - break; - - case SC_START_STOP_UNIT: - common->data_size_from_cmnd = 0; - reply = check_command(common, 6, DATA_DIR_NONE, - (1<<1) | (1<<4), 0, - "START-STOP UNIT"); - if (reply == 0) - reply = do_start_stop(common); - break; - - case SC_SYNCHRONIZE_CACHE: - common->data_size_from_cmnd = 0; - reply = check_command(common, 10, DATA_DIR_NONE, - (0xf<<2) | (3<<7), 1, - "SYNCHRONIZE CACHE"); - if (reply == 0) - reply = do_synchronize_cache(common); - break; - - case SC_TEST_UNIT_READY: - common->data_size_from_cmnd = 0; - reply = check_command(common, 6, DATA_DIR_NONE, - 0, 1, - "TEST UNIT READY"); - break; - - /* Although optional, this command is used by MS-Windows. We - * support a minimal version: BytChk must be 0. */ - case SC_VERIFY: - common->data_size_from_cmnd = 0; - reply = check_command(common, 10, DATA_DIR_NONE, - (1<<1) | (0xf<<2) | (3<<7), 1, - "VERIFY"); - if (reply == 0) - reply = do_verify(common); - break; - - case SC_WRITE_6: - i = common->cmnd[4]; - common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9; - reply = check_command(common, 6, DATA_DIR_FROM_HOST, - (7<<1) | (1<<4), 1, - "WRITE(6)"); - if (reply == 0) - reply = do_write(common); - break; - - case SC_WRITE_10: - common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]) << 9; - reply = check_command(common, 10, DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (3<<7), 1, - "WRITE(10)"); - if (reply == 0) - reply = do_write(common); - break; - - case SC_WRITE_12: - common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]) << 9; - reply = check_command(common, 12, DATA_DIR_FROM_HOST, - (1<<1) | (0xf<<2) | (0xf<<6), 1, - "WRITE(12)"); - if (reply == 0) - reply = do_write(common); - break; - - /* Some mandatory commands that we recognize but don't implement. - * They don't mean much in this setting. It's left as an exercise - * for anyone interested to implement RESERVE and RELEASE in terms - * of Posix locks. */ - case SC_FORMAT_UNIT: - case SC_RELEASE: - case SC_RESERVE: - case SC_SEND_DIAGNOSTIC: - /* Fall through */ - - default: -unknown_cmnd: - common->data_size_from_cmnd = 0; - sprintf(unknown, "Unknown x%02x", common->cmnd[0]); - reply = check_command(common, common->cmnd_size, - DATA_DIR_UNKNOWN, 0xff, 0, unknown); - if (reply == 0) { - curlun->sense_data = SS_INVALID_COMMAND; - reply = -EINVAL; - } - break; - } - up_read(&common->filesem); - - if (reply == -EINTR) - return -EINTR; - - /* Set up the single reply buffer for finish_reply() */ - if (reply == -EINVAL) - reply = 0; /* Error reply length */ - if (reply >= 0 && common->data_dir == DATA_DIR_TO_HOST) { - reply = min((u32) reply, common->data_size_from_cmnd); - bh->inreq->length = reply; - bh->state = BUF_STATE_FULL; - common->residue -= reply; - } /* Otherwise it's already set */ - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) -{ - struct usb_request *req = bh->outreq; - struct fsg_bulk_cb_wrap *cbw = req->buf; - struct fsg_common *common = fsg->common; - - /* Was this a real packet? Should it be ignored? */ - if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) - return -EINVAL; - - /* Is the CBW valid? */ - if (req->actual != USB_BULK_CB_WRAP_LEN || - cbw->Signature != cpu_to_le32( - USB_BULK_CB_SIG)) { - DBG(fsg, "invalid CBW: len %u sig 0x%x\n", - req->actual, - le32_to_cpu(cbw->Signature)); - - /* The Bulk-only spec says we MUST stall the IN endpoint - * (6.6.1), so it's unavoidable. It also says we must - * retain this state until the next reset, but there's - * no way to tell the controller driver it should ignore - * Clear-Feature(HALT) requests. - * - * We aren't required to halt the OUT endpoint; instead - * we can simply accept and discard any data received - * until the next reset. */ - wedge_bulk_in_endpoint(fsg); - set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - return -EINVAL; - } - - /* Is the CBW meaningful? */ - if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG || - cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { - DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " - "cmdlen %u\n", - cbw->Lun, cbw->Flags, cbw->Length); - - /* We can do anything we want here, so let's stall the - * bulk pipes if we are allowed to. */ - if (common->can_stall) { - fsg_set_halt(fsg, fsg->bulk_out); - halt_bulk_in_endpoint(fsg); - } - return -EINVAL; - } - - /* Save the command for later */ - common->cmnd_size = cbw->Length; - memcpy(common->cmnd, cbw->CDB, common->cmnd_size); - if (cbw->Flags & USB_BULK_IN_FLAG) - common->data_dir = DATA_DIR_TO_HOST; - else - common->data_dir = DATA_DIR_FROM_HOST; - common->data_size = le32_to_cpu(cbw->DataTransferLength); - if (common->data_size == 0) - common->data_dir = DATA_DIR_NONE; - common->lun = cbw->Lun; - common->tag = cbw->Tag; - return 0; -} - - -static int get_next_command(struct fsg_common *common) -{ - struct fsg_buffhd *bh; - int rc = 0; - - /* Wait for the next buffer to become available */ - bh = common->next_buffhd_to_fill; - while (bh->state != BUF_STATE_EMPTY) { - rc = sleep_thread(common); - if (rc) - return rc; - } - - /* Queue a request to read a Bulk-only CBW */ - set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN); - bh->outreq->short_not_ok = 1; - START_TRANSFER_OR(common, bulk_out, bh->outreq, - &bh->outreq_busy, &bh->state) - /* Don't know what to do if common->fsg is NULL */ - return -EIO; - - /* We will drain the buffer in software, which means we - * can reuse it for the next filling. No need to advance - * next_buffhd_to_fill. */ - - /* Wait for the CBW to arrive */ - while (bh->state != BUF_STATE_FULL) { - rc = sleep_thread(common); - if (rc) - return rc; - } - - rc = fsg_is_set(common) ? received_cbw(common->fsg, bh) : -EIO; - bh->state = BUF_STATE_EMPTY; - - return rc; -} - - -/*-------------------------------------------------------------------------*/ - -static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep, - const struct usb_endpoint_descriptor *d) -{ - int rc; - - ep->driver_data = common; - rc = usb_ep_enable(ep, d); - if (rc) - ERROR(common, "can't enable %s, result %d\n", ep->name, rc); - return rc; -} - -static int alloc_request(struct fsg_common *common, struct usb_ep *ep, - struct usb_request **preq) -{ - *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (*preq) - return 0; - ERROR(common, "can't allocate request for %s\n", ep->name); - return -ENOMEM; -} - -/* Reset interface setting and re-init endpoint state (toggle etc). */ -static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg) -{ - const struct usb_endpoint_descriptor *d; - struct fsg_dev *fsg; - int i, rc = 0; - - if (common->running) - DBG(common, "reset interface\n"); - -reset: - /* Deallocate the requests */ - if (common->fsg) { - fsg = common->fsg; - - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { - struct fsg_buffhd *bh = &common->buffhds[i]; - - if (bh->inreq) { - usb_ep_free_request(fsg->bulk_in, bh->inreq); - bh->inreq = NULL; - } - if (bh->outreq) { - usb_ep_free_request(fsg->bulk_out, bh->outreq); - bh->outreq = NULL; - } - } - - /* Disable the endpoints */ - if (fsg->bulk_in_enabled) { - usb_ep_disable(fsg->bulk_in); - fsg->bulk_in_enabled = 0; - } - if (fsg->bulk_out_enabled) { - usb_ep_disable(fsg->bulk_out); - fsg->bulk_out_enabled = 0; - } - - common->fsg = NULL; - /* wake_up(&common->fsg_wait); */ - } - - common->running = 0; - if (!new_fsg || rc) - return rc; - - common->fsg = new_fsg; - fsg = common->fsg; - - /* Enable the endpoints */ - d = fsg_ep_desc(common->gadget, - &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc); - rc = enable_endpoint(common, fsg->bulk_in, d); - if (rc) - goto reset; - fsg->bulk_in_enabled = 1; - - d = fsg_ep_desc(common->gadget, - &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc); - rc = enable_endpoint(common, fsg->bulk_out, d); - if (rc) - goto reset; - fsg->bulk_out_enabled = 1; - common->bulk_out_maxpacket = - le16_to_cpu(get_unaligned(&d->wMaxPacketSize)); - clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); - - /* Allocate the requests */ - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { - struct fsg_buffhd *bh = &common->buffhds[i]; - - rc = alloc_request(common, fsg->bulk_in, &bh->inreq); - if (rc) - goto reset; - rc = alloc_request(common, fsg->bulk_out, &bh->outreq); - if (rc) - goto reset; - bh->inreq->buf = bh->outreq->buf = bh->buf; - bh->inreq->context = bh->outreq->context = bh; - bh->inreq->complete = bulk_in_complete; - bh->outreq->complete = bulk_out_complete; - } - - common->running = 1; - - return rc; -} - - -/****************************** ALT CONFIGS ******************************/ - - -static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) -{ - struct fsg_dev *fsg = fsg_from_func(f); - fsg->common->new_fsg = fsg; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); - return 0; -} - -static void fsg_disable(struct usb_function *f) -{ - struct fsg_dev *fsg = fsg_from_func(f); - fsg->common->new_fsg = NULL; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); -} - -/*-------------------------------------------------------------------------*/ - -static void handle_exception(struct fsg_common *common) -{ - int i; - struct fsg_buffhd *bh; - enum fsg_state old_state; - struct fsg_lun *curlun; - unsigned int exception_req_tag; - - /* Cancel all the pending transfers */ - if (common->fsg) { - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { - bh = &common->buffhds[i]; - if (bh->inreq_busy) - usb_ep_dequeue(common->fsg->bulk_in, bh->inreq); - if (bh->outreq_busy) - usb_ep_dequeue(common->fsg->bulk_out, - bh->outreq); - } - - /* Wait until everything is idle */ - for (;;) { - int num_active = 0; - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { - bh = &common->buffhds[i]; - num_active += bh->inreq_busy + bh->outreq_busy; - } - if (num_active == 0) - break; - if (sleep_thread(common)) - return; - } - - /* Clear out the controller's fifos */ - if (common->fsg->bulk_in_enabled) - usb_ep_fifo_flush(common->fsg->bulk_in); - if (common->fsg->bulk_out_enabled) - usb_ep_fifo_flush(common->fsg->bulk_out); - } - - /* Reset the I/O buffer states and pointers, the SCSI - * state, and the exception. Then invoke the handler. */ - - for (i = 0; i < FSG_NUM_BUFFERS; ++i) { - bh = &common->buffhds[i]; - bh->state = BUF_STATE_EMPTY; - } - common->next_buffhd_to_fill = &common->buffhds[0]; - common->next_buffhd_to_drain = &common->buffhds[0]; - exception_req_tag = common->exception_req_tag; - old_state = common->state; - - if (old_state == FSG_STATE_ABORT_BULK_OUT) - common->state = FSG_STATE_STATUS_PHASE; - else { - for (i = 0; i < common->nluns; ++i) { - curlun = &common->luns[i]; - curlun->sense_data = SS_NO_SENSE; - curlun->info_valid = 0; - } - common->state = FSG_STATE_IDLE; - } - - /* Carry out any extra actions required for the exception */ - switch (old_state) { - case FSG_STATE_ABORT_BULK_OUT: - send_status(common); - - if (common->state == FSG_STATE_STATUS_PHASE) - common->state = FSG_STATE_IDLE; - break; - - case FSG_STATE_RESET: - /* In case we were forced against our will to halt a - * bulk endpoint, clear the halt now. (The SuperH UDC - * requires this.) */ - if (!fsg_is_set(common)) - break; - if (test_and_clear_bit(IGNORE_BULK_OUT, - &common->fsg->atomic_bitflags)) - usb_ep_clear_halt(common->fsg->bulk_in); - - if (common->ep0_req_tag == exception_req_tag) - ep0_queue(common); /* Complete the status stage */ - - break; - - case FSG_STATE_CONFIG_CHANGE: - do_set_interface(common, common->new_fsg); - break; - - case FSG_STATE_EXIT: - case FSG_STATE_TERMINATED: - do_set_interface(common, NULL); /* Free resources */ - common->state = FSG_STATE_TERMINATED; /* Stop the thread */ - break; - - case FSG_STATE_INTERFACE_CHANGE: - case FSG_STATE_DISCONNECT: - case FSG_STATE_COMMAND_PHASE: - case FSG_STATE_DATA_PHASE: - case FSG_STATE_STATUS_PHASE: - case FSG_STATE_IDLE: - break; - } -} - -/*-------------------------------------------------------------------------*/ - -int fsg_main_thread(void *common_) -{ - int ret; - struct fsg_common *common = the_fsg_common; - /* The main loop */ - do { - if (exception_in_progress(common)) { - handle_exception(common); - continue; - } - - if (!common->running) { - ret = sleep_thread(common); - if (ret) - return ret; - - continue; - } - - ret = get_next_command(common); - if (ret) - return ret; - - if (!exception_in_progress(common)) - common->state = FSG_STATE_DATA_PHASE; - - if (do_scsi_command(common) || finish_reply(common)) - continue; - - if (!exception_in_progress(common)) - common->state = FSG_STATE_STATUS_PHASE; - - if (send_status(common)) - continue; - - if (!exception_in_progress(common)) - common->state = FSG_STATE_IDLE; - } while (0); - - common->thread_task = NULL; - - return 0; -} - -static void fsg_common_release(struct kref *ref); - -static struct fsg_common *fsg_common_init(struct fsg_common *common, - struct usb_composite_dev *cdev) -{ - struct usb_gadget *gadget = cdev->gadget; - struct fsg_buffhd *bh; - struct fsg_lun *curlun; - int nluns, i, rc; - - /* Find out how many LUNs there should be */ - nluns = 1; - if (nluns < 1 || nluns > FSG_MAX_LUNS) { - printf("invalid number of LUNs: %u\n", nluns); - return ERR_PTR(-EINVAL); - } - - /* Allocate? */ - if (!common) { - common = calloc(sizeof *common, 1); - if (!common) - return ERR_PTR(-ENOMEM); - common->free_storage_on_release = 1; - } else { - memset(common, 0, sizeof common); - common->free_storage_on_release = 0; - } - - common->ops = NULL; - common->private_data = NULL; - - common->gadget = gadget; - common->ep0 = gadget->ep0; - common->ep0req = cdev->req; - - /* Maybe allocate device-global string IDs, and patch descriptors */ - if (fsg_strings[FSG_STRING_INTERFACE].id == 0) { - rc = usb_string_id(cdev); - if (unlikely(rc < 0)) - goto error_release; - fsg_strings[FSG_STRING_INTERFACE].id = rc; - fsg_intf_desc.iInterface = rc; - } - - /* Create the LUNs, open their backing files, and register the - * LUN devices in sysfs. */ - curlun = calloc(nluns, sizeof *curlun); - if (!curlun) { - rc = -ENOMEM; - goto error_release; - } - common->nluns = nluns; - - for (i = 0; i < nluns; i++) { - common->luns[i].removable = 1; - - rc = fsg_lun_open(&common->luns[i], ""); - if (rc) - goto error_luns; - } - common->lun = 0; - - /* Data buffers cyclic list */ - bh = common->buffhds; - - i = FSG_NUM_BUFFERS; - goto buffhds_first_it; - do { - bh->next = bh + 1; - ++bh; -buffhds_first_it: - bh->inreq_busy = 0; - bh->outreq_busy = 0; - bh->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, FSG_BUFLEN); - if (unlikely(!bh->buf)) { - rc = -ENOMEM; - goto error_release; - } - } while (--i); - bh->next = common->buffhds; - - snprintf(common->inquiry_string, sizeof common->inquiry_string, - "%-8s%-16s%04x", - "Linux ", - "File-Store Gadget", - 0xffff); - - /* Some peripheral controllers are known not to be able to - * halt bulk endpoints correctly. If one of them is present, - * disable stalls. - */ - - /* Tell the thread to start working */ - common->thread_task = - kthread_create(fsg_main_thread, common, - OR(cfg->thread_name, "file-storage")); - if (IS_ERR(common->thread_task)) { - rc = PTR_ERR(common->thread_task); - goto error_release; - } - -#undef OR - /* Information */ - INFO(common, FSG_DRIVER_DESC ", version: " FSG_DRIVER_VERSION "\n"); - INFO(common, "Number of LUNs=%d\n", common->nluns); - - return common; - -error_luns: - common->nluns = i + 1; -error_release: - common->state = FSG_STATE_TERMINATED; /* The thread is dead */ - /* Call fsg_common_release() directly, ref might be not - * initialised */ - fsg_common_release(&common->ref); - return ERR_PTR(rc); -} - -static void fsg_common_release(struct kref *ref) -{ - struct fsg_common *common = container_of(ref, struct fsg_common, ref); - - /* If the thread isn't already dead, tell it to exit now */ - if (common->state != FSG_STATE_TERMINATED) { - raise_exception(common, FSG_STATE_EXIT); - wait_for_completion(&common->thread_notifier); - } - - if (likely(common->luns)) { - struct fsg_lun *lun = common->luns; - unsigned i = common->nluns; - - /* In error recovery common->nluns may be zero. */ - for (; i; --i, ++lun) - fsg_lun_close(lun); - - kfree(common->luns); - } - - { - struct fsg_buffhd *bh = common->buffhds; - unsigned i = FSG_NUM_BUFFERS; - do { - kfree(bh->buf); - } while (++bh, --i); - } - - if (common->free_storage_on_release) - kfree(common); -} - - -/*-------------------------------------------------------------------------*/ - -/** - * usb_copy_descriptors - copy a vector of USB descriptors - * @src: null-terminated vector to copy - * Context: initialization code, which may sleep - * - * This makes a copy of a vector of USB descriptors. Its primary use - * is to support usb_function objects which can have multiple copies, - * each needing different descriptors. Functions may have static - * tables of descriptors, which are used as templates and customized - * with identifiers (for interfaces, strings, endpoints, and more) - * as needed by a given function instance. - */ -struct usb_descriptor_header ** -usb_copy_descriptors(struct usb_descriptor_header **src) -{ - struct usb_descriptor_header **tmp; - unsigned bytes; - unsigned n_desc; - void *mem; - struct usb_descriptor_header **ret; - - /* count descriptors and their sizes; then add vector size */ - for (bytes = 0, n_desc = 0, tmp = src; *tmp; tmp++, n_desc++) - bytes += (*tmp)->bLength; - bytes += (n_desc + 1) * sizeof(*tmp); - - mem = memalign(CONFIG_SYS_CACHELINE_SIZE, bytes); - if (!mem) - return NULL; - - /* fill in pointers starting at "tmp", - * to descriptors copied starting at "mem"; - * and return "ret" - */ - tmp = mem; - ret = mem; - mem += (n_desc + 1) * sizeof(*tmp); - while (*src) { - memcpy(mem, *src, (*src)->bLength); - *tmp = mem; - tmp++; - mem += (*src)->bLength; - src++; - } - *tmp = NULL; - - return ret; -} - -static void fsg_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct fsg_dev *fsg = fsg_from_func(f); - - DBG(fsg, "unbind\n"); - if (fsg->common->fsg == fsg) { - fsg->common->new_fsg = NULL; - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); - } - - free(fsg->function.descriptors); - free(fsg->function.hs_descriptors); - kfree(fsg); -} - -static int fsg_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct fsg_dev *fsg = fsg_from_func(f); - struct usb_gadget *gadget = c->cdev->gadget; - int i; - struct usb_ep *ep; - fsg->gadget = gadget; - - /* New interface */ - i = usb_interface_id(c, f); - if (i < 0) - return i; - fsg_intf_desc.bInterfaceNumber = i; - fsg->interface_number = i; - - /* Find all the endpoints we will use */ - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg->common; /* claim the endpoint */ - fsg->bulk_in = ep; - - ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); - if (!ep) - goto autoconf_fail; - ep->driver_data = fsg->common; /* claim the endpoint */ - fsg->bulk_out = ep; - - /* Copy descriptors */ - f->descriptors = usb_copy_descriptors(fsg_fs_function); - if (unlikely(!f->descriptors)) - return -ENOMEM; - - if (gadget_is_dualspeed(gadget)) { - /* Assume endpoint addresses are the same for both speeds */ - fsg_hs_bulk_in_desc.bEndpointAddress = - fsg_fs_bulk_in_desc.bEndpointAddress; - fsg_hs_bulk_out_desc.bEndpointAddress = - fsg_fs_bulk_out_desc.bEndpointAddress; - f->hs_descriptors = usb_copy_descriptors(fsg_hs_function); - if (unlikely(!f->hs_descriptors)) { - free(f->descriptors); - return -ENOMEM; - } - } - return 0; - -autoconf_fail: - ERROR(fsg, "unable to autoconfigure all endpoints\n"); - return -ENOTSUPP; -} - - -/****************************** ADD FUNCTION ******************************/ - -static struct usb_gadget_strings *fsg_strings_array[] = { - &fsg_stringtab, - NULL, -}; - -static int fsg_bind_config(struct usb_composite_dev *cdev, - struct usb_configuration *c, - struct fsg_common *common) -{ - struct fsg_dev *fsg; - int rc; - - fsg = calloc(1, sizeof *fsg); - if (!fsg) - return -ENOMEM; - fsg->function.name = FSG_DRIVER_DESC; - fsg->function.strings = fsg_strings_array; - fsg->function.bind = fsg_bind; - fsg->function.unbind = fsg_unbind; - fsg->function.setup = fsg_setup; - fsg->function.set_alt = fsg_set_alt; - fsg->function.disable = fsg_disable; - - fsg->common = common; - common->fsg = fsg; - /* Our caller holds a reference to common structure so we - * don't have to be worry about it being freed until we return - * from this function. So instead of incrementing counter now - * and decrement in error recovery we increment it only when - * call to usb_add_function() was successful. */ - - rc = usb_add_function(c, &fsg->function); - - if (rc) - kfree(fsg); - - return rc; -} - -int fsg_add(struct usb_configuration *c) -{ - struct fsg_common *fsg_common; - - fsg_common = fsg_common_init(NULL, c->cdev); - - fsg_common->vendor_name = 0; - fsg_common->product_name = 0; - fsg_common->release = 0xffff; - - fsg_common->ops = NULL; - fsg_common->private_data = NULL; - - the_fsg_common = fsg_common; - - return fsg_bind_config(c->cdev, c, fsg_common); -} - -int fsg_init(struct ums *ums_dev) -{ - ums = ums_dev; - - return 0; -} - -DECLARE_GADGET_BIND_CALLBACK(usb_dnl_ums, fsg_add); diff --git a/qemu/roms/u-boot/drivers/usb/gadget/f_thor.c b/qemu/roms/u-boot/drivers/usb/gadget/f_thor.c deleted file mode 100644 index feef9e461..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/f_thor.c +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * f_thor.c -- USB TIZEN THOR Downloader gadget function - * - * Copyright (C) 2013 Samsung Electronics - * Lukasz Majewski <l.majewski@samsung.com> - * - * Based on code from: - * git://review.tizen.org/kernel/u-boot - * - * Developed by: - * Copyright (C) 2009 Samsung Electronics - * Minkyu Kang <mk7.kang@samsung.com> - * Sanghee Kim <sh0130.kim@samsung.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <errno.h> -#include <common.h> -#include <malloc.h> -#include <version.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb/composite.h> -#include <linux/usb/cdc.h> -#include <g_dnl.h> -#include <dfu.h> - -#include "f_thor.h" - -static void thor_tx_data(unsigned char *data, int len); -static void thor_set_dma(void *addr, int len); -static int thor_rx_data(void); - -static struct f_thor *thor_func; -static inline struct f_thor *func_to_thor(struct usb_function *f) -{ - return container_of(f, struct f_thor, usb_function); -} - -DEFINE_CACHE_ALIGN_BUFFER(unsigned char, thor_tx_data_buf, - sizeof(struct rsp_box)); -DEFINE_CACHE_ALIGN_BUFFER(unsigned char, thor_rx_data_buf, - sizeof(struct rqt_box)); - -/* ********************************************************** */ -/* THOR protocol - transmission handling */ -/* ********************************************************** */ -DEFINE_CACHE_ALIGN_BUFFER(char, f_name, F_NAME_BUF_SIZE); -static unsigned long long int thor_file_size; -static int alt_setting_num; - -static void send_rsp(const struct rsp_box *rsp) -{ - memcpy(thor_tx_data_buf, rsp, sizeof(struct rsp_box)); - thor_tx_data(thor_tx_data_buf, sizeof(struct rsp_box)); - - debug("-RSP: %d, %d\n", rsp->rsp, rsp->rsp_data); -} - -static void send_data_rsp(s32 ack, s32 count) -{ - ALLOC_CACHE_ALIGN_BUFFER(struct data_rsp_box, rsp, - sizeof(struct data_rsp_box)); - - rsp->ack = ack; - rsp->count = count; - - memcpy(thor_tx_data_buf, rsp, sizeof(struct data_rsp_box)); - thor_tx_data(thor_tx_data_buf, sizeof(struct data_rsp_box)); - - debug("-DATA RSP: %d, %d\n", ack, count); -} - -static int process_rqt_info(const struct rqt_box *rqt) -{ - ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box)); - memset(rsp, 0, sizeof(struct rsp_box)); - - rsp->rsp = rqt->rqt; - rsp->rsp_data = rqt->rqt_data; - - switch (rqt->rqt_data) { - case RQT_INFO_VER_PROTOCOL: - rsp->int_data[0] = VER_PROTOCOL_MAJOR; - rsp->int_data[1] = VER_PROTOCOL_MINOR; - break; - case RQT_INIT_VER_HW: - snprintf(rsp->str_data[0], sizeof(rsp->str_data[0]), - "%x", checkboard()); - break; - case RQT_INIT_VER_BOOT: - sprintf(rsp->str_data[0], "%s", U_BOOT_VERSION); - break; - case RQT_INIT_VER_KERNEL: - sprintf(rsp->str_data[0], "%s", "k unknown"); - break; - case RQT_INIT_VER_PLATFORM: - sprintf(rsp->str_data[0], "%s", "p unknown"); - break; - case RQT_INIT_VER_CSC: - sprintf(rsp->str_data[0], "%s", "c unknown"); - break; - default: - return -EINVAL; - } - - send_rsp(rsp); - return true; -} - -static int process_rqt_cmd(const struct rqt_box *rqt) -{ - ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box)); - memset(rsp, 0, sizeof(struct rsp_box)); - - rsp->rsp = rqt->rqt; - rsp->rsp_data = rqt->rqt_data; - - switch (rqt->rqt_data) { - case RQT_CMD_REBOOT: - debug("TARGET RESET\n"); - send_rsp(rsp); - g_dnl_unregister(); - dfu_free_entities(); - run_command("reset", 0); - break; - case RQT_CMD_POWEROFF: - case RQT_CMD_EFSCLEAR: - send_rsp(rsp); - default: - printf("Command not supported -> cmd: %d\n", rqt->rqt_data); - return -EINVAL; - } - - return true; -} - -static long long int download_head(unsigned long long total, - unsigned int packet_size, - long long int *left, - int *cnt) -{ - long long int rcv_cnt = 0, left_to_rcv, ret_rcv; - void *transfer_buffer = dfu_get_buf(); - void *buf = transfer_buffer; - int usb_pkt_cnt = 0, ret; - - /* - * Files smaller than THOR_STORE_UNIT_SIZE (now 32 MiB) are stored on - * the medium. - * The packet response is sent on the purpose after successful data - * chunk write. There is a room for improvement when asynchronous write - * is performed. - */ - while (total - rcv_cnt >= packet_size) { - thor_set_dma(buf, packet_size); - buf += packet_size; - ret_rcv = thor_rx_data(); - if (ret_rcv < 0) - return ret_rcv; - rcv_cnt += ret_rcv; - debug("%d: RCV data count: %llu cnt: %d\n", usb_pkt_cnt, - rcv_cnt, *cnt); - - if ((rcv_cnt % THOR_STORE_UNIT_SIZE) == 0) { - ret = dfu_write(dfu_get_entity(alt_setting_num), - transfer_buffer, THOR_STORE_UNIT_SIZE, - (*cnt)++); - if (ret) { - error("DFU write failed [%d] cnt: %d", - ret, *cnt); - return ret; - } - buf = transfer_buffer; - } - send_data_rsp(0, ++usb_pkt_cnt); - } - - /* Calculate the amount of data to arrive from PC (in bytes) */ - left_to_rcv = total - rcv_cnt; - - /* - * Calculate number of data already received. but not yet stored - * on the medium (they are smaller than THOR_STORE_UNIT_SIZE) - */ - *left = left_to_rcv + buf - transfer_buffer; - debug("%s: left: %llu left_to_rcv: %llu buf: 0x%p\n", __func__, - *left, left_to_rcv, buf); - - if (left_to_rcv) { - thor_set_dma(buf, packet_size); - ret_rcv = thor_rx_data(); - if (ret_rcv < 0) - return ret_rcv; - rcv_cnt += ret_rcv; - send_data_rsp(0, ++usb_pkt_cnt); - } - - debug("%s: %llu total: %llu cnt: %d\n", __func__, rcv_cnt, total, *cnt); - - return rcv_cnt; -} - -static int download_tail(long long int left, int cnt) -{ - struct dfu_entity *dfu_entity = dfu_get_entity(alt_setting_num); - void *transfer_buffer = dfu_get_buf(); - int ret; - - debug("%s: left: %llu cnt: %d\n", __func__, left, cnt); - - if (left) { - ret = dfu_write(dfu_entity, transfer_buffer, left, cnt++); - if (ret) { - error("DFU write failed [%d]: left: %llu", ret, left); - return ret; - } - } - - /* - * To store last "packet" DFU storage backend requires dfu_write with - * size parameter equal to 0 - * - * This also frees memory malloc'ed by dfu_get_buf(), so no explicit - * need fo call dfu_free_buf() is needed. - */ - ret = dfu_write(dfu_entity, transfer_buffer, 0, cnt); - if (ret) - error("DFU write failed [%d] cnt: %d", ret, cnt); - - ret = dfu_flush(dfu_entity, transfer_buffer, 0, cnt); - if (ret) { - error("DFU flush failed!"); - return ret; - } - - return ret; -} - -static long long int process_rqt_download(const struct rqt_box *rqt) -{ - ALLOC_CACHE_ALIGN_BUFFER(struct rsp_box, rsp, sizeof(struct rsp_box)); - static long long int left, ret_head; - int file_type, ret = 0; - static int cnt; - - memset(rsp, 0, sizeof(struct rsp_box)); - rsp->rsp = rqt->rqt; - rsp->rsp_data = rqt->rqt_data; - - switch (rqt->rqt_data) { - case RQT_DL_INIT: - thor_file_size = rqt->int_data[0]; - debug("INIT: total %d bytes\n", rqt->int_data[0]); - break; - case RQT_DL_FILE_INFO: - file_type = rqt->int_data[0]; - if (file_type == FILE_TYPE_PIT) { - puts("PIT table file - not supported\n"); - rsp->ack = -ENOTSUPP; - ret = rsp->ack; - break; - } - - thor_file_size = rqt->int_data[1]; - memcpy(f_name, rqt->str_data[0], F_NAME_BUF_SIZE); - - debug("INFO: name(%s, %d), size(%llu), type(%d)\n", - f_name, 0, thor_file_size, file_type); - - rsp->int_data[0] = THOR_PACKET_SIZE; - - alt_setting_num = dfu_get_alt(f_name); - if (alt_setting_num < 0) { - error("Alt setting [%d] to write not found!", - alt_setting_num); - rsp->ack = -ENODEV; - ret = rsp->ack; - } - break; - case RQT_DL_FILE_START: - send_rsp(rsp); - ret_head = download_head(thor_file_size, THOR_PACKET_SIZE, - &left, &cnt); - if (ret_head < 0) { - left = 0; - cnt = 0; - } - return ret_head; - case RQT_DL_FILE_END: - debug("DL FILE_END\n"); - rsp->ack = download_tail(left, cnt); - ret = rsp->ack; - left = 0; - cnt = 0; - break; - case RQT_DL_EXIT: - debug("DL EXIT\n"); - break; - default: - error("Operation not supported: %d", rqt->rqt_data); - ret = -ENOTSUPP; - } - - send_rsp(rsp); - return ret; -} - -static int process_data(void) -{ - ALLOC_CACHE_ALIGN_BUFFER(struct rqt_box, rqt, sizeof(struct rqt_box)); - int ret = -EINVAL; - - memset(rqt, 0, sizeof(rqt)); - memcpy(rqt, thor_rx_data_buf, sizeof(struct rqt_box)); - - debug("+RQT: %d, %d\n", rqt->rqt, rqt->rqt_data); - - switch (rqt->rqt) { - case RQT_INFO: - ret = process_rqt_info(rqt); - break; - case RQT_CMD: - ret = process_rqt_cmd(rqt); - break; - case RQT_DL: - ret = (int) process_rqt_download(rqt); - break; - case RQT_UL: - puts("RQT: UPLOAD not supported!\n"); - break; - default: - error("unknown request (%d)", rqt->rqt); - } - - return ret; -} - -/* ********************************************************** */ -/* THOR USB Function */ -/* ********************************************************** */ - -static inline struct usb_endpoint_descriptor * -ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, - struct usb_endpoint_descriptor *fs) -{ - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; -} - -static struct usb_interface_descriptor thor_downloader_intf_data = { - .bLength = sizeof(thor_downloader_intf_data), - .bDescriptorType = USB_DT_INTERFACE, - - .bNumEndpoints = 2, - .bInterfaceClass = USB_CLASS_CDC_DATA, -}; - -static struct usb_endpoint_descriptor fs_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -static struct usb_endpoint_descriptor fs_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, -}; - -/* CDC configuration */ -static struct usb_interface_descriptor thor_downloader_intf_int = { - .bLength = sizeof(thor_downloader_intf_int), - .bDescriptorType = USB_DT_INTERFACE, - - .bNumEndpoints = 1, - .bInterfaceClass = USB_CLASS_COMM, - /* 0x02 Abstract Line Control Model */ - .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, - /* 0x01 Common AT commands */ - .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, -}; - -static struct usb_cdc_header_desc thor_downloader_cdc_header = { - .bLength = sizeof(thor_downloader_cdc_header), - .bDescriptorType = 0x24, /* CS_INTERFACE */ - .bDescriptorSubType = 0x00, - .bcdCDC = 0x0110, -}; - -static struct usb_cdc_call_mgmt_descriptor thor_downloader_cdc_call = { - .bLength = sizeof(thor_downloader_cdc_call), - .bDescriptorType = 0x24, /* CS_INTERFACE */ - .bDescriptorSubType = 0x01, - .bmCapabilities = 0x00, - .bDataInterface = 0x01, -}; - -static struct usb_cdc_acm_descriptor thor_downloader_cdc_abstract = { - .bLength = sizeof(thor_downloader_cdc_abstract), - .bDescriptorType = 0x24, /* CS_INTERFACE */ - .bDescriptorSubType = 0x02, - .bmCapabilities = 0x00, -}; - -static struct usb_cdc_union_desc thor_downloader_cdc_union = { - .bLength = sizeof(thor_downloader_cdc_union), - .bDescriptorType = 0x24, /* CS_INTERFACE */ - .bDescriptorSubType = USB_CDC_UNION_TYPE, -}; - -static struct usb_endpoint_descriptor fs_int_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = 3 | USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(16), - - .bInterval = 0x9, -}; - -static struct usb_interface_assoc_descriptor -thor_iad_descriptor = { - .bLength = sizeof(thor_iad_descriptor), - .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, - - .bFirstInterface = 0, - .bInterfaceCount = 2, /* control + data */ - .bFunctionClass = USB_CLASS_COMM, - .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, - .bFunctionProtocol = USB_CDC_PROTO_NONE, -}; - -static struct usb_endpoint_descriptor hs_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor hs_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = __constant_cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor hs_int_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = __constant_cpu_to_le16(16), - - .bInterval = 0x9, -}; - -static struct usb_qualifier_descriptor dev_qualifier = { - .bLength = sizeof(dev_qualifier), - .bDescriptorType = USB_DT_DEVICE_QUALIFIER, - - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_VENDOR_SPEC, - - .bNumConfigurations = 2, -}; - -/* - * This attribute vendor descriptor is necessary for correct operation with - * Windows version of THOR download program - * - * It prevents windows driver from sending zero lenght packet (ZLP) after - * each THOR_PACKET_SIZE. This assures consistent behaviour with libusb - */ -static struct usb_cdc_attribute_vendor_descriptor thor_downloader_cdc_av = { - .bLength = sizeof(thor_downloader_cdc_av), - .bDescriptorType = 0x24, - .bDescriptorSubType = 0x80, - .DAUType = 0x0002, - .DAULength = 0x0001, - .DAUValue = 0x00, -}; - -static const struct usb_descriptor_header *hs_thor_downloader_function[] = { - (struct usb_descriptor_header *)&thor_iad_descriptor, - - (struct usb_descriptor_header *)&thor_downloader_intf_int, - (struct usb_descriptor_header *)&thor_downloader_cdc_header, - (struct usb_descriptor_header *)&thor_downloader_cdc_call, - (struct usb_descriptor_header *)&thor_downloader_cdc_abstract, - (struct usb_descriptor_header *)&thor_downloader_cdc_union, - (struct usb_descriptor_header *)&hs_int_desc, - - (struct usb_descriptor_header *)&thor_downloader_intf_data, - (struct usb_descriptor_header *)&thor_downloader_cdc_av, - (struct usb_descriptor_header *)&hs_in_desc, - (struct usb_descriptor_header *)&hs_out_desc, - NULL, -}; - -/*-------------------------------------------------------------------------*/ -static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length) -{ - struct usb_request *req; - - req = usb_ep_alloc_request(ep, 0); - if (!req) - return req; - - req->length = length; - req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, length); - if (!req->buf) { - usb_ep_free_request(ep, req); - req = NULL; - } - - return req; -} - -static int thor_rx_data(void) -{ - struct thor_dev *dev = thor_func->dev; - int data_to_rx, tmp, status; - - data_to_rx = dev->out_req->length; - tmp = data_to_rx; - do { - dev->out_req->length = data_to_rx; - debug("dev->out_req->length:%d dev->rxdata:%d\n", - dev->out_req->length, dev->rxdata); - - status = usb_ep_queue(dev->out_ep, dev->out_req, 0); - if (status) { - error("kill %s: resubmit %d bytes --> %d", - dev->out_ep->name, dev->out_req->length, status); - usb_ep_set_halt(dev->out_ep); - return -EAGAIN; - } - - while (!dev->rxdata) { - usb_gadget_handle_interrupts(); - if (ctrlc()) - return -1; - } - dev->rxdata = 0; - data_to_rx -= dev->out_req->actual; - } while (data_to_rx); - - return tmp; -} - -static void thor_tx_data(unsigned char *data, int len) -{ - struct thor_dev *dev = thor_func->dev; - unsigned char *ptr = dev->in_req->buf; - int status; - - memset(ptr, 0, len); - memcpy(ptr, data, len); - - dev->in_req->length = len; - - debug("%s: dev->in_req->length:%d to_cpy:%d\n", __func__, - dev->in_req->length, sizeof(data)); - - status = usb_ep_queue(dev->in_ep, dev->in_req, 0); - if (status) { - error("kill %s: resubmit %d bytes --> %d", - dev->in_ep->name, dev->in_req->length, status); - usb_ep_set_halt(dev->in_ep); - } - - /* Wait until tx interrupt received */ - while (!dev->txdata) - usb_gadget_handle_interrupts(); - - dev->txdata = 0; -} - -static void thor_rx_tx_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct thor_dev *dev = thor_func->dev; - int status = req->status; - - debug("%s: ep_ptr:%p, req_ptr:%p\n", __func__, ep, req); - switch (status) { - case 0: - if (ep == dev->out_ep) - dev->rxdata = 1; - else - dev->txdata = 1; - - break; - - /* this endpoint is normally active while we're configured */ - case -ECONNABORTED: /* hardware forced ep reset */ - case -ECONNRESET: /* request dequeued */ - case -ESHUTDOWN: /* disconnect from host */ - case -EREMOTEIO: /* short read */ - case -EOVERFLOW: - error("ERROR:%d", status); - break; - } - - debug("%s complete --> %d, %d/%d\n", ep->name, - status, req->actual, req->length); -} - -static struct usb_request *thor_start_ep(struct usb_ep *ep) -{ - struct usb_request *req; - - req = alloc_ep_req(ep, THOR_PACKET_SIZE); - debug("%s: ep:%p req:%p\n", __func__, ep, req); - - if (!req) - return NULL; - - memset(req->buf, 0, req->length); - req->complete = thor_rx_tx_complete; - - return req; -} - -static void thor_setup_complete(struct usb_ep *ep, struct usb_request *req) -{ - if (req->status || req->actual != req->length) - debug("setup complete --> %d, %d/%d\n", - req->status, req->actual, req->length); -} - -static int -thor_func_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) -{ - struct thor_dev *dev = thor_func->dev; - struct usb_request *req = dev->req; - struct usb_gadget *gadget = dev->gadget; - int value = 0; - - u16 len = le16_to_cpu(ctrl->wLength); - - debug("Req_Type: 0x%x Req: 0x%x wValue: 0x%x wIndex: 0x%x wLen: 0x%x\n", - ctrl->bRequestType, ctrl->bRequest, ctrl->wValue, ctrl->wIndex, - ctrl->wLength); - - switch (ctrl->bRequest) { - case USB_CDC_REQ_SET_CONTROL_LINE_STATE: - value = 0; - break; - case USB_CDC_REQ_SET_LINE_CODING: - value = len; - /* Line Coding set done = configuration done */ - thor_func->dev->configuration_done = 1; - break; - - default: - error("thor_setup: unknown request: %d", ctrl->bRequest); - } - - if (value >= 0) { - req->length = value; - req->zero = value < len; - value = usb_ep_queue(gadget->ep0, req, 0); - if (value < 0) { - debug("%s: ep_queue: %d\n", __func__, value); - req->status = 0; - } - } - - return value; -} - -/* Specific to the THOR protocol */ -static void thor_set_dma(void *addr, int len) -{ - struct thor_dev *dev = thor_func->dev; - - debug("in_req:%p, out_req:%p\n", dev->in_req, dev->out_req); - debug("addr:%p, len:%d\n", addr, len); - - dev->out_req->buf = addr; - dev->out_req->length = len; -} - -int thor_init(void) -{ - struct thor_dev *dev = thor_func->dev; - - /* Wait for a device enumeration and configuration settings */ - debug("THOR enumeration/configuration setting....\n"); - while (!dev->configuration_done) - usb_gadget_handle_interrupts(); - - thor_set_dma(thor_rx_data_buf, strlen("THOR")); - /* detect the download request from Host PC */ - if (thor_rx_data() < 0) { - printf("%s: Data not received!\n", __func__); - return -1; - } - - if (!strncmp((char *)thor_rx_data_buf, "THOR", strlen("THOR"))) { - puts("Download request from the Host PC\n"); - udelay(30 * 1000); /* 30 ms */ - - strcpy((char *)thor_tx_data_buf, "ROHT"); - thor_tx_data(thor_tx_data_buf, strlen("ROHT")); - } else { - puts("Wrong reply information\n"); - return -1; - } - - return 0; -} - -int thor_handle(void) -{ - int ret; - - /* receive the data from Host PC */ - while (1) { - thor_set_dma(thor_rx_data_buf, sizeof(struct rqt_box)); - ret = thor_rx_data(); - - if (ret > 0) { - ret = process_data(); - if (ret < 0) - return ret; - } else { - printf("%s: No data received!\n", __func__); - break; - } - } - - return 0; -} - -static int thor_func_bind(struct usb_configuration *c, struct usb_function *f) -{ - struct usb_gadget *gadget = c->cdev->gadget; - struct f_thor *f_thor = func_to_thor(f); - struct thor_dev *dev; - struct usb_ep *ep; - int status; - - thor_func = f_thor; - dev = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*dev)); - if (!dev) - return -ENOMEM; - - memset(dev, 0, sizeof(*dev)); - dev->gadget = gadget; - f_thor->dev = dev; - - debug("%s: usb_configuration: 0x%p usb_function: 0x%p\n", - __func__, c, f); - debug("f_thor: 0x%p thor: 0x%p\n", f_thor, dev); - - /* EP0 */ - /* preallocate control response and buffer */ - dev->req = usb_ep_alloc_request(gadget->ep0, 0); - if (!dev->req) { - status = -ENOMEM; - goto fail; - } - dev->req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, - gadget->ep0->maxpacket); - if (!dev->req->buf) { - status = -ENOMEM; - goto fail; - } - - dev->req->complete = thor_setup_complete; - - /* DYNAMIC interface numbers assignments */ - status = usb_interface_id(c, f); - - if (status < 0) - goto fail; - - thor_downloader_intf_int.bInterfaceNumber = status; - thor_downloader_cdc_union.bMasterInterface0 = status; - - status = usb_interface_id(c, f); - - if (status < 0) - goto fail; - - thor_downloader_intf_data.bInterfaceNumber = status; - thor_downloader_cdc_union.bSlaveInterface0 = status; - - /* allocate instance-specific endpoints */ - ep = usb_ep_autoconfig(gadget, &fs_in_desc); - if (!ep) { - status = -ENODEV; - goto fail; - } - - if (gadget_is_dualspeed(gadget)) { - hs_in_desc.bEndpointAddress = - fs_in_desc.bEndpointAddress; - } - - dev->in_ep = ep; /* Store IN EP for enabling @ setup */ - - ep = usb_ep_autoconfig(gadget, &fs_out_desc); - if (!ep) { - status = -ENODEV; - goto fail; - } - - if (gadget_is_dualspeed(gadget)) - hs_out_desc.bEndpointAddress = - fs_out_desc.bEndpointAddress; - - dev->out_ep = ep; /* Store OUT EP for enabling @ setup */ - - ep = usb_ep_autoconfig(gadget, &fs_int_desc); - if (!ep) { - status = -ENODEV; - goto fail; - } - - dev->int_ep = ep; - - if (gadget_is_dualspeed(gadget)) { - hs_int_desc.bEndpointAddress = - fs_int_desc.bEndpointAddress; - - f->hs_descriptors = (struct usb_descriptor_header **) - &hs_thor_downloader_function; - - if (!f->hs_descriptors) - goto fail; - } - - debug("%s: out_ep:%p out_req:%p\n", __func__, - dev->out_ep, dev->out_req); - - return 0; - - fail: - free(dev); - return status; -} - -static void free_ep_req(struct usb_ep *ep, struct usb_request *req) -{ - free(req->buf); - usb_ep_free_request(ep, req); -} - -static void thor_unbind(struct usb_configuration *c, struct usb_function *f) -{ - struct f_thor *f_thor = func_to_thor(f); - struct thor_dev *dev = f_thor->dev; - - free(dev); - memset(thor_func, 0, sizeof(*thor_func)); - thor_func = NULL; -} - -static void thor_func_disable(struct usb_function *f) -{ - struct f_thor *f_thor = func_to_thor(f); - struct thor_dev *dev = f_thor->dev; - - debug("%s:\n", __func__); - - /* Avoid freeing memory when ep is still claimed */ - if (dev->in_ep->driver_data) { - free_ep_req(dev->in_ep, dev->in_req); - usb_ep_disable(dev->in_ep); - dev->in_ep->driver_data = NULL; - } - - if (dev->out_ep->driver_data) { - dev->out_req->buf = NULL; - usb_ep_free_request(dev->out_ep, dev->out_req); - usb_ep_disable(dev->out_ep); - dev->out_ep->driver_data = NULL; - } - - if (dev->int_ep->driver_data) { - usb_ep_disable(dev->int_ep); - dev->int_ep->driver_data = NULL; - } -} - -static int thor_eps_setup(struct usb_function *f) -{ - struct usb_composite_dev *cdev = f->config->cdev; - struct usb_gadget *gadget = cdev->gadget; - struct thor_dev *dev = thor_func->dev; - struct usb_endpoint_descriptor *d; - struct usb_request *req; - struct usb_ep *ep; - int result; - - ep = dev->in_ep; - d = ep_desc(gadget, &hs_in_desc, &fs_in_desc); - debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress); - - result = usb_ep_enable(ep, d); - if (result) - goto exit; - - ep->driver_data = cdev; /* claim */ - req = thor_start_ep(ep); - if (!req) { - usb_ep_disable(ep); - result = -EIO; - goto exit; - } - - dev->in_req = req; - ep = dev->out_ep; - d = ep_desc(gadget, &hs_out_desc, &fs_out_desc); - debug("(d)bEndpointAddress: 0x%x\n", d->bEndpointAddress); - - result = usb_ep_enable(ep, d); - if (result) - goto exit; - - ep->driver_data = cdev; /* claim */ - req = thor_start_ep(ep); - if (!req) { - usb_ep_disable(ep); - result = -EIO; - goto exit; - } - - dev->out_req = req; - /* ACM control EP */ - ep = dev->int_ep; - ep->driver_data = cdev; /* claim */ - - exit: - return result; -} - -static int thor_func_set_alt(struct usb_function *f, - unsigned intf, unsigned alt) -{ - struct thor_dev *dev = thor_func->dev; - int result; - - debug("%s: func: %s intf: %d alt: %d\n", - __func__, f->name, intf, alt); - - switch (intf) { - case 0: - debug("ACM INTR interface\n"); - break; - case 1: - debug("Communication Data interface\n"); - result = thor_eps_setup(f); - if (result) - error("%s: EPs setup failed!", __func__); - dev->configuration_done = 1; - break; - } - - return 0; -} - -static int thor_func_init(struct usb_configuration *c) -{ - struct f_thor *f_thor; - int status; - - debug("%s: cdev: 0x%p\n", __func__, c->cdev); - - f_thor = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*f_thor)); - if (!f_thor) - return -ENOMEM; - - memset(f_thor, 0, sizeof(*f_thor)); - - f_thor->usb_function.name = "f_thor"; - f_thor->usb_function.bind = thor_func_bind; - f_thor->usb_function.unbind = thor_unbind; - f_thor->usb_function.setup = thor_func_setup; - f_thor->usb_function.set_alt = thor_func_set_alt; - f_thor->usb_function.disable = thor_func_disable; - - status = usb_add_function(c, &f_thor->usb_function); - if (status) - free(f_thor); - - return status; -} - -int thor_add(struct usb_configuration *c) -{ - debug("%s:\n", __func__); - return thor_func_init(c); -} - -DECLARE_GADGET_BIND_CALLBACK(usb_dnl_thor, thor_add); diff --git a/qemu/roms/u-boot/drivers/usb/gadget/f_thor.h b/qemu/roms/u-boot/drivers/usb/gadget/f_thor.h deleted file mode 100644 index 833a9d24a..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/f_thor.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * f_thor.h - USB TIZEN THOR - internal gadget definitions - * - * Copyright (C) 2013 Samsung Electronics - * Lukasz Majewski <l.majewski@samsung.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef _USB_THOR_H_ -#define _USB_THOR_H_ - -#include <linux/compiler.h> -#include <linux/sizes.h> - -/* THOR Composite Gadget */ -#define STRING_MANUFACTURER_IDX 0 -#define STRING_PRODUCT_IDX 1 -#define STRING_SERIAL_IDX 2 - -/* ********************************************************** */ -/* THOR protocol definitions */ -/* ********************************************************** */ - -/* - * Attribute Vendor descriptor - necessary to prevent ZLP transmission - * from Windows XP HOST PC - */ -struct usb_cdc_attribute_vendor_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __u8 bDescriptorSubType; - __u16 DAUType; - __u16 DAULength; - __u8 DAUValue; -} __packed; - -#define VER_PROTOCOL_MAJOR 4 -#define VER_PROTOCOL_MINOR 0 - -enum rqt { - RQT_INFO = 200, - RQT_CMD, - RQT_DL, - RQT_UL, -}; - -enum rqt_data { - /* RQT_INFO */ - RQT_INFO_VER_PROTOCOL = 1, - RQT_INIT_VER_HW, - RQT_INIT_VER_BOOT, - RQT_INIT_VER_KERNEL, - RQT_INIT_VER_PLATFORM, - RQT_INIT_VER_CSC, - - /* RQT_CMD */ - RQT_CMD_REBOOT = 1, - RQT_CMD_POWEROFF, - RQT_CMD_EFSCLEAR, - - /* RQT_DL */ - RQT_DL_INIT = 1, - RQT_DL_FILE_INFO, - RQT_DL_FILE_START, - RQT_DL_FILE_END, - RQT_DL_EXIT, - - /* RQT_UL */ - RQT_UL_INIT = 1, - RQT_UL_START, - RQT_UL_END, - RQT_UL_EXIT, -}; - -struct rqt_box { /* total: 256B */ - s32 rqt; /* request id */ - s32 rqt_data; /* request data id */ - s32 int_data[14]; /* int data */ - char str_data[5][32]; /* string data */ - char md5[32]; /* md5 checksum */ -} __packed; - -struct rsp_box { /* total: 128B */ - s32 rsp; /* response id (= request id) */ - s32 rsp_data; /* response data id */ - s32 ack; /* ack */ - s32 int_data[5]; /* int data */ - char str_data[3][32]; /* string data */ -} __packed; - -struct data_rsp_box { /* total: 8B */ - s32 ack; /* response id (= request id) */ - s32 count; /* response data id */ -} __packed; - -enum { - FILE_TYPE_NORMAL, - FILE_TYPE_PIT, -}; - -struct thor_dev { - struct usb_gadget *gadget; - struct usb_request *req; /* EP0 -> control responses */ - - /* IN/OUT EP's and correspoinding requests */ - struct usb_ep *in_ep, *out_ep, *int_ep; - struct usb_request *in_req, *out_req; - - /* Control flow variables */ - unsigned char configuration_done; - unsigned char rxdata; - unsigned char txdata; -}; - -struct f_thor { - struct usb_function usb_function; - struct thor_dev *dev; -}; - -#define F_NAME_BUF_SIZE 32 -#define THOR_PACKET_SIZE SZ_1M /* 1 MiB */ -#define THOR_STORE_UNIT_SIZE SZ_32M /* 32 MiB */ -#endif /* _USB_THOR_H_ */ diff --git a/qemu/roms/u-boot/drivers/usb/gadget/fotg210.c b/qemu/roms/u-boot/drivers/usb/gadget/fotg210.c deleted file mode 100644 index 3acf6a1f4..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/fotg210.c +++ /dev/null @@ -1,962 +0,0 @@ -/* - * Faraday USB 2.0 OTG Controller - * - * (C) Copyright 2010 Faraday Technology - * Dante Su <dantesu@faraday-tech.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <command.h> -#include <config.h> -#include <net.h> -#include <malloc.h> -#include <asm/io.h> -#include <asm/errno.h> -#include <linux/types.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - -#include <usb/fotg210.h> - -#define CFG_NUM_ENDPOINTS 4 -#define CFG_EP0_MAX_PACKET_SIZE 64 -#define CFG_EPX_MAX_PACKET_SIZE 512 - -#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */ - -struct fotg210_chip; - -struct fotg210_ep { - struct usb_ep ep; - - uint maxpacket; - uint id; - uint stopped; - - struct list_head queue; - struct fotg210_chip *chip; - const struct usb_endpoint_descriptor *desc; -}; - -struct fotg210_request { - struct usb_request req; - struct list_head queue; - struct fotg210_ep *ep; -}; - -struct fotg210_chip { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct fotg210_regs *regs; - uint8_t irq; - uint16_t addr; - int pullup; - enum usb_device_state state; - struct fotg210_ep ep[1 + CFG_NUM_ENDPOINTS]; -}; - -static struct usb_endpoint_descriptor ep0_desc = { - .bLength = sizeof(struct usb_endpoint_descriptor), - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, -}; - -static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in) -{ - return (id < 0) ? 0 : ((id & 0x03) + 1); -} - -static inline int ep_to_fifo(struct fotg210_chip *chip, int id) -{ - return (id <= 0) ? -1 : ((id - 1) & 0x03); -} - -static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr) -{ - int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK; - struct fotg210_regs *regs = chip->regs; - - if (ep_addr & USB_DIR_IN) { - /* reset endpoint */ - setbits_le32(®s->iep[ep - 1], IEP_RESET); - mdelay(1); - clrbits_le32(®s->iep[ep - 1], IEP_RESET); - /* clear endpoint stall */ - clrbits_le32(®s->iep[ep - 1], IEP_STALL); - } else { - /* reset endpoint */ - setbits_le32(®s->oep[ep - 1], OEP_RESET); - mdelay(1); - clrbits_le32(®s->oep[ep - 1], OEP_RESET); - /* clear endpoint stall */ - clrbits_le32(®s->oep[ep - 1], OEP_STALL); - } - - return 0; -} - -static int fotg210_reset(struct fotg210_chip *chip) -{ - struct fotg210_regs *regs = chip->regs; - uint32_t i; - - chip->state = USB_STATE_POWERED; - - /* chip enable */ - writel(DEVCTRL_EN, ®s->dev_ctrl); - - /* device address reset */ - chip->addr = 0; - writel(0, ®s->dev_addr); - - /* set idle counter to 7ms */ - writel(7, ®s->idle); - - /* disable all interrupts */ - writel(IMR_MASK, ®s->imr); - writel(GIMR_MASK, ®s->gimr); - writel(GIMR0_MASK, ®s->gimr0); - writel(GIMR1_MASK, ®s->gimr1); - writel(GIMR2_MASK, ®s->gimr2); - - /* clear interrupts */ - writel(ISR_MASK, ®s->isr); - writel(0, ®s->gisr); - writel(0, ®s->gisr0); - writel(0, ®s->gisr1); - writel(0, ®s->gisr2); - - /* chip reset */ - setbits_le32(®s->dev_ctrl, DEVCTRL_RESET); - mdelay(10); - if (readl(®s->dev_ctrl) & DEVCTRL_RESET) { - printf("fotg210: chip reset failed\n"); - return -1; - } - - /* CX FIFO reset */ - setbits_le32(®s->cxfifo, CXFIFO_CXFIFOCLR); - mdelay(10); - if (readl(®s->cxfifo) & CXFIFO_CXFIFOCLR) { - printf("fotg210: ep0 fifo reset failed\n"); - return -1; - } - - /* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */ - writel(EPMAP14_DEFAULT, ®s->epmap14); - writel(EPMAP58_DEFAULT, ®s->epmap58); - writel(FIFOMAP_DEFAULT, ®s->fifomap); - writel(0, ®s->fifocfg); - for (i = 0; i < 8; ++i) { - writel(CFG_EPX_MAX_PACKET_SIZE, ®s->iep[i]); - writel(CFG_EPX_MAX_PACKET_SIZE, ®s->oep[i]); - } - - /* FIFO reset */ - for (i = 0; i < 4; ++i) { - writel(FIFOCSR_RESET, ®s->fifocsr[i]); - mdelay(10); - if (readl(®s->fifocsr[i]) & FIFOCSR_RESET) { - printf("fotg210: fifo%d reset failed\n", i); - return -1; - } - } - - /* enable only device interrupt and triggered at level-high */ - writel(IMR_IRQLH | IMR_HOST | IMR_OTG, ®s->imr); - writel(ISR_MASK, ®s->isr); - /* disable EP0 IN/OUT interrupt */ - writel(GIMR0_CXOUT | GIMR0_CXIN, ®s->gimr0); - /* disable EPX IN+SPK+OUT interrupts */ - writel(GIMR1_MASK, ®s->gimr1); - /* disable wakeup+idle+dma+zlp interrupts */ - writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN - | GIMR2_ZLPRX | GIMR2_ZLPTX, ®s->gimr2); - /* enable all group interrupt */ - writel(0, ®s->gimr); - - /* suspend delay = 3 ms */ - writel(3, ®s->idle); - - /* turn-on device interrupts */ - setbits_le32(®s->dev_ctrl, DEVCTRL_GIRQ_EN); - - return 0; -} - -static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask) -{ - struct fotg210_regs *regs = chip->regs; - int ret = -1; - ulong ts; - - for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { - if ((readl(®s->cxfifo) & mask) != mask) - continue; - ret = 0; - break; - } - - if (ret) - printf("fotg210: cx/ep0 timeout\n"); - - return ret; -} - -static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req) -{ - struct fotg210_chip *chip = ep->chip; - struct fotg210_regs *regs = chip->regs; - uint32_t tmp, ts; - uint8_t *buf = req->req.buf + req->req.actual; - uint32_t len = req->req.length - req->req.actual; - int fifo = ep_to_fifo(chip, ep->id); - int ret = -EBUSY; - - /* 1. init dma buffer */ - if (len > ep->maxpacket) - len = ep->maxpacket; - - /* 2. wait for dma ready (hardware) */ - for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { - if (!(readl(®s->dma_ctrl) & DMACTRL_START)) { - ret = 0; - break; - } - } - if (ret) { - printf("fotg210: dma busy\n"); - req->req.status = ret; - return ret; - } - - /* 3. DMA target setup */ - if (ep->desc->bEndpointAddress & USB_DIR_IN) - flush_dcache_range((ulong)buf, (ulong)buf + len); - else - invalidate_dcache_range((ulong)buf, (ulong)buf + len); - - writel(virt_to_phys(buf), ®s->dma_addr); - - if (ep->desc->bEndpointAddress & USB_DIR_IN) { - if (ep->id == 0) { - /* Wait until cx/ep0 fifo empty */ - fotg210_cxwait(chip, CXFIFO_CXFIFOE); - udelay(1); - writel(DMAFIFO_CX, ®s->dma_fifo); - } else { - /* Wait until epx fifo empty */ - fotg210_cxwait(chip, CXFIFO_FIFOE(fifo)); - writel(DMAFIFO_FIFO(fifo), ®s->dma_fifo); - } - writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, ®s->dma_ctrl); - } else { - uint32_t blen; - - if (ep->id == 0) { - writel(DMAFIFO_CX, ®s->dma_fifo); - do { - blen = CXFIFO_BYTES(readl(®s->cxfifo)); - } while (blen < len); - } else { - writel(DMAFIFO_FIFO(fifo), ®s->dma_fifo); - blen = FIFOCSR_BYTES(readl(®s->fifocsr[fifo])); - } - len = (len < blen) ? len : blen; - writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, ®s->dma_ctrl); - } - - /* 4. DMA start */ - setbits_le32(®s->dma_ctrl, DMACTRL_START); - - /* 5. DMA wait */ - ret = -EBUSY; - for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { - tmp = readl(®s->gisr2); - /* DMA complete */ - if (tmp & GISR2_DMAFIN) { - ret = 0; - break; - } - /* DMA error */ - if (tmp & GISR2_DMAERR) { - printf("fotg210: dma error\n"); - break; - } - /* resume, suspend, reset */ - if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) { - printf("fotg210: dma reset by host\n"); - break; - } - } - - /* 7. DMA target reset */ - if (ret) - writel(DMACTRL_ABORT | DMACTRL_CLRFF, ®s->dma_ctrl); - - writel(0, ®s->gisr2); - writel(0, ®s->dma_fifo); - - req->req.status = ret; - if (!ret) - req->req.actual += len; - else - printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret); - - return len; -} - -/* - * result of setup packet - */ -#define CX_IDLE 0 -#define CX_FINISH 1 -#define CX_STALL 2 - -static void fotg210_setup(struct fotg210_chip *chip) -{ - int id, ret = CX_IDLE; - uint32_t tmp[2]; - struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp; - struct fotg210_regs *regs = chip->regs; - - /* - * If this is the first Cx 8 byte command, - * we can now query USB mode (high/full speed; USB 2.0/USB 1.0) - */ - if (chip->state == USB_STATE_POWERED) { - chip->state = USB_STATE_DEFAULT; - if (readl(®s->otgcsr) & OTGCSR_DEV_B) { - /* Mini-B */ - if (readl(®s->dev_ctrl) & DEVCTRL_HS) { - puts("fotg210: HS\n"); - chip->gadget.speed = USB_SPEED_HIGH; - /* SOF mask timer = 1100 ticks */ - writel(SOFMTR_TMR(1100), ®s->sof_mtr); - } else { - puts("fotg210: FS\n"); - chip->gadget.speed = USB_SPEED_FULL; - /* SOF mask timer = 10000 ticks */ - writel(SOFMTR_TMR(10000), ®s->sof_mtr); - } - } else { - printf("fotg210: mini-A?\n"); - } - } - - /* switch data port to ep0 */ - writel(DMAFIFO_CX, ®s->dma_fifo); - /* fetch 8 bytes setup packet */ - tmp[0] = readl(®s->ep0_data); - tmp[1] = readl(®s->ep0_data); - /* release data port */ - writel(0, ®s->dma_fifo); - - if (req->bRequestType & USB_DIR_IN) - ep0_desc.bEndpointAddress = USB_DIR_IN; - else - ep0_desc.bEndpointAddress = USB_DIR_OUT; - - ret = CX_IDLE; - - if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { - switch (req->bRequest) { - case USB_REQ_SET_CONFIGURATION: - debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF); - if (!(req->wValue & 0x00FF)) { - chip->state = USB_STATE_ADDRESS; - writel(chip->addr, ®s->dev_addr); - } else { - chip->state = USB_STATE_CONFIGURED; - writel(chip->addr | DEVADDR_CONF, - ®s->dev_addr); - } - ret = CX_IDLE; - break; - - case USB_REQ_SET_ADDRESS: - debug("fotg210: set_addr(0x%04X)\n", req->wValue); - chip->state = USB_STATE_ADDRESS; - chip->addr = req->wValue & DEVADDR_ADDR_MASK; - ret = CX_FINISH; - writel(chip->addr, ®s->dev_addr); - break; - - case USB_REQ_CLEAR_FEATURE: - debug("fotg210: clr_feature(%d, %d)\n", - req->bRequestType & 0x03, req->wValue); - switch (req->wValue) { - case 0: /* [Endpoint] halt */ - ep_reset(chip, req->wIndex); - ret = CX_FINISH; - break; - case 1: /* [Device] remote wake-up */ - case 2: /* [Device] test mode */ - default: - ret = CX_STALL; - break; - } - break; - - case USB_REQ_SET_FEATURE: - debug("fotg210: set_feature(%d, %d)\n", - req->wValue, req->wIndex & 0xf); - switch (req->wValue) { - case 0: /* Endpoint Halt */ - id = req->wIndex & 0xf; - setbits_le32(®s->iep[id - 1], IEP_STALL); - setbits_le32(®s->oep[id - 1], OEP_STALL); - ret = CX_FINISH; - break; - case 1: /* Remote Wakeup */ - case 2: /* Test Mode */ - default: - ret = CX_STALL; - break; - } - break; - - case USB_REQ_GET_STATUS: - debug("fotg210: get_status\n"); - ret = CX_STALL; - break; - - case USB_REQ_SET_DESCRIPTOR: - debug("fotg210: set_descriptor\n"); - ret = CX_STALL; - break; - - case USB_REQ_SYNCH_FRAME: - debug("fotg210: sync frame\n"); - ret = CX_STALL; - break; - } - } /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */ - - if (ret == CX_IDLE && chip->driver->setup) { - if (chip->driver->setup(&chip->gadget, req) < 0) - ret = CX_STALL; - else - ret = CX_FINISH; - } - - switch (ret) { - case CX_FINISH: - setbits_le32(®s->cxfifo, CXFIFO_CXFIN); - break; - - case CX_STALL: - setbits_le32(®s->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN); - printf("fotg210: cx_stall!\n"); - break; - - case CX_IDLE: - debug("fotg210: cx_idle?\n"); - default: - break; - } -} - -/* - * fifo - FIFO id - * zlp - zero length packet - */ -static void fotg210_recv(struct fotg210_chip *chip, int ep_id) -{ - struct fotg210_regs *regs = chip->regs; - struct fotg210_ep *ep = chip->ep + ep_id; - struct fotg210_request *req; - int len; - - if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) { - printf("fotg210: ep%d recv, invalid!\n", ep->id); - return; - } - - if (list_empty(&ep->queue)) { - printf("fotg210: ep%d recv, drop!\n", ep->id); - return; - } - - req = list_first_entry(&ep->queue, struct fotg210_request, queue); - len = fotg210_dma(ep, req); - if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) { - list_del_init(&req->queue); - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - } - - if (ep->id > 0 && list_empty(&ep->queue)) { - setbits_le32(®s->gimr1, - GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id))); - } -} - -/* - * USB Gadget Layer - */ -static int fotg210_ep_enable( - struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) -{ - struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); - struct fotg210_chip *chip = ep->chip; - struct fotg210_regs *regs = chip->regs; - int id = ep_to_fifo(chip, ep->id); - int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0; - - if (!_ep || !desc - || desc->bDescriptorType != USB_DT_ENDPOINT - || le16_to_cpu(desc->wMaxPacketSize) == 0) { - printf("fotg210: bad ep or descriptor\n"); - return -EINVAL; - } - - ep->desc = desc; - ep->stopped = 0; - - if (in) - setbits_le32(®s->fifomap, FIFOMAP(id, FIFOMAP_IN)); - - switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_CONTROL: - return -EINVAL; - - case USB_ENDPOINT_XFER_ISOC: - setbits_le32(®s->fifocfg, - FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC)); - break; - - case USB_ENDPOINT_XFER_BULK: - setbits_le32(®s->fifocfg, - FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK)); - break; - - case USB_ENDPOINT_XFER_INT: - setbits_le32(®s->fifocfg, - FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR)); - break; - } - - return 0; -} - -static int fotg210_ep_disable(struct usb_ep *_ep) -{ - struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); - struct fotg210_chip *chip = ep->chip; - struct fotg210_regs *regs = chip->regs; - int id = ep_to_fifo(chip, ep->id); - - ep->desc = NULL; - ep->stopped = 1; - - clrbits_le32(®s->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK)); - clrbits_le32(®s->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK)); - - return 0; -} - -static struct usb_request *fotg210_ep_alloc_request( - struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct fotg210_request *req = malloc(sizeof(*req)); - - if (req) { - memset(req, 0, sizeof(*req)); - INIT_LIST_HEAD(&req->queue); - } - return &req->req; -} - -static void fotg210_ep_free_request( - struct usb_ep *_ep, struct usb_request *_req) -{ - struct fotg210_request *req; - - req = container_of(_req, struct fotg210_request, req); - free(req); -} - -static int fotg210_ep_queue( - struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); - struct fotg210_chip *chip = ep->chip; - struct fotg210_regs *regs = chip->regs; - struct fotg210_request *req; - - req = container_of(_req, struct fotg210_request, req); - if (!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue)) { - printf("fotg210: invalid request to ep%d\n", ep->id); - return -EINVAL; - } - - if (!chip || chip->state == USB_STATE_SUSPENDED) { - printf("fotg210: request while chip suspended\n"); - return -EINVAL; - } - - req->req.actual = 0; - req->req.status = -EINPROGRESS; - - if (req->req.length == 0) { - req->req.status = 0; - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - return 0; - } - - if (ep->id == 0) { - do { - int len = fotg210_dma(ep, req); - if (len < ep->ep.maxpacket) - break; - if (ep->desc->bEndpointAddress & USB_DIR_IN) - udelay(100); - } while (req->req.length > req->req.actual); - } else { - if (ep->desc->bEndpointAddress & USB_DIR_IN) { - do { - int len = fotg210_dma(ep, req); - if (len < ep->ep.maxpacket) - break; - } while (req->req.length > req->req.actual); - } else { - list_add_tail(&req->queue, &ep->queue); - clrbits_le32(®s->gimr1, - GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id))); - } - } - - if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) { - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - } - - return 0; -} - -static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); - struct fotg210_request *req; - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) - return -EINVAL; - - /* remove the request */ - list_del_init(&req->queue); - - /* update status & invoke complete callback */ - if (req->req.status == -EINPROGRESS) { - req->req.status = -ECONNRESET; - if (req->req.complete) - req->req.complete(_ep, &req->req); - } - - return 0; -} - -static int fotg210_ep_halt(struct usb_ep *_ep, int halt) -{ - struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep); - struct fotg210_chip *chip = ep->chip; - struct fotg210_regs *regs = chip->regs; - int ret = -1; - - debug("fotg210: ep%d halt=%d\n", ep->id, halt); - - /* Endpoint STALL */ - if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) { - if (halt) { - /* wait until all ep fifo empty */ - fotg210_cxwait(chip, 0xf00); - /* stall */ - if (ep->desc->bEndpointAddress & USB_DIR_IN) { - setbits_le32(®s->iep[ep->id - 1], - IEP_STALL); - } else { - setbits_le32(®s->oep[ep->id - 1], - OEP_STALL); - } - } else { - if (ep->desc->bEndpointAddress & USB_DIR_IN) { - clrbits_le32(®s->iep[ep->id - 1], - IEP_STALL); - } else { - clrbits_le32(®s->oep[ep->id - 1], - OEP_STALL); - } - } - ret = 0; - } - - return ret; -} - -/* - * activate/deactivate link with host. - */ -static void pullup(struct fotg210_chip *chip, int is_on) -{ - struct fotg210_regs *regs = chip->regs; - - if (is_on) { - if (!chip->pullup) { - chip->state = USB_STATE_POWERED; - chip->pullup = 1; - /* enable the chip */ - setbits_le32(®s->dev_ctrl, DEVCTRL_EN); - /* clear unplug bit (BIT0) */ - clrbits_le32(®s->phy_tmsr, PHYTMSR_UNPLUG); - } - } else { - chip->state = USB_STATE_NOTATTACHED; - chip->pullup = 0; - chip->addr = 0; - writel(chip->addr, ®s->dev_addr); - /* set unplug bit (BIT0) */ - setbits_le32(®s->phy_tmsr, PHYTMSR_UNPLUG); - /* disable the chip */ - clrbits_le32(®s->dev_ctrl, DEVCTRL_EN); - } -} - -static int fotg210_pullup(struct usb_gadget *_gadget, int is_on) -{ - struct fotg210_chip *chip; - - chip = container_of(_gadget, struct fotg210_chip, gadget); - - debug("fotg210: pullup=%d\n", is_on); - - pullup(chip, is_on); - - return 0; -} - -static int fotg210_get_frame(struct usb_gadget *_gadget) -{ - struct fotg210_chip *chip; - struct fotg210_regs *regs; - - chip = container_of(_gadget, struct fotg210_chip, gadget); - regs = chip->regs; - - return SOFFNR_FNR(readl(®s->sof_fnr)); -} - -static struct usb_gadget_ops fotg210_gadget_ops = { - .get_frame = fotg210_get_frame, - .pullup = fotg210_pullup, -}; - -static struct usb_ep_ops fotg210_ep_ops = { - .enable = fotg210_ep_enable, - .disable = fotg210_ep_disable, - .queue = fotg210_ep_queue, - .dequeue = fotg210_ep_dequeue, - .set_halt = fotg210_ep_halt, - .alloc_request = fotg210_ep_alloc_request, - .free_request = fotg210_ep_free_request, -}; - -static struct fotg210_chip controller = { - .regs = (void __iomem *)CONFIG_FOTG210_BASE, - .gadget = { - .name = "fotg210_udc", - .ops = &fotg210_gadget_ops, - .ep0 = &controller.ep[0].ep, - .speed = USB_SPEED_UNKNOWN, - .is_dualspeed = 1, - .is_otg = 0, - .is_a_peripheral = 0, - .b_hnp_enable = 0, - .a_hnp_support = 0, - .a_alt_hnp_support = 0, - }, - .ep[0] = { - .id = 0, - .ep = { - .name = "ep0", - .ops = &fotg210_ep_ops, - }, - .desc = &ep0_desc, - .chip = &controller, - .maxpacket = CFG_EP0_MAX_PACKET_SIZE, - }, - .ep[1] = { - .id = 1, - .ep = { - .name = "ep1", - .ops = &fotg210_ep_ops, - }, - .chip = &controller, - .maxpacket = CFG_EPX_MAX_PACKET_SIZE, - }, - .ep[2] = { - .id = 2, - .ep = { - .name = "ep2", - .ops = &fotg210_ep_ops, - }, - .chip = &controller, - .maxpacket = CFG_EPX_MAX_PACKET_SIZE, - }, - .ep[3] = { - .id = 3, - .ep = { - .name = "ep3", - .ops = &fotg210_ep_ops, - }, - .chip = &controller, - .maxpacket = CFG_EPX_MAX_PACKET_SIZE, - }, - .ep[4] = { - .id = 4, - .ep = { - .name = "ep4", - .ops = &fotg210_ep_ops, - }, - .chip = &controller, - .maxpacket = CFG_EPX_MAX_PACKET_SIZE, - }, -}; - -int usb_gadget_handle_interrupts(void) -{ - struct fotg210_chip *chip = &controller; - struct fotg210_regs *regs = chip->regs; - uint32_t id, st, isr, gisr; - - isr = readl(®s->isr) & (~readl(®s->imr)); - gisr = readl(®s->gisr) & (~readl(®s->gimr)); - if (!(isr & ISR_DEV) || !gisr) - return 0; - - writel(ISR_DEV, ®s->isr); - - /* CX interrupts */ - if (gisr & GISR_GRP0) { - st = readl(®s->gisr0); - /* - * Write 1 and then 0 works for both W1C & RW. - * - * HW v1.11.0+: It's a W1C register (write 1 clear) - * HW v1.10.0-: It's a R/W register (write 0 clear) - */ - writel(st & GISR0_CXABORT, ®s->gisr0); - writel(0, ®s->gisr0); - - if (st & GISR0_CXERR) - printf("fotg210: cmd error\n"); - - if (st & GISR0_CXABORT) - printf("fotg210: cmd abort\n"); - - if (st & GISR0_CXSETUP) /* setup */ - fotg210_setup(chip); - else if (st & GISR0_CXEND) /* command finish */ - setbits_le32(®s->cxfifo, CXFIFO_CXFIN); - } - - /* FIFO interrupts */ - if (gisr & GISR_GRP1) { - st = readl(®s->gisr1); - for (id = 0; id < 4; ++id) { - if (st & GISR1_RX_FIFO(id)) - fotg210_recv(chip, fifo_to_ep(chip, id, 0)); - } - } - - /* Device Status Interrupts */ - if (gisr & GISR_GRP2) { - st = readl(®s->gisr2); - /* - * Write 1 and then 0 works for both W1C & RW. - * - * HW v1.11.0+: It's a W1C register (write 1 clear) - * HW v1.10.0-: It's a R/W register (write 0 clear) - */ - writel(st, ®s->gisr2); - writel(0, ®s->gisr2); - - if (st & GISR2_RESET) - printf("fotg210: reset by host\n"); - else if (st & GISR2_SUSPEND) - printf("fotg210: suspend/removed\n"); - else if (st & GISR2_RESUME) - printf("fotg210: resume\n"); - - /* Errors */ - if (st & GISR2_ISOCERR) - printf("fotg210: iso error\n"); - if (st & GISR2_ISOCABT) - printf("fotg210: iso abort\n"); - if (st & GISR2_DMAERR) - printf("fotg210: dma error\n"); - } - - return 0; -} - -int usb_gadget_register_driver(struct usb_gadget_driver *driver) -{ - int i, ret = 0; - struct fotg210_chip *chip = &controller; - - if (!driver || !driver->bind || !driver->setup) { - puts("fotg210: bad parameter.\n"); - return -EINVAL; - } - - INIT_LIST_HEAD(&chip->gadget.ep_list); - for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) { - struct fotg210_ep *ep = chip->ep + i; - - ep->ep.maxpacket = ep->maxpacket; - INIT_LIST_HEAD(&ep->queue); - - if (ep->id == 0) { - ep->stopped = 0; - } else { - ep->stopped = 1; - list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list); - } - } - - if (fotg210_reset(chip)) { - puts("fotg210: reset failed.\n"); - return -EINVAL; - } - - ret = driver->bind(&chip->gadget); - if (ret) { - debug("fotg210: driver->bind() returned %d\n", ret); - return ret; - } - chip->driver = driver; - - return ret; -} - -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct fotg210_chip *chip = &controller; - - driver->unbind(&chip->gadget); - chip->driver = NULL; - - pullup(chip, 0); - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/g_dnl.c b/qemu/roms/u-boot/drivers/usb/gadget/g_dnl.c deleted file mode 100644 index 25611acd6..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/g_dnl.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * g_dnl.c -- USB Downloader Gadget - * - * Copyright (C) 2012 Samsung Electronics - * Lukasz Majewski <l.majewski@samsung.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <malloc.h> - -#include <mmc.h> -#include <part.h> - -#include <g_dnl.h> -#include <usb_mass_storage.h> -#include <dfu.h> -#include <thor.h> - -#include "gadget_chips.h" -#include "composite.c" - -/* - * One needs to define the following: - * CONFIG_G_DNL_VENDOR_NUM - * CONFIG_G_DNL_PRODUCT_NUM - * CONFIG_G_DNL_MANUFACTURER - * at e.g. ./include/configs/<board>.h - */ - -#define STRING_MANUFACTURER 25 -#define STRING_PRODUCT 2 -/* Index of String Descriptor describing this configuration */ -#define STRING_USBDOWN 2 -/* Index of String serial */ -#define STRING_SERIAL 3 -#define MAX_STRING_SERIAL 32 -/* Number of supported configurations */ -#define CONFIGURATION_NUMBER 1 - -#define DRIVER_VERSION "usb_dnl 2.0" - -static const char product[] = "USB download gadget"; -static char g_dnl_serial[MAX_STRING_SERIAL]; -static const char manufacturer[] = CONFIG_G_DNL_MANUFACTURER; - -void g_dnl_set_serialnumber(char *s) -{ - memset(g_dnl_serial, 0, MAX_STRING_SERIAL); - if (strlen(s) < MAX_STRING_SERIAL) - strncpy(g_dnl_serial, s, strlen(s)); -} - -static struct usb_device_descriptor device_desc = { - .bLength = sizeof device_desc, - .bDescriptorType = USB_DT_DEVICE, - - .bcdUSB = __constant_cpu_to_le16(0x0200), - .bDeviceClass = USB_CLASS_COMM, - .bDeviceSubClass = 0x02, /*0x02:CDC-modem , 0x00:CDC-serial*/ - - .idVendor = __constant_cpu_to_le16(CONFIG_G_DNL_VENDOR_NUM), - .idProduct = __constant_cpu_to_le16(CONFIG_G_DNL_PRODUCT_NUM), - .iProduct = STRING_PRODUCT, - .iSerialNumber = STRING_SERIAL, - .bNumConfigurations = 1, -}; - -/* - * static strings, in UTF-8 - * IDs for those strings are assigned dynamically at g_dnl_bind() - */ -static struct usb_string g_dnl_string_defs[] = { - {.s = manufacturer}, - {.s = product}, - {.s = g_dnl_serial}, - { } /* end of list */ -}; - -static struct usb_gadget_strings g_dnl_string_tab = { - .language = 0x0409, /* en-us */ - .strings = g_dnl_string_defs, -}; - -static struct usb_gadget_strings *g_dnl_composite_strings[] = { - &g_dnl_string_tab, - NULL, -}; - -static int g_dnl_unbind(struct usb_composite_dev *cdev) -{ - struct usb_gadget *gadget = cdev->gadget; - - free(cdev->config); - cdev->config = NULL; - debug("%s: calling usb_gadget_disconnect for " - "controller '%s'\n", __func__, gadget->name); - usb_gadget_disconnect(gadget); - - return 0; -} - -static inline struct g_dnl_bind_callback *g_dnl_bind_callback_first(void) -{ - return ll_entry_start(struct g_dnl_bind_callback, - g_dnl_bind_callbacks); -} - -static inline struct g_dnl_bind_callback *g_dnl_bind_callback_end(void) -{ - return ll_entry_end(struct g_dnl_bind_callback, - g_dnl_bind_callbacks); -} - -static int g_dnl_do_config(struct usb_configuration *c) -{ - const char *s = c->cdev->driver->name; - struct g_dnl_bind_callback *callback = g_dnl_bind_callback_first(); - - debug("%s: configuration: 0x%p composite dev: 0x%p\n", - __func__, c, c->cdev); - - for (; callback != g_dnl_bind_callback_end(); callback++) - if (!strcmp(s, callback->usb_function_name)) - return callback->fptr(c); - return -ENODEV; -} - -static int g_dnl_config_register(struct usb_composite_dev *cdev) -{ - struct usb_configuration *config; - const char *name = "usb_dnload"; - - config = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*config)); - if (!config) - return -ENOMEM; - - memset(config, 0, sizeof(*config)); - - config->label = name; - config->bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER; - config->bConfigurationValue = CONFIGURATION_NUMBER; - config->iConfiguration = STRING_USBDOWN; - config->bind = g_dnl_do_config; - - return usb_add_config(cdev, config); -} - -__weak -int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) -{ - return 0; -} - -__weak int g_dnl_get_board_bcd_device_number(int gcnum) -{ - return gcnum; -} - -__weak int g_dnl_board_usb_cable_connected(void) -{ - return -EOPNOTSUPP; -} - -static int g_dnl_get_bcd_device_number(struct usb_composite_dev *cdev) -{ - struct usb_gadget *gadget = cdev->gadget; - int gcnum; - - gcnum = usb_gadget_controller_number(gadget); - if (gcnum > 0) - gcnum += 0x200; - - return g_dnl_get_board_bcd_device_number(gcnum); -} - -static int g_dnl_bind(struct usb_composite_dev *cdev) -{ - struct usb_gadget *gadget = cdev->gadget; - int id, ret; - int gcnum; - - debug("%s: gadget: 0x%p cdev: 0x%p\n", __func__, gadget, cdev); - - id = usb_string_id(cdev); - - if (id < 0) - return id; - g_dnl_string_defs[0].id = id; - device_desc.iManufacturer = id; - - id = usb_string_id(cdev); - if (id < 0) - return id; - - g_dnl_string_defs[1].id = id; - device_desc.iProduct = id; - - id = usb_string_id(cdev); - if (id < 0) - return id; - - g_dnl_string_defs[2].id = id; - device_desc.iSerialNumber = id; - - g_dnl_bind_fixup(&device_desc, cdev->driver->name); - ret = g_dnl_config_register(cdev); - if (ret) - goto error; - - gcnum = g_dnl_get_bcd_device_number(cdev); - if (gcnum >= 0) - device_desc.bcdDevice = cpu_to_le16(gcnum); - else { - debug("%s: controller '%s' not recognized\n", - __func__, gadget->name); - device_desc.bcdDevice = __constant_cpu_to_le16(0x9999); - } - - debug("%s: calling usb_gadget_connect for " - "controller '%s'\n", __func__, gadget->name); - usb_gadget_connect(gadget); - - return 0; - - error: - g_dnl_unbind(cdev); - return -ENOMEM; -} - -static struct usb_composite_driver g_dnl_driver = { - .name = NULL, - .dev = &device_desc, - .strings = g_dnl_composite_strings, - - .bind = g_dnl_bind, - .unbind = g_dnl_unbind, -}; - -/* - * NOTICE: - * Registering via USB function name won't be necessary after rewriting - * g_dnl to support multiple USB functions. - */ -int g_dnl_register(const char *name) -{ - int ret; - - debug("%s: g_dnl_driver.name = %s\n", __func__, name); - g_dnl_driver.name = name; - - ret = usb_composite_register(&g_dnl_driver); - if (ret) { - printf("%s: failed!, error: %d\n", __func__, ret); - return ret; - } - return 0; -} - -void g_dnl_unregister(void) -{ - usb_composite_unregister(&g_dnl_driver); -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/gadget_chips.h b/qemu/roms/u-boot/drivers/usb/gadget/gadget_chips.h deleted file mode 100644 index cc94771e3..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/gadget_chips.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * USB device controllers have lots of quirks. Use these macros in - * gadget drivers or other code that needs to deal with them, and which - * autoconfigures instead of using early binding to the hardware. - * - * This SHOULD eventually work like the ARM mach_is_*() stuff, driven by - * some config file that gets updated as new hardware is supported. - * (And avoiding all runtime comparisons in typical one-choice configs!) - * - * NOTE: some of these controller drivers may not be available yet. - * Some are available on 2.4 kernels; several are available, but not - * yet pushed in the 2.6 mainline tree. - * - * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and - * Remy Bohmer <linux@bohmer.net> - */ -#ifdef CONFIG_USB_GADGET_NET2280 -#define gadget_is_net2280(g) (!strcmp("net2280", (g)->name)) -#else -#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 -#define gadget_is_dummy(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_PXA2XX -#define gadget_is_pxa(g) (!strcmp("pxa2xx_udc", (g)->name)) -#else -#define gadget_is_pxa(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_GOKU -#define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) -#else -#define gadget_is_goku(g) 0 -#endif - -/* SH3 UDC -- not yet ported 2.4 --> 2.6 */ -#ifdef CONFIG_USB_GADGET_SUPERH -#define gadget_is_sh(g) (!strcmp("sh_udc", (g)->name)) -#else -#define gadget_is_sh(g) 0 -#endif - -/* not yet stable on 2.6 (would help "original Zaurus") */ -#ifdef CONFIG_USB_GADGET_SA1100 -#define gadget_is_sa1100(g) (!strcmp("sa1100_udc", (g)->name)) -#else -#define gadget_is_sa1100(g) 0 -#endif - -/* handhelds.org tree (?) */ -#ifdef CONFIG_USB_GADGET_MQ11XX -#define gadget_is_mq11xx(g) (!strcmp("mq11xx_udc", (g)->name)) -#else -#define gadget_is_mq11xx(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_OMAP -#define gadget_is_omap(g) (!strcmp("omap_udc", (g)->name)) -#else -#define gadget_is_omap(g) 0 -#endif - -/* not yet ported 2.4 --> 2.6 */ -#ifdef CONFIG_USB_GADGET_N9604 -#define gadget_is_n9604(g) (!strcmp("n9604_udc", (g)->name)) -#else -#define gadget_is_n9604(g) 0 -#endif - -/* various unstable versions available */ -#ifdef CONFIG_USB_GADGET_PXA27X -#define gadget_is_pxa27x(g) (!strcmp("pxa27x_udc", (g)->name)) -#else -#define gadget_is_pxa27x(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_ATMEL_USBA -#define gadget_is_atmel_usba(g) (!strcmp("atmel_usba_udc", (g)->name)) -#else -#define gadget_is_atmel_usba(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_S3C2410 -#define gadget_is_s3c2410(g) (!strcmp("s3c2410_udc", (g)->name)) -#else -#define gadget_is_s3c2410(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_AT91 -#define gadget_is_at91(g) (!strcmp("at91_udc", (g)->name)) -#else -#define gadget_is_at91(g) 0 -#endif - -/* status unclear */ -#ifdef CONFIG_USB_GADGET_IMX -#define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) -#else -#define gadget_is_imx(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_FSL_USB2 -#define gadget_is_fsl_usb2(g) (!strcmp("fsl-usb2-udc", (g)->name)) -#else -#define gadget_is_fsl_usb2(g) 0 -#endif - -/* Mentor high speed function controller */ -/* from Montavista kernel (?) */ -#ifdef CONFIG_USB_GADGET_MUSBHSFC -#define gadget_is_musbhsfc(g) (!strcmp("musbhsfc_udc", (g)->name)) -#else -#define gadget_is_musbhsfc(g) 0 -#endif - -/* Mentor high speed "dual role" controller, in peripheral role */ -#ifdef CONFIG_MUSB_GADGET -#define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) -#else -#define gadget_is_musbhdrc(g) 0 -#endif - -/* from Montavista kernel (?) */ -#ifdef CONFIG_USB_GADGET_MPC8272 -#define gadget_is_mpc8272(g) (!strcmp("mpc8272_udc", (g)->name)) -#else -#define gadget_is_mpc8272(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_M66592 -#define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) -#else -#define gadget_is_m66592(g) 0 -#endif - -#ifdef CONFIG_CI_UDC -#define gadget_is_ci(g) (!strcmp("ci_udc", (g)->name)) -#else -#define gadget_is_ci(g) 0 -#endif - -#ifdef CONFIG_USB_GADGET_FOTG210 -#define gadget_is_fotg210(g) (!strcmp("fotg210_udc", (g)->name)) -#else -#define gadget_is_fotg210(g) 0 -#endif - -/* - * CONFIG_USB_GADGET_SX2 - * CONFIG_USB_GADGET_AU1X00 - * ... - */ - -/** - * usb_gadget_controller_number - support bcdDevice id convention - * @gadget: the controller being driven - * - * Return a 2-digit BCD value associated with the peripheral controller, - * suitable for use as part of a bcdDevice value, or a negative error code. - * - * NOTE: this convention is purely optional, and has no meaning in terms of - * any USB specification. If you want to use a different convention in your - * gadget driver firmware -- maybe a more formal revision ID -- feel free. - * - * Hosts see these bcdDevice numbers, and are allowed (but not encouraged!) - * to change their behavior accordingly. For example it might help avoiding - * some chip bug. - */ -static inline int usb_gadget_controller_number(struct usb_gadget *gadget) -{ - if (gadget_is_net2280(gadget)) - return 0x01; - else if (gadget_is_dummy(gadget)) - return 0x02; - else if (gadget_is_pxa(gadget)) - return 0x03; - else if (gadget_is_sh(gadget)) - return 0x04; - else if (gadget_is_sa1100(gadget)) - return 0x05; - else if (gadget_is_goku(gadget)) - return 0x06; - else if (gadget_is_mq11xx(gadget)) - return 0x07; - else if (gadget_is_omap(gadget)) - return 0x08; - else if (gadget_is_n9604(gadget)) - return 0x09; - else if (gadget_is_pxa27x(gadget)) - return 0x10; - else if (gadget_is_s3c2410(gadget)) - return 0x11; - else if (gadget_is_at91(gadget)) - return 0x12; - else if (gadget_is_imx(gadget)) - return 0x13; - else if (gadget_is_musbhsfc(gadget)) - return 0x14; - else if (gadget_is_musbhdrc(gadget)) - return 0x15; - else if (gadget_is_mpc8272(gadget)) - return 0x16; - else if (gadget_is_atmel_usba(gadget)) - return 0x17; - else if (gadget_is_fsl_usb2(gadget)) - return 0x18; - else if (gadget_is_amd5536udc(gadget)) - return 0x19; - else if (gadget_is_m66592(gadget)) - return 0x20; - else if (gadget_is_ci(gadget)) - return 0x21; - else if (gadget_is_fotg210(gadget)) - return 0x22; - return -ENOENT; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/mpc8xx_udc.c b/qemu/roms/u-boot/drivers/usb/gadget/mpc8xx_udc.c deleted file mode 100644 index 7f72972dc..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/mpc8xx_udc.c +++ /dev/null @@ -1,1386 +0,0 @@ -/* - * Copyright (C) 2006 by Bryan O'Donoghue, CodeHermit - * bodonoghue@CodeHermit.ie - * - * References - * DasUBoot/drivers/usb/gadget/omap1510_udc.c, for design and implementation - * ideas. - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -/* - * Notes : - * 1. #define __SIMULATE_ERROR__ to inject a CRC error into every 2nd TX - * packet to force the USB re-transmit protocol. - * - * 2. #define __DEBUG_UDC__ to switch on debug tracing to serial console - * be careful that tracing doesn't create Hiesen-bugs with respect to - * response timeouts to control requests. - * - * 3. This driver should be able to support any higher level driver that - * that wants to do either of the two standard UDC implementations - * Control-Bulk-Interrupt or Bulk-IN/Bulk-Out standards. Hence - * gserial and cdc_acm should work with this code. - * - * 4. NAK events never actually get raised at all, the documentation - * is just wrong ! - * - * 5. For some reason, cbd_datlen is *always* +2 the value it should be. - * this means that having an RX cbd of 16 bytes is not possible, since - * the same size is reported for 14 bytes received as 16 bytes received - * until we can find out why this happens, RX cbds must be limited to 8 - * bytes. TODO: check errata for this behaviour. - * - * 6. Right now this code doesn't support properly powering up with the USB - * cable attached to the USB host my development board the Adder87x doesn't - * have a pull-up fitted to allow this, so it is necessary to power the - * board and *then* attached the USB cable to the host. However somebody - * with a different design in their board may be able to keep the cable - * constantly connected and simply enable/disable a pull-up re - * figure 31.1 in MPC885RM.pdf instead of having to power up the board and - * then attach the cable ! - * - */ -#include <common.h> -#include <config.h> -#include <commproc.h> -#include <usbdevice.h> -#include <usb/mpc8xx_udc.h> -#include <usb/udc.h> - -#include "ep0.h" - -DECLARE_GLOBAL_DATA_PTR; - -#define ERR(fmt, args...)\ - serial_printf("ERROR : [%s] %s:%d: "fmt,\ - __FILE__,__FUNCTION__,__LINE__, ##args) -#ifdef __DEBUG_UDC__ -#define DBG(fmt,args...)\ - serial_printf("[%s] %s:%d: "fmt,\ - __FILE__,__FUNCTION__,__LINE__, ##args) -#else -#define DBG(fmt,args...) -#endif - -/* Static Data */ -#ifdef __SIMULATE_ERROR__ -static char err_poison_test = 0; -#endif -static struct mpc8xx_ep ep_ref[MAX_ENDPOINTS]; -static u32 address_base = STATE_NOT_READY; -static mpc8xx_udc_state_t udc_state = 0; -static struct usb_device_instance *udc_device = 0; -static volatile usb_epb_t *endpoints[MAX_ENDPOINTS]; -static volatile cbd_t *tx_cbd[TX_RING_SIZE]; -static volatile cbd_t *rx_cbd[RX_RING_SIZE]; -static volatile immap_t *immr = 0; -static volatile cpm8xx_t *cp = 0; -static volatile usb_pram_t *usb_paramp = 0; -static volatile usb_t *usbp = 0; -static int rx_ct = 0; -static int tx_ct = 0; - -/* Static Function Declarations */ -static void mpc8xx_udc_state_transition_up (usb_device_state_t initial, - usb_device_state_t final); -static void mpc8xx_udc_state_transition_down (usb_device_state_t initial, - usb_device_state_t final); -static void mpc8xx_udc_stall (unsigned int ep); -static void mpc8xx_udc_flush_tx_fifo (int epid); -static void mpc8xx_udc_flush_rx_fifo (void); -static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp); -static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi, - struct urb *tx_urb); -static void mpc8xx_udc_dump_request (struct usb_device_request *request); -static void mpc8xx_udc_clock_init (volatile immap_t * immr, - volatile cpm8xx_t * cp); -static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi); -static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp); -static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp); -static void mpc8xx_udc_cbd_init (void); -static void mpc8xx_udc_endpoint_init (void); -static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size); -static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment); -static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp); -static void mpc8xx_udc_set_nak (unsigned int ep); -static short mpc8xx_udc_handle_txerr (void); -static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid); - -/****************************************************************************** - Global Linkage - *****************************************************************************/ - -/* udc_init - * - * Do initial bus gluing - */ -int udc_init (void) -{ - /* Init various pointers */ - immr = (immap_t *) CONFIG_SYS_IMMR; - cp = (cpm8xx_t *) & (immr->im_cpm); - usb_paramp = (usb_pram_t *) & (cp->cp_dparam[PROFF_USB]); - usbp = (usb_t *) & (cp->cp_scc[0]); - - memset (ep_ref, 0x00, (sizeof (struct mpc8xx_ep) * MAX_ENDPOINTS)); - - udc_device = 0; - udc_state = STATE_NOT_READY; - - usbp->usmod = 0x00; - usbp->uscom = 0; - - /* Set USB Frame #0, Respond at Address & Get a clock source */ - usbp->usaddr = 0x00; - mpc8xx_udc_clock_init (immr, cp); - - /* PA15, PA14 as perhiperal USBRXD and USBOE */ - immr->im_ioport.iop_padir &= ~0x0003; - immr->im_ioport.iop_papar |= 0x0003; - - /* PC11/PC10 as peripheral USBRXP USBRXN */ - immr->im_ioport.iop_pcso |= 0x0030; - - /* PC7/PC6 as perhiperal USBTXP and USBTXN */ - immr->im_ioport.iop_pcdir |= 0x0300; - immr->im_ioport.iop_pcpar |= 0x0300; - - /* Set the base address */ - address_base = (u32) (cp->cp_dpmem + CPM_USB_BASE); - - /* Initialise endpoints and circular buffers */ - mpc8xx_udc_endpoint_init (); - mpc8xx_udc_cbd_init (); - - /* Assign allocated Dual Port Endpoint descriptors */ - usb_paramp->ep0ptr = (u32) endpoints[0]; - usb_paramp->ep1ptr = (u32) endpoints[1]; - usb_paramp->ep2ptr = (u32) endpoints[2]; - usb_paramp->ep3ptr = (u32) endpoints[3]; - usb_paramp->frame_n = 0; - - DBG ("ep0ptr=0x%08x ep1ptr=0x%08x ep2ptr=0x%08x ep3ptr=0x%08x\n", - usb_paramp->ep0ptr, usb_paramp->ep1ptr, usb_paramp->ep2ptr, - usb_paramp->ep3ptr); - - return 0; -} - -/* udc_irq - * - * Poll for whatever events may have occured - */ -void udc_irq (void) -{ - int epid = 0; - volatile cbd_t *rx_cbdp = 0; - volatile cbd_t *rx_cbdp_base = 0; - - if (udc_state != STATE_READY) { - return; - } - - if (usbp->usber & USB_E_BSY) { - /* This shouldn't happen. If it does then it's a bug ! */ - usbp->usber |= USB_E_BSY; - mpc8xx_udc_flush_rx_fifo (); - } - - /* Scan all RX/Bidirectional Endpoints for RX data. */ - for (epid = 0; epid < MAX_ENDPOINTS; epid++) { - if (!ep_ref[epid].prx) { - continue; - } - rx_cbdp = rx_cbdp_base = ep_ref[epid].prx; - - do { - if (!(rx_cbdp->cbd_sc & RX_BD_E)) { - - if (rx_cbdp->cbd_sc & 0x1F) { - /* Corrupt data discard it. - * Controller has NAK'd this packet. - */ - mpc8xx_udc_clear_rxbd (rx_cbdp); - - } else { - if (!epid) { - mpc8xx_udc_ep0_rx (rx_cbdp); - - } else { - /* Process data */ - mpc8xx_udc_set_nak (epid); - mpc8xx_udc_epn_rx (epid, rx_cbdp); - mpc8xx_udc_clear_rxbd (rx_cbdp); - } - } - - /* Advance RX CBD pointer */ - mpc8xx_udc_advance_rx (&rx_cbdp, epid); - ep_ref[epid].prx = rx_cbdp; - } else { - /* Advance RX CBD pointer */ - mpc8xx_udc_advance_rx (&rx_cbdp, epid); - } - - } while (rx_cbdp != rx_cbdp_base); - } - - /* Handle TX events as appropiate, the correct place to do this is - * in a tx routine. Perhaps TX on epn was pre-empted by ep0 - */ - - if (usbp->usber & USB_E_TXB) { - usbp->usber |= USB_E_TXB; - } - - if (usbp->usber & (USB_TX_ERRMASK)) { - mpc8xx_udc_handle_txerr (); - } - - /* Switch to the default state, respond at the default address */ - if (usbp->usber & USB_E_RESET) { - usbp->usber |= USB_E_RESET; - usbp->usaddr = 0x00; - udc_device->device_state = STATE_DEFAULT; - } - - /* if(usbp->usber&USB_E_IDLE){ - We could suspend here ! - usbp->usber|=USB_E_IDLE; - DBG("idle state change\n"); - } - if(usbp->usbs){ - We could resume here when IDLE is deasserted ! - Not worth doing, so long as we are self powered though. - } - */ - - return; -} - -/* udc_endpoint_write - * - * Write some data to an endpoint - */ -int udc_endpoint_write (struct usb_endpoint_instance *epi) -{ - int ep = 0; - short epid = 1, unnak = 0, ret = 0; - - if (udc_state != STATE_READY) { - ERR ("invalid udc_state != STATE_READY!\n"); - return -1; - } - - if (!udc_device || !epi) { - return -1; - } - - if (udc_device->device_state != STATE_CONFIGURED) { - return -1; - } - - ep = epi->endpoint_address & 0x03; - if (ep >= MAX_ENDPOINTS) { - return -1; - } - - /* Set NAK for all RX endpoints during TX */ - for (epid = 1; epid < MAX_ENDPOINTS; epid++) { - - /* Don't set NAK on DATA IN/CONTROL endpoints */ - if (ep_ref[epid].sc & USB_DIR_IN) { - continue; - } - - if (!(usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK))) { - unnak |= 1 << epid; - } - - mpc8xx_udc_set_nak (epid); - } - - mpc8xx_udc_init_tx (&udc_device->bus->endpoint_array[ep], - epi->tx_urb); - ret = mpc8xx_udc_ep_tx (&udc_device->bus->endpoint_array[ep]); - - /* Remove temporary NAK */ - for (epid = 1; epid < MAX_ENDPOINTS; epid++) { - if (unnak & (1 << epid)) { - udc_unset_nak (epid); - } - } - - return ret; -} - -/* mpc8xx_udc_assign_urb - * - * Associate a given urb to an endpoint TX or RX transmit/receive buffers - */ -static int mpc8xx_udc_assign_urb (int ep, char direction) -{ - struct usb_endpoint_instance *epi = 0; - - if (ep >= MAX_ENDPOINTS) { - goto err; - } - epi = &udc_device->bus->endpoint_array[ep]; - if (!epi) { - goto err; - } - - if (!ep_ref[ep].urb) { - ep_ref[ep].urb = usbd_alloc_urb (udc_device, udc_device->bus->endpoint_array); - if (!ep_ref[ep].urb) { - goto err; - } - } else { - ep_ref[ep].urb->actual_length = 0; - } - - switch (direction) { - case USB_DIR_IN: - epi->tx_urb = ep_ref[ep].urb; - break; - case USB_DIR_OUT: - epi->rcv_urb = ep_ref[ep].urb; - break; - default: - goto err; - } - return 0; - - err: - udc_state = STATE_ERROR; - return -1; -} - -/* udc_setup_ep - * - * Associate U-Boot software endpoints to mpc8xx endpoint parameter ram - * Isochronous endpoints aren't yet supported! - */ -void udc_setup_ep (struct usb_device_instance *device, unsigned int ep, - struct usb_endpoint_instance *epi) -{ - uchar direction = 0; - int ep_attrib = 0; - - if (epi && (ep < MAX_ENDPOINTS)) { - - if (ep == 0) { - if (epi->rcv_attributes != USB_ENDPOINT_XFER_CONTROL - || epi->tx_attributes != - USB_ENDPOINT_XFER_CONTROL) { - - /* ep0 must be a control endpoint */ - udc_state = STATE_ERROR; - return; - - } - if (!(ep_ref[ep].sc & EP_ATTACHED)) { - mpc8xx_udc_cbd_attach (ep, epi->tx_packetSize, - epi->rcv_packetSize); - } - usbp->usep[ep] = 0x0000; - return; - } - - if ((epi->endpoint_address & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) { - - direction = 1; - ep_attrib = epi->tx_attributes; - epi->rcv_packetSize = 0; - ep_ref[ep].sc |= USB_DIR_IN; - } else { - - direction = 0; - ep_attrib = epi->rcv_attributes; - epi->tx_packetSize = 0; - ep_ref[ep].sc &= ~USB_DIR_IN; - } - - if (mpc8xx_udc_assign_urb (ep, epi->endpoint_address - & USB_ENDPOINT_DIR_MASK)) { - return; - } - - switch (ep_attrib) { - case USB_ENDPOINT_XFER_CONTROL: - if (!(ep_ref[ep].sc & EP_ATTACHED)) { - mpc8xx_udc_cbd_attach (ep, - epi->tx_packetSize, - epi->rcv_packetSize); - } - usbp->usep[ep] = ep << 12; - epi->rcv_urb = epi->tx_urb = ep_ref[ep].urb; - - break; - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - if (!(ep_ref[ep].sc & EP_ATTACHED)) { - if (direction) { - mpc8xx_udc_cbd_attach (ep, - epi->tx_packetSize, - 0); - } else { - mpc8xx_udc_cbd_attach (ep, - 0, - epi->rcv_packetSize); - } - } - usbp->usep[ep] = (ep << 12) | ((ep_attrib) << 8); - - break; - case USB_ENDPOINT_XFER_ISOC: - default: - serial_printf ("Error endpoint attrib %d>3\n", ep_attrib); - udc_state = STATE_ERROR; - break; - } - } - -} - -/* udc_connect - * - * Move state, switch on the USB - */ -void udc_connect (void) -{ - /* Enable pull-up resistor on D+ - * TODO: fit a pull-up resistor to drive SE0 for > 2.5us - */ - - if (udc_state != STATE_ERROR) { - udc_state = STATE_READY; - usbp->usmod |= USMOD_EN; - } -} - -/* udc_disconnect - * - * Disconnect is not used but, is included for completeness - */ -void udc_disconnect (void) -{ - /* Disable pull-up resistor on D- - * TODO: fix a pullup resistor to control this - */ - - if (udc_state != STATE_ERROR) { - udc_state = STATE_NOT_READY; - } - usbp->usmod &= ~USMOD_EN; -} - -/* udc_enable - * - * Grab an EP0 URB, register interest in a subset of USB events - */ -void udc_enable (struct usb_device_instance *device) -{ - if (udc_state == STATE_ERROR) { - return; - } - - udc_device = device; - - if (!ep_ref[0].urb) { - ep_ref[0].urb = usbd_alloc_urb (device, device->bus->endpoint_array); - } - - /* Register interest in all events except SOF, enable transceiver */ - usbp->usber = 0x03FF; - usbp->usbmr = 0x02F7; - - return; -} - -/* udc_disable - * - * disable the currently hooked device - */ -void udc_disable (void) -{ - int i = 0; - - if (udc_state == STATE_ERROR) { - DBG ("Won't disable UDC. udc_state==STATE_ERROR !\n"); - return; - } - - udc_device = 0; - - for (; i < MAX_ENDPOINTS; i++) { - if (ep_ref[i].urb) { - usbd_dealloc_urb (ep_ref[i].urb); - ep_ref[i].urb = 0; - } - } - - usbp->usbmr = 0x00; - usbp->usmod = ~USMOD_EN; - udc_state = STATE_NOT_READY; -} - -/* udc_startup_events - * - * Enable the specified device - */ -void udc_startup_events (struct usb_device_instance *device) -{ - udc_enable (device); - if (udc_state == STATE_READY) { - usbd_device_event_irq (device, DEVICE_CREATE, 0); - } -} - -/* udc_set_nak - * - * Allow upper layers to signal lower layers should not accept more RX data - * - */ -void udc_set_nak (int epid) -{ - if (epid) { - mpc8xx_udc_set_nak (epid); - } -} - -/* udc_unset_nak - * - * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint. - * Switch off NAKing on this endpoint to accept more data output from host. - * - */ -void udc_unset_nak (int epid) -{ - if (epid > MAX_ENDPOINTS) { - return; - } - - if (usbp->usep[epid] & (USEP_THS_NAK | USEP_RHS_NAK)) { - usbp->usep[epid] &= ~(USEP_THS_NAK | USEP_RHS_NAK); - __asm__ ("eieio"); - } -} - -/****************************************************************************** - Static Linkage -******************************************************************************/ - -/* udc_state_transition_up - * udc_state_transition_down - * - * Helper functions to implement device state changes. The device states and - * the events that transition between them are: - * - * STATE_ATTACHED - * || /\ - * \/ || - * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET - * || /\ - * \/ || - * STATE_POWERED - * || /\ - * \/ || - * DEVICE_RESET DEVICE_POWER_INTERRUPTION - * || /\ - * \/ || - * STATE_DEFAULT - * || /\ - * \/ || - * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET - * || /\ - * \/ || - * STATE_ADDRESSED - * || /\ - * \/ || - * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED - * || /\ - * \/ || - * STATE_CONFIGURED - * - * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED - * to STATE_CONFIGURED) from the specified initial state to the specified final - * state, passing through each intermediate state on the way. If the initial - * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then - * no state transitions will take place. - * - * udc_state_transition_down transitions down (in the direction from - * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the - * specified final state, passing through each intermediate state on the way. - * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final - * state, then no state transitions will take place. - * - */ - -static void mpc8xx_udc_state_transition_up (usb_device_state_t initial, - usb_device_state_t final) -{ - if (initial < final) { - switch (initial) { - case STATE_ATTACHED: - usbd_device_event_irq (udc_device, - DEVICE_HUB_CONFIGURED, 0); - if (final == STATE_POWERED) - break; - case STATE_POWERED: - usbd_device_event_irq (udc_device, DEVICE_RESET, 0); - if (final == STATE_DEFAULT) - break; - case STATE_DEFAULT: - usbd_device_event_irq (udc_device, - DEVICE_ADDRESS_ASSIGNED, 0); - if (final == STATE_ADDRESSED) - break; - case STATE_ADDRESSED: - usbd_device_event_irq (udc_device, DEVICE_CONFIGURED, - 0); - case STATE_CONFIGURED: - break; - default: - break; - } - } -} - -static void mpc8xx_udc_state_transition_down (usb_device_state_t initial, - usb_device_state_t final) -{ - if (initial > final) { - switch (initial) { - case STATE_CONFIGURED: - usbd_device_event_irq (udc_device, - DEVICE_DE_CONFIGURED, 0); - if (final == STATE_ADDRESSED) - break; - case STATE_ADDRESSED: - usbd_device_event_irq (udc_device, DEVICE_RESET, 0); - if (final == STATE_DEFAULT) - break; - case STATE_DEFAULT: - usbd_device_event_irq (udc_device, - DEVICE_POWER_INTERRUPTION, 0); - if (final == STATE_POWERED) - break; - case STATE_POWERED: - usbd_device_event_irq (udc_device, DEVICE_HUB_RESET, - 0); - case STATE_ATTACHED: - break; - default: - break; - } - } -} - -/* mpc8xx_udc_stall - * - * Force returning of STALL tokens on the given endpoint. Protocol or function - * STALL conditions are permissable here - */ -static void mpc8xx_udc_stall (unsigned int ep) -{ - usbp->usep[ep] |= STALL_BITMASK; -} - -/* mpc8xx_udc_set_nak - * - * Force returning of NAK responses for the given endpoint as a kind of very - * simple flow control - */ -static void mpc8xx_udc_set_nak (unsigned int ep) -{ - usbp->usep[ep] |= NAK_BITMASK; - __asm__ ("eieio"); -} - -/* mpc8xx_udc_handle_txerr - * - * Handle errors relevant to TX. Return a status code to allow calling - * indicative of what if anything happened - */ -static short mpc8xx_udc_handle_txerr () -{ - short ep = 0, ret = 0; - - for (; ep < TX_RING_SIZE; ep++) { - if (usbp->usber & (0x10 << ep)) { - - /* Timeout or underrun */ - if (tx_cbd[ep]->cbd_sc & 0x06) { - ret = 1; - mpc8xx_udc_flush_tx_fifo (ep); - - } else { - if (usbp->usep[ep] & STALL_BITMASK) { - if (!ep) { - usbp->usep[ep] &= ~STALL_BITMASK; - } - } /* else NAK */ - } - usbp->usber |= (0x10 << ep); - } - } - return ret; -} - -/* mpc8xx_udc_advance_rx - * - * Advance cbd rx - */ -static void mpc8xx_udc_advance_rx (volatile cbd_t ** rx_cbdp, int epid) -{ - if ((*rx_cbdp)->cbd_sc & RX_BD_W) { - *rx_cbdp = (volatile cbd_t *) (endpoints[epid]->rbase + CONFIG_SYS_IMMR); - - } else { - (*rx_cbdp)++; - } -} - - -/* mpc8xx_udc_flush_tx_fifo - * - * Flush a given TX fifo. Assumes one tx cbd per endpoint - */ -static void mpc8xx_udc_flush_tx_fifo (int epid) -{ - volatile cbd_t *tx_cbdp = 0; - - if (epid > MAX_ENDPOINTS) { - return; - } - - /* TX stop */ - immr->im_cpm.cp_cpcr = ((epid << 2) | 0x1D01); - __asm__ ("eieio"); - while (immr->im_cpm.cp_cpcr & 0x01); - - usbp->uscom = 0x40 | 0; - - /* reset ring */ - tx_cbdp = (cbd_t *) (endpoints[epid]->tbptr + CONFIG_SYS_IMMR); - tx_cbdp->cbd_sc = (TX_BD_I | TX_BD_W); - - - endpoints[epid]->tptr = endpoints[epid]->tbase; - endpoints[epid]->tstate = 0x00; - endpoints[epid]->tbcnt = 0x00; - - /* TX start */ - immr->im_cpm.cp_cpcr = ((epid << 2) | 0x2D01); - __asm__ ("eieio"); - while (immr->im_cpm.cp_cpcr & 0x01); - - return; -} - -/* mpc8xx_udc_flush_rx_fifo - * - * For the sake of completeness of the namespace, it seems like - * a good-design-decision (tm) to include mpc8xx_udc_flush_rx_fifo(); - * If RX_BD_E is true => a driver bug either here or in an upper layer - * not polling frequently enough. If RX_BD_E is true we have told the host - * we have accepted data but, the CPM found it had no-where to put that data - * which needless to say would be a bad thing. - */ -static void mpc8xx_udc_flush_rx_fifo () -{ - int i = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) { - ERR ("buf %p used rx data len = 0x%x sc=0x%x!\n", - rx_cbd[i], rx_cbd[i]->cbd_datlen, - rx_cbd[i]->cbd_sc); - - } - } - ERR ("BUG : Input over-run\n"); -} - -/* mpc8xx_udc_clear_rxbd - * - * Release control of RX CBD to CP. - */ -static void mpc8xx_udc_clear_rxbd (volatile cbd_t * rx_cbdp) -{ - rx_cbdp->cbd_datlen = 0x0000; - rx_cbdp->cbd_sc = ((rx_cbdp->cbd_sc & RX_BD_W) | (RX_BD_E | RX_BD_I)); - __asm__ ("eieio"); -} - -/* mpc8xx_udc_tx_irq - * - * Parse for tx timeout, control RX or USB reset/busy conditions - * Return -1 on timeout, -2 on fatal error, else return zero - */ -static int mpc8xx_udc_tx_irq (int ep) -{ - int i = 0; - - if (usbp->usber & (USB_TX_ERRMASK)) { - if (mpc8xx_udc_handle_txerr ()) { - /* Timeout, controlling function must retry send */ - return -1; - } - } - - if (usbp->usber & (USB_E_RESET | USB_E_BSY)) { - /* Fatal, abandon TX transaction */ - return -2; - } - - if (usbp->usber & USB_E_RXB) { - for (i = 0; i < RX_RING_SIZE; i++) { - if (!(rx_cbd[i]->cbd_sc & RX_BD_E)) { - if ((rx_cbd[i] == ep_ref[0].prx) || ep) { - return -2; - } - } - } - } - - return 0; -} - -/* mpc8xx_udc_ep_tx - * - * Transmit in a re-entrant fashion outbound USB packets. - * Implement retry/timeout mechanism described in USB specification - * Toggle DATA0/DATA1 pids as necessary - * Introduces non-standard tx_retry. The USB standard has no scope for slave - * devices to give up TX, however tx_retry stops us getting stuck in an endless - * TX loop. - */ -static int mpc8xx_udc_ep_tx (struct usb_endpoint_instance *epi) -{ - struct urb *urb = epi->tx_urb; - volatile cbd_t *tx_cbdp = 0; - unsigned int ep = 0, pkt_len = 0, x = 0, tx_retry = 0; - int ret = 0; - - if (!epi || (epi->endpoint_address & 0x03) >= MAX_ENDPOINTS || !urb) { - return -1; - } - - ep = epi->endpoint_address & 0x03; - tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CONFIG_SYS_IMMR); - - if (tx_cbdp->cbd_sc & TX_BD_R || usbp->usber & USB_E_TXB) { - mpc8xx_udc_flush_tx_fifo (ep); - usbp->usber |= USB_E_TXB; - }; - - while (tx_retry++ < 100) { - ret = mpc8xx_udc_tx_irq (ep); - if (ret == -1) { - /* ignore timeout here */ - } else if (ret == -2) { - /* Abandon TX */ - mpc8xx_udc_flush_tx_fifo (ep); - return -1; - } - - tx_cbdp = (cbd_t *) (endpoints[ep]->tbptr + CONFIG_SYS_IMMR); - while (tx_cbdp->cbd_sc & TX_BD_R) { - }; - tx_cbdp->cbd_sc = (tx_cbdp->cbd_sc & TX_BD_W); - - pkt_len = urb->actual_length - epi->sent; - - if (pkt_len > epi->tx_packetSize || pkt_len > EP_MAX_PKT) { - pkt_len = MIN (epi->tx_packetSize, EP_MAX_PKT); - } - - for (x = 0; x < pkt_len; x++) { - *((unsigned char *) (tx_cbdp->cbd_bufaddr + x)) = - urb->buffer[epi->sent + x]; - } - tx_cbdp->cbd_datlen = pkt_len; - tx_cbdp->cbd_sc |= (CBD_TX_BITMASK | ep_ref[ep].pid); - __asm__ ("eieio"); - -#ifdef __SIMULATE_ERROR__ - if (++err_poison_test == 2) { - err_poison_test = 0; - tx_cbdp->cbd_sc &= ~TX_BD_TC; - } -#endif - - usbp->uscom = (USCOM_STR | ep); - - while (!(usbp->usber & USB_E_TXB)) { - ret = mpc8xx_udc_tx_irq (ep); - if (ret == -1) { - /* TX timeout */ - break; - } else if (ret == -2) { - if (usbp->usber & USB_E_TXB) { - usbp->usber |= USB_E_TXB; - } - mpc8xx_udc_flush_tx_fifo (ep); - return -1; - } - }; - - if (usbp->usber & USB_E_TXB) { - usbp->usber |= USB_E_TXB; - } - - /* ACK must be present <= 18bit times from TX */ - if (ret == -1) { - continue; - } - - /* TX ACK : USB 2.0 8.7.2, Toggle PID, Advance TX */ - epi->sent += pkt_len; - epi->last = MIN (urb->actual_length - epi->sent, epi->tx_packetSize); - TOGGLE_TX_PID (ep_ref[ep].pid); - - if (epi->sent >= epi->tx_urb->actual_length) { - - epi->tx_urb->actual_length = 0; - epi->sent = 0; - - if (ep_ref[ep].sc & EP_SEND_ZLP) { - ep_ref[ep].sc &= ~EP_SEND_ZLP; - } else { - return 0; - } - } - } - - ERR ("TX fail, endpoint 0x%x tx bytes 0x%x/0x%x\n", ep, epi->sent, - epi->tx_urb->actual_length); - - return -1; -} - -/* mpc8xx_udc_dump_request - * - * Dump a control request to console - */ -static void mpc8xx_udc_dump_request (struct usb_device_request *request) -{ - DBG ("bmRequestType:%02x bRequest:%02x wValue:%04x " - "wIndex:%04x wLength:%04x ?\n", - request->bmRequestType, - request->bRequest, - request->wValue, request->wIndex, request->wLength); - - return; -} - -/* mpc8xx_udc_ep0_rx_setup - * - * Decode received ep0 SETUP packet. return non-zero on error - */ -static int mpc8xx_udc_ep0_rx_setup (volatile cbd_t * rx_cbdp) -{ - unsigned int x = 0; - struct urb *purb = ep_ref[0].urb; - struct usb_endpoint_instance *epi = - &udc_device->bus->endpoint_array[0]; - - for (; x < rx_cbdp->cbd_datlen; x++) { - *(((unsigned char *) &ep_ref[0].urb->device_request) + x) = - *((unsigned char *) (rx_cbdp->cbd_bufaddr + x)); - } - - mpc8xx_udc_clear_rxbd (rx_cbdp); - - if (ep0_recv_setup (purb)) { - mpc8xx_udc_dump_request (&purb->device_request); - return -1; - } - - if ((purb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) - == USB_REQ_HOST2DEVICE) { - - switch (purb->device_request.bRequest) { - case USB_REQ_SET_ADDRESS: - /* Send the Status OUT ZLP */ - ep_ref[0].pid = TX_BD_PID_DATA1; - purb->actual_length = 0; - mpc8xx_udc_init_tx (epi, purb); - mpc8xx_udc_ep_tx (epi); - - /* Move to the addressed state */ - usbp->usaddr = udc_device->address; - mpc8xx_udc_state_transition_up (udc_device->device_state, - STATE_ADDRESSED); - return 0; - - case USB_REQ_SET_CONFIGURATION: - if (!purb->device_request.wValue) { - /* Respond at default address */ - usbp->usaddr = 0x00; - mpc8xx_udc_state_transition_down (udc_device->device_state, - STATE_ADDRESSED); - } else { - /* TODO: Support multiple configurations */ - mpc8xx_udc_state_transition_up (udc_device->device_state, - STATE_CONFIGURED); - for (x = 1; x < MAX_ENDPOINTS; x++) { - if ((udc_device->bus->endpoint_array[x].endpoint_address & USB_ENDPOINT_DIR_MASK) - == USB_DIR_IN) { - ep_ref[x].pid = TX_BD_PID_DATA0; - } else { - ep_ref[x].pid = RX_BD_PID_DATA0; - } - /* Set configuration must unstall endpoints */ - usbp->usep[x] &= ~STALL_BITMASK; - } - } - break; - default: - /* CDC/Vendor specific */ - break; - } - - /* Send ZLP as ACK in Status OUT phase */ - ep_ref[0].pid = TX_BD_PID_DATA1; - purb->actual_length = 0; - mpc8xx_udc_init_tx (epi, purb); - mpc8xx_udc_ep_tx (epi); - - } else { - - if (purb->actual_length) { - ep_ref[0].pid = TX_BD_PID_DATA1; - mpc8xx_udc_init_tx (epi, purb); - - if (!(purb->actual_length % EP0_MAX_PACKET_SIZE)) { - ep_ref[0].sc |= EP_SEND_ZLP; - } - - if (purb->device_request.wValue == - USB_DESCRIPTOR_TYPE_DEVICE) { - if (le16_to_cpu (purb->device_request.wLength) - > purb->actual_length) { - /* Send EP0_MAX_PACKET_SIZE bytes - * unless correct size requested. - */ - if (purb->actual_length > epi->tx_packetSize) { - purb->actual_length = epi->tx_packetSize; - } - } - } - mpc8xx_udc_ep_tx (epi); - - } else { - /* Corrupt SETUP packet? */ - ERR ("Zero length data or SETUP with DATA-IN phase ?\n"); - return 1; - } - } - return 0; -} - -/* mpc8xx_udc_init_tx - * - * Setup some basic parameters for a TX transaction - */ -static void mpc8xx_udc_init_tx (struct usb_endpoint_instance *epi, - struct urb *tx_urb) -{ - epi->sent = 0; - epi->last = 0; - epi->tx_urb = tx_urb; -} - -/* mpc8xx_udc_ep0_rx - * - * Receive ep0/control USB data. Parse and possibly send a response. - */ -static void mpc8xx_udc_ep0_rx (volatile cbd_t * rx_cbdp) -{ - if (rx_cbdp->cbd_sc & RX_BD_PID_SETUP) { - - /* Unconditionally accept SETUP packets */ - if (mpc8xx_udc_ep0_rx_setup (rx_cbdp)) { - mpc8xx_udc_stall (0); - } - - } else { - - mpc8xx_udc_clear_rxbd (rx_cbdp); - - if ((rx_cbdp->cbd_datlen - 2)) { - /* SETUP with a DATA phase - * outside of SETUP packet. - * Reply with STALL. - */ - mpc8xx_udc_stall (0); - } - } -} - -/* mpc8xx_udc_epn_rx - * - * Receive some data from cbd into USB system urb data abstraction - * Upper layers should NAK if there is insufficient RX data space - */ -static int mpc8xx_udc_epn_rx (unsigned int epid, volatile cbd_t * rx_cbdp) -{ - struct usb_endpoint_instance *epi = 0; - struct urb *urb = 0; - unsigned int x = 0; - - if (epid >= MAX_ENDPOINTS || !rx_cbdp->cbd_datlen) { - return 0; - } - - /* USB 2.0 PDF section 8.6.4 - * Discard data with invalid PID it is a resend. - */ - if (ep_ref[epid].pid != (rx_cbdp->cbd_sc & 0xC0)) { - return 1; - } - TOGGLE_RX_PID (ep_ref[epid].pid); - - epi = &udc_device->bus->endpoint_array[epid]; - urb = epi->rcv_urb; - - for (; x < (rx_cbdp->cbd_datlen - 2); x++) { - *((unsigned char *) (urb->buffer + urb->actual_length + x)) = - *((unsigned char *) (rx_cbdp->cbd_bufaddr + x)); - } - - if (x) { - usbd_rcv_complete (epi, x, 0); - if (ep_ref[epid].urb->status == RECV_ERROR) { - DBG ("RX error unset NAK\n"); - udc_unset_nak (epid); - } - } - return x; -} - -/* mpc8xx_udc_clock_init - * - * Obtain a clock reference for Full Speed Signaling - */ -static void mpc8xx_udc_clock_init (volatile immap_t * immr, - volatile cpm8xx_t * cp) -{ - -#if defined(CONFIG_SYS_USB_EXTC_CLK) - - /* This has been tested with a 48MHz crystal on CLK6 */ - switch (CONFIG_SYS_USB_EXTC_CLK) { - case 1: - immr->im_ioport.iop_papar |= 0x0100; - immr->im_ioport.iop_padir &= ~0x0100; - cp->cp_sicr |= 0x24; - break; - case 2: - immr->im_ioport.iop_papar |= 0x0200; - immr->im_ioport.iop_padir &= ~0x0200; - cp->cp_sicr |= 0x2D; - break; - case 3: - immr->im_ioport.iop_papar |= 0x0400; - immr->im_ioport.iop_padir &= ~0x0400; - cp->cp_sicr |= 0x36; - break; - case 4: - immr->im_ioport.iop_papar |= 0x0800; - immr->im_ioport.iop_padir &= ~0x0800; - cp->cp_sicr |= 0x3F; - break; - default: - udc_state = STATE_ERROR; - break; - } - -#elif defined(CONFIG_SYS_USB_BRGCLK) - - /* This has been tested with brgclk == 50MHz */ - int divisor = 0; - - if (gd->cpu_clk < 48000000L) { - ERR ("brgclk is too slow for full-speed USB!\n"); - udc_state = STATE_ERROR; - return; - } - - /* Assume the brgclk is 'good enough', we want !(gd->cpu_clk%48MHz) - * but, can /probably/ live with close-ish alternative rates. - */ - divisor = (gd->cpu_clk / 48000000L) - 1; - cp->cp_sicr &= ~0x0000003F; - - switch (CONFIG_SYS_USB_BRGCLK) { - case 1: - cp->cp_brgc1 |= (divisor | CPM_BRG_EN); - cp->cp_sicr &= ~0x2F; - break; - case 2: - cp->cp_brgc2 |= (divisor | CPM_BRG_EN); - cp->cp_sicr |= 0x00000009; - break; - case 3: - cp->cp_brgc3 |= (divisor | CPM_BRG_EN); - cp->cp_sicr |= 0x00000012; - break; - case 4: - cp->cp_brgc4 = (divisor | CPM_BRG_EN); - cp->cp_sicr |= 0x0000001B; - break; - default: - udc_state = STATE_ERROR; - break; - } - -#else -#error "CONFIG_SYS_USB_EXTC_CLK or CONFIG_SYS_USB_BRGCLK must be defined" -#endif - -} - -/* mpc8xx_udc_cbd_attach - * - * attach a cbd to and endpoint - */ -static void mpc8xx_udc_cbd_attach (int ep, uchar tx_size, uchar rx_size) -{ - - if (!tx_cbd[ep] || !rx_cbd[ep] || ep >= MAX_ENDPOINTS) { - udc_state = STATE_ERROR; - return; - } - - if (tx_size > USB_MAX_PKT || rx_size > USB_MAX_PKT || - (!tx_size && !rx_size)) { - udc_state = STATE_ERROR; - return; - } - - /* Attach CBD to appropiate Parameter RAM Endpoint data structure */ - if (rx_size) { - endpoints[ep]->rbase = (u32) rx_cbd[rx_ct]; - endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; - rx_ct++; - - if (!ep) { - - endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; - rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; - rx_ct++; - - } else { - rx_ct += 2; - endpoints[ep]->rbptr = (u32) rx_cbd[rx_ct]; - rx_cbd[rx_ct]->cbd_sc |= RX_BD_W; - rx_ct++; - } - - /* Where we expect to RX data on this endpoint */ - ep_ref[ep].prx = rx_cbd[rx_ct - 1]; - } else { - - ep_ref[ep].prx = 0; - endpoints[ep]->rbase = 0; - endpoints[ep]->rbptr = 0; - } - - if (tx_size) { - endpoints[ep]->tbase = (u32) tx_cbd[tx_ct]; - endpoints[ep]->tbptr = (u32) tx_cbd[tx_ct]; - tx_ct++; - } else { - endpoints[ep]->tbase = 0; - endpoints[ep]->tbptr = 0; - } - - endpoints[ep]->tstate = 0; - endpoints[ep]->tbcnt = 0; - endpoints[ep]->mrblr = EP_MAX_PKT; - endpoints[ep]->rfcr = 0x18; - endpoints[ep]->tfcr = 0x18; - ep_ref[ep].sc |= EP_ATTACHED; - - DBG ("ep %d rbase 0x%08x rbptr 0x%08x tbase 0x%08x tbptr 0x%08x prx = %p\n", - ep, endpoints[ep]->rbase, endpoints[ep]->rbptr, - endpoints[ep]->tbase, endpoints[ep]->tbptr, - ep_ref[ep].prx); - - return; -} - -/* mpc8xx_udc_cbd_init - * - * Allocate space for a cbd and allocate TX/RX data space - */ -static void mpc8xx_udc_cbd_init (void) -{ - int i = 0; - - for (; i < TX_RING_SIZE; i++) { - tx_cbd[i] = (cbd_t *) - mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int)); - } - - for (i = 0; i < RX_RING_SIZE; i++) { - rx_cbd[i] = (cbd_t *) - mpc8xx_udc_alloc (sizeof (cbd_t), sizeof (int)); - } - - for (i = 0; i < TX_RING_SIZE; i++) { - tx_cbd[i]->cbd_bufaddr = - mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int)); - - tx_cbd[i]->cbd_sc = (TX_BD_I | TX_BD_W); - tx_cbd[i]->cbd_datlen = 0x0000; - } - - - for (i = 0; i < RX_RING_SIZE; i++) { - rx_cbd[i]->cbd_bufaddr = - mpc8xx_udc_alloc (EP_MAX_PKT, sizeof (int)); - rx_cbd[i]->cbd_sc = (RX_BD_I | RX_BD_E); - rx_cbd[i]->cbd_datlen = 0x0000; - - } - - return; -} - -/* mpc8xx_udc_endpoint_init - * - * Attach an endpoint to some dpram - */ -static void mpc8xx_udc_endpoint_init (void) -{ - int i = 0; - - for (; i < MAX_ENDPOINTS; i++) { - endpoints[i] = (usb_epb_t *) - mpc8xx_udc_alloc (sizeof (usb_epb_t), 32); - } -} - -/* mpc8xx_udc_alloc - * - * Grab the address of some dpram - */ -static u32 mpc8xx_udc_alloc (u32 data_size, u32 alignment) -{ - u32 retaddr = address_base; - - while (retaddr % alignment) { - retaddr++; - } - address_base += data_size; - - return retaddr; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/ndis.h b/qemu/roms/u-boot/drivers/usb/gadget/ndis.h deleted file mode 100644 index 753838f79..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/ndis.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * ndis.h - * - * ntddndis.h modified by Benedikt Spranger <b.spranger@pengutronix.de> - * - * Thanks to the cygwin development team, - * espacially to Casper S. Hornstrup <chorns@users.sourceforge.net> - * - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#ifndef _USBGADGET_NDIS_H -#define _USBGADGET_NDIS_H - - -#define NDIS_STATUS_MULTICAST_FULL 0xC0010009 -#define NDIS_STATUS_MULTICAST_EXISTS 0xC001000A -#define NDIS_STATUS_MULTICAST_NOT_FOUND 0xC001000B - -enum NDIS_DEVICE_POWER_STATE { - NdisDeviceStateUnspecified = 0, - NdisDeviceStateD0, - NdisDeviceStateD1, - NdisDeviceStateD2, - NdisDeviceStateD3, - NdisDeviceStateMaximum -}; - -struct NDIS_PM_WAKE_UP_CAPABILITIES { - enum NDIS_DEVICE_POWER_STATE MinMagicPacketWakeUp; - enum NDIS_DEVICE_POWER_STATE MinPatternWakeUp; - enum NDIS_DEVICE_POWER_STATE MinLinkChangeWakeUp; -}; - -/* NDIS_PNP_CAPABILITIES.Flags constants */ -#define NDIS_DEVICE_WAKE_UP_ENABLE 0x00000001 -#define NDIS_DEVICE_WAKE_ON_PATTERN_MATCH_ENABLE 0x00000002 -#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004 - -struct NDIS_PNP_CAPABILITIES { - __le32 Flags; - struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities; -}; - -struct NDIS_PM_PACKET_PATTERN { - __le32 Priority; - __le32 Reserved; - __le32 MaskSize; - __le32 PatternOffset; - __le32 PatternSize; - __le32 PatternFlags; -}; - - -/* Required Object IDs (OIDs) */ -#define OID_GEN_SUPPORTED_LIST 0x00010101 -#define OID_GEN_HARDWARE_STATUS 0x00010102 -#define OID_GEN_MEDIA_SUPPORTED 0x00010103 -#define OID_GEN_MEDIA_IN_USE 0x00010104 -#define OID_GEN_MAXIMUM_LOOKAHEAD 0x00010105 -#define OID_GEN_MAXIMUM_FRAME_SIZE 0x00010106 -#define OID_GEN_LINK_SPEED 0x00010107 -#define OID_GEN_TRANSMIT_BUFFER_SPACE 0x00010108 -#define OID_GEN_RECEIVE_BUFFER_SPACE 0x00010109 -#define OID_GEN_TRANSMIT_BLOCK_SIZE 0x0001010A -#define OID_GEN_RECEIVE_BLOCK_SIZE 0x0001010B -#define OID_GEN_VENDOR_ID 0x0001010C -#define OID_GEN_VENDOR_DESCRIPTION 0x0001010D -#define OID_GEN_CURRENT_PACKET_FILTER 0x0001010E -#define OID_GEN_CURRENT_LOOKAHEAD 0x0001010F -#define OID_GEN_DRIVER_VERSION 0x00010110 -#define OID_GEN_MAXIMUM_TOTAL_SIZE 0x00010111 -#define OID_GEN_PROTOCOL_OPTIONS 0x00010112 -#define OID_GEN_MAC_OPTIONS 0x00010113 -#define OID_GEN_MEDIA_CONNECT_STATUS 0x00010114 -#define OID_GEN_MAXIMUM_SEND_PACKETS 0x00010115 -#define OID_GEN_VENDOR_DRIVER_VERSION 0x00010116 -#define OID_GEN_SUPPORTED_GUIDS 0x00010117 -#define OID_GEN_NETWORK_LAYER_ADDRESSES 0x00010118 -#define OID_GEN_TRANSPORT_HEADER_OFFSET 0x00010119 -#define OID_GEN_MACHINE_NAME 0x0001021A -#define OID_GEN_RNDIS_CONFIG_PARAMETER 0x0001021B -#define OID_GEN_VLAN_ID 0x0001021C - -/* Optional OIDs */ -#define OID_GEN_MEDIA_CAPABILITIES 0x00010201 -#define OID_GEN_PHYSICAL_MEDIUM 0x00010202 - -/* Required statistics OIDs */ -#define OID_GEN_XMIT_OK 0x00020101 -#define OID_GEN_RCV_OK 0x00020102 -#define OID_GEN_XMIT_ERROR 0x00020103 -#define OID_GEN_RCV_ERROR 0x00020104 -#define OID_GEN_RCV_NO_BUFFER 0x00020105 - -/* Optional statistics OIDs */ -#define OID_GEN_DIRECTED_BYTES_XMIT 0x00020201 -#define OID_GEN_DIRECTED_FRAMES_XMIT 0x00020202 -#define OID_GEN_MULTICAST_BYTES_XMIT 0x00020203 -#define OID_GEN_MULTICAST_FRAMES_XMIT 0x00020204 -#define OID_GEN_BROADCAST_BYTES_XMIT 0x00020205 -#define OID_GEN_BROADCAST_FRAMES_XMIT 0x00020206 -#define OID_GEN_DIRECTED_BYTES_RCV 0x00020207 -#define OID_GEN_DIRECTED_FRAMES_RCV 0x00020208 -#define OID_GEN_MULTICAST_BYTES_RCV 0x00020209 -#define OID_GEN_MULTICAST_FRAMES_RCV 0x0002020A -#define OID_GEN_BROADCAST_BYTES_RCV 0x0002020B -#define OID_GEN_BROADCAST_FRAMES_RCV 0x0002020C -#define OID_GEN_RCV_CRC_ERROR 0x0002020D -#define OID_GEN_TRANSMIT_QUEUE_LENGTH 0x0002020E -#define OID_GEN_GET_TIME_CAPS 0x0002020F -#define OID_GEN_GET_NETCARD_TIME 0x00020210 -#define OID_GEN_NETCARD_LOAD 0x00020211 -#define OID_GEN_DEVICE_PROFILE 0x00020212 -#define OID_GEN_INIT_TIME_MS 0x00020213 -#define OID_GEN_RESET_COUNTS 0x00020214 -#define OID_GEN_MEDIA_SENSE_COUNTS 0x00020215 -#define OID_GEN_FRIENDLY_NAME 0x00020216 -#define OID_GEN_MINIPORT_INFO 0x00020217 -#define OID_GEN_RESET_VERIFY_PARAMETERS 0x00020218 - -/* IEEE 802.3 (Ethernet) OIDs */ -#define NDIS_802_3_MAC_OPTION_PRIORITY 0x00000001 - -#define OID_802_3_PERMANENT_ADDRESS 0x01010101 -#define OID_802_3_CURRENT_ADDRESS 0x01010102 -#define OID_802_3_MULTICAST_LIST 0x01010103 -#define OID_802_3_MAXIMUM_LIST_SIZE 0x01010104 -#define OID_802_3_MAC_OPTIONS 0x01010105 -#define OID_802_3_RCV_ERROR_ALIGNMENT 0x01020101 -#define OID_802_3_XMIT_ONE_COLLISION 0x01020102 -#define OID_802_3_XMIT_MORE_COLLISIONS 0x01020103 -#define OID_802_3_XMIT_DEFERRED 0x01020201 -#define OID_802_3_XMIT_MAX_COLLISIONS 0x01020202 -#define OID_802_3_RCV_OVERRUN 0x01020203 -#define OID_802_3_XMIT_UNDERRUN 0x01020204 -#define OID_802_3_XMIT_HEARTBEAT_FAILURE 0x01020205 -#define OID_802_3_XMIT_TIMES_CRS_LOST 0x01020206 -#define OID_802_3_XMIT_LATE_COLLISIONS 0x01020207 - -/* OID_GEN_MINIPORT_INFO constants */ -#define NDIS_MINIPORT_BUS_MASTER 0x00000001 -#define NDIS_MINIPORT_WDM_DRIVER 0x00000002 -#define NDIS_MINIPORT_SG_LIST 0x00000004 -#define NDIS_MINIPORT_SUPPORTS_MEDIA_QUERY 0x00000008 -#define NDIS_MINIPORT_INDICATES_PACKETS 0x00000010 -#define NDIS_MINIPORT_IGNORE_PACKET_QUEUE 0x00000020 -#define NDIS_MINIPORT_IGNORE_REQUEST_QUEUE 0x00000040 -#define NDIS_MINIPORT_IGNORE_TOKEN_RING_ERRORS 0x00000080 -#define NDIS_MINIPORT_INTERMEDIATE_DRIVER 0x00000100 -#define NDIS_MINIPORT_IS_NDIS_5 0x00000200 -#define NDIS_MINIPORT_IS_CO 0x00000400 -#define NDIS_MINIPORT_DESERIALIZE 0x00000800 -#define NDIS_MINIPORT_REQUIRES_MEDIA_POLLING 0x00001000 -#define NDIS_MINIPORT_SUPPORTS_MEDIA_SENSE 0x00002000 -#define NDIS_MINIPORT_NETBOOT_CARD 0x00004000 -#define NDIS_MINIPORT_PM_SUPPORTED 0x00008000 -#define NDIS_MINIPORT_SUPPORTS_MAC_ADDRESS_OVERWRITE 0x00010000 -#define NDIS_MINIPORT_USES_SAFE_BUFFER_APIS 0x00020000 -#define NDIS_MINIPORT_HIDDEN 0x00040000 -#define NDIS_MINIPORT_SWENUM 0x00080000 -#define NDIS_MINIPORT_SURPRISE_REMOVE_OK 0x00100000 -#define NDIS_MINIPORT_NO_HALT_ON_SUSPEND 0x00200000 -#define NDIS_MINIPORT_HARDWARE_DEVICE 0x00400000 -#define NDIS_MINIPORT_SUPPORTS_CANCEL_SEND_PACKETS 0x00800000 -#define NDIS_MINIPORT_64BITS_DMA 0x01000000 - -#define NDIS_MEDIUM_802_3 0x00000000 -#define NDIS_MEDIUM_802_5 0x00000001 -#define NDIS_MEDIUM_FDDI 0x00000002 -#define NDIS_MEDIUM_WAN 0x00000003 -#define NDIS_MEDIUM_LOCAL_TALK 0x00000004 -#define NDIS_MEDIUM_DIX 0x00000005 -#define NDIS_MEDIUM_ARCENT_RAW 0x00000006 -#define NDIS_MEDIUM_ARCENT_878_2 0x00000007 -#define NDIS_MEDIUM_ATM 0x00000008 -#define NDIS_MEDIUM_WIRELESS_LAN 0x00000009 -#define NDIS_MEDIUM_IRDA 0x0000000A -#define NDIS_MEDIUM_BPC 0x0000000B -#define NDIS_MEDIUM_CO_WAN 0x0000000C -#define NDIS_MEDIUM_1394 0x0000000D - -#define NDIS_PACKET_TYPE_DIRECTED 0x00000001 -#define NDIS_PACKET_TYPE_MULTICAST 0x00000002 -#define NDIS_PACKET_TYPE_ALL_MULTICAST 0x00000004 -#define NDIS_PACKET_TYPE_BROADCAST 0x00000008 -#define NDIS_PACKET_TYPE_SOURCE_ROUTING 0x00000010 -#define NDIS_PACKET_TYPE_PROMISCUOUS 0x00000020 -#define NDIS_PACKET_TYPE_SMT 0x00000040 -#define NDIS_PACKET_TYPE_ALL_LOCAL 0x00000080 -#define NDIS_PACKET_TYPE_GROUP 0x00000100 -#define NDIS_PACKET_TYPE_ALL_FUNCTIONAL 0x00000200 -#define NDIS_PACKET_TYPE_FUNCTIONAL 0x00000400 -#define NDIS_PACKET_TYPE_MAC_FRAME 0x00000800 - -#define NDIS_MEDIA_STATE_CONNECTED 0x00000000 -#define NDIS_MEDIA_STATE_DISCONNECTED 0x00000001 - -#define NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA 0x00000001 -#define NDIS_MAC_OPTION_RECEIVE_SERIALIZED 0x00000002 -#define NDIS_MAC_OPTION_TRANSFERS_NOT_PEND 0x00000004 -#define NDIS_MAC_OPTION_NO_LOOPBACK 0x00000008 -#define NDIS_MAC_OPTION_FULL_DUPLEX 0x00000010 -#define NDIS_MAC_OPTION_EOTX_INDICATION 0x00000020 -#define NDIS_MAC_OPTION_8021P_PRIORITY 0x00000040 -#define NDIS_MAC_OPTION_RESERVED 0x80000000 - -#endif /* _USBGADGET_NDIS_H */ diff --git a/qemu/roms/u-boot/drivers/usb/gadget/omap1510_udc.c b/qemu/roms/u-boot/drivers/usb/gadget/omap1510_udc.c deleted file mode 100644 index bdc1b886f..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/omap1510_udc.c +++ /dev/null @@ -1,1555 +0,0 @@ -/* - * (C) Copyright 2003 - * Gerry Hamel, geh@ti.com, Texas Instruments - * - * Based on - * linux/drivers/usb/device/bi/omap.c - * TI OMAP1510 USB bus interface driver - * - * Author: MontaVista Software, Inc. - * source@mvista.com - * (C) Copyright 2002 - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#include <common.h> -#include <asm/io.h> -#ifdef CONFIG_OMAP_SX1 -#include <i2c.h> -#endif -#include <usbdevice.h> -#include <usb/omap1510_udc.h> -#include <usb/udc.h> - -#include "ep0.h" - - -#define UDC_INIT_MDELAY 80 /* Device settle delay */ -#define UDC_MAX_ENDPOINTS 31 /* Number of endpoints on this UDC */ - -/* Some kind of debugging output... */ -#if 1 -#define UDCDBG(str) -#define UDCDBGA(fmt,args...) -#else /* The bugs still exists... */ -#define UDCDBG(str) serial_printf("[%s] %s:%d: " str "\n", __FILE__,__FUNCTION__,__LINE__) -#define UDCDBGA(fmt,args...) serial_printf("[%s] %s:%d: " fmt "\n", __FILE__,__FUNCTION__,__LINE__, ##args) -#endif - -#if 1 -#define UDCREG(name) -#define UDCREGL(name) -#else /* The bugs still exists... */ -#define UDCREG(name) serial_printf("%s():%d: %s[%08x]=%.4x\n",__FUNCTION__,__LINE__, (#name), name, inw(name)) /* For 16-bit regs */ -#define UDCREGL(name) serial_printf("%s():%d: %s[%08x]=%.8x\n",__FUNCTION__,__LINE__, (#name), name, inl(name)) /* For 32-bit regs */ -#endif - - -static struct urb *ep0_urb = NULL; - -static struct usb_device_instance *udc_device; /* Used in interrupt handler */ -static u16 udc_devstat = 0; /* UDC status (DEVSTAT) */ -static u32 udc_interrupts = 0; - -static void udc_stall_ep (unsigned int ep_addr); - - -static struct usb_endpoint_instance *omap1510_find_ep (int ep) -{ - int i; - - for (i = 0; i < udc_device->bus->max_endpoints; i++) { - if (udc_device->bus->endpoint_array[i].endpoint_address == ep) - return &udc_device->bus->endpoint_array[i]; - } - return NULL; -} - -/* ************************************************************************** */ -/* IO - */ - -/* - * omap1510_prepare_endpoint_for_rx - * - * This function implements TRM Figure 14-11. - * - * The endpoint to prepare for transfer is specified as a physical endpoint - * number. For OUT (rx) endpoints 1 through 15, the corresponding endpoint - * configuration register is checked to see if the endpoint is ISO or not. - * If the OUT endpoint is valid and is non-ISO then its FIFO is enabled. - * No action is taken for endpoint 0 or for IN (tx) endpoints 16 through 30. - */ -static void omap1510_prepare_endpoint_for_rx (int ep_addr) -{ - int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; - - UDCDBGA ("omap1510_prepare_endpoint %x", ep_addr); - if (((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)) { - if ((inw (UDC_EP_RX (ep_num)) & - (UDC_EPn_RX_Valid | UDC_EPn_RX_Iso)) == - UDC_EPn_RX_Valid) { - /* rx endpoint is valid, non-ISO, so enable its FIFO */ - outw (UDC_EP_Sel | ep_num, UDC_EP_NUM); - outw (UDC_Set_FIFO_En, UDC_CTRL); - outw (0, UDC_EP_NUM); - } - } -} - -/* omap1510_configure_endpoints - * - * This function implements TRM Figure 14-10. - */ -static void omap1510_configure_endpoints (struct usb_device_instance *device) -{ - int ep; - struct usb_bus_instance *bus; - struct usb_endpoint_instance *endpoint; - unsigned short ep_ptr; - unsigned short ep_size; - unsigned short ep_isoc; - unsigned short ep_doublebuffer; - int ep_addr; - int packet_size; - int buffer_size; - int attributes; - - bus = device->bus; - - /* There is a dedicated 2048 byte buffer for USB packets that may be - * arbitrarily partitioned among the endpoints on 8-byte boundaries. - * The first 8 bytes are reserved for receiving setup packets on - * endpoint 0. - */ - ep_ptr = 8; /* reserve the first 8 bytes for the setup fifo */ - - for (ep = 0; ep < bus->max_endpoints; ep++) { - endpoint = bus->endpoint_array + ep; - ep_addr = endpoint->endpoint_address; - if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - /* IN endpoint */ - packet_size = endpoint->tx_packetSize; - attributes = endpoint->tx_attributes; - } else { - /* OUT endpoint */ - packet_size = endpoint->rcv_packetSize; - attributes = endpoint->rcv_attributes; - } - - switch (packet_size) { - case 0: - ep_size = 0; - break; - case 8: - ep_size = 0; - break; - case 16: - ep_size = 1; - break; - case 32: - ep_size = 2; - break; - case 64: - ep_size = 3; - break; - case 128: - ep_size = 4; - break; - case 256: - ep_size = 5; - break; - case 512: - ep_size = 6; - break; - default: - UDCDBGA ("ep 0x%02x has bad packet size %d", - ep_addr, packet_size); - packet_size = 0; - ep_size = 0; - break; - } - - switch (attributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_CONTROL: - case USB_ENDPOINT_XFER_BULK: - case USB_ENDPOINT_XFER_INT: - default: - /* A non-isochronous endpoint may optionally be - * double-buffered. For now we disable - * double-buffering. - */ - ep_doublebuffer = 0; - ep_isoc = 0; - if (packet_size > 64) - packet_size = 0; - if (!ep || !ep_doublebuffer) - buffer_size = packet_size; - else - buffer_size = packet_size * 2; - break; - case USB_ENDPOINT_XFER_ISOC: - /* Isochronous endpoints are always double- - * buffered, but the double-buffering bit - * in the endpoint configuration register - * becomes the msb of the endpoint size so we - * set the double-buffering flag to zero. - */ - ep_doublebuffer = 0; - ep_isoc = 1; - buffer_size = packet_size * 2; - break; - } - - /* check to see if our packet buffer RAM is exhausted */ - if ((ep_ptr + buffer_size) > 2048) { - UDCDBGA ("out of packet RAM for ep 0x%02x buf size %d", ep_addr, buffer_size); - buffer_size = packet_size = 0; - } - - /* force a default configuration for endpoint 0 since it is - * always enabled - */ - if (!ep && ((packet_size < 8) || (packet_size > 64))) { - buffer_size = packet_size = 64; - ep_size = 3; - } - - if (!ep) { - /* configure endpoint 0 */ - outw ((ep_size << 12) | (ep_ptr >> 3), UDC_EP0); - /*UDCDBGA("ep 0 buffer offset 0x%03x packet size 0x%03x", */ - /* ep_ptr, packet_size); */ - } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - /* IN endpoint */ - if (packet_size) { - outw ((1 << 15) | (ep_doublebuffer << 14) | - (ep_size << 12) | (ep_isoc << 11) | - (ep_ptr >> 3), - UDC_EP_TX (ep_addr & - USB_ENDPOINT_NUMBER_MASK)); - UDCDBGA ("IN ep %d buffer offset 0x%03x" - " packet size 0x%03x", - ep_addr & USB_ENDPOINT_NUMBER_MASK, - ep_ptr, packet_size); - } else { - outw (0, - UDC_EP_TX (ep_addr & - USB_ENDPOINT_NUMBER_MASK)); - } - } else { - /* OUT endpoint */ - if (packet_size) { - outw ((1 << 15) | (ep_doublebuffer << 14) | - (ep_size << 12) | (ep_isoc << 11) | - (ep_ptr >> 3), - UDC_EP_RX (ep_addr & - USB_ENDPOINT_NUMBER_MASK)); - UDCDBGA ("OUT ep %d buffer offset 0x%03x" - " packet size 0x%03x", - ep_addr & USB_ENDPOINT_NUMBER_MASK, - ep_ptr, packet_size); - } else { - outw (0, - UDC_EP_RX (ep_addr & - USB_ENDPOINT_NUMBER_MASK)); - } - } - ep_ptr += buffer_size; - } -} - -/* omap1510_deconfigure_device - * - * This function balances omap1510_configure_device. - */ -static void omap1510_deconfigure_device (void) -{ - int epnum; - - UDCDBG ("clear Cfg_Lock"); - outw (inw (UDC_SYSCON1) & ~UDC_Cfg_Lock, UDC_SYSCON1); - UDCREG (UDC_SYSCON1); - - /* deconfigure all endpoints */ - for (epnum = 1; epnum <= 15; epnum++) { - outw (0, UDC_EP_RX (epnum)); - outw (0, UDC_EP_TX (epnum)); - } -} - -/* omap1510_configure_device - * - * This function implements TRM Figure 14-9. - */ -static void omap1510_configure_device (struct usb_device_instance *device) -{ - omap1510_configure_endpoints (device); - - - /* Figure 14-9 indicates we should enable interrupts here, but we have - * other routines (udc_all_interrupts, udc_suspended_interrupts) to - * do that. - */ - - UDCDBG ("set Cfg_Lock"); - outw (inw (UDC_SYSCON1) | UDC_Cfg_Lock, UDC_SYSCON1); - UDCREG (UDC_SYSCON1); -} - -/* omap1510_write_noniso_tx_fifo - * - * This function implements TRM Figure 14-30. - * - * If the endpoint has an active tx_urb, then the next packet of data from the - * URB is written to the tx FIFO. The total amount of data in the urb is given - * by urb->actual_length. The maximum amount of data that can be sent in any - * one packet is given by endpoint->tx_packetSize. The number of data bytes - * from this URB that have already been transmitted is given by endpoint->sent. - * endpoint->last is updated by this routine with the number of data bytes - * transmitted in this packet. - * - * In accordance with Figure 14-30, the EP_NUM register must already have been - * written with the value to select the appropriate tx FIFO before this routine - * is called. - */ -static void omap1510_write_noniso_tx_fifo (struct usb_endpoint_instance - *endpoint) -{ - struct urb *urb = endpoint->tx_urb; - - if (urb) { - unsigned int last, i; - - UDCDBGA ("urb->buffer %p, buffer_length %d, actual_length %d", - urb->buffer, urb->buffer_length, urb->actual_length); - if ((last = - MIN (urb->actual_length - endpoint->sent, - endpoint->tx_packetSize))) { - u8 *cp = urb->buffer + endpoint->sent; - - UDCDBGA ("endpoint->sent %d, tx_packetSize %d, last %d", endpoint->sent, endpoint->tx_packetSize, last); - - if (((u32) cp & 1) == 0) { /* word aligned? */ - outsw (UDC_DATA, cp, last >> 1); - } else { /* byte aligned. */ - for (i = 0; i < (last >> 1); i++) { - u16 w = ((u16) cp[2 * i + 1] << 8) | - (u16) cp[2 * i]; - outw (w, UDC_DATA); - } - } - if (last & 1) { - outb (*(cp + last - 1), UDC_DATA); - } - } - endpoint->last = last; - } -} - -/* omap1510_read_noniso_rx_fifo - * - * This function implements TRM Figure 14-28. - * - * If the endpoint has an active rcv_urb, then the next packet of data is read - * from the rcv FIFO and written to rcv_urb->buffer at offset - * rcv_urb->actual_length to append the packet data to the data from any - * previous packets for this transfer. We assume that there is sufficient room - * left in the buffer to hold an entire packet of data. - * - * The return value is the number of bytes read from the FIFO for this packet. - * - * In accordance with Figure 14-28, the EP_NUM register must already have been - * written with the value to select the appropriate rcv FIFO before this routine - * is called. - */ -static int omap1510_read_noniso_rx_fifo (struct usb_endpoint_instance - *endpoint) -{ - struct urb *urb = endpoint->rcv_urb; - int len = 0; - - if (urb) { - len = inw (UDC_RXFSTAT); - - if (len) { - unsigned char *cp = urb->buffer + urb->actual_length; - - insw (UDC_DATA, cp, len >> 1); - if (len & 1) - *(cp + len - 1) = inb (UDC_DATA); - } - } - return len; -} - -/* omap1510_prepare_for_control_write_status - * - * This function implements TRM Figure 14-17. - * - * We have to deal here with non-autodecoded control writes that haven't already - * been dealt with by ep0_recv_setup. The non-autodecoded standard control - * write requests are: set/clear endpoint feature, set configuration, set - * interface, and set descriptor. ep0_recv_setup handles set/clear requests for - * ENDPOINT_HALT by halting the endpoint for a set request and resetting the - * endpoint for a clear request. ep0_recv_setup returns an error for - * SET_DESCRIPTOR requests which causes them to be terminated with a stall by - * the setup handler. A SET_INTERFACE request is handled by ep0_recv_setup by - * generating a DEVICE_SET_INTERFACE event. This leaves only the - * SET_CONFIGURATION event for us to deal with here. - * - */ -static void omap1510_prepare_for_control_write_status (struct urb *urb) -{ - struct usb_device_request *request = &urb->device_request;; - - /* check for a SET_CONFIGURATION request */ - if (request->bRequest == USB_REQ_SET_CONFIGURATION) { - int configuration = le16_to_cpu (request->wValue) & 0xff; - unsigned short devstat = inw (UDC_DEVSTAT); - - if ((devstat & (UDC_ADD | UDC_CFG)) == UDC_ADD) { - /* device is currently in ADDRESSED state */ - if (configuration) { - /* Assume the specified non-zero configuration - * value is valid and switch to the CONFIGURED - * state. - */ - outw (UDC_Dev_Cfg, UDC_SYSCON2); - } - } else if ((devstat & UDC_CFG) == UDC_CFG) { - /* device is currently in CONFIGURED state */ - if (!configuration) { - /* Switch to ADDRESSED state. */ - outw (UDC_Clr_Cfg, UDC_SYSCON2); - } - } - } - - /* select EP0 tx FIFO */ - outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM); - /* clear endpoint (no data bytes in status stage) */ - outw (UDC_Clr_EP, UDC_CTRL); - /* enable the EP0 tx FIFO */ - outw (UDC_Set_FIFO_En, UDC_CTRL); - /* deselect the endpoint */ - outw (UDC_EP_Dir, UDC_EP_NUM); -} - -/* udc_state_transition_up - * udc_state_transition_down - * - * Helper functions to implement device state changes. The device states and - * the events that transition between them are: - * - * STATE_ATTACHED - * || /\ - * \/ || - * DEVICE_HUB_CONFIGURED DEVICE_HUB_RESET - * || /\ - * \/ || - * STATE_POWERED - * || /\ - * \/ || - * DEVICE_RESET DEVICE_POWER_INTERRUPTION - * || /\ - * \/ || - * STATE_DEFAULT - * || /\ - * \/ || - * DEVICE_ADDRESS_ASSIGNED DEVICE_RESET - * || /\ - * \/ || - * STATE_ADDRESSED - * || /\ - * \/ || - * DEVICE_CONFIGURED DEVICE_DE_CONFIGURED - * || /\ - * \/ || - * STATE_CONFIGURED - * - * udc_state_transition_up transitions up (in the direction from STATE_ATTACHED - * to STATE_CONFIGURED) from the specified initial state to the specified final - * state, passing through each intermediate state on the way. If the initial - * state is at or above (i.e. nearer to STATE_CONFIGURED) the final state, then - * no state transitions will take place. - * - * udc_state_transition_down transitions down (in the direction from - * STATE_CONFIGURED to STATE_ATTACHED) from the specified initial state to the - * specified final state, passing through each intermediate state on the way. - * If the initial state is at or below (i.e. nearer to STATE_ATTACHED) the final - * state, then no state transitions will take place. - * - * These functions must only be called with interrupts disabled. - */ -static void udc_state_transition_up (usb_device_state_t initial, - usb_device_state_t final) -{ - if (initial < final) { - switch (initial) { - case STATE_ATTACHED: - usbd_device_event_irq (udc_device, - DEVICE_HUB_CONFIGURED, 0); - if (final == STATE_POWERED) - break; - case STATE_POWERED: - usbd_device_event_irq (udc_device, DEVICE_RESET, 0); - if (final == STATE_DEFAULT) - break; - case STATE_DEFAULT: - usbd_device_event_irq (udc_device, - DEVICE_ADDRESS_ASSIGNED, 0); - if (final == STATE_ADDRESSED) - break; - case STATE_ADDRESSED: - usbd_device_event_irq (udc_device, DEVICE_CONFIGURED, - 0); - case STATE_CONFIGURED: - break; - default: - break; - } - } -} - -static void udc_state_transition_down (usb_device_state_t initial, - usb_device_state_t final) -{ - if (initial > final) { - switch (initial) { - case STATE_CONFIGURED: - usbd_device_event_irq (udc_device, DEVICE_DE_CONFIGURED, 0); - if (final == STATE_ADDRESSED) - break; - case STATE_ADDRESSED: - usbd_device_event_irq (udc_device, DEVICE_RESET, 0); - if (final == STATE_DEFAULT) - break; - case STATE_DEFAULT: - usbd_device_event_irq (udc_device, DEVICE_POWER_INTERRUPTION, 0); - if (final == STATE_POWERED) - break; - case STATE_POWERED: - usbd_device_event_irq (udc_device, DEVICE_HUB_RESET, 0); - case STATE_ATTACHED: - break; - default: - break; - } - } -} - -/* Handle all device state changes. - * This function implements TRM Figure 14-21. - */ -static void omap1510_udc_state_changed (void) -{ - u16 bits; - u16 devstat = inw (UDC_DEVSTAT); - - UDCDBGA ("state changed, devstat %x, old %x", devstat, udc_devstat); - - bits = devstat ^ udc_devstat; - if (bits) { - if (bits & UDC_ATT) { - if (devstat & UDC_ATT) { - UDCDBG ("device attached and powered"); - udc_state_transition_up (udc_device->device_state, STATE_POWERED); - } else { - UDCDBG ("device detached or unpowered"); - udc_state_transition_down (udc_device->device_state, STATE_ATTACHED); - } - } - if (bits & UDC_USB_Reset) { - if (devstat & UDC_USB_Reset) { - UDCDBG ("device reset in progess"); - udc_state_transition_down (udc_device->device_state, STATE_POWERED); - } else { - UDCDBG ("device reset completed"); - } - } - if (bits & UDC_DEF) { - if (devstat & UDC_DEF) { - UDCDBG ("device entering default state"); - udc_state_transition_up (udc_device->device_state, STATE_DEFAULT); - } else { - UDCDBG ("device leaving default state"); - udc_state_transition_down (udc_device->device_state, STATE_POWERED); - } - } - if (bits & UDC_SUS) { - if (devstat & UDC_SUS) { - UDCDBG ("entering suspended state"); - usbd_device_event_irq (udc_device, DEVICE_BUS_INACTIVE, 0); - } else { - UDCDBG ("leaving suspended state"); - usbd_device_event_irq (udc_device, DEVICE_BUS_ACTIVITY, 0); - } - } - if (bits & UDC_R_WK_OK) { - UDCDBGA ("remote wakeup %s", (devstat & UDC_R_WK_OK) - ? "enabled" : "disabled"); - } - if (bits & UDC_ADD) { - if (devstat & UDC_ADD) { - UDCDBG ("default -> addressed"); - udc_state_transition_up (udc_device->device_state, STATE_ADDRESSED); - } else { - UDCDBG ("addressed -> default"); - udc_state_transition_down (udc_device->device_state, STATE_DEFAULT); - } - } - if (bits & UDC_CFG) { - if (devstat & UDC_CFG) { - UDCDBG ("device configured"); - /* The ep0_recv_setup function generates the - * DEVICE_CONFIGURED event when a - * USB_REQ_SET_CONFIGURATION setup packet is - * received, so we should already be in the - * state STATE_CONFIGURED. - */ - udc_state_transition_up (udc_device->device_state, STATE_CONFIGURED); - } else { - UDCDBG ("device deconfigured"); - udc_state_transition_down (udc_device->device_state, STATE_ADDRESSED); - } - } - } - - /* Clear interrupt source */ - outw (UDC_DS_Chg, UDC_IRQ_SRC); - - /* Save current DEVSTAT */ - udc_devstat = devstat; -} - -/* Handle SETUP USB interrupt. - * This function implements TRM Figure 14-14. - */ -static void omap1510_udc_setup (struct usb_endpoint_instance *endpoint) -{ - UDCDBG ("-> Entering device setup"); - - do { - const int setup_pktsize = 8; - unsigned char *datap = - (unsigned char *) &ep0_urb->device_request; - - /* Gain access to EP 0 setup FIFO */ - outw (UDC_Setup_Sel, UDC_EP_NUM); - - /* Read control request data */ - insb (UDC_DATA, datap, setup_pktsize); - - UDCDBGA ("EP0 setup read [%x %x %x %x %x %x %x %x]", - *(datap + 0), *(datap + 1), *(datap + 2), - *(datap + 3), *(datap + 4), *(datap + 5), - *(datap + 6), *(datap + 7)); - - /* Reset EP0 setup FIFO */ - outw (0, UDC_EP_NUM); - } while (inw (UDC_IRQ_SRC) & UDC_Setup); - - /* Try to process setup packet */ - if (ep0_recv_setup (ep0_urb)) { - /* Not a setup packet, stall next EP0 transaction */ - udc_stall_ep (0); - UDCDBG ("can't parse setup packet, still waiting for setup"); - return; - } - - /* Check direction */ - if ((ep0_urb->device_request.bmRequestType & USB_REQ_DIRECTION_MASK) - == USB_REQ_HOST2DEVICE) { - UDCDBG ("control write on EP0"); - if (le16_to_cpu (ep0_urb->device_request.wLength)) { - /* We don't support control write data stages. - * The only standard control write request with a data - * stage is SET_DESCRIPTOR, and ep0_recv_setup doesn't - * support that so we just stall those requests. A - * function driver might support a non-standard - * write request with a data stage, but it isn't - * obvious what we would do with the data if we read it - * so we'll just stall it. It seems like the API isn't - * quite right here. - */ -#if 0 - /* Here is what we would do if we did support control - * write data stages. - */ - ep0_urb->actual_length = 0; - outw (0, UDC_EP_NUM); - /* enable the EP0 rx FIFO */ - outw (UDC_Set_FIFO_En, UDC_CTRL); -#else - /* Stall this request */ - UDCDBG ("Stalling unsupported EP0 control write data " - "stage."); - udc_stall_ep (0); -#endif - } else { - omap1510_prepare_for_control_write_status (ep0_urb); - } - } else { - UDCDBG ("control read on EP0"); - /* The ep0_recv_setup function has already placed our response - * packet data in ep0_urb->buffer and the packet length in - * ep0_urb->actual_length. - */ - endpoint->tx_urb = ep0_urb; - endpoint->sent = 0; - /* select the EP0 tx FIFO */ - outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM); - /* Write packet data to the FIFO. omap1510_write_noniso_tx_fifo - * will update endpoint->last with the number of bytes written - * to the FIFO. - */ - omap1510_write_noniso_tx_fifo (endpoint); - /* enable the FIFO to start the packet transmission */ - outw (UDC_Set_FIFO_En, UDC_CTRL); - /* deselect the EP0 tx FIFO */ - outw (UDC_EP_Dir, UDC_EP_NUM); - } - - UDCDBG ("<- Leaving device setup"); -} - -/* Handle endpoint 0 RX interrupt - * This routine implements TRM Figure 14-16. - */ -static void omap1510_udc_ep0_rx (struct usb_endpoint_instance *endpoint) -{ - unsigned short status; - - UDCDBG ("RX on EP0"); - /* select EP0 rx FIFO */ - outw (UDC_EP_Sel, UDC_EP_NUM); - - status = inw (UDC_STAT_FLG); - - if (status & UDC_ACK) { - /* Check direction */ - if ((ep0_urb->device_request.bmRequestType - & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) { - /* This rx interrupt must be for a control write data - * stage packet. - * - * We don't support control write data stages. - * We should never end up here. - */ - - /* clear the EP0 rx FIFO */ - outw (UDC_Clr_EP, UDC_CTRL); - - /* deselect the EP0 rx FIFO */ - outw (0, UDC_EP_NUM); - - UDCDBG ("Stalling unexpected EP0 control write " - "data stage packet"); - udc_stall_ep (0); - } else { - /* This rx interrupt must be for a control read status - * stage packet. - */ - UDCDBG ("ACK on EP0 control read status stage packet"); - /* deselect EP0 rx FIFO */ - outw (0, UDC_EP_NUM); - } - } else if (status & UDC_STALL) { - UDCDBG ("EP0 stall during RX"); - /* deselect EP0 rx FIFO */ - outw (0, UDC_EP_NUM); - } else { - /* deselect EP0 rx FIFO */ - outw (0, UDC_EP_NUM); - } -} - -/* Handle endpoint 0 TX interrupt - * This routine implements TRM Figure 14-18. - */ -static void omap1510_udc_ep0_tx (struct usb_endpoint_instance *endpoint) -{ - unsigned short status; - struct usb_device_request *request = &ep0_urb->device_request; - - UDCDBG ("TX on EP0"); - /* select EP0 TX FIFO */ - outw (UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM); - - status = inw (UDC_STAT_FLG); - if (status & UDC_ACK) { - /* Check direction */ - if ((request->bmRequestType & USB_REQ_DIRECTION_MASK) == - USB_REQ_HOST2DEVICE) { - /* This tx interrupt must be for a control write status - * stage packet. - */ - UDCDBG ("ACK on EP0 control write status stage packet"); - /* deselect EP0 TX FIFO */ - outw (UDC_EP_Dir, UDC_EP_NUM); - } else { - /* This tx interrupt must be for a control read data - * stage packet. - */ - int wLength = le16_to_cpu (request->wLength); - - /* Update our count of bytes sent so far in this - * transfer. - */ - endpoint->sent += endpoint->last; - - /* We are finished with this transfer if we have sent - * all of the bytes in our tx urb (urb->actual_length) - * unless we need a zero-length terminating packet. We - * need a zero-length terminating packet if we returned - * fewer bytes than were requested (wLength) by the host, - * and the number of bytes we returned is an exact - * multiple of the packet size endpoint->tx_packetSize. - */ - if ((endpoint->sent == ep0_urb->actual_length) - && ((ep0_urb->actual_length == wLength) - || (endpoint->last != - endpoint->tx_packetSize))) { - /* Done with control read data stage. */ - UDCDBG ("control read data stage complete"); - /* deselect EP0 TX FIFO */ - outw (UDC_EP_Dir, UDC_EP_NUM); - /* select EP0 RX FIFO to prepare for control - * read status stage. - */ - outw (UDC_EP_Sel, UDC_EP_NUM); - /* clear the EP0 RX FIFO */ - outw (UDC_Clr_EP, UDC_CTRL); - /* enable the EP0 RX FIFO */ - outw (UDC_Set_FIFO_En, UDC_CTRL); - /* deselect the EP0 RX FIFO */ - outw (0, UDC_EP_NUM); - } else { - /* We still have another packet of data to send - * in this control read data stage or else we - * need a zero-length terminating packet. - */ - UDCDBG ("ACK control read data stage packet"); - omap1510_write_noniso_tx_fifo (endpoint); - /* enable the EP0 tx FIFO to start transmission */ - outw (UDC_Set_FIFO_En, UDC_CTRL); - /* deselect EP0 TX FIFO */ - outw (UDC_EP_Dir, UDC_EP_NUM); - } - } - } else if (status & UDC_STALL) { - UDCDBG ("EP0 stall during TX"); - /* deselect EP0 TX FIFO */ - outw (UDC_EP_Dir, UDC_EP_NUM); - } else { - /* deselect EP0 TX FIFO */ - outw (UDC_EP_Dir, UDC_EP_NUM); - } -} - -/* Handle RX transaction on non-ISO endpoint. - * This function implements TRM Figure 14-27. - * The ep argument is a physical endpoint number for a non-ISO OUT endpoint - * in the range 1 to 15. - */ -static void omap1510_udc_epn_rx (int ep) -{ - unsigned short status; - - /* Check endpoint status */ - status = inw (UDC_STAT_FLG); - - if (status & UDC_ACK) { - int nbytes; - struct usb_endpoint_instance *endpoint = - omap1510_find_ep (ep); - - nbytes = omap1510_read_noniso_rx_fifo (endpoint); - usbd_rcv_complete (endpoint, nbytes, 0); - - /* enable rx FIFO to prepare for next packet */ - outw (UDC_Set_FIFO_En, UDC_CTRL); - } else if (status & UDC_STALL) { - UDCDBGA ("STALL on RX endpoint %d", ep); - } else if (status & UDC_NAK) { - UDCDBGA ("NAK on RX ep %d", ep); - } else { - serial_printf ("omap-bi: RX on ep %d with status %x", ep, - status); - } -} - -/* Handle TX transaction on non-ISO endpoint. - * This function implements TRM Figure 14-29. - * The ep argument is a physical endpoint number for a non-ISO IN endpoint - * in the range 16 to 30. - */ -static void omap1510_udc_epn_tx (int ep) -{ - unsigned short status; - - /*serial_printf("omap1510_udc_epn_tx( %x )\n",ep); */ - - /* Check endpoint status */ - status = inw (UDC_STAT_FLG); - - if (status & UDC_ACK) { - struct usb_endpoint_instance *endpoint = - omap1510_find_ep (ep); - - /* We need to transmit a terminating zero-length packet now if - * we have sent all of the data in this URB and the transfer - * size was an exact multiple of the packet size. - */ - if (endpoint->tx_urb - && (endpoint->last == endpoint->tx_packetSize) - && (endpoint->tx_urb->actual_length - endpoint->sent - - endpoint->last == 0)) { - /* Prepare to transmit a zero-length packet. */ - endpoint->sent += endpoint->last; - /* write 0 bytes of data to FIFO */ - omap1510_write_noniso_tx_fifo (endpoint); - /* enable tx FIFO to start transmission */ - outw (UDC_Set_FIFO_En, UDC_CTRL); - } else if (endpoint->tx_urb - && endpoint->tx_urb->actual_length) { - /* retire the data that was just sent */ - usbd_tx_complete (endpoint); - /* Check to see if we have more data ready to transmit - * now. - */ - if (endpoint->tx_urb - && endpoint->tx_urb->actual_length) { - /* write data to FIFO */ - omap1510_write_noniso_tx_fifo (endpoint); - /* enable tx FIFO to start transmission */ - outw (UDC_Set_FIFO_En, UDC_CTRL); - } - } - } else if (status & UDC_STALL) { - UDCDBGA ("STALL on TX endpoint %d", ep); - } else if (status & UDC_NAK) { - UDCDBGA ("NAK on TX endpoint %d", ep); - } else { - /*serial_printf("omap-bi: TX on ep %d with status %x\n", ep, status); */ - } -} - - -/* -------------------------------------------------------------------------------- -*/ - -/* Handle general USB interrupts and dispatch according to type. - * This function implements TRM Figure 14-13. - */ -void omap1510_udc_irq (void) -{ - u16 irq_src = inw (UDC_IRQ_SRC); - int valid_irq = 0; - - if (!(irq_src & ~UDC_SOF_Flg)) /* ignore SOF interrupts ) */ - return; - - UDCDBGA ("< IRQ #%d start >- %x", udc_interrupts, irq_src); - /*serial_printf("< IRQ #%d start >- %x\n", udc_interrupts, irq_src); */ - - if (irq_src & UDC_DS_Chg) { - /* Device status changed */ - omap1510_udc_state_changed (); - valid_irq++; - } - if (irq_src & UDC_EP0_RX) { - /* Endpoint 0 receive */ - outw (UDC_EP0_RX, UDC_IRQ_SRC); /* ack interrupt */ - omap1510_udc_ep0_rx (udc_device->bus->endpoint_array + 0); - valid_irq++; - } - if (irq_src & UDC_EP0_TX) { - /* Endpoint 0 transmit */ - outw (UDC_EP0_TX, UDC_IRQ_SRC); /* ack interrupt */ - omap1510_udc_ep0_tx (udc_device->bus->endpoint_array + 0); - valid_irq++; - } - if (irq_src & UDC_Setup) { - /* Device setup */ - omap1510_udc_setup (udc_device->bus->endpoint_array + 0); - valid_irq++; - } - /*if (!valid_irq) */ - /* serial_printf("unknown interrupt, IRQ_SRC %.4x\n", irq_src); */ - UDCDBGA ("< IRQ #%d end >", udc_interrupts); - udc_interrupts++; -} - -/* This function implements TRM Figure 14-26. */ -void omap1510_udc_noniso_irq (void) -{ - unsigned short epnum; - unsigned short irq_src = inw (UDC_IRQ_SRC); - int valid_irq = 0; - - if (!(irq_src & (UDC_EPn_RX | UDC_EPn_TX))) - return; - - UDCDBGA ("non-ISO IRQ, IRQ_SRC %x", inw (UDC_IRQ_SRC)); - - if (irq_src & UDC_EPn_RX) { /* Endpoint N OUT transaction */ - /* Determine the endpoint number for this interrupt */ - epnum = (inw (UDC_EPN_STAT) & 0x0f00) >> 8; - UDCDBGA ("RX on ep %x", epnum); - - /* acknowledge interrupt */ - outw (UDC_EPn_RX, UDC_IRQ_SRC); - - if (epnum) { - /* select the endpoint FIFO */ - outw (UDC_EP_Sel | epnum, UDC_EP_NUM); - - omap1510_udc_epn_rx (epnum); - - /* deselect the endpoint FIFO */ - outw (epnum, UDC_EP_NUM); - } - valid_irq++; - } - if (irq_src & UDC_EPn_TX) { /* Endpoint N IN transaction */ - /* Determine the endpoint number for this interrupt */ - epnum = (inw (UDC_EPN_STAT) & 0x000f) | USB_DIR_IN; - UDCDBGA ("TX on ep %x", epnum); - - /* acknowledge interrupt */ - outw (UDC_EPn_TX, UDC_IRQ_SRC); - - if (epnum) { - /* select the endpoint FIFO */ - outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM); - - omap1510_udc_epn_tx (epnum); - - /* deselect the endpoint FIFO */ - outw (UDC_EP_Dir | epnum, UDC_EP_NUM); - } - valid_irq++; - } - if (!valid_irq) - serial_printf (": unknown non-ISO interrupt, IRQ_SRC %.4x\n", - irq_src); -} - -/* -------------------------------------------------------------------------------- -*/ - - -/* - * Start of public functions. - */ - -/* Called to start packet transmission. */ -int udc_endpoint_write (struct usb_endpoint_instance *endpoint) -{ - unsigned short epnum = - endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; - - UDCDBGA ("Starting transmit on ep %x", epnum); - - if (endpoint->tx_urb) { - /* select the endpoint FIFO */ - outw (UDC_EP_Sel | UDC_EP_Dir | epnum, UDC_EP_NUM); - /* write data to FIFO */ - omap1510_write_noniso_tx_fifo (endpoint); - /* enable tx FIFO to start transmission */ - outw (UDC_Set_FIFO_En, UDC_CTRL); - /* deselect the endpoint FIFO */ - outw (UDC_EP_Dir | epnum, UDC_EP_NUM); - } - - return 0; -} - -/* Start to initialize h/w stuff */ -int udc_init (void) -{ - u16 udc_rev; - uchar value; - ulong gpio; - int i; - - /* Let the device settle down before we start */ - for (i = 0; i < UDC_INIT_MDELAY; i++) udelay(1000); - - udc_device = NULL; - - UDCDBG ("starting"); - - /* Check peripheral reset. Must be 1 to make sure - MPU TIPB peripheral reset is inactive */ - UDCREG (ARM_RSTCT2); - - /* Set and check clock control. - * We might ought to be using the clock control API to do - * this instead of fiddling with the clock registers directly - * here. - */ - outw ((1 << 4) | (1 << 5), CLOCK_CTRL); - UDCREG (CLOCK_CTRL); - -#ifdef CONFIG_OMAP1510 - /* This code was originally implemented for OMAP1510 and - * therefore is only applicable for OMAP1510 boards. For - * OMAP5912 or OMAP16xx the register APLL_CTRL does not - * exist and DPLL_CTRL is already configured. - */ - - /* Set and check APLL */ - outw (0x0008, APLL_CTRL); - UDCREG (APLL_CTRL); - /* Set and check DPLL */ - outw (0x2210, DPLL_CTRL); - UDCREG (DPLL_CTRL); -#endif - /* Set and check SOFT - * The below line of code has been changed to perform a - * read-modify-write instead of a simple write for - * configuring the SOFT_REQ register. This allows the code - * to be compatible with OMAP5912 and OMAP16xx devices - */ - outw ((1 << 4) | (1 << 3) | 1 | (inw(SOFT_REQ)), SOFT_REQ); - - /* Short delay to wait for DPLL */ - udelay (1000); - - /* Print banner with device revision */ - udc_rev = inw (UDC_REV) & 0xff; -#ifdef CONFIG_OMAP1510 - printf ("USB: TI OMAP1510 USB function module rev %d.%d\n", - udc_rev >> 4, udc_rev & 0xf); -#endif - -#ifdef CONFIG_OMAP1610 - printf ("USB: TI OMAP5912 USB function module rev %d.%d\n", - udc_rev >> 4, udc_rev & 0xf); -#endif - -#ifdef CONFIG_OMAP_SX1 - i2c_read (0x32, 0x04, 1, &value, 1); - value |= 0x04; - i2c_write (0x32, 0x04, 1, &value, 1); - - i2c_read (0x32, 0x03, 1, &value, 1); - value |= 0x01; - i2c_write (0x32, 0x03, 1, &value, 1); - - gpio = inl(GPIO_PIN_CONTROL_REG); - gpio |= 0x0002; /* A_IRDA_OFF */ - gpio |= 0x0800; /* A_SWITCH */ - gpio |= 0x8000; /* A_USB_ON */ - outl (gpio, GPIO_PIN_CONTROL_REG); - - gpio = inl(GPIO_DIR_CONTROL_REG); - gpio &= ~0x0002; /* A_IRDA_OFF */ - gpio &= ~0x0800; /* A_SWITCH */ - gpio &= ~0x8000; /* A_USB_ON */ - outl (gpio, GPIO_DIR_CONTROL_REG); - - gpio = inl(GPIO_DATA_OUTPUT_REG); - gpio |= 0x0002; /* A_IRDA_OFF */ - gpio &= ~0x0800; /* A_SWITCH */ - gpio &= ~0x8000; /* A_USB_ON */ - outl (gpio, GPIO_DATA_OUTPUT_REG); -#endif - - /* The VBUS_MODE bit selects whether VBUS detection is done via - * software (1) or hardware (0). When software detection is - * selected, VBUS_CTRL selects whether USB is not connected (0) - * or connected (1). - */ - outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0); - outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0); - UDCREGL (FUNC_MUX_CTRL_0); - - /* - * At this point, device is ready for configuration... - */ - - UDCDBG ("disable USB interrupts"); - outw (0, UDC_IRQ_EN); - UDCREG (UDC_IRQ_EN); - - UDCDBG ("disable USB DMA"); - outw (0, UDC_DMA_IRQ_EN); - UDCREG (UDC_DMA_IRQ_EN); - - UDCDBG ("initialize SYSCON1"); - outw (UDC_Self_Pwr | UDC_Pullup_En, UDC_SYSCON1); - UDCREG (UDC_SYSCON1); - - return 0; -} - -/* Stall endpoint */ -static void udc_stall_ep (unsigned int ep_addr) -{ - /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */ - int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; - - UDCDBGA ("stall ep_addr %d", ep_addr); - - /* REVISIT? - * The OMAP TRM section 14.2.4.2 says we must check that the FIFO - * is empty before halting the endpoint. The current implementation - * doesn't check that the FIFO is empty. - */ - - if (!ep_num) { - outw (UDC_Stall_Cmd, UDC_SYSCON2); - } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) { - /* we have a valid rx endpoint, so halt it */ - outw (UDC_EP_Sel | ep_num, UDC_EP_NUM); - outw (UDC_Set_Halt, UDC_CTRL); - outw (ep_num, UDC_EP_NUM); - } - } else { - if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) { - /* we have a valid tx endpoint, so halt it */ - outw (UDC_EP_Sel | UDC_EP_Dir | ep_num, UDC_EP_NUM); - outw (UDC_Set_Halt, UDC_CTRL); - outw (ep_num, UDC_EP_NUM); - } - } -} - -/* Reset endpoint */ -#if 0 -static void udc_reset_ep (unsigned int ep_addr) -{ - /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */ - int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; - - UDCDBGA ("reset ep_addr %d", ep_addr); - - if (!ep_num) { - /* control endpoint 0 can't be reset */ - } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - UDCDBGA ("UDC_EP_RX(%d) = 0x%04x", ep_num, - inw (UDC_EP_RX (ep_num))); - if (inw (UDC_EP_RX (ep_num)) & UDC_EPn_RX_Valid) { - /* we have a valid rx endpoint, so reset it */ - outw (ep_num | UDC_EP_Sel, UDC_EP_NUM); - outw (UDC_Reset_EP, UDC_CTRL); - outw (ep_num, UDC_EP_NUM); - UDCDBGA ("OUT endpoint %d reset", ep_num); - } - } else { - UDCDBGA ("UDC_EP_TX(%d) = 0x%04x", ep_num, - inw (UDC_EP_TX (ep_num))); - /* Resetting of tx endpoints seems to be causing the USB function - * module to fail, which causes problems when the driver is - * uninstalled. We'll skip resetting tx endpoints for now until - * we figure out what the problem is. - */ -#if 0 - if (inw (UDC_EP_TX (ep_num)) & UDC_EPn_TX_Valid) { - /* we have a valid tx endpoint, so reset it */ - outw (ep_num | UDC_EP_Dir | UDC_EP_Sel, UDC_EP_NUM); - outw (UDC_Reset_EP, UDC_CTRL); - outw (ep_num | UDC_EP_Dir, UDC_EP_NUM); - UDCDBGA ("IN endpoint %d reset", ep_num); - } -#endif - } -} -#endif - -/* ************************************************************************** */ - -/** - * udc_check_ep - check logical endpoint - * - * Return physical endpoint number to use for this logical endpoint or zero if not valid. - */ -#if 0 -int udc_check_ep (int logical_endpoint, int packetsize) -{ - if ((logical_endpoint == 0x80) || - ((logical_endpoint & 0x8f) != logical_endpoint)) { - return 0; - } - - switch (packetsize) { - case 8: - case 16: - case 32: - case 64: - case 128: - case 256: - case 512: - break; - default: - return 0; - } - - return EP_ADDR_TO_PHYS_EP (logical_endpoint); -} -#endif - -/* - * udc_setup_ep - setup endpoint - * - * Associate a physical endpoint with endpoint_instance - */ -void udc_setup_ep (struct usb_device_instance *device, - unsigned int ep, struct usb_endpoint_instance *endpoint) -{ - UDCDBGA ("setting up endpoint addr %x", endpoint->endpoint_address); - - /* This routine gets called by bi_modinit for endpoint 0 and from - * bi_config for all of the other endpoints. bi_config gets called - * during the DEVICE_CREATE, DEVICE_CONFIGURED, and - * DEVICE_SET_INTERFACE events. We need to reconfigure the OMAP packet - * RAM after bi_config scans the selected device configuration and - * initializes the endpoint structures, but before this routine enables - * the OUT endpoint FIFOs. Since bi_config calls this routine in a - * loop for endpoints 1 through UDC_MAX_ENDPOINTS, we reconfigure our - * packet RAM here when ep==1. - * I really hate to do this here, but it seems like the API exported - * by the USB bus interface controller driver to the usbd-bi module - * isn't quite right so there is no good place to do this. - */ - if (ep == 1) { - omap1510_deconfigure_device (); - omap1510_configure_device (device); - } - - if (endpoint && (ep < UDC_MAX_ENDPOINTS)) { - int ep_addr = endpoint->endpoint_address; - - if (!ep_addr) { - /* nothing to do for endpoint 0 */ - } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - /* nothing to do for IN (tx) endpoints */ - } else { /* OUT (rx) endpoint */ - if (endpoint->rcv_packetSize) { - /*struct urb* urb = &(urb_out_array[ep&0xFF]); */ - /*urb->endpoint = endpoint; */ - /*urb->device = device; */ - /*urb->buffer_length = sizeof(urb->buffer); */ - - /*endpoint->rcv_urb = urb; */ - omap1510_prepare_endpoint_for_rx (ep_addr); - } - } - } -} - -/** - * udc_disable_ep - disable endpoint - * @ep: - * - * Disable specified endpoint - */ -#if 0 -void udc_disable_ep (unsigned int ep_addr) -{ - /*int ep_addr = PHYS_EP_TO_EP_ADDR(ep); */ - int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; - struct usb_endpoint_instance *endpoint = omap1510_find_ep (ep_addr); /*udc_device->bus->endpoint_array + ep; */ - - UDCDBGA ("disable ep_addr %d", ep_addr); - - if (!ep_num) { - /* nothing to do for endpoint 0 */ ; - } else if ((ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - if (endpoint->tx_packetSize) { - /* we have a valid tx endpoint */ - /*usbd_flush_tx(endpoint); */ - endpoint->tx_urb = NULL; - } - } else { - if (endpoint->rcv_packetSize) { - /* we have a valid rx endpoint */ - /*usbd_flush_rcv(endpoint); */ - endpoint->rcv_urb = NULL; - } - } -} -#endif - -/* ************************************************************************** */ - -/** - * udc_connected - is the USB cable connected - * - * Return non-zero if cable is connected. - */ -#if 0 -int udc_connected (void) -{ - return ((inw (UDC_DEVSTAT) & UDC_ATT) == UDC_ATT); -} -#endif - -/* Turn on the USB connection by enabling the pullup resistor */ -void udc_connect (void) -{ - UDCDBG ("connect, enable Pullup"); - outl (0x00000018, FUNC_MUX_CTRL_D); -} - -/* Turn off the USB connection by disabling the pullup resistor */ -void udc_disconnect (void) -{ - UDCDBG ("disconnect, disable Pullup"); - outl (0x00000000, FUNC_MUX_CTRL_D); -} - -/* ************************************************************************** */ - - -/* - * udc_disable_interrupts - disable interrupts - * switch off interrupts - */ -#if 0 -void udc_disable_interrupts (struct usb_device_instance *device) -{ - UDCDBG ("disabling all interrupts"); - outw (0, UDC_IRQ_EN); -} -#endif - -/* ************************************************************************** */ - -/** - * udc_ep0_packetsize - return ep0 packetsize - */ -#if 0 -int udc_ep0_packetsize (void) -{ - return EP0_PACKETSIZE; -} -#endif - -/* Switch on the UDC */ -void udc_enable (struct usb_device_instance *device) -{ - UDCDBGA ("enable device %p, status %d", device, device->status); - - /* initialize driver state variables */ - udc_devstat = 0; - - /* Save the device structure pointer */ - udc_device = device; - - /* Setup ep0 urb */ - if (!ep0_urb) { - ep0_urb = - usbd_alloc_urb (udc_device, - udc_device->bus->endpoint_array); - } else { - serial_printf ("udc_enable: ep0_urb already allocated %p\n", - ep0_urb); - } - - UDCDBG ("Check clock status"); - UDCREG (STATUS_REQ); - - /* The VBUS_MODE bit selects whether VBUS detection is done via - * software (1) or hardware (0). When software detection is - * selected, VBUS_CTRL selects whether USB is not connected (0) - * or connected (1). - */ - outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_CTRL | UDC_VBUS_MODE, - FUNC_MUX_CTRL_0); - UDCREGL (FUNC_MUX_CTRL_0); - - omap1510_configure_device (device); -} - -/* Switch off the UDC */ -void udc_disable (void) -{ - UDCDBG ("disable UDC"); - - omap1510_deconfigure_device (); - - /* The VBUS_MODE bit selects whether VBUS detection is done via - * software (1) or hardware (0). When software detection is - * selected, VBUS_CTRL selects whether USB is not connected (0) - * or connected (1). - */ - outl (inl (FUNC_MUX_CTRL_0) | UDC_VBUS_MODE, FUNC_MUX_CTRL_0); - outl (inl (FUNC_MUX_CTRL_0) & ~UDC_VBUS_CTRL, FUNC_MUX_CTRL_0); - UDCREGL (FUNC_MUX_CTRL_0); - - /* Free ep0 URB */ - if (ep0_urb) { - /*usbd_dealloc_urb(ep0_urb); */ - ep0_urb = NULL; - } - - /* Reset device pointer. - * We ought to do this here to balance the initialization of udc_device - * in udc_enable, but some of our other exported functions get called - * by the bus interface driver after udc_disable, so we have to hang on - * to the device pointer to avoid a null pointer dereference. */ - /* udc_device = NULL; */ -} - -/** - * udc_startup - allow udc code to do any additional startup - */ -void udc_startup_events (struct usb_device_instance *device) -{ - /* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */ - usbd_device_event_irq (device, DEVICE_INIT, 0); - - /* The DEVICE_CREATE event puts the USB device in the state - * STATE_ATTACHED. - */ - usbd_device_event_irq (device, DEVICE_CREATE, 0); - - /* Some USB controller driver implementations signal - * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. - * DEVICE_HUB_CONFIGURED causes a transition to the state STATE_POWERED, - * and DEVICE_RESET causes a transition to the state STATE_DEFAULT. - * The OMAP USB client controller has the capability to detect when the - * USB cable is connected to a powered USB bus via the ATT bit in the - * DEVSTAT register, so we will defer the DEVICE_HUB_CONFIGURED and - * DEVICE_RESET events until later. - */ - - udc_enable (device); -} - -/** - * udc_irq - do pseudo interrupts - */ -void udc_irq(void) -{ - /* Loop while we have interrupts. - * If we don't do this, the input chain - * polling delay is likely to miss - * host requests. - */ - while (inw (UDC_IRQ_SRC) & ~UDC_SOF_Flg) { - /* Handle any new IRQs */ - omap1510_udc_irq (); - omap1510_udc_noniso_irq (); - } -} - -/* Flow control */ -void udc_set_nak(int epid) -{ - /* TODO: implement this functionality in omap1510 */ -} - -void udc_unset_nak (int epid) -{ - /* TODO: implement this functionality in omap1510 */ -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/pxa25x_udc.c b/qemu/roms/u-boot/drivers/usb/gadget/pxa25x_udc.c deleted file mode 100644 index 8945c5b66..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/pxa25x_udc.c +++ /dev/null @@ -1,2047 +0,0 @@ -/* - * Intel PXA25x and IXP4xx on-chip full speed USB device controllers - * - * Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker) - * Copyright (C) 2003 Robert Schwebel, Pengutronix - * Copyright (C) 2003 Benedikt Spranger, Pengutronix - * Copyright (C) 2003 David Brownell - * Copyright (C) 2003 Joshua Wise - * Copyright (C) 2012 Lukasz Dalek <luk0104@gmail.com> - * - * SPDX-License-Identifier: GPL-2.0+ - * - * MODULE_AUTHOR("Frank Becker, Robert Schwebel, David Brownell"); - */ - -#define CONFIG_USB_PXA25X_SMALL -#define DRIVER_NAME "pxa25x_udc_linux" -#define ARCH_HAS_PREFETCH - -#include <common.h> -#include <errno.h> -#include <asm/byteorder.h> -#include <asm/system.h> -#include <asm/mach-types.h> -#include <asm/unaligned.h> -#include <linux/compat.h> -#include <malloc.h> -#include <asm/io.h> -#include <asm/arch/pxa.h> - -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <usb/lin_gadget_compat.h> -#include <asm/arch/pxa-regs.h> - -#include "pxa25x_udc.h" - -/* - * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x - * series processors. The UDC for the IXP 4xx series is very similar. - * There are fifteen endpoints, in addition to ep0. - * - * Such controller drivers work with a gadget driver. The gadget driver - * returns descriptors, implements configuration and data protocols used - * by the host to interact with this device, and allocates endpoints to - * the different protocol interfaces. The controller driver virtualizes - * usb hardware so that the gadget drivers will be more portable. - * - * This UDC hardware wants to implement a bit too much USB protocol, so - * it constrains the sorts of USB configuration change events that work. - * The errata for these chips are misleading; some "fixed" bugs from - * pxa250 a0/a1 b0/b1/b2 sure act like they're still there. - * - * Note that the UDC hardware supports DMA (except on IXP) but that's - * not used here. IN-DMA (to host) is simple enough, when the data is - * suitably aligned (16 bytes) ... the network stack doesn't do that, - * other software can. OUT-DMA is buggy in most chip versions, as well - * as poorly designed (data toggle not automatic). So this driver won't - * bother using DMA. (Mostly-working IN-DMA support was available in - * kernels before 2.6.23, but was never enabled or well tested.) - */ - -#define DRIVER_VERSION "18-August-2012" -#define DRIVER_DESC "PXA 25x USB Device Controller driver" - -static const char driver_name[] = "pxa25x_udc"; -static const char ep0name[] = "ep0"; - -/* Watchdog */ -static inline void start_watchdog(struct pxa25x_udc *udc) -{ - debug("Started watchdog\n"); - udc->watchdog.base = get_timer(0); - udc->watchdog.running = 1; -} - -static inline void stop_watchdog(struct pxa25x_udc *udc) -{ - udc->watchdog.running = 0; - debug("Stopped watchdog\n"); -} - -static inline void test_watchdog(struct pxa25x_udc *udc) -{ - if (!udc->watchdog.running) - return; - - debug("watchdog %ld %ld\n", get_timer(udc->watchdog.base), - udc->watchdog.period); - - if (get_timer(udc->watchdog.base) >= udc->watchdog.period) { - stop_watchdog(udc); - udc->watchdog.function(udc); - } -} - -static void udc_watchdog(struct pxa25x_udc *dev) -{ - uint32_t udccs0 = readl(&dev->regs->udccs[0]); - - debug("Fired up udc_watchdog\n"); - - local_irq_disable(); - if (dev->ep0state == EP0_STALL - && (udccs0 & UDCCS0_FST) == 0 - && (udccs0 & UDCCS0_SST) == 0) { - writel(UDCCS0_FST|UDCCS0_FTF, &dev->regs->udccs[0]); - debug("ep0 re-stall\n"); - start_watchdog(dev); - } - local_irq_enable(); -} - -#ifdef DEBUG - -static const char * const state_name[] = { - "EP0_IDLE", - "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE", - "EP0_END_XFER", "EP0_STALL" -}; - -static void -dump_udccr(const char *label) -{ - u32 udccr = readl(&UDC_REGS->udccr); - debug("%s %02X =%s%s%s%s%s%s%s%s\n", - label, udccr, - (udccr & UDCCR_REM) ? " rem" : "", - (udccr & UDCCR_RSTIR) ? " rstir" : "", - (udccr & UDCCR_SRM) ? " srm" : "", - (udccr & UDCCR_SUSIR) ? " susir" : "", - (udccr & UDCCR_RESIR) ? " resir" : "", - (udccr & UDCCR_RSM) ? " rsm" : "", - (udccr & UDCCR_UDA) ? " uda" : "", - (udccr & UDCCR_UDE) ? " ude" : ""); -} - -static void -dump_udccs0(const char *label) -{ - u32 udccs0 = readl(&UDC_REGS->udccs[0]); - - debug("%s %s %02X =%s%s%s%s%s%s%s%s\n", - label, state_name[the_controller->ep0state], udccs0, - (udccs0 & UDCCS0_SA) ? " sa" : "", - (udccs0 & UDCCS0_RNE) ? " rne" : "", - (udccs0 & UDCCS0_FST) ? " fst" : "", - (udccs0 & UDCCS0_SST) ? " sst" : "", - (udccs0 & UDCCS0_DRWF) ? " dwrf" : "", - (udccs0 & UDCCS0_FTF) ? " ftf" : "", - (udccs0 & UDCCS0_IPR) ? " ipr" : "", - (udccs0 & UDCCS0_OPR) ? " opr" : ""); -} - -static void -dump_state(struct pxa25x_udc *dev) -{ - u32 tmp; - unsigned i; - - debug("%s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n", - state_name[dev->ep0state], - readl(&UDC_REGS->uicr1), readl(&UDC_REGS->uicr0), - readl(&UDC_REGS->usir1), readl(&UDC_REGS->usir0), - readl(&UDC_REGS->ufnrh), readl(&UDC_REGS->ufnrl)); - dump_udccr("udccr"); - if (dev->has_cfr) { - tmp = readl(&UDC_REGS->udccfr); - debug("udccfr %02X =%s%s\n", tmp, - (tmp & UDCCFR_AREN) ? " aren" : "", - (tmp & UDCCFR_ACM) ? " acm" : ""); - } - - if (!dev->driver) { - debug("no gadget driver bound\n"); - return; - } else - debug("ep0 driver '%s'\n", "ether"); - - dump_udccs0("udccs0"); - debug("ep0 IN %lu/%lu, OUT %lu/%lu\n", - dev->stats.write.bytes, dev->stats.write.ops, - dev->stats.read.bytes, dev->stats.read.ops); - - for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) { - if (dev->ep[i].desc == NULL) - continue; - debug("udccs%d = %02x\n", i, *dev->ep->reg_udccs); - } -} - -#else /* DEBUG */ - -static inline void dump_udccr(const char *label) { } -static inline void dump_udccs0(const char *label) { } -static inline void dump_state(struct pxa25x_udc *dev) { } - -#endif /* DEBUG */ - -/* - * --------------------------------------------------------------------------- - * endpoint related parts of the api to the usb controller hardware, - * used by gadget driver; and the inner talker-to-hardware core. - * --------------------------------------------------------------------------- - */ - -static void pxa25x_ep_fifo_flush(struct usb_ep *ep); -static void nuke(struct pxa25x_ep *, int status); - -/* one GPIO should control a D+ pullup, so host sees this device (or not) */ -static void pullup_off(void) -{ - struct pxa2xx_udc_mach_info *mach = the_controller->mach; - - if (mach->udc_command) - mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT); -} - -static void pullup_on(void) -{ - struct pxa2xx_udc_mach_info *mach = the_controller->mach; - - if (mach->udc_command) - mach->udc_command(PXA2XX_UDC_CMD_CONNECT); -} - -static void pio_irq_enable(int bEndpointAddress) -{ - bEndpointAddress &= 0xf; - if (bEndpointAddress < 8) { - clrbits_le32(&the_controller->regs->uicr0, - 1 << bEndpointAddress); - } else { - bEndpointAddress -= 8; - clrbits_le32(&the_controller->regs->uicr1, - 1 << bEndpointAddress); - } -} - -static void pio_irq_disable(int bEndpointAddress) -{ - bEndpointAddress &= 0xf; - if (bEndpointAddress < 8) { - setbits_le32(&the_controller->regs->uicr0, - 1 << bEndpointAddress); - } else { - bEndpointAddress -= 8; - setbits_le32(&the_controller->regs->uicr1, - 1 << bEndpointAddress); - } -} - -static inline void udc_set_mask_UDCCR(int mask) -{ - /* - * The UDCCR reg contains mask and interrupt status bits, - * so using '|=' isn't safe as it may ack an interrupt. - */ - const uint32_t mask_bits = UDCCR_REM | UDCCR_SRM | UDCCR_UDE; - - mask &= mask_bits; - clrsetbits_le32(&the_controller->regs->udccr, ~mask_bits, mask); -} - -static inline void udc_clear_mask_UDCCR(int mask) -{ - const uint32_t mask_bits = UDCCR_REM | UDCCR_SRM | UDCCR_UDE; - - mask = ~mask & mask_bits; - clrbits_le32(&the_controller->regs->udccr, ~mask); -} - -static inline void udc_ack_int_UDCCR(int mask) -{ - const uint32_t mask_bits = UDCCR_REM | UDCCR_SRM | UDCCR_UDE; - - mask &= ~mask_bits; - clrsetbits_le32(&the_controller->regs->udccr, ~mask_bits, mask); -} - -/* - * endpoint enable/disable - * - * we need to verify the descriptors used to enable endpoints. since pxa25x - * endpoint configurations are fixed, and are pretty much always enabled, - * there's not a lot to manage here. - * - * because pxa25x can't selectively initialize bulk (or interrupt) endpoints, - * (resetting endpoint halt and toggle), SET_INTERFACE is unusable except - * for a single interface (with only the default altsetting) and for gadget - * drivers that don't halt endpoints (not reset by set_interface). that also - * means that if you use ISO, you must violate the USB spec rule that all - * iso endpoints must be in non-default altsettings. - */ -static int pxa25x_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct pxa25x_ep *ep; - struct pxa25x_udc *dev; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT - || ep->bEndpointAddress != desc->bEndpointAddress - || ep->fifo_size < - le16_to_cpu(get_unaligned(&desc->wMaxPacketSize))) { - printf("%s, bad ep or descriptor\n", __func__); - return -EINVAL; - } - - /* xfer types must match, except that interrupt ~= bulk */ - if (ep->bmAttributes != desc->bmAttributes - && ep->bmAttributes != USB_ENDPOINT_XFER_BULK - && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { - printf("%s, %s type mismatch\n", __func__, _ep->name); - return -EINVAL; - } - - /* hardware _could_ do smaller, but driver doesn't */ - if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)) - != BULK_FIFO_SIZE) - || !get_unaligned(&desc->wMaxPacketSize)) { - printf("%s, bad %s maxpacket\n", __func__, _ep->name); - return -ERANGE; - } - - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { - printf("%s, bogus device state\n", __func__); - return -ESHUTDOWN; - } - - ep->desc = desc; - ep->stopped = 0; - ep->pio_irqs = 0; - ep->ep.maxpacket = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); - - /* flush fifo (mostly for OUT buffers) */ - pxa25x_ep_fifo_flush(_ep); - - /* ... reset halt state too, if we could ... */ - - debug("enabled %s\n", _ep->name); - return 0; -} - -static int pxa25x_ep_disable(struct usb_ep *_ep) -{ - struct pxa25x_ep *ep; - unsigned long flags; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (!_ep || !ep->desc) { - printf("%s, %s not enabled\n", __func__, - _ep ? ep->ep.name : NULL); - return -EINVAL; - } - local_irq_save(flags); - - nuke(ep, -ESHUTDOWN); - - /* flush fifo (mostly for IN buffers) */ - pxa25x_ep_fifo_flush(_ep); - - ep->desc = NULL; - ep->stopped = 1; - - local_irq_restore(flags); - debug("%s disabled\n", _ep->name); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* - * for the pxa25x, these can just wrap kmalloc/kfree. gadget drivers - * must still pass correctly initialized endpoints, since other controller - * drivers may care about how it's currently set up (dma issues etc). - */ - -/* - * pxa25x_ep_alloc_request - allocate a request data structure - */ -static struct usb_request * -pxa25x_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags) -{ - struct pxa25x_request *req; - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - INIT_LIST_HEAD(&req->queue); - return &req->req; -} - - -/* - * pxa25x_ep_free_request - deallocate a request data structure - */ -static void -pxa25x_ep_free_request(struct usb_ep *_ep, struct usb_request *_req) -{ - struct pxa25x_request *req; - - req = container_of(_req, struct pxa25x_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -/*-------------------------------------------------------------------------*/ - -/* - * done - retire a request; caller blocked irqs - */ -static void done(struct pxa25x_ep *ep, struct pxa25x_request *req, int status) -{ - unsigned stopped = ep->stopped; - - list_del_init(&req->queue); - - if (likely(req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - if (status && status != -ESHUTDOWN) - debug("complete %s req %p stat %d len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - req->req.complete(&ep->ep, &req->req); - ep->stopped = stopped; -} - - -static inline void ep0_idle(struct pxa25x_udc *dev) -{ - dev->ep0state = EP0_IDLE; -} - -static int -write_packet(u32 *uddr, struct pxa25x_request *req, unsigned max) -{ - u8 *buf; - unsigned length, count; - - debug("%s(): uddr %p\n", __func__, uddr); - - buf = req->req.buf + req->req.actual; - prefetch(buf); - - /* how big will this packet be? */ - length = min(req->req.length - req->req.actual, max); - req->req.actual += length; - - count = length; - while (likely(count--)) - writeb(*buf++, uddr); - - return length; -} - -/* - * write to an IN endpoint fifo, as many packets as possible. - * irqs will use this to write the rest later. - * caller guarantees at least one packet buffer is ready (or a zlp). - */ -static int -write_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req) -{ - unsigned max; - - max = le16_to_cpu(get_unaligned(&ep->desc->wMaxPacketSize)); - do { - unsigned count; - int is_last, is_short; - - count = write_packet(ep->reg_uddr, req, max); - - /* last packet is usually short (or a zlp) */ - if (unlikely(count != max)) - is_last = is_short = 1; - else { - if (likely(req->req.length != req->req.actual) - || req->req.zero) - is_last = 0; - else - is_last = 1; - /* interrupt/iso maxpacket may not fill the fifo */ - is_short = unlikely(max < ep->fifo_size); - } - - debug_cond(NOISY, "wrote %s %d bytes%s%s %d left %p\n", - ep->ep.name, count, - is_last ? "/L" : "", is_short ? "/S" : "", - req->req.length - req->req.actual, req); - - /* - * let loose that packet. maybe try writing another one, - * double buffering might work. TSP, TPC, and TFS - * bit values are the same for all normal IN endpoints. - */ - writel(UDCCS_BI_TPC, ep->reg_udccs); - if (is_short) - writel(UDCCS_BI_TSP, ep->reg_udccs); - - /* requests complete when all IN data is in the FIFO */ - if (is_last) { - done(ep, req, 0); - if (list_empty(&ep->queue)) - pio_irq_disable(ep->bEndpointAddress); - return 1; - } - - /* - * TODO experiment: how robust can fifo mode tweaking be? - * double buffering is off in the default fifo mode, which - * prevents TFS from being set here. - */ - - } while (readl(ep->reg_udccs) & UDCCS_BI_TFS); - return 0; -} - -/* - * caller asserts req->pending (ep0 irq status nyet cleared); starts - * ep0 data stage. these chips want very simple state transitions. - */ -static inline -void ep0start(struct pxa25x_udc *dev, u32 flags, const char *tag) -{ - writel(flags|UDCCS0_SA|UDCCS0_OPR, &dev->regs->udccs[0]); - writel(USIR0_IR0, &dev->regs->usir0); - dev->req_pending = 0; - debug_cond(NOISY, "%s() %s, udccs0: %02x/%02x usir: %X.%X\n", - __func__, tag, readl(&dev->regs->udccs[0]), flags, - readl(&dev->regs->usir1), readl(&dev->regs->usir0)); -} - -static int -write_ep0_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req) -{ - unsigned count; - int is_short; - - count = write_packet(&ep->dev->regs->uddr0, req, EP0_FIFO_SIZE); - ep->dev->stats.write.bytes += count; - - /* last packet "must be" short (or a zlp) */ - is_short = (count != EP0_FIFO_SIZE); - - debug_cond(NOISY, "ep0in %d bytes %d left %p\n", count, - req->req.length - req->req.actual, req); - - if (unlikely(is_short)) { - if (ep->dev->req_pending) - ep0start(ep->dev, UDCCS0_IPR, "short IN"); - else - writel(UDCCS0_IPR, &ep->dev->regs->udccs[0]); - - count = req->req.length; - done(ep, req, 0); - ep0_idle(ep->dev); - - /* - * This seems to get rid of lost status irqs in some cases: - * host responds quickly, or next request involves config - * change automagic, or should have been hidden, or ... - * - * FIXME get rid of all udelays possible... - */ - if (count >= EP0_FIFO_SIZE) { - count = 100; - do { - if ((readl(&ep->dev->regs->udccs[0]) & - UDCCS0_OPR) != 0) { - /* clear OPR, generate ack */ - writel(UDCCS0_OPR, - &ep->dev->regs->udccs[0]); - break; - } - count--; - udelay(1); - } while (count); - } - } else if (ep->dev->req_pending) - ep0start(ep->dev, 0, "IN"); - - return is_short; -} - - -/* - * read_fifo - unload packet(s) from the fifo we use for usb OUT - * transfers and put them into the request. caller should have made - * sure there's at least one packet ready. - * - * returns true if the request completed because of short packet or the - * request buffer having filled (and maybe overran till end-of-packet). - */ -static int -read_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req) -{ - u32 udccs; - u8 *buf; - unsigned bufferspace, count, is_short; - - for (;;) { - /* - * make sure there's a packet in the FIFO. - * UDCCS_{BO,IO}_RPC are all the same bit value. - * UDCCS_{BO,IO}_RNE are all the same bit value. - */ - udccs = readl(ep->reg_udccs); - if (unlikely((udccs & UDCCS_BO_RPC) == 0)) - break; - buf = req->req.buf + req->req.actual; - prefetchw(buf); - bufferspace = req->req.length - req->req.actual; - - /* read all bytes from this packet */ - if (likely(udccs & UDCCS_BO_RNE)) { - count = 1 + (0x0ff & readl(ep->reg_ubcr)); - req->req.actual += min(count, bufferspace); - } else /* zlp */ - count = 0; - is_short = (count < ep->ep.maxpacket); - debug_cond(NOISY, "read %s %02x, %d bytes%s req %p %d/%d\n", - ep->ep.name, udccs, count, - is_short ? "/S" : "", - req, req->req.actual, req->req.length); - while (likely(count-- != 0)) { - u8 byte = readb(ep->reg_uddr); - - if (unlikely(bufferspace == 0)) { - /* - * this happens when the driver's buffer - * is smaller than what the host sent. - * discard the extra data. - */ - if (req->req.status != -EOVERFLOW) - printf("%s overflow %d\n", - ep->ep.name, count); - req->req.status = -EOVERFLOW; - } else { - *buf++ = byte; - bufferspace--; - } - } - writel(UDCCS_BO_RPC, ep->reg_udccs); - /* RPC/RSP/RNE could now reflect the other packet buffer */ - - /* iso is one request per packet */ - if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - if (udccs & UDCCS_IO_ROF) - req->req.status = -EHOSTUNREACH; - /* more like "is_done" */ - is_short = 1; - } - - /* completion */ - if (is_short || req->req.actual == req->req.length) { - done(ep, req, 0); - if (list_empty(&ep->queue)) - pio_irq_disable(ep->bEndpointAddress); - return 1; - } - - /* finished that packet. the next one may be waiting... */ - } - return 0; -} - -/* - * special ep0 version of the above. no UBCR0 or double buffering; status - * handshaking is magic. most device protocols don't need control-OUT. - * CDC vendor commands (and RNDIS), mass storage CB/CBI, and some other - * protocols do use them. - */ -static int -read_ep0_fifo(struct pxa25x_ep *ep, struct pxa25x_request *req) -{ - u8 *buf, byte; - unsigned bufferspace; - - buf = req->req.buf + req->req.actual; - bufferspace = req->req.length - req->req.actual; - - while (readl(&ep->dev->regs->udccs[0]) & UDCCS0_RNE) { - byte = (u8)readb(&ep->dev->regs->uddr0); - - if (unlikely(bufferspace == 0)) { - /* - * this happens when the driver's buffer - * is smaller than what the host sent. - * discard the extra data. - */ - if (req->req.status != -EOVERFLOW) - printf("%s overflow\n", ep->ep.name); - req->req.status = -EOVERFLOW; - } else { - *buf++ = byte; - req->req.actual++; - bufferspace--; - } - } - - writel(UDCCS0_OPR | UDCCS0_IPR, &ep->dev->regs->udccs[0]); - - /* completion */ - if (req->req.actual >= req->req.length) - return 1; - - /* finished that packet. the next one may be waiting... */ - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int -pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) -{ - struct pxa25x_request *req; - struct pxa25x_ep *ep; - struct pxa25x_udc *dev; - unsigned long flags; - - req = container_of(_req, struct pxa25x_request, req); - if (unlikely(!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue))) { - printf("%s, bad params\n", __func__); - return -EINVAL; - } - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { - printf("%s, bad ep\n", __func__); - return -EINVAL; - } - - dev = ep->dev; - if (unlikely(!dev->driver - || dev->gadget.speed == USB_SPEED_UNKNOWN)) { - printf("%s, bogus device state\n", __func__); - return -ESHUTDOWN; - } - - /* - * iso is always one packet per request, that's the only way - * we can report per-packet status. that also helps with dma. - */ - if (unlikely(ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - && req->req.length > - le16_to_cpu(get_unaligned(&ep->desc->wMaxPacketSize)))) - return -EMSGSIZE; - - debug_cond(NOISY, "%s queue req %p, len %d buf %p\n", - _ep->name, _req, _req->length, _req->buf); - - local_irq_save(flags); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - /* kickstart this i/o queue? */ - if (list_empty(&ep->queue) && !ep->stopped) { - if (ep->desc == NULL/* ep0 */) { - unsigned length = _req->length; - - switch (dev->ep0state) { - case EP0_IN_DATA_PHASE: - dev->stats.write.ops++; - if (write_ep0_fifo(ep, req)) - req = NULL; - break; - - case EP0_OUT_DATA_PHASE: - dev->stats.read.ops++; - /* messy ... */ - if (dev->req_config) { - debug("ep0 config ack%s\n", - dev->has_cfr ? "" : " raced"); - if (dev->has_cfr) - writel(UDCCFR_AREN|UDCCFR_ACM - |UDCCFR_MB1, - &ep->dev->regs->udccfr); - done(ep, req, 0); - dev->ep0state = EP0_END_XFER; - local_irq_restore(flags); - return 0; - } - if (dev->req_pending) - ep0start(dev, UDCCS0_IPR, "OUT"); - if (length == 0 || - ((readl( - &ep->dev->regs->udccs[0]) - & UDCCS0_RNE) != 0 - && read_ep0_fifo(ep, req))) { - ep0_idle(dev); - done(ep, req, 0); - req = NULL; - } - break; - - default: - printf("ep0 i/o, odd state %d\n", - dev->ep0state); - local_irq_restore(flags); - return -EL2HLT; - } - /* can the FIFO can satisfy the request immediately? */ - } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) { - if ((readl(ep->reg_udccs) & UDCCS_BI_TFS) != 0 - && write_fifo(ep, req)) - req = NULL; - } else if ((readl(ep->reg_udccs) & UDCCS_BO_RFS) != 0 - && read_fifo(ep, req)) { - req = NULL; - } - - if (likely(req && ep->desc)) - pio_irq_enable(ep->bEndpointAddress); - } - - /* pio or dma irq handler advances the queue. */ - if (likely(req != NULL)) - list_add_tail(&req->queue, &ep->queue); - local_irq_restore(flags); - - return 0; -} - - -/* - * nuke - dequeue ALL requests - */ -static void nuke(struct pxa25x_ep *ep, int status) -{ - struct pxa25x_request *req; - - /* called with irqs blocked */ - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct pxa25x_request, - queue); - done(ep, req, status); - } - if (ep->desc) - pio_irq_disable(ep->bEndpointAddress); -} - - -/* dequeue JUST ONE request */ -static int pxa25x_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct pxa25x_ep *ep; - struct pxa25x_request *req; - unsigned long flags; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (!_ep || ep->ep.name == ep0name) - return -EINVAL; - - local_irq_save(flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - local_irq_restore(flags); - return -EINVAL; - } - - done(ep, req, -ECONNRESET); - - local_irq_restore(flags); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct pxa25x_ep *ep; - unsigned long flags; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (unlikely(!_ep - || (!ep->desc && ep->ep.name != ep0name)) - || ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { - printf("%s, bad ep\n", __func__); - return -EINVAL; - } - if (value == 0) { - /* - * this path (reset toggle+halt) is needed to implement - * SET_INTERFACE on normal hardware. but it can't be - * done from software on the PXA UDC, and the hardware - * forgets to do it as part of SET_INTERFACE automagic. - */ - printf("only host can clear %s halt\n", _ep->name); - return -EROFS; - } - - local_irq_save(flags); - - if ((ep->bEndpointAddress & USB_DIR_IN) != 0 - && ((readl(ep->reg_udccs) & UDCCS_BI_TFS) == 0 - || !list_empty(&ep->queue))) { - local_irq_restore(flags); - return -EAGAIN; - } - - /* FST bit is the same for control, bulk in, bulk out, interrupt in */ - writel(UDCCS_BI_FST|UDCCS_BI_FTF, ep->reg_udccs); - - /* ep0 needs special care */ - if (!ep->desc) { - start_watchdog(ep->dev); - ep->dev->req_pending = 0; - ep->dev->ep0state = EP0_STALL; - - /* and bulk/intr endpoints like dropping stalls too */ - } else { - unsigned i; - for (i = 0; i < 1000; i += 20) { - if (readl(ep->reg_udccs) & UDCCS_BI_SST) - break; - udelay(20); - } - } - local_irq_restore(flags); - - debug("%s halt\n", _ep->name); - return 0; -} - -static int pxa25x_ep_fifo_status(struct usb_ep *_ep) -{ - struct pxa25x_ep *ep; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (!_ep) { - printf("%s, bad ep\n", __func__); - return -ENODEV; - } - /* pxa can't report unclaimed bytes from IN fifos */ - if ((ep->bEndpointAddress & USB_DIR_IN) != 0) - return -EOPNOTSUPP; - if (ep->dev->gadget.speed == USB_SPEED_UNKNOWN - || (readl(ep->reg_udccs) & UDCCS_BO_RFS) == 0) - return 0; - else - return (readl(ep->reg_ubcr) & 0xfff) + 1; -} - -static void pxa25x_ep_fifo_flush(struct usb_ep *_ep) -{ - struct pxa25x_ep *ep; - - ep = container_of(_ep, struct pxa25x_ep, ep); - if (!_ep || ep->ep.name == ep0name || !list_empty(&ep->queue)) { - printf("%s, bad ep\n", __func__); - return; - } - - /* toggle and halt bits stay unchanged */ - - /* for OUT, just read and discard the FIFO contents. */ - if ((ep->bEndpointAddress & USB_DIR_IN) == 0) { - while (((readl(ep->reg_udccs)) & UDCCS_BO_RNE) != 0) - (void)readb(ep->reg_uddr); - return; - } - - /* most IN status is the same, but ISO can't stall */ - writel(UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR - | (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - ? 0 : UDCCS_BI_SST), ep->reg_udccs); -} - - -static struct usb_ep_ops pxa25x_ep_ops = { - .enable = pxa25x_ep_enable, - .disable = pxa25x_ep_disable, - - .alloc_request = pxa25x_ep_alloc_request, - .free_request = pxa25x_ep_free_request, - - .queue = pxa25x_ep_queue, - .dequeue = pxa25x_ep_dequeue, - - .set_halt = pxa25x_ep_set_halt, - .fifo_status = pxa25x_ep_fifo_status, - .fifo_flush = pxa25x_ep_fifo_flush, -}; - - -/* --------------------------------------------------------------------------- - * device-scoped parts of the api to the usb controller hardware - * --------------------------------------------------------------------------- - */ - -static int pxa25x_udc_get_frame(struct usb_gadget *_gadget) -{ - return ((readl(&the_controller->regs->ufnrh) & 0x07) << 8) | - (readl(&the_controller->regs->ufnrl) & 0xff); -} - -static int pxa25x_udc_wakeup(struct usb_gadget *_gadget) -{ - /* host may not have enabled remote wakeup */ - if ((readl(&the_controller->regs->udccs[0]) & UDCCS0_DRWF) == 0) - return -EHOSTUNREACH; - udc_set_mask_UDCCR(UDCCR_RSM); - return 0; -} - -static void stop_activity(struct pxa25x_udc *, struct usb_gadget_driver *); -static void udc_enable(struct pxa25x_udc *); -static void udc_disable(struct pxa25x_udc *); - -/* - * We disable the UDC -- and its 48 MHz clock -- whenever it's not - * in active use. - */ -static int pullup(struct pxa25x_udc *udc) -{ - if (udc->pullup) - pullup_on(); - else - pullup_off(); - - - int is_active = udc->pullup; - if (is_active) { - if (!udc->active) { - udc->active = 1; - udc_enable(udc); - } - } else { - if (udc->active) { - if (udc->gadget.speed != USB_SPEED_UNKNOWN) - stop_activity(udc, udc->driver); - udc_disable(udc); - udc->active = 0; - } - - } - return 0; -} - -/* VBUS reporting logically comes from a transceiver */ -static int pxa25x_udc_vbus_session(struct usb_gadget *_gadget, int is_active) -{ - struct pxa25x_udc *udc; - - udc = container_of(_gadget, struct pxa25x_udc, gadget); - printf("vbus %s\n", is_active ? "supplied" : "inactive"); - pullup(udc); - return 0; -} - -/* drivers may have software control over D+ pullup */ -static int pxa25x_udc_pullup(struct usb_gadget *_gadget, int is_active) -{ - struct pxa25x_udc *udc; - - udc = container_of(_gadget, struct pxa25x_udc, gadget); - - /* not all boards support pullup control */ - if (!udc->mach->udc_command) - return -EOPNOTSUPP; - - udc->pullup = (is_active != 0); - pullup(udc); - return 0; -} - -/* - * boards may consume current from VBUS, up to 100-500mA based on config. - * the 500uA suspend ceiling means that exclusively vbus-powered PXA designs - * violate USB specs. - */ -static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA) -{ - return -EOPNOTSUPP; -} - -static const struct usb_gadget_ops pxa25x_udc_ops = { - .get_frame = pxa25x_udc_get_frame, - .wakeup = pxa25x_udc_wakeup, - .vbus_session = pxa25x_udc_vbus_session, - .pullup = pxa25x_udc_pullup, - .vbus_draw = pxa25x_udc_vbus_draw, -}; - -/*-------------------------------------------------------------------------*/ - -/* - * udc_disable - disable USB device controller - */ -static void udc_disable(struct pxa25x_udc *dev) -{ - /* block all irqs */ - udc_set_mask_UDCCR(UDCCR_SRM|UDCCR_REM); - writel(0xff, &dev->regs->uicr0); - writel(0xff, &dev->regs->uicr1); - writel(UFNRH_SIM, &dev->regs->ufnrh); - - /* if hardware supports it, disconnect from usb */ - pullup_off(); - - udc_clear_mask_UDCCR(UDCCR_UDE); - - ep0_idle(dev); - dev->gadget.speed = USB_SPEED_UNKNOWN; -} - -/* - * udc_reinit - initialize software state - */ -static void udc_reinit(struct pxa25x_udc *dev) -{ - u32 i; - - /* device/ep0 records init */ - INIT_LIST_HEAD(&dev->gadget.ep_list); - INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); - dev->ep0state = EP0_IDLE; - - /* basic endpoint records init */ - for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { - struct pxa25x_ep *ep = &dev->ep[i]; - - if (i != 0) - list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); - - ep->desc = NULL; - ep->stopped = 0; - INIT_LIST_HEAD(&ep->queue); - ep->pio_irqs = 0; - } - - /* the rest was statically initialized, and is read-only */ -} - -/* - * until it's enabled, this UDC should be completely invisible - * to any USB host. - */ -static void udc_enable(struct pxa25x_udc *dev) -{ - debug("udc: enabling udc\n"); - - udc_clear_mask_UDCCR(UDCCR_UDE); - - /* - * Try to clear these bits before we enable the udc. - * Do not touch reset ack bit, we would take care of it in - * interrupt handle routine - */ - udc_ack_int_UDCCR(UDCCR_SUSIR|UDCCR_RESIR); - - ep0_idle(dev); - dev->gadget.speed = USB_SPEED_UNKNOWN; - dev->stats.irqs = 0; - - /* - * sequence taken from chapter 12.5.10, PXA250 AppProcDevManual: - * - enable UDC - * - if RESET is already in progress, ack interrupt - * - unmask reset interrupt - */ - udc_set_mask_UDCCR(UDCCR_UDE); - if (!(readl(&dev->regs->udccr) & UDCCR_UDA)) - udc_ack_int_UDCCR(UDCCR_RSTIR); - - if (dev->has_cfr /* UDC_RES2 is defined */) { - /* - * pxa255 (a0+) can avoid a set_config race that could - * prevent gadget drivers from configuring correctly - */ - writel(UDCCFR_ACM | UDCCFR_MB1, &dev->regs->udccfr); - } - - /* enable suspend/resume and reset irqs */ - udc_clear_mask_UDCCR(UDCCR_SRM | UDCCR_REM); - - /* enable ep0 irqs */ - clrbits_le32(&dev->regs->uicr0, UICR0_IM0); - - /* if hardware supports it, pullup D+ and wait for reset */ - pullup_on(); -} - -static inline void clear_ep_state(struct pxa25x_udc *dev) -{ - unsigned i; - - /* - * hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint - * fifos, and pending transactions mustn't be continued in any case. - */ - for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) - nuke(&dev->ep[i], -ECONNABORTED); -} - -static void handle_ep0(struct pxa25x_udc *dev) -{ - u32 udccs0 = readl(&dev->regs->udccs[0]); - struct pxa25x_ep *ep = &dev->ep[0]; - struct pxa25x_request *req; - union { - struct usb_ctrlrequest r; - u8 raw[8]; - u32 word[2]; - } u; - - if (list_empty(&ep->queue)) - req = NULL; - else - req = list_entry(ep->queue.next, struct pxa25x_request, queue); - - /* clear stall status */ - if (udccs0 & UDCCS0_SST) { - nuke(ep, -EPIPE); - writel(UDCCS0_SST, &dev->regs->udccs[0]); - stop_watchdog(dev); - ep0_idle(dev); - } - - /* previous request unfinished? non-error iff back-to-back ... */ - if ((udccs0 & UDCCS0_SA) != 0 && dev->ep0state != EP0_IDLE) { - nuke(ep, 0); - stop_watchdog(dev); - ep0_idle(dev); - } - - switch (dev->ep0state) { - case EP0_IDLE: - /* late-breaking status? */ - udccs0 = readl(&dev->regs->udccs[0]); - - /* start control request? */ - if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE)) - == (UDCCS0_OPR|UDCCS0_SA|UDCCS0_RNE))) { - int i; - - nuke(ep, -EPROTO); - - /* read SETUP packet */ - for (i = 0; i < 8; i++) { - if (unlikely(!(readl(&dev->regs->udccs[0]) & - UDCCS0_RNE))) { -bad_setup: - debug("SETUP %d!\n", i); - goto stall; - } - u.raw[i] = (u8)readb(&dev->regs->uddr0); - } - if (unlikely((readl(&dev->regs->udccs[0]) & - UDCCS0_RNE) != 0)) - goto bad_setup; - -got_setup: - debug("SETUP %02x.%02x v%04x i%04x l%04x\n", - u.r.bRequestType, u.r.bRequest, - le16_to_cpu(u.r.wValue), - le16_to_cpu(u.r.wIndex), - le16_to_cpu(u.r.wLength)); - - /* cope with automagic for some standard requests. */ - dev->req_std = (u.r.bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD; - dev->req_config = 0; - dev->req_pending = 1; - switch (u.r.bRequest) { - /* hardware restricts gadget drivers here! */ - case USB_REQ_SET_CONFIGURATION: - debug("GOT SET_CONFIGURATION\n"); - if (u.r.bRequestType == USB_RECIP_DEVICE) { - /* - * reflect hardware's automagic - * up to the gadget driver. - */ -config_change: - dev->req_config = 1; - clear_ep_state(dev); - /* - * if !has_cfr, there's no synch - * else use AREN (later) not SA|OPR - * USIR0_IR0 acts edge sensitive - */ - } - break; - /* ... and here, even more ... */ - case USB_REQ_SET_INTERFACE: - if (u.r.bRequestType == USB_RECIP_INTERFACE) { - /* - * udc hardware is broken by design: - * - altsetting may only be zero; - * - hw resets all interfaces' eps; - * - ep reset doesn't include halt(?). - */ - printf("broken set_interface (%d/%d)\n", - le16_to_cpu(u.r.wIndex), - le16_to_cpu(u.r.wValue)); - goto config_change; - } - break; - /* hardware was supposed to hide this */ - case USB_REQ_SET_ADDRESS: - debug("GOT SET ADDRESS\n"); - if (u.r.bRequestType == USB_RECIP_DEVICE) { - ep0start(dev, 0, "address"); - return; - } - break; - } - - if (u.r.bRequestType & USB_DIR_IN) - dev->ep0state = EP0_IN_DATA_PHASE; - else - dev->ep0state = EP0_OUT_DATA_PHASE; - - i = dev->driver->setup(&dev->gadget, &u.r); - if (i < 0) { - /* hardware automagic preventing STALL... */ - if (dev->req_config) { - /* - * hardware sometimes neglects to tell - * tell us about config change events, - * so later ones may fail... - */ - printf("config change %02x fail %d?\n", - u.r.bRequest, i); - return; - /* - * TODO experiment: if has_cfr, - * hardware didn't ACK; maybe we - * could actually STALL! - */ - } - if (0) { -stall: - /* uninitialized when goto stall */ - i = 0; - } - debug("protocol STALL, " - "%02x err %d\n", - readl(&dev->regs->udccs[0]), i); - - /* - * the watchdog timer helps deal with cases - * where udc seems to clear FST wrongly, and - * then NAKs instead of STALLing. - */ - ep0start(dev, UDCCS0_FST|UDCCS0_FTF, "stall"); - start_watchdog(dev); - dev->ep0state = EP0_STALL; - - /* deferred i/o == no response yet */ - } else if (dev->req_pending) { - if (likely(dev->ep0state == EP0_IN_DATA_PHASE - || dev->req_std || u.r.wLength)) - ep0start(dev, 0, "defer"); - else - ep0start(dev, UDCCS0_IPR, "defer/IPR"); - } - - /* expect at least one data or status stage irq */ - return; - - } else if (likely((udccs0 & (UDCCS0_OPR|UDCCS0_SA)) - == (UDCCS0_OPR|UDCCS0_SA))) { - unsigned i; - - /* - * pxa210/250 erratum 131 for B0/B1 says RNE lies. - * still observed on a pxa255 a0. - */ - debug("e131\n"); - nuke(ep, -EPROTO); - - /* read SETUP data, but don't trust it too much */ - for (i = 0; i < 8; i++) - u.raw[i] = (u8)readb(&dev->regs->uddr0); - if ((u.r.bRequestType & USB_RECIP_MASK) - > USB_RECIP_OTHER) - goto stall; - if (u.word[0] == 0 && u.word[1] == 0) - goto stall; - goto got_setup; - } else { - /* - * some random early IRQ: - * - we acked FST - * - IPR cleared - * - OPR got set, without SA (likely status stage) - */ - debug("random IRQ %X %X\n", udccs0, - readl(&dev->regs->udccs[0])); - writel(udccs0 & (UDCCS0_SA|UDCCS0_OPR), - &dev->regs->udccs[0]); - } - break; - case EP0_IN_DATA_PHASE: /* GET_DESCRIPTOR etc */ - if (udccs0 & UDCCS0_OPR) { - debug("ep0in premature status\n"); - if (req) - done(ep, req, 0); - ep0_idle(dev); - } else /* irq was IPR clearing */ { - if (req) { - debug("next ep0 in packet\n"); - /* this IN packet might finish the request */ - (void) write_ep0_fifo(ep, req); - } /* else IN token before response was written */ - } - break; - case EP0_OUT_DATA_PHASE: /* SET_DESCRIPTOR etc */ - if (udccs0 & UDCCS0_OPR) { - if (req) { - /* this OUT packet might finish the request */ - if (read_ep0_fifo(ep, req)) - done(ep, req, 0); - /* else more OUT packets expected */ - } /* else OUT token before read was issued */ - } else /* irq was IPR clearing */ { - debug("ep0out premature status\n"); - if (req) - done(ep, req, 0); - ep0_idle(dev); - } - break; - case EP0_END_XFER: - if (req) - done(ep, req, 0); - /* - * ack control-IN status (maybe in-zlp was skipped) - * also appears after some config change events. - */ - if (udccs0 & UDCCS0_OPR) - writel(UDCCS0_OPR, &dev->regs->udccs[0]); - ep0_idle(dev); - break; - case EP0_STALL: - writel(UDCCS0_FST, &dev->regs->udccs[0]); - break; - } - - writel(USIR0_IR0, &dev->regs->usir0); -} - -static void handle_ep(struct pxa25x_ep *ep) -{ - struct pxa25x_request *req; - int is_in = ep->bEndpointAddress & USB_DIR_IN; - int completed; - u32 udccs, tmp; - - do { - completed = 0; - if (likely(!list_empty(&ep->queue))) - req = list_entry(ep->queue.next, - struct pxa25x_request, queue); - else - req = NULL; - - /* TODO check FST handling */ - - udccs = readl(ep->reg_udccs); - if (unlikely(is_in)) { /* irq from TPC, SST, or (ISO) TUR */ - tmp = UDCCS_BI_TUR; - if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK)) - tmp |= UDCCS_BI_SST; - tmp &= udccs; - if (likely(tmp)) - writel(tmp, ep->reg_udccs); - if (req && likely((udccs & UDCCS_BI_TFS) != 0)) - completed = write_fifo(ep, req); - - } else { /* irq from RPC (or for ISO, ROF) */ - if (likely(ep->bmAttributes == USB_ENDPOINT_XFER_BULK)) - tmp = UDCCS_BO_SST | UDCCS_BO_DME; - else - tmp = UDCCS_IO_ROF | UDCCS_IO_DME; - tmp &= udccs; - if (likely(tmp)) - writel(tmp, ep->reg_udccs); - - /* fifos can hold packets, ready for reading... */ - if (likely(req)) - completed = read_fifo(ep, req); - else - pio_irq_disable(ep->bEndpointAddress); - } - ep->pio_irqs++; - } while (completed); -} - -/* - * pxa25x_udc_irq - interrupt handler - * - * avoid delays in ep0 processing. the control handshaking isn't always - * under software control (pxa250c0 and the pxa255 are better), and delays - * could cause usb protocol errors. - */ -static struct pxa25x_udc memory; -static int -pxa25x_udc_irq(void) -{ - struct pxa25x_udc *dev = &memory; - int handled; - - test_watchdog(dev); - - dev->stats.irqs++; - do { - u32 udccr = readl(&dev->regs->udccr); - - handled = 0; - - /* SUSpend Interrupt Request */ - if (unlikely(udccr & UDCCR_SUSIR)) { - udc_ack_int_UDCCR(UDCCR_SUSIR); - handled = 1; - debug("USB suspend\n"); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->suspend) - dev->driver->suspend(&dev->gadget); - ep0_idle(dev); - } - - /* RESume Interrupt Request */ - if (unlikely(udccr & UDCCR_RESIR)) { - udc_ack_int_UDCCR(UDCCR_RESIR); - handled = 1; - debug("USB resume\n"); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->resume) - dev->driver->resume(&dev->gadget); - } - - /* ReSeT Interrupt Request - USB reset */ - if (unlikely(udccr & UDCCR_RSTIR)) { - udc_ack_int_UDCCR(UDCCR_RSTIR); - handled = 1; - - if ((readl(&dev->regs->udccr) & UDCCR_UDA) == 0) { - debug("USB reset start\n"); - - /* - * reset driver and endpoints, - * in case that's not yet done - */ - stop_activity(dev, dev->driver); - - } else { - debug("USB reset end\n"); - dev->gadget.speed = USB_SPEED_FULL; - memset(&dev->stats, 0, sizeof dev->stats); - /* driver and endpoints are still reset */ - } - - } else { - u32 uicr0 = readl(&dev->regs->uicr0); - u32 uicr1 = readl(&dev->regs->uicr1); - u32 usir0 = readl(&dev->regs->usir0); - u32 usir1 = readl(&dev->regs->usir1); - - usir0 = usir0 & ~uicr0; - usir1 = usir1 & ~uicr1; - int i; - - if (unlikely(!usir0 && !usir1)) - continue; - - debug_cond(NOISY, "irq %02x.%02x\n", usir1, usir0); - - /* control traffic */ - if (usir0 & USIR0_IR0) { - dev->ep[0].pio_irqs++; - handle_ep0(dev); - handled = 1; - } - - /* endpoint data transfers */ - for (i = 0; i < 8; i++) { - u32 tmp = 1 << i; - - if (i && (usir0 & tmp)) { - handle_ep(&dev->ep[i]); - setbits_le32(&dev->regs->usir0, tmp); - handled = 1; - } -#ifndef CONFIG_USB_PXA25X_SMALL - if (usir1 & tmp) { - handle_ep(&dev->ep[i+8]); - setbits_le32(&dev->regs->usir1, tmp); - handled = 1; - } -#endif - } - } - - /* we could also ask for 1 msec SOF (SIR) interrupts */ - - } while (handled); - return IRQ_HANDLED; -} - -/*-------------------------------------------------------------------------*/ - -/* - * this uses load-time allocation and initialization (instead of - * doing it at run-time) to save code, eliminate fault paths, and - * be more obviously correct. - */ -static struct pxa25x_udc memory = { - .regs = UDC_REGS, - - .gadget = { - .ops = &pxa25x_udc_ops, - .ep0 = &memory.ep[0].ep, - .name = driver_name, - }, - - /* control endpoint */ - .ep[0] = { - .ep = { - .name = ep0name, - .ops = &pxa25x_ep_ops, - .maxpacket = EP0_FIFO_SIZE, - }, - .dev = &memory, - .reg_udccs = &UDC_REGS->udccs[0], - .reg_uddr = &UDC_REGS->uddr0, - }, - - /* first group of endpoints */ - .ep[1] = { - .ep = { - .name = "ep1in-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 1, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDC_REGS->udccs[1], - .reg_uddr = &UDC_REGS->uddr1, - }, - .ep[2] = { - .ep = { - .name = "ep2out-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = 2, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDC_REGS->udccs[2], - .reg_ubcr = &UDC_REGS->ubcr2, - .reg_uddr = &UDC_REGS->uddr2, - }, -#ifndef CONFIG_USB_PXA25X_SMALL - .ep[3] = { - .ep = { - .name = "ep3in-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 3, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDC_REGS->udccs[3], - .reg_uddr = &UDC_REGS->uddr3, - }, - .ep[4] = { - .ep = { - .name = "ep4out-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = 4, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDC_REGS->udccs[4], - .reg_ubcr = &UDC_REGS->ubcr4, - .reg_uddr = &UDC_REGS->uddr4, - }, - .ep[5] = { - .ep = { - .name = "ep5in-int", - .ops = &pxa25x_ep_ops, - .maxpacket = INT_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = INT_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 5, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .reg_udccs = &UDC_REGS->udccs[5], - .reg_uddr = &UDC_REGS->uddr5, - }, - - /* second group of endpoints */ - .ep[6] = { - .ep = { - .name = "ep6in-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 6, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDC_REGS->udccs[6], - .reg_uddr = &UDC_REGS->uddr6, - }, - .ep[7] = { - .ep = { - .name = "ep7out-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = 7, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDC_REGS->udccs[7], - .reg_ubcr = &UDC_REGS->ubcr7, - .reg_uddr = &UDC_REGS->uddr7, - }, - .ep[8] = { - .ep = { - .name = "ep8in-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 8, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDC_REGS->udccs[8], - .reg_uddr = &UDC_REGS->uddr8, - }, - .ep[9] = { - .ep = { - .name = "ep9out-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = 9, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDC_REGS->udccs[9], - .reg_ubcr = &UDC_REGS->ubcr9, - .reg_uddr = &UDC_REGS->uddr9, - }, - .ep[10] = { - .ep = { - .name = "ep10in-int", - .ops = &pxa25x_ep_ops, - .maxpacket = INT_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = INT_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 10, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .reg_udccs = &UDC_REGS->udccs[10], - .reg_uddr = &UDC_REGS->uddr10, - }, - - /* third group of endpoints */ - .ep[11] = { - .ep = { - .name = "ep11in-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 11, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDC_REGS->udccs[11], - .reg_uddr = &UDC_REGS->uddr11, - }, - .ep[12] = { - .ep = { - .name = "ep12out-bulk", - .ops = &pxa25x_ep_ops, - .maxpacket = BULK_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = BULK_FIFO_SIZE, - .bEndpointAddress = 12, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .reg_udccs = &UDC_REGS->udccs[12], - .reg_ubcr = &UDC_REGS->ubcr12, - .reg_uddr = &UDC_REGS->uddr12, - }, - .ep[13] = { - .ep = { - .name = "ep13in-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 13, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDC_REGS->udccs[13], - .reg_uddr = &UDC_REGS->uddr13, - }, - .ep[14] = { - .ep = { - .name = "ep14out-iso", - .ops = &pxa25x_ep_ops, - .maxpacket = ISO_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = ISO_FIFO_SIZE, - .bEndpointAddress = 14, - .bmAttributes = USB_ENDPOINT_XFER_ISOC, - .reg_udccs = &UDC_REGS->udccs[14], - .reg_ubcr = &UDC_REGS->ubcr14, - .reg_uddr = &UDC_REGS->uddr14, - }, - .ep[15] = { - .ep = { - .name = "ep15in-int", - .ops = &pxa25x_ep_ops, - .maxpacket = INT_FIFO_SIZE, - }, - .dev = &memory, - .fifo_size = INT_FIFO_SIZE, - .bEndpointAddress = USB_DIR_IN | 15, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .reg_udccs = &UDC_REGS->udccs[15], - .reg_uddr = &UDC_REGS->uddr15, - }, -#endif /* !CONFIG_USB_PXA25X_SMALL */ -}; - -static void udc_command(int cmd) -{ - switch (cmd) { - case PXA2XX_UDC_CMD_CONNECT: - setbits_le32(GPDR(CONFIG_USB_DEV_PULLUP_GPIO), - GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO)); - - /* enable pullup */ - writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), - GPCR(CONFIG_USB_DEV_PULLUP_GPIO)); - - debug("Connected to USB\n"); - break; - - case PXA2XX_UDC_CMD_DISCONNECT: - /* disable pullup resistor */ - writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), - GPSR(CONFIG_USB_DEV_PULLUP_GPIO)); - - /* setup pin as input, line will float */ - clrbits_le32(GPDR(CONFIG_USB_DEV_PULLUP_GPIO), - GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO)); - - debug("Disconnected from USB\n"); - break; - } -} - -static struct pxa2xx_udc_mach_info mach_info = { - .udc_command = udc_command, -}; - -/* - * when a driver is successfully registered, it will receive - * control requests including set_configuration(), which enables - * non-control requests. then usb traffic follows until a - * disconnect is reported. then a host may connect again, or - * the driver might get unbound. - */ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) -{ - struct pxa25x_udc *dev = &memory; - int retval; - uint32_t chiprev; - - if (!driver - || driver->speed < USB_SPEED_FULL - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; - - /* Enable clock for usb controller */ - setbits_le32(CKEN, CKEN11_USB); - - /* first hook up the driver ... */ - dev->driver = driver; - dev->pullup = 1; - - /* trigger chiprev-specific logic */ - switch ((chiprev = pxa_get_cpu_revision())) { - case PXA255_A0: - dev->has_cfr = 1; - break; - case PXA250_A0: - case PXA250_A1: - /* A0/A1 "not released"; ep 13, 15 unusable */ - /* fall through */ - case PXA250_B2: case PXA210_B2: - case PXA250_B1: case PXA210_B1: - case PXA250_B0: case PXA210_B0: - /* OUT-DMA is broken ... */ - /* fall through */ - case PXA250_C0: case PXA210_C0: - break; - default: - printf("%s: unrecognized processor: %08x\n", - DRIVER_NAME, chiprev); - return -ENODEV; - } - - the_controller = dev; - - /* prepare watchdog timer */ - dev->watchdog.running = 0; - dev->watchdog.period = 5000 * CONFIG_SYS_HZ / 1000000; /* 5 ms */ - dev->watchdog.function = udc_watchdog; - - udc_disable(dev); - udc_reinit(dev); - - dev->mach = &mach_info; - - dev->gadget.name = "pxa2xx_udc"; - retval = driver->bind(&dev->gadget); - if (retval) { - printf("bind to driver %s --> error %d\n", - DRIVER_NAME, retval); - dev->driver = NULL; - return retval; - } - - /* - * ... then enable host detection and ep0; and we're ready - * for set_configuration as well as eventual disconnect. - */ - printf("registered gadget driver '%s'\n", DRIVER_NAME); - - pullup(dev); - dump_state(dev); - return 0; -} - -static void -stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver) -{ - int i; - - /* don't disconnect drivers more than once */ - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = NULL; - dev->gadget.speed = USB_SPEED_UNKNOWN; - - /* prevent new request submissions, kill any outstanding requests */ - for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) { - struct pxa25x_ep *ep = &dev->ep[i]; - - ep->stopped = 1; - nuke(ep, -ESHUTDOWN); - } - stop_watchdog(dev); - - /* report disconnect; the driver is already quiesced */ - if (driver) - driver->disconnect(&dev->gadget); - - /* re-init driver-visible data structures */ - udc_reinit(dev); -} - -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct pxa25x_udc *dev = the_controller; - - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver || !driver->unbind) - return -EINVAL; - - local_irq_disable(); - dev->pullup = 0; - pullup(dev); - stop_activity(dev, driver); - local_irq_enable(); - - driver->unbind(&dev->gadget); - dev->driver = NULL; - - printf("unregistered gadget driver '%s'\n", DRIVER_NAME); - dump_state(dev); - - the_controller = NULL; - - clrbits_le32(CKEN, CKEN11_USB); - - return 0; -} - -extern void udc_disconnect(void) -{ - setbits_le32(CKEN, CKEN11_USB); - udc_clear_mask_UDCCR(UDCCR_UDE); - udc_command(PXA2XX_UDC_CMD_DISCONNECT); - clrbits_le32(CKEN, CKEN11_USB); -} - -/*-------------------------------------------------------------------------*/ - -extern int -usb_gadget_handle_interrupts(void) -{ - return pxa25x_udc_irq(); -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/pxa25x_udc.h b/qemu/roms/u-boot/drivers/usb/gadget/pxa25x_udc.h deleted file mode 100644 index f543b2d58..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/pxa25x_udc.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * Intel PXA25x on-chip full speed USB device controller - * - * Copyright (C) 2003 Robert Schwebel <r.schwebel@pengutronix.de>, Pengutronix - * Copyright (C) 2003 David Brownell - * Copyright (C) 2012 Lukasz Dalek <luk0104@gmail.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __LINUX_USB_GADGET_PXA25X_H -#define __LINUX_USB_GADGET_PXA25X_H - -#include <linux/types.h> -#include <asm/arch/regs-usb.h> - -/* - * Prefetching support - only ARMv5. - */ - -#ifdef ARCH_HAS_PREFETCH -static inline void prefetch(const void *ptr) -{ - __asm__ __volatile__( - "pld\t%a0" - : - : "p" (ptr) - : "cc"); -} - -#define prefetchw(ptr) prefetch(ptr) -#endif /* ARCH_HAS_PREFETCH */ - -/*-------------------------------------------------------------------------*/ - -#define UDC_REGS ((struct pxa25x_udc_regs *)PXA25X_UDC_BASE) - -/*-------------------------------------------------------------------------*/ - -struct pxa2xx_udc_mach_info { - int (*udc_is_connected)(void); /* do we see host? */ - void (*udc_command)(int cmd); -#define PXA2XX_UDC_CMD_CONNECT 0 /* let host see us */ -#define PXA2XX_UDC_CMD_DISCONNECT 1 /* so host won't see us */ -}; - -struct pxa25x_udc; - -struct pxa25x_ep { - struct usb_ep ep; - struct pxa25x_udc *dev; - - const struct usb_endpoint_descriptor *desc; - struct list_head queue; - unsigned long pio_irqs; - - unsigned short fifo_size; - u8 bEndpointAddress; - u8 bmAttributes; - - unsigned stopped:1; - - /* UDCCS = UDC Control/Status for this EP - * UBCR = UDC Byte Count Remaining (contents of OUT fifo) - * UDDR = UDC Endpoint Data Register (the fifo) - * DRCM = DMA Request Channel Map - */ - u32 *reg_udccs; - u32 *reg_ubcr; - u32 *reg_uddr; -}; - -struct pxa25x_request { - struct usb_request req; - struct list_head queue; -}; - -enum ep0_state { - EP0_IDLE, - EP0_IN_DATA_PHASE, - EP0_OUT_DATA_PHASE, - EP0_END_XFER, - EP0_STALL, -}; - -#define EP0_FIFO_SIZE 16U -#define BULK_FIFO_SIZE 64U -#define ISO_FIFO_SIZE 256U -#define INT_FIFO_SIZE 8U - -struct udc_stats { - struct ep0stats { - unsigned long ops; - unsigned long bytes; - } read, write; - unsigned long irqs; -}; - -#ifdef CONFIG_USB_PXA25X_SMALL -/* when memory's tight, SMALL config saves code+data. */ -#define PXA_UDC_NUM_ENDPOINTS 3 -#endif - -#ifndef PXA_UDC_NUM_ENDPOINTS -#define PXA_UDC_NUM_ENDPOINTS 16 -#endif - -struct pxa25x_watchdog { - unsigned running:1; - ulong period; - ulong base; - struct pxa25x_udc *udc; - - void (*function)(struct pxa25x_udc *udc); -}; - -struct pxa25x_udc { - struct usb_gadget gadget; - struct usb_gadget_driver *driver; - struct pxa25x_udc_regs *regs; - - enum ep0_state ep0state; - struct udc_stats stats; - unsigned got_irq:1, - pullup:1, - has_cfr:1, - req_pending:1, - req_std:1, - req_config:1, - active:1; - - struct clk *clk; - struct pxa2xx_udc_mach_info *mach; - u64 dma_mask; - struct pxa25x_ep ep[PXA_UDC_NUM_ENDPOINTS]; - - struct pxa25x_watchdog watchdog; -}; - -/*-------------------------------------------------------------------------*/ - -static struct pxa25x_udc *the_controller; - -/*-------------------------------------------------------------------------*/ - -#ifndef DEBUG -# define NOISY 0 -#endif - -#endif /* __LINUX_USB_GADGET_PXA25X_H */ diff --git a/qemu/roms/u-boot/drivers/usb/gadget/pxa27x_udc.c b/qemu/roms/u-boot/drivers/usb/gadget/pxa27x_udc.c deleted file mode 100644 index 733558def..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/pxa27x_udc.c +++ /dev/null @@ -1,703 +0,0 @@ -/* - * PXA27x USB device driver for u-boot. - * - * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it> - * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it> - * Copyright (C) 2008 Vivek Kutal <vivek.kutal@azingo.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - - -#include <common.h> -#include <config.h> -#include <asm/byteorder.h> -#include <usbdevice.h> -#include <asm/arch/hardware.h> -#include <asm/io.h> -#include <usb/pxa27x_udc.h> -#include <usb/udc.h> - -#include "ep0.h" - -/* number of endpoints on this UDC */ -#define UDC_MAX_ENDPOINTS 24 - -static struct urb *ep0_urb; -static struct usb_device_instance *udc_device; -static int ep0state = EP0_IDLE; - -#ifdef USBDDBG -static void udc_dump_buffer(char *name, u8 *buf, int len) -{ - usbdbg("%s - buf %p, len %d", name, buf, len); - print_buffer(0, buf, 1, len, 0); -} -#else -#define udc_dump_buffer(name, buf, len) /* void */ -#endif - -static inline void udc_ack_int_UDCCR(int mask) -{ - writel(readl(USIR1) | mask, USIR1); -} - -/* - * If the endpoint has an active tx_urb, then the next packet of data from the - * URB is written to the tx FIFO. - * The total amount of data in the urb is given by urb->actual_length. - * The maximum amount of data that can be sent in any one packet is given by - * endpoint->tx_packetSize. - * The number of data bytes from this URB that have already been transmitted - * is given by endpoint->sent. - * endpoint->last is updated by this routine with the number of data bytes - * transmitted in this packet. - */ -static int udc_write_urb(struct usb_endpoint_instance *endpoint) -{ - struct urb *urb = endpoint->tx_urb; - int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; - u32 *data32 = (u32 *) urb->buffer; - u8 *data8 = (u8 *) urb->buffer; - unsigned int i, n, w, b, is_short; - int timeout = 2000; /* 2ms */ - - if (!urb || !urb->actual_length) - return -1; - - n = MIN(urb->actual_length - endpoint->sent, endpoint->tx_packetSize); - if (n <= 0) - return -1; - - usbdbg("write urb on ep %d", ep_num); -#if defined(USBDDBG) && defined(USBDPARANOIA) - usbdbg("urb: buf %p, buf_len %d, actual_len %d", - urb->buffer, urb->buffer_length, urb->actual_length); - usbdbg("endpoint: sent %d, tx_packetSize %d, last %d", - endpoint->sent, endpoint->tx_packetSize, endpoint->last); -#endif - - is_short = n != endpoint->tx_packetSize; - w = n / 4; - b = n % 4; - usbdbg("n %d%s w %d b %d", n, is_short ? "-s" : "", w, b); - udc_dump_buffer("urb write", data8 + endpoint->sent, n); - - /* Prepare for data send */ - if (ep_num) - writel(UDCCSR_PC ,UDCCSN(ep_num)); - - for (i = 0; i < w; i++) - writel(data32[endpoint->sent / 4 + i], UDCDN(ep_num)); - - for (i = 0; i < b; i++) - writeb(data8[endpoint->sent + w * 4 + i], UDCDN(ep_num)); - - /* Set "Packet Complete" if less data then tx_packetSize */ - if (is_short) - writel(ep_num ? UDCCSR_SP : UDCCSR0_IPR, UDCCSN(ep_num)); - - /* Wait for data sent */ - if (ep_num) { - while (!(readl(UDCCSN(ep_num)) & UDCCSR_PC)) { - if (timeout-- == 0) - return -1; - else - udelay(1); - } - } - - endpoint->last = n; - - if (ep_num) { - usbd_tx_complete(endpoint); - } else { - endpoint->sent += n; - endpoint->last -= n; - } - - if (endpoint->sent >= urb->actual_length) { - urb->actual_length = 0; - endpoint->sent = 0; - endpoint->last = 0; - } - - if ((endpoint->sent >= urb->actual_length) && (!ep_num)) { - usbdbg("ep0 IN stage done"); - if (is_short) - ep0state = EP0_IDLE; - else - ep0state = EP0_XFER_COMPLETE; - } - - return 0; -} - -static int udc_read_urb(struct usb_endpoint_instance *endpoint) -{ - struct urb *urb = endpoint->rcv_urb; - int ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; - u32 *data32 = (u32 *) urb->buffer; - unsigned int i, n; - - usbdbg("read urb on ep %d", ep_num); -#if defined(USBDDBG) && defined(USBDPARANOIA) - usbdbg("urb: buf %p, buf_len %d, actual_len %d", - urb->buffer, urb->buffer_length, urb->actual_length); - usbdbg("endpoint: rcv_packetSize %d", - endpoint->rcv_packetSize); -#endif - - if (readl(UDCCSN(ep_num)) & UDCCSR_BNE) - n = readl(UDCBCN(ep_num)) & 0x3ff; - else /* zlp */ - n = 0; - - usbdbg("n %d%s", n, n != endpoint->rcv_packetSize ? "-s" : ""); - for (i = 0; i < n; i += 4) - data32[urb->actual_length / 4 + i / 4] = readl(UDCDN(ep_num)); - - udc_dump_buffer("urb read", (u8 *) data32, urb->actual_length + n); - usbd_rcv_complete(endpoint, n, 0); - - return 0; -} - -static int udc_read_urb_ep0(void) -{ - u32 *data32 = (u32 *) ep0_urb->buffer; - u8 *data8 = (u8 *) ep0_urb->buffer; - unsigned int i, n, w, b; - - usbdbg("read urb on ep 0"); -#if defined(USBDDBG) && defined(USBDPARANOIA) - usbdbg("urb: buf %p, buf_len %d, actual_len %d", - ep0_urb->buffer, ep0_urb->buffer_length, ep0_urb->actual_length); -#endif - - n = readl(UDCBCR0); - w = n / 4; - b = n % 4; - - for (i = 0; i < w; i++) { - data32[ep0_urb->actual_length / 4 + i] = readl(UDCDN(0)); - /* ep0_urb->actual_length += 4; */ - } - - for (i = 0; i < b; i++) { - data8[ep0_urb->actual_length + w * 4 + i] = readb(UDCDN(0)); - /* ep0_urb->actual_length++; */ - } - - ep0_urb->actual_length += n; - - udc_dump_buffer("urb read", (u8 *) data32, ep0_urb->actual_length); - - writel(UDCCSR0_OPC | UDCCSR0_IPR, UDCCSR0); - if (ep0_urb->actual_length == ep0_urb->device_request.wLength) - return 1; - - return 0; -} - -static void udc_handle_ep0(struct usb_endpoint_instance *endpoint) -{ - u32 udccsr0 = readl(UDCCSR0); - u32 *data = (u32 *) &ep0_urb->device_request; - int i; - - usbdbg("udccsr0 %x", udccsr0); - - /* Clear stall status */ - if (udccsr0 & UDCCSR0_SST) { - usberr("clear stall status"); - writel(UDCCSR0_SST, UDCCSR0); - ep0state = EP0_IDLE; - } - - /* previous request unfinished? non-error iff back-to-back ... */ - if ((udccsr0 & UDCCSR0_SA) != 0 && ep0state != EP0_IDLE) - ep0state = EP0_IDLE; - - switch (ep0state) { - - case EP0_IDLE: - udccsr0 = readl(UDCCSR0); - /* Start control request? */ - if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) - == (UDCCSR0_OPC | UDCCSR0_SA | UDCCSR0_RNE)) { - - /* Read SETUP packet. - * SETUP packet size is 8 bytes (aka 2 words) - */ - usbdbg("try reading SETUP packet"); - for (i = 0; i < 2; i++) { - if ((readl(UDCCSR0) & UDCCSR0_RNE) == 0) { - usberr("setup packet too short:%d", i); - goto stall; - } - data[i] = readl(UDCDR0); - } - - writel(readl(UDCCSR0) | UDCCSR0_OPC | UDCCSR0_SA, UDCCSR0); - if ((readl(UDCCSR0) & UDCCSR0_RNE) != 0) { - usberr("setup packet too long"); - goto stall; - } - - udc_dump_buffer("ep0 setup read", (u8 *) data, 8); - - if (ep0_urb->device_request.wLength == 0) { - usbdbg("Zero Data control Packet\n"); - if (ep0_recv_setup(ep0_urb)) { - usberr("Invalid Setup Packet\n"); - udc_dump_buffer("ep0 setup read", - (u8 *)data, 8); - goto stall; - } - writel(UDCCSR0_IPR, UDCCSR0); - ep0state = EP0_IDLE; - } else { - /* Check direction */ - if ((ep0_urb->device_request.bmRequestType & - USB_REQ_DIRECTION_MASK) - == USB_REQ_HOST2DEVICE) { - ep0state = EP0_OUT_DATA; - ep0_urb->buffer = - (u8 *)ep0_urb->buffer_data; - ep0_urb->buffer_length = - sizeof(ep0_urb->buffer_data); - ep0_urb->actual_length = 0; - writel(UDCCSR0_IPR, UDCCSR0); - } else { - /* The ep0_recv_setup function has - * already placed our response packet - * data in ep0_urb->buffer and the - * packet length in - * ep0_urb->actual_length. - */ - if (ep0_recv_setup(ep0_urb)) { -stall: - usberr("Invalid setup packet"); - udc_dump_buffer("ep0 setup read" - , (u8 *) data, 8); - ep0state = EP0_IDLE; - - writel(UDCCSR0_SA | - UDCCSR0_OPC | UDCCSR0_FST | - UDCCS0_FTF, UDCCSR0); - - return; - } - - endpoint->tx_urb = ep0_urb; - endpoint->sent = 0; - usbdbg("EP0_IN_DATA"); - ep0state = EP0_IN_DATA; - if (udc_write_urb(endpoint) < 0) - goto stall; - - } - } - return; - } else if ((udccsr0 & (UDCCSR0_OPC | UDCCSR0_SA)) - == (UDCCSR0_OPC|UDCCSR0_SA)) { - usberr("Setup Active but no data. Stalling ....\n"); - goto stall; - } else { - usbdbg("random early IRQs"); - /* Some random early IRQs: - * - we acked FST - * - IPR cleared - * - OPC got set, without SA (likely status stage) - */ - writel(udccsr0 & (UDCCSR0_SA | UDCCSR0_OPC), UDCCSR0); - } - break; - - case EP0_OUT_DATA: - - if ((udccsr0 & UDCCSR0_OPC) && !(udccsr0 & UDCCSR0_SA)) { - if (udc_read_urb_ep0()) { -read_complete: - ep0state = EP0_IDLE; - if (ep0_recv_setup(ep0_urb)) { - /* Not a setup packet, stall next - * EP0 transaction - */ - udc_dump_buffer("ep0 setup read", - (u8 *) data, 8); - usberr("can't parse setup packet\n"); - goto stall; - } - } - } else if (!(udccsr0 & UDCCSR0_OPC) && - !(udccsr0 & UDCCSR0_IPR)) { - if (ep0_urb->device_request.wLength == - ep0_urb->actual_length) - goto read_complete; - - usberr("Premature Status\n"); - ep0state = EP0_IDLE; - } - break; - - case EP0_IN_DATA: - /* GET_DESCRIPTOR etc */ - if (udccsr0 & UDCCSR0_OPC) { - writel(UDCCSR0_OPC | UDCCSR0_FTF, UDCCSR0); - usberr("ep0in premature status"); - ep0state = EP0_IDLE; - } else { - /* irq was IPR clearing */ - if (udc_write_urb(endpoint) < 0) { - usberr("ep0_write_error\n"); - goto stall; - } - } - break; - - case EP0_XFER_COMPLETE: - writel(UDCCSR0_IPR, UDCCSR0); - ep0state = EP0_IDLE; - break; - - default: - usbdbg("Default\n"); - } - writel(USIR0_IR0, USIR0); -} - -static void udc_handle_ep(struct usb_endpoint_instance *endpoint) -{ - int ep_addr = endpoint->endpoint_address; - int ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; - int ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; - - u32 flags = readl(UDCCSN(ep_num)) & (UDCCSR_SST | UDCCSR_TRN); - if (flags) - writel(flags, UDCCSN(ep_num)); - - if (ep_isout) - udc_read_urb(endpoint); - else - udc_write_urb(endpoint); - - writel(UDCCSR_PC, UDCCSN(ep_num)); -} - -static void udc_state_changed(void) -{ - - writel(readl(UDCCR) | UDCCR_SMAC, UDCCR); - - usbdbg("New UDC settings are: conf %d - inter %d - alter %d", - (readl(UDCCR) & UDCCR_ACN) >> UDCCR_ACN_S, - (readl(UDCCR) & UDCCR_AIN) >> UDCCR_AIN_S, - (readl(UDCCR) & UDCCR_AAISN) >> UDCCR_AAISN_S); - - usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0); - writel(UDCISR1_IRCC, UDCISR1); -} - -void udc_irq(void) -{ - int handled; - struct usb_endpoint_instance *endpoint; - int ep_num, i; - u32 udcisr0; - - do { - handled = 0; - /* Suspend Interrupt Request */ - if (readl(USIR1) & UDCCR_SUSIR) { - usbdbg("Suspend\n"); - udc_ack_int_UDCCR(UDCCR_SUSIR); - handled = 1; - ep0state = EP0_IDLE; - } - - /* Resume Interrupt Request */ - if (readl(USIR1) & UDCCR_RESIR) { - udc_ack_int_UDCCR(UDCCR_RESIR); - handled = 1; - usbdbg("USB resume\n"); - } - - if (readl(USIR1) & (1<<31)) { - handled = 1; - udc_state_changed(); - } - - /* Reset Interrupt Request */ - if (readl(USIR1) & UDCCR_RSTIR) { - udc_ack_int_UDCCR(UDCCR_RSTIR); - handled = 1; - usbdbg("Reset\n"); - usbd_device_event_irq(udc_device, DEVICE_RESET, 0); - } else { - if (readl(USIR0)) - usbdbg("UISR0: %x \n", readl(USIR0)); - - if (readl(USIR0) & 0x2) - writel(0x2, USIR0); - - /* Control traffic */ - if (readl(USIR0) & USIR0_IR0) { - handled = 1; - writel(USIR0_IR0, USIR0); - udc_handle_ep0(udc_device->bus->endpoint_array); - } - - endpoint = udc_device->bus->endpoint_array; - for (i = 0; i < udc_device->bus->max_endpoints; i++) { - ep_num = (endpoint[i].endpoint_address) & - USB_ENDPOINT_NUMBER_MASK; - if (!ep_num) - continue; - udcisr0 = readl(UDCISR0); - if (udcisr0 & - UDCISR_INT(ep_num, UDC_INT_PACKETCMP)) { - writel(UDCISR_INT(ep_num, UDC_INT_PACKETCMP), - UDCISR0); - udc_handle_ep(&endpoint[i]); - } - } - } - - } while (handled); -} - -/* The UDCCR reg contains mask and interrupt status bits, - * so using '|=' isn't safe as it may ack an interrupt. - */ -#define UDCCR_OEN (1 << 31) /* On-the-Go Enable */ -#define UDCCR_MASK_BITS (UDCCR_OEN | UDCCR_UDE) - -static inline void udc_set_mask_UDCCR(int mask) -{ - writel((readl(UDCCR) & UDCCR_MASK_BITS) | (mask & UDCCR_MASK_BITS), UDCCR); -} - -static inline void udc_clear_mask_UDCCR(int mask) -{ - writel((readl(UDCCR) & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS), UDCCR); -} - -static void pio_irq_enable(int ep_num) -{ - if (ep_num < 16) - writel(readl(UDCICR0) | 3 << (ep_num * 2), UDCICR0); - else { - ep_num -= 16; - writel(readl(UDCICR1) | 3 << (ep_num * 2), UDCICR1); - } -} - -/* - * udc_set_nak - * - * Allow upper layers to signal lower layers should not accept more RX data - */ -void udc_set_nak(int ep_num) -{ - /* TODO */ -} - -/* - * udc_unset_nak - * - * Suspend sending of NAK tokens for DATA OUT tokens on a given endpoint. - * Switch off NAKing on this endpoint to accept more data output from host. - */ -void udc_unset_nak(int ep_num) -{ - /* TODO */ -} - -int udc_endpoint_write(struct usb_endpoint_instance *endpoint) -{ - return udc_write_urb(endpoint); -} - -/* Associate a physical endpoint with endpoint instance */ -void udc_setup_ep(struct usb_device_instance *device, unsigned int id, - struct usb_endpoint_instance *endpoint) -{ - int ep_num, ep_addr, ep_isout, ep_type, ep_size; - int config, interface, alternate; - u32 tmp; - - usbdbg("setting up endpoint id %d", id); - - if (!endpoint) { - usberr("endpoint void!"); - return; - } - - ep_num = endpoint->endpoint_address & USB_ENDPOINT_NUMBER_MASK; - if (ep_num >= UDC_MAX_ENDPOINTS) { - usberr("unable to setup ep %d!", ep_num); - return; - } - - pio_irq_enable(ep_num); - if (ep_num == 0) { - /* Done for ep0 */ - return; - } - - config = 1; - interface = 0; - alternate = 0; - - usbdbg("config %d - interface %d - alternate %d", - config, interface, alternate); - - ep_addr = endpoint->endpoint_address; - ep_num = ep_addr & USB_ENDPOINT_NUMBER_MASK; - ep_isout = (ep_addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT; - ep_type = ep_isout ? endpoint->rcv_attributes : endpoint->tx_attributes; - ep_size = ep_isout ? endpoint->rcv_packetSize : endpoint->tx_packetSize; - - usbdbg("addr %x, num %d, dir %s, type %s, packet size %d", - ep_addr, ep_num, - ep_isout ? "out" : "in", - ep_type == USB_ENDPOINT_XFER_ISOC ? "isoc" : - ep_type == USB_ENDPOINT_XFER_BULK ? "bulk" : - ep_type == USB_ENDPOINT_XFER_INT ? "int" : "???", - ep_size - ); - - /* Configure UDCCRx */ - tmp = 0; - tmp |= (config << UDCCONR_CN_S) & UDCCONR_CN; - tmp |= (interface << UDCCONR_IN_S) & UDCCONR_IN; - tmp |= (alternate << UDCCONR_AISN_S) & UDCCONR_AISN; - tmp |= (ep_num << UDCCONR_EN_S) & UDCCONR_EN; - tmp |= (ep_type << UDCCONR_ET_S) & UDCCONR_ET; - tmp |= ep_isout ? 0 : UDCCONR_ED; - tmp |= (ep_size << UDCCONR_MPS_S) & UDCCONR_MPS; - tmp |= UDCCONR_EE; - - writel(tmp, UDCCN(ep_num)); - - usbdbg("UDCCR%c = %x", 'A' + ep_num-1, readl(UDCCN(ep_num))); - usbdbg("UDCCSR%c = %x", 'A' + ep_num-1, readl(UDCCSN(ep_num))); -} - -/* Connect the USB device to the bus */ -void udc_connect(void) -{ - usbdbg("UDC connect"); - -#ifdef CONFIG_USB_DEV_PULLUP_GPIO - /* Turn on the USB connection by enabling the pullup resistor */ - writel(readl(GPDR(CONFIG_USB_DEV_PULLUP_GPIO)) - | GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), - GPDR(CONFIG_USB_DEV_PULLUP_GPIO)); - writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPSR(CONFIG_USB_DEV_PULLUP_GPIO)); -#else - /* Host port 2 transceiver D+ pull up enable */ - writel(readl(UP2OCR) | UP2OCR_DPPUE, UP2OCR); -#endif -} - -/* Disconnect the USB device to the bus */ -void udc_disconnect(void) -{ - usbdbg("UDC disconnect"); - -#ifdef CONFIG_USB_DEV_PULLUP_GPIO - /* Turn off the USB connection by disabling the pullup resistor */ - writel(GPIO_bit(CONFIG_USB_DEV_PULLUP_GPIO), GPCR(CONFIG_USB_DEV_PULLUP_GPIO)); -#else - /* Host port 2 transceiver D+ pull up disable */ - writel(readl(UP2OCR) & ~UP2OCR_DPPUE, UP2OCR); -#endif -} - -/* Switch on the UDC */ -void udc_enable(struct usb_device_instance *device) -{ - - ep0state = EP0_IDLE; - - /* enable endpoint 0, A, B's Packet Complete Interrupt. */ - writel(0xffffffff, UDCICR0); - writel(0xa8000000, UDCICR1); - - /* clear the interrupt status/control registers */ - writel(0xffffffff, UDCISR0); - writel(0xffffffff, UDCISR1); - - /* set UDC-enable */ - udc_set_mask_UDCCR(UDCCR_UDE); - - udc_device = device; - if (!ep0_urb) - ep0_urb = usbd_alloc_urb(udc_device, - udc_device->bus->endpoint_array); - else - usbinfo("ep0_urb %p already allocated", ep0_urb); - - usbdbg("UDC Enabled\n"); -} - -/* Need to check this again */ -void udc_disable(void) -{ - usbdbg("disable UDC"); - - udc_clear_mask_UDCCR(UDCCR_UDE); - - /* Disable clock for USB device */ - writel(readl(CKEN) & ~CKEN11_USB, CKEN); - - /* Free ep0 URB */ - if (ep0_urb) { - usbd_dealloc_urb(ep0_urb); - ep0_urb = NULL; - } - - /* Reset device pointer */ - udc_device = NULL; -} - -/* Allow udc code to do any additional startup */ -void udc_startup_events(struct usb_device_instance *device) -{ - /* The DEVICE_INIT event puts the USB device in the state STATE_INIT */ - usbd_device_event_irq(device, DEVICE_INIT, 0); - - /* The DEVICE_CREATE event puts the USB device in the state - * STATE_ATTACHED */ - usbd_device_event_irq(device, DEVICE_CREATE, 0); - - /* Some USB controller driver implementations signal - * DEVICE_HUB_CONFIGURED and DEVICE_RESET events here. - * DEVICE_HUB_CONFIGURED causes a transition to the state - * STATE_POWERED, and DEVICE_RESET causes a transition to - * the state STATE_DEFAULT. - */ - udc_enable(device); -} - -/* Initialize h/w stuff */ -int udc_init(void) -{ - udc_device = NULL; - usbdbg("PXA27x usbd start"); - - /* Enable clock for USB device */ - writel(readl(CKEN) | CKEN11_USB, CKEN); - - /* Disable the UDC */ - udc_clear_mask_UDCCR(UDCCR_UDE); - - /* Disable IRQs: we don't use them */ - writel(0, UDCICR0); - writel(0, UDCICR1); - - return 0; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/regs-otg.h b/qemu/roms/u-boot/drivers/usb/gadget/regs-otg.h deleted file mode 100644 index ac5d11213..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/regs-otg.h +++ /dev/null @@ -1,273 +0,0 @@ -/* linux/arch/arm/plat-s3c/include/plat/regs-otg.h - * - * Copyright (C) 2004 Herbert Poetzl <herbert@13thfloor.at> - * - * Registers remapping: - * Lukasz Majewski <l.majewski@samsumg.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -#ifndef __ASM_ARCH_REGS_USB_OTG_HS_H -#define __ASM_ARCH_REGS_USB_OTG_HS_H - -/* USB2.0 OTG Controller register */ -struct s3c_usbotg_phy { - u32 phypwr; - u32 phyclk; - u32 rstcon; -}; - -/* Device Logical IN Endpoint-Specific Registers */ -struct s3c_dev_in_endp { - u32 diepctl; - u8 res1[4]; - u32 diepint; - u8 res2[4]; - u32 dieptsiz; - u32 diepdma; - u8 res3[4]; - u32 diepdmab; -}; - -/* Device Logical OUT Endpoint-Specific Registers */ -struct s3c_dev_out_endp { - u32 doepctl; - u8 res1[4]; - u32 doepint; - u8 res2[4]; - u32 doeptsiz; - u32 doepdma; - u8 res3[4]; - u32 doepdmab; -}; - -struct ep_fifo { - u32 fifo; - u8 res[4092]; -}; - -/* USB2.0 OTG Controller register */ -struct s3c_usbotg_reg { - /* Core Global Registers */ - u32 gotgctl; /* OTG Control & Status */ - u32 gotgint; /* OTG Interrupt */ - u32 gahbcfg; /* Core AHB Configuration */ - u32 gusbcfg; /* Core USB Configuration */ - u32 grstctl; /* Core Reset */ - u32 gintsts; /* Core Interrupt */ - u32 gintmsk; /* Core Interrupt Mask */ - u32 grxstsr; /* Receive Status Debug Read/Status Read */ - u32 grxstsp; /* Receive Status Debug Pop/Status Pop */ - u32 grxfsiz; /* Receive FIFO Size */ - u32 gnptxfsiz; /* Non-Periodic Transmit FIFO Size */ - u8 res1[216]; - u32 dieptxf[15]; /* Device Periodic Transmit FIFO size register */ - u8 res2[1728]; - /* Device Configuration */ - u32 dcfg; /* Device Configuration Register */ - u32 dctl; /* Device Control */ - u32 dsts; /* Device Status */ - u8 res3[4]; - u32 diepmsk; /* Device IN Endpoint Common Interrupt Mask */ - u32 doepmsk; /* Device OUT Endpoint Common Interrupt Mask */ - u32 daint; /* Device All Endpoints Interrupt */ - u32 daintmsk; /* Device All Endpoints Interrupt Mask */ - u8 res4[224]; - struct s3c_dev_in_endp in_endp[16]; - struct s3c_dev_out_endp out_endp[16]; - u8 res5[768]; - struct ep_fifo ep[16]; -}; - -/*===================================================================== */ -/*definitions related to CSR setting */ - -/* S3C_UDC_OTG_GOTGCTL */ -#define B_SESSION_VALID (0x1<<19) -#define A_SESSION_VALID (0x1<<18) - -/* S3C_UDC_OTG_GAHBCFG */ -#define PTXFE_HALF (0<<8) -#define PTXFE_ZERO (1<<8) -#define NPTXFE_HALF (0<<7) -#define NPTXFE_ZERO (1<<7) -#define MODE_SLAVE (0<<5) -#define MODE_DMA (1<<5) -#define BURST_SINGLE (0<<1) -#define BURST_INCR (1<<1) -#define BURST_INCR4 (3<<1) -#define BURST_INCR8 (5<<1) -#define BURST_INCR16 (7<<1) -#define GBL_INT_UNMASK (1<<0) -#define GBL_INT_MASK (0<<0) - -/* S3C_UDC_OTG_GRSTCTL */ -#define AHB_MASTER_IDLE (1u<<31) -#define CORE_SOFT_RESET (0x1<<0) - -/* S3C_UDC_OTG_GINTSTS/S3C_UDC_OTG_GINTMSK core interrupt register */ -#define INT_RESUME (1u<<31) -#define INT_DISCONN (0x1<<29) -#define INT_CONN_ID_STS_CNG (0x1<<28) -#define INT_OUT_EP (0x1<<19) -#define INT_IN_EP (0x1<<18) -#define INT_ENUMDONE (0x1<<13) -#define INT_RESET (0x1<<12) -#define INT_SUSPEND (0x1<<11) -#define INT_EARLY_SUSPEND (0x1<<10) -#define INT_NP_TX_FIFO_EMPTY (0x1<<5) -#define INT_RX_FIFO_NOT_EMPTY (0x1<<4) -#define INT_SOF (0x1<<3) -#define INT_DEV_MODE (0x0<<0) -#define INT_HOST_MODE (0x1<<1) -#define INT_GOUTNakEff (0x01<<7) -#define INT_GINNakEff (0x01<<6) - -#define FULL_SPEED_CONTROL_PKT_SIZE 8 -#define FULL_SPEED_BULK_PKT_SIZE 64 - -#define HIGH_SPEED_CONTROL_PKT_SIZE 64 -#define HIGH_SPEED_BULK_PKT_SIZE 512 - -#define RX_FIFO_SIZE (1024*4) -#define NPTX_FIFO_SIZE (1024*4) -#define PTX_FIFO_SIZE (1536*1) - -#define DEPCTL_TXFNUM_0 (0x0<<22) -#define DEPCTL_TXFNUM_1 (0x1<<22) -#define DEPCTL_TXFNUM_2 (0x2<<22) -#define DEPCTL_TXFNUM_3 (0x3<<22) -#define DEPCTL_TXFNUM_4 (0x4<<22) - -/* Enumeration speed */ -#define USB_HIGH_30_60MHZ (0x0<<1) -#define USB_FULL_30_60MHZ (0x1<<1) -#define USB_LOW_6MHZ (0x2<<1) -#define USB_FULL_48MHZ (0x3<<1) - -/* S3C_UDC_OTG_GRXSTSP STATUS */ -#define OUT_PKT_RECEIVED (0x2<<17) -#define OUT_TRANSFER_COMPLELTED (0x3<<17) -#define SETUP_TRANSACTION_COMPLETED (0x4<<17) -#define SETUP_PKT_RECEIVED (0x6<<17) -#define GLOBAL_OUT_NAK (0x1<<17) - -/* S3C_UDC_OTG_DCTL device control register */ -#define NORMAL_OPERATION (0x1<<0) -#define SOFT_DISCONNECT (0x1<<1) - -/* S3C_UDC_OTG_DAINT device all endpoint interrupt register */ -#define DAINT_OUT_BIT (16) -#define DAINT_MASK (0xFFFF) - -/* S3C_UDC_OTG_DIEPCTL0/DOEPCTL0 device - control IN/OUT endpoint 0 control register */ -#define DEPCTL_EPENA (0x1<<31) -#define DEPCTL_EPDIS (0x1<<30) -#define DEPCTL_SETD1PID (0x1<<29) -#define DEPCTL_SETD0PID (0x1<<28) -#define DEPCTL_SNAK (0x1<<27) -#define DEPCTL_CNAK (0x1<<26) -#define DEPCTL_STALL (0x1<<21) -#define DEPCTL_TYPE_BIT (18) -#define DEPCTL_TYPE_MASK (0x3<<18) -#define DEPCTL_CTRL_TYPE (0x0<<18) -#define DEPCTL_ISO_TYPE (0x1<<18) -#define DEPCTL_BULK_TYPE (0x2<<18) -#define DEPCTL_INTR_TYPE (0x3<<18) -#define DEPCTL_USBACTEP (0x1<<15) -#define DEPCTL_NEXT_EP_BIT (11) -#define DEPCTL_MPS_BIT (0) -#define DEPCTL_MPS_MASK (0x7FF) - -#define DEPCTL0_MPS_64 (0x0<<0) -#define DEPCTL0_MPS_32 (0x1<<0) -#define DEPCTL0_MPS_16 (0x2<<0) -#define DEPCTL0_MPS_8 (0x3<<0) -#define DEPCTL_MPS_BULK_512 (512<<0) -#define DEPCTL_MPS_INT_MPS_16 (16<<0) - -#define DIEPCTL0_NEXT_EP_BIT (11) - - -/* S3C_UDC_OTG_DIEPMSK/DOEPMSK device IN/OUT endpoint - common interrupt mask register */ -/* S3C_UDC_OTG_DIEPINTn/DOEPINTn device IN/OUT endpoint interrupt register */ -#define BACK2BACK_SETUP_RECEIVED (0x1<<6) -#define INTKNEPMIS (0x1<<5) -#define INTKN_TXFEMP (0x1<<4) -#define NON_ISO_IN_EP_TIMEOUT (0x1<<3) -#define CTRL_OUT_EP_SETUP_PHASE_DONE (0x1<<3) -#define AHB_ERROR (0x1<<2) -#define EPDISBLD (0x1<<1) -#define TRANSFER_DONE (0x1<<0) - -#define USB_PHY_CTRL_EN0 (0x1 << 0) - -/* OPHYPWR */ -#define PHY_0_SLEEP (0x1 << 5) -#define OTG_DISABLE_0 (0x1 << 4) -#define ANALOG_PWRDOWN (0x1 << 3) -#define FORCE_SUSPEND_0 (0x1 << 0) - -/* URSTCON */ -#define HOST_SW_RST (0x1 << 4) -#define PHY_SW_RST1 (0x1 << 3) -#define PHYLNK_SW_RST (0x1 << 2) -#define LINK_SW_RST (0x1 << 1) -#define PHY_SW_RST0 (0x1 << 0) - -/* OPHYCLK */ -#define COMMON_ON_N1 (0x1 << 7) -#define COMMON_ON_N0 (0x1 << 4) -#define ID_PULLUP0 (0x1 << 2) -#define CLK_SEL_24MHZ (0x3 << 0) -#define CLK_SEL_12MHZ (0x2 << 0) -#define CLK_SEL_48MHZ (0x0 << 0) - -#define EXYNOS4X12_ID_PULLUP0 (0x01 << 3) -#define EXYNOS4X12_COMMON_ON_N0 (0x01 << 4) -#define EXYNOS4X12_CLK_SEL_12MHZ (0x02 << 0) -#define EXYNOS4X12_CLK_SEL_24MHZ (0x05 << 0) - -/* Device Configuration Register DCFG */ -#define DEV_SPEED_HIGH_SPEED_20 (0x0 << 0) -#define DEV_SPEED_FULL_SPEED_20 (0x1 << 0) -#define DEV_SPEED_LOW_SPEED_11 (0x2 << 0) -#define DEV_SPEED_FULL_SPEED_11 (0x3 << 0) -#define EP_MISS_CNT(x) (x << 18) -#define DEVICE_ADDRESS(x) (x << 4) - -/* Core Reset Register (GRSTCTL) */ -#define TX_FIFO_FLUSH (0x1 << 5) -#define RX_FIFO_FLUSH (0x1 << 4) -#define TX_FIFO_NUMBER(x) (x << 6) -#define TX_FIFO_FLUSH_ALL TX_FIFO_NUMBER(0x10) - -/* Masks definitions */ -#define GINTMSK_INIT (INT_OUT_EP | INT_IN_EP | INT_RESUME | INT_ENUMDONE\ - | INT_RESET | INT_SUSPEND) -#define DOEPMSK_INIT (CTRL_OUT_EP_SETUP_PHASE_DONE | AHB_ERROR|TRANSFER_DONE) -#define DIEPMSK_INIT (NON_ISO_IN_EP_TIMEOUT|AHB_ERROR|TRANSFER_DONE) -#define GAHBCFG_INIT (PTXFE_HALF | NPTXFE_HALF | MODE_DMA | BURST_INCR4\ - | GBL_INT_UNMASK) - -/* Device Endpoint X Transfer Size Register (DIEPTSIZX) */ -#define DIEPT_SIZ_PKT_CNT(x) (x << 19) -#define DIEPT_SIZ_XFER_SIZE(x) (x << 0) - -/* Device OUT Endpoint X Transfer Size Register (DOEPTSIZX) */ -#define DOEPT_SIZ_PKT_CNT(x) (x << 19) -#define DOEPT_SIZ_XFER_SIZE(x) (x << 0) -#define DOEPT_SIZ_XFER_SIZE_MAX_EP0 (0x7F << 0) -#define DOEPT_SIZ_XFER_SIZE_MAX_EP (0x7FFF << 0) - -/* Device Endpoint-N Control Register (DIEPCTLn/DOEPCTLn) */ -#define DIEPCTL_TX_FIFO_NUM(x) (x << 22) -#define DIEPCTL_TX_FIFO_NUM_MASK (~DIEPCTL_TX_FIFO_NUM(0xF)) - -/* Device ALL Endpoints Interrupt Register (DAINT) */ -#define DAINT_IN_EP_INT(x) (x << 0) -#define DAINT_OUT_EP_INT(x) (x << 16) -#endif diff --git a/qemu/roms/u-boot/drivers/usb/gadget/rndis.c b/qemu/roms/u-boot/drivers/usb/gadget/rndis.c deleted file mode 100644 index 404a7b96f..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/rndis.c +++ /dev/null @@ -1,1316 +0,0 @@ -/* - * RNDIS MSG parser - * - * Authors: Benedikt Spranger, Pengutronix - * Robert Schwebel, Pengutronix - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * This software was originally developed in conformance with - * Microsoft's Remote NDIS Specification License Agreement. - * - * 03/12/2004 Kai-Uwe Bloem <linux-development@auerswald.de> - * Fixed message length bug in init_response - * - * 03/25/2004 Kai-Uwe Bloem <linux-development@auerswald.de> - * Fixed rndis_rm_hdr length bug. - * - * Copyright (C) 2004 by David Brownell - * updates to merge with Linux 2.6, better match RNDIS spec - */ - -#include <common.h> -#include <net.h> -#include <malloc.h> -#include <linux/types.h> -#include <linux/list.h> -#include <linux/netdevice.h> - -#include <asm/byteorder.h> -#include <asm/unaligned.h> -#include <asm/errno.h> - -#undef RNDIS_PM -#undef RNDIS_WAKEUP -#undef VERBOSE - -#include "rndis.h" - -#define ETH_ALEN 6 /* Octets in one ethernet addr */ -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETH_FRAME_LEN PKTSIZE_ALIGN /* Max. octets in frame sans FCS */ -#define ETH_FCS_LEN 4 /* Octets in the FCS */ -#define ENOTSUPP 524 /* Operation is not supported */ - - -/* - * The driver for your USB chip needs to support ep0 OUT to work with - * RNDIS, plus all three CDC Ethernet endpoints (interrupt not optional). - * - * Windows hosts need an INF file like Documentation/usb/linux.inf - * and will be happier if you provide the host_addr module parameter. - */ - -#define RNDIS_MAX_CONFIGS 1 - -static rndis_params rndis_per_dev_params[RNDIS_MAX_CONFIGS]; - -/* Driver Version */ -static const __le32 rndis_driver_version = __constant_cpu_to_le32(1); - -/* Function Prototypes */ -static rndis_resp_t *rndis_add_response(int configNr, u32 length); - - -/* supported OIDs */ -static const u32 oid_supported_list[] = { - /* the general stuff */ - OID_GEN_SUPPORTED_LIST, - OID_GEN_HARDWARE_STATUS, - OID_GEN_MEDIA_SUPPORTED, - OID_GEN_MEDIA_IN_USE, - OID_GEN_MAXIMUM_FRAME_SIZE, - OID_GEN_LINK_SPEED, - OID_GEN_TRANSMIT_BLOCK_SIZE, - OID_GEN_RECEIVE_BLOCK_SIZE, - OID_GEN_VENDOR_ID, - OID_GEN_VENDOR_DESCRIPTION, - OID_GEN_VENDOR_DRIVER_VERSION, - OID_GEN_CURRENT_PACKET_FILTER, - OID_GEN_MAXIMUM_TOTAL_SIZE, - OID_GEN_MEDIA_CONNECT_STATUS, - OID_GEN_PHYSICAL_MEDIUM, -#if 0 - OID_GEN_RNDIS_CONFIG_PARAMETER, -#endif - - /* the statistical stuff */ - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_XMIT_ERROR, - OID_GEN_RCV_ERROR, - OID_GEN_RCV_NO_BUFFER, -#ifdef RNDIS_OPTIONAL_STATS - OID_GEN_DIRECTED_BYTES_XMIT, - OID_GEN_DIRECTED_FRAMES_XMIT, - OID_GEN_MULTICAST_BYTES_XMIT, - OID_GEN_MULTICAST_FRAMES_XMIT, - OID_GEN_BROADCAST_BYTES_XMIT, - OID_GEN_BROADCAST_FRAMES_XMIT, - OID_GEN_DIRECTED_BYTES_RCV, - OID_GEN_DIRECTED_FRAMES_RCV, - OID_GEN_MULTICAST_BYTES_RCV, - OID_GEN_MULTICAST_FRAMES_RCV, - OID_GEN_BROADCAST_BYTES_RCV, - OID_GEN_BROADCAST_FRAMES_RCV, - OID_GEN_RCV_CRC_ERROR, - OID_GEN_TRANSMIT_QUEUE_LENGTH, -#endif /* RNDIS_OPTIONAL_STATS */ - - /* mandatory 802.3 */ - /* the general stuff */ - OID_802_3_PERMANENT_ADDRESS, - OID_802_3_CURRENT_ADDRESS, - OID_802_3_MULTICAST_LIST, - OID_802_3_MAC_OPTIONS, - OID_802_3_MAXIMUM_LIST_SIZE, - - /* the statistical stuff */ - OID_802_3_RCV_ERROR_ALIGNMENT, - OID_802_3_XMIT_ONE_COLLISION, - OID_802_3_XMIT_MORE_COLLISIONS, -#ifdef RNDIS_OPTIONAL_STATS - OID_802_3_XMIT_DEFERRED, - OID_802_3_XMIT_MAX_COLLISIONS, - OID_802_3_RCV_OVERRUN, - OID_802_3_XMIT_UNDERRUN, - OID_802_3_XMIT_HEARTBEAT_FAILURE, - OID_802_3_XMIT_TIMES_CRS_LOST, - OID_802_3_XMIT_LATE_COLLISIONS, -#endif /* RNDIS_OPTIONAL_STATS */ - -#ifdef RNDIS_PM - /* PM and wakeup are mandatory for USB: */ - - /* power management */ - OID_PNP_CAPABILITIES, - OID_PNP_QUERY_POWER, - OID_PNP_SET_POWER, - -#ifdef RNDIS_WAKEUP - /* wake up host */ - OID_PNP_ENABLE_WAKE_UP, - OID_PNP_ADD_WAKE_UP_PATTERN, - OID_PNP_REMOVE_WAKE_UP_PATTERN, -#endif /* RNDIS_WAKEUP */ -#endif /* RNDIS_PM */ -}; - - -/* NDIS Functions */ -static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, - unsigned buf_len, rndis_resp_t *r) -{ - int retval = -ENOTSUPP; - u32 length = 4; /* usually */ - __le32 *outbuf; - int i, count; - rndis_query_cmplt_type *resp; - rndis_params *params; - - if (!r) - return -ENOMEM; - resp = (rndis_query_cmplt_type *) r->buf; - - if (!resp) - return -ENOMEM; - -#if defined(DEBUG) && defined(DEBUG_VERBOSE) - if (buf_len) { - debug("query OID %08x value, len %d:\n", OID, buf_len); - for (i = 0; i < buf_len; i += 16) { - debug("%03d: %08x %08x %08x %08x\n", i, - get_unaligned_le32(&buf[i]), - get_unaligned_le32(&buf[i + 4]), - get_unaligned_le32(&buf[i + 8]), - get_unaligned_le32(&buf[i + 12])); - } - } -#endif - - /* response goes here, right after the header */ - outbuf = (__le32 *) &resp[1]; - resp->InformationBufferOffset = __constant_cpu_to_le32(16); - - params = &rndis_per_dev_params[configNr]; - switch (OID) { - - /* general oids (table 4-1) */ - - /* mandatory */ - case OID_GEN_SUPPORTED_LIST: - debug("%s: OID_GEN_SUPPORTED_LIST\n", __func__); - length = sizeof(oid_supported_list); - count = length / sizeof(u32); - for (i = 0; i < count; i++) - outbuf[i] = cpu_to_le32(oid_supported_list[i]); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_HARDWARE_STATUS: - debug("%s: OID_GEN_HARDWARE_STATUS\n", __func__); - /* - * Bogus question! - * Hardware must be ready to receive high level protocols. - * BTW: - * reddite ergo quae sunt Caesaris Caesari - * et quae sunt Dei Deo! - */ - *outbuf = __constant_cpu_to_le32(0); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MEDIA_SUPPORTED: - debug("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__); - *outbuf = cpu_to_le32(params->medium); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MEDIA_IN_USE: - debug("%s: OID_GEN_MEDIA_IN_USE\n", __func__); - /* one medium, one transport... (maybe you do it better) */ - *outbuf = cpu_to_le32(params->medium); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MAXIMUM_FRAME_SIZE: - debug("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__); - if (params->dev) { - *outbuf = cpu_to_le32(params->mtu); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_LINK_SPEED: -#if defined(DEBUG) && defined(DEBUG_VERBOSE) - debug("%s: OID_GEN_LINK_SPEED\n", __func__); -#endif - if (params->media_state == NDIS_MEDIA_STATE_DISCONNECTED) - *outbuf = __constant_cpu_to_le32(0); - else - *outbuf = cpu_to_le32(params->speed); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_TRANSMIT_BLOCK_SIZE: - debug("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__); - if (params->dev) { - *outbuf = cpu_to_le32(params->mtu); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_RECEIVE_BLOCK_SIZE: - debug("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__); - if (params->dev) { - *outbuf = cpu_to_le32(params->mtu); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_VENDOR_ID: - debug("%s: OID_GEN_VENDOR_ID\n", __func__); - *outbuf = cpu_to_le32(params->vendorID); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_VENDOR_DESCRIPTION: - debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__); - length = strlen(params->vendorDescr); - memcpy(outbuf, params->vendorDescr, length); - retval = 0; - break; - - case OID_GEN_VENDOR_DRIVER_VERSION: - debug("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __func__); - /* Created as LE */ - *outbuf = rndis_driver_version; - retval = 0; - break; - - /* mandatory */ - case OID_GEN_CURRENT_PACKET_FILTER: - debug("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__); - *outbuf = cpu_to_le32(*params->filter); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MAXIMUM_TOTAL_SIZE: - debug("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__); - *outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); - retval = 0; - break; - - /* mandatory */ - case OID_GEN_MEDIA_CONNECT_STATUS: -#if defined(DEBUG) && defined(DEBUG_VERBOSE) - debug("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__); -#endif - *outbuf = cpu_to_le32(params->media_state); - retval = 0; - break; - - case OID_GEN_PHYSICAL_MEDIUM: - debug("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__); - *outbuf = __constant_cpu_to_le32(0); - retval = 0; - break; - - /* - * The RNDIS specification is incomplete/wrong. Some versions - * of MS-Windows expect OIDs that aren't specified there. Other - * versions emit undefined RNDIS messages. DOCUMENT ALL THESE! - */ - case OID_GEN_MAC_OPTIONS: /* from WinME */ - debug("%s: OID_GEN_MAC_OPTIONS\n", __func__); - *outbuf = __constant_cpu_to_le32( - NDIS_MAC_OPTION_RECEIVE_SERIALIZED - | NDIS_MAC_OPTION_FULL_DUPLEX); - retval = 0; - break; - - /* statistics OIDs (table 4-2) */ - - /* mandatory */ - case OID_GEN_XMIT_OK: -#if defined(DEBUG) && defined(DEBUG_VERBOSE) - debug("%s: OID_GEN_XMIT_OK\n", __func__); -#endif - if (params->stats) { - *outbuf = cpu_to_le32( - params->stats->tx_packets - - params->stats->tx_errors - - params->stats->tx_dropped); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_RCV_OK: -#if defined(DEBUG) && defined(DEBUG_VERBOSE) - debug("%s: OID_GEN_RCV_OK\n", __func__); -#endif - if (params->stats) { - *outbuf = cpu_to_le32( - params->stats->rx_packets - - params->stats->rx_errors - - params->stats->rx_dropped); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_XMIT_ERROR: -#if defined(DEBUG) && defined(DEBUG_VERBOSE) - debug("%s: OID_GEN_XMIT_ERROR\n", __func__); -#endif - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->tx_errors); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_RCV_ERROR: -#if defined(DEBUG) && defined(DEBUG_VERBOSE) - debug("%s: OID_GEN_RCV_ERROR\n", __func__); -#endif - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->rx_errors); - retval = 0; - } - break; - - /* mandatory */ - case OID_GEN_RCV_NO_BUFFER: - debug("%s: OID_GEN_RCV_NO_BUFFER\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->rx_dropped); - retval = 0; - } - break; - -#ifdef RNDIS_OPTIONAL_STATS - case OID_GEN_DIRECTED_BYTES_XMIT: - debug("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __func__); - /* - * Aunt Tilly's size of shoes - * minus antarctica count of penguins - * divided by weight of Alpha Centauri - */ - if (params->stats) { - *outbuf = cpu_to_le32( - (params->stats->tx_packets - - params->stats->tx_errors - - params->stats->tx_dropped) - * 123); - retval = 0; - } - break; - - case OID_GEN_DIRECTED_FRAMES_XMIT: - debug("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __func__); - /* dito */ - if (params->stats) { - *outbuf = cpu_to_le32( - (params->stats->tx_packets - - params->stats->tx_errors - - params->stats->tx_dropped) - / 123); - retval = 0; - } - break; - - case OID_GEN_MULTICAST_BYTES_XMIT: - debug("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->multicast * 1234); - retval = 0; - } - break; - - case OID_GEN_MULTICAST_FRAMES_XMIT: - debug("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->multicast); - retval = 0; - } - break; - - case OID_GEN_BROADCAST_BYTES_XMIT: - debug("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->tx_packets/42*255); - retval = 0; - } - break; - - case OID_GEN_BROADCAST_FRAMES_XMIT: - debug("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->tx_packets / 42); - retval = 0; - } - break; - - case OID_GEN_DIRECTED_BYTES_RCV: - debug("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __func__); - *outbuf = __constant_cpu_to_le32(0); - retval = 0; - break; - - case OID_GEN_DIRECTED_FRAMES_RCV: - debug("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __func__); - *outbuf = __constant_cpu_to_le32(0); - retval = 0; - break; - - case OID_GEN_MULTICAST_BYTES_RCV: - debug("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->multicast * 1111); - retval = 0; - } - break; - - case OID_GEN_MULTICAST_FRAMES_RCV: - debug("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->multicast); - retval = 0; - } - break; - - case OID_GEN_BROADCAST_BYTES_RCV: - debug("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->rx_packets/42*255); - retval = 0; - } - break; - - case OID_GEN_BROADCAST_FRAMES_RCV: - debug("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->rx_packets / 42); - retval = 0; - } - break; - - case OID_GEN_RCV_CRC_ERROR: - debug("%s: OID_GEN_RCV_CRC_ERROR\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->rx_crc_errors); - retval = 0; - } - break; - - case OID_GEN_TRANSMIT_QUEUE_LENGTH: - debug("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __func__); - *outbuf = __constant_cpu_to_le32(0); - retval = 0; - break; -#endif /* RNDIS_OPTIONAL_STATS */ - - /* ieee802.3 OIDs (table 4-3) */ - - /* mandatory */ - case OID_802_3_PERMANENT_ADDRESS: - debug("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__); - if (params->dev) { - length = ETH_ALEN; - memcpy(outbuf, params->host_mac, length); - retval = 0; - } - break; - - /* mandatory */ - case OID_802_3_CURRENT_ADDRESS: - debug("%s: OID_802_3_CURRENT_ADDRESS\n", __func__); - if (params->dev) { - length = ETH_ALEN; - memcpy(outbuf, params->host_mac, length); - retval = 0; - } - break; - - /* mandatory */ - case OID_802_3_MULTICAST_LIST: - debug("%s: OID_802_3_MULTICAST_LIST\n", __func__); - /* Multicast base address only */ - *outbuf = __constant_cpu_to_le32(0xE0000000); - retval = 0; - break; - - /* mandatory */ - case OID_802_3_MAXIMUM_LIST_SIZE: - debug("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__); - /* Multicast base address only */ - *outbuf = __constant_cpu_to_le32(1); - retval = 0; - break; - - case OID_802_3_MAC_OPTIONS: - debug("%s: OID_802_3_MAC_OPTIONS\n", __func__); - break; - - /* ieee802.3 statistics OIDs (table 4-4) */ - - /* mandatory */ - case OID_802_3_RCV_ERROR_ALIGNMENT: - debug("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__); - if (params->stats) { - *outbuf = cpu_to_le32(params->stats->rx_frame_errors); - retval = 0; - } - break; - - /* mandatory */ - case OID_802_3_XMIT_ONE_COLLISION: - debug("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__); - *outbuf = __constant_cpu_to_le32(0); - retval = 0; - break; - - /* mandatory */ - case OID_802_3_XMIT_MORE_COLLISIONS: - debug("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__); - *outbuf = __constant_cpu_to_le32(0); - retval = 0; - break; - -#ifdef RNDIS_OPTIONAL_STATS - case OID_802_3_XMIT_DEFERRED: - debug("%s: OID_802_3_XMIT_DEFERRED\n", __func__); - /* TODO */ - break; - - case OID_802_3_XMIT_MAX_COLLISIONS: - debug("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __func__); - /* TODO */ - break; - - case OID_802_3_RCV_OVERRUN: - debug("%s: OID_802_3_RCV_OVERRUN\n", __func__); - /* TODO */ - break; - - case OID_802_3_XMIT_UNDERRUN: - debug("%s: OID_802_3_XMIT_UNDERRUN\n", __func__); - /* TODO */ - break; - - case OID_802_3_XMIT_HEARTBEAT_FAILURE: - debug("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __func__); - /* TODO */ - break; - - case OID_802_3_XMIT_TIMES_CRS_LOST: - debug("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __func__); - /* TODO */ - break; - - case OID_802_3_XMIT_LATE_COLLISIONS: - debug("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __func__); - /* TODO */ - break; -#endif /* RNDIS_OPTIONAL_STATS */ - -#ifdef RNDIS_PM - /* power management OIDs (table 4-5) */ - case OID_PNP_CAPABILITIES: - debug("%s: OID_PNP_CAPABILITIES\n", __func__); - - /* for now, no wakeup capabilities */ - length = sizeof(struct NDIS_PNP_CAPABILITIES); - memset(outbuf, 0, length); - retval = 0; - break; - case OID_PNP_QUERY_POWER: - debug("%s: OID_PNP_QUERY_POWER D%d\n", __func__, - get_unaligned_le32(buf) - 1); - /* - * only suspend is a real power state, and - * it can't be entered by OID_PNP_SET_POWER... - */ - length = 0; - retval = 0; - break; -#endif - - default: - debug("%s: query unknown OID 0x%08X\n", __func__, OID); - } - if (retval < 0) - length = 0; - - resp->InformationBufferLength = cpu_to_le32(length); - r->length = length + sizeof *resp; - resp->MessageLength = cpu_to_le32(r->length); - return retval; -} - -static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, - rndis_resp_t *r) -{ - rndis_set_cmplt_type *resp; - int retval = -ENOTSUPP; - struct rndis_params *params; -#if (defined(DEBUG) && defined(DEBUG_VERBOSE)) || defined(RNDIS_PM) - int i; -#endif - - if (!r) - return -ENOMEM; - resp = (rndis_set_cmplt_type *) r->buf; - if (!resp) - return -ENOMEM; - -#if defined(DEBUG) && defined(DEBUG_VERBOSE) - if (buf_len) { - debug("set OID %08x value, len %d:\n", OID, buf_len); - for (i = 0; i < buf_len; i += 16) { - debug("%03d: %08x %08x %08x %08x\n", i, - get_unaligned_le32(&buf[i]), - get_unaligned_le32(&buf[i + 4]), - get_unaligned_le32(&buf[i + 8]), - get_unaligned_le32(&buf[i + 12])); - } - } -#endif - - params = &rndis_per_dev_params[configNr]; - switch (OID) { - case OID_GEN_CURRENT_PACKET_FILTER: - - /* - * these NDIS_PACKET_TYPE_* bitflags are shared with - * cdc_filter; it's not RNDIS-specific - * NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in: - * PROMISCUOUS, DIRECTED, - * MULTICAST, ALL_MULTICAST, BROADCAST - */ - *params->filter = (u16) get_unaligned_le32(buf); - debug("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", - __func__, *params->filter); - - /* - * this call has a significant side effect: it's - * what makes the packet flow start and stop, like - * activating the CDC Ethernet altsetting. - */ -#ifdef RNDIS_PM -update_linkstate: -#endif - retval = 0; - if (*params->filter) - params->state = RNDIS_DATA_INITIALIZED; - else - params->state = RNDIS_INITIALIZED; - break; - - case OID_802_3_MULTICAST_LIST: - /* I think we can ignore this */ - debug("%s: OID_802_3_MULTICAST_LIST\n", __func__); - retval = 0; - break; -#if 0 - case OID_GEN_RNDIS_CONFIG_PARAMETER: - { - struct rndis_config_parameter *param; - param = (struct rndis_config_parameter *) buf; - debug("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n", - __func__, - min(cpu_to_le32(param->ParameterNameLength), 80), - buf + param->ParameterNameOffset); - retval = 0; - } - break; -#endif - -#ifdef RNDIS_PM - case OID_PNP_SET_POWER: - /* - * The only real power state is USB suspend, and RNDIS requests - * can't enter it; this one isn't really about power. After - * resuming, Windows forces a reset, and then SET_POWER D0. - * FIXME ... then things go batty; Windows wedges itself. - */ - i = get_unaligned_le32(buf); - debug("%s: OID_PNP_SET_POWER D%d\n", __func__, i - 1); - switch (i) { - case NdisDeviceStateD0: - *params->filter = params->saved_filter; - goto update_linkstate; - case NdisDeviceStateD3: - case NdisDeviceStateD2: - case NdisDeviceStateD1: - params->saved_filter = *params->filter; - retval = 0; - break; - } - break; - -#ifdef RNDIS_WAKEUP - /* - * no wakeup support advertised, so wakeup OIDs always fail: - * - OID_PNP_ENABLE_WAKE_UP - * - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN - */ -#endif - -#endif /* RNDIS_PM */ - - default: - debug("%s: set unknown OID 0x%08X, size %d\n", - __func__, OID, buf_len); - } - - return retval; -} - -/* - * Response Functions - */ - -static int rndis_init_response(int configNr, rndis_init_msg_type *buf) -{ - rndis_init_cmplt_type *resp; - rndis_resp_t *r; - - if (!rndis_per_dev_params[configNr].dev) - return -ENOTSUPP; - - r = rndis_add_response(configNr, sizeof(rndis_init_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_init_cmplt_type *) r->buf; - - resp->MessageType = __constant_cpu_to_le32( - REMOTE_NDIS_INITIALIZE_CMPLT); - resp->MessageLength = __constant_cpu_to_le32(52); - resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */ - resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS); - resp->MajorVersion = __constant_cpu_to_le32(RNDIS_MAJOR_VERSION); - resp->MinorVersion = __constant_cpu_to_le32(RNDIS_MINOR_VERSION); - resp->DeviceFlags = __constant_cpu_to_le32(RNDIS_DF_CONNECTIONLESS); - resp->Medium = __constant_cpu_to_le32(RNDIS_MEDIUM_802_3); - resp->MaxPacketsPerTransfer = __constant_cpu_to_le32(1); - resp->MaxTransferSize = cpu_to_le32( - rndis_per_dev_params[configNr].mtu - + ETHER_HDR_SIZE - + sizeof(struct rndis_packet_msg_type) - + 22); - resp->PacketAlignmentFactor = __constant_cpu_to_le32(0); - resp->AFListOffset = __constant_cpu_to_le32(0); - resp->AFListSize = __constant_cpu_to_le32(0); - - if (rndis_per_dev_params[configNr].ack) - rndis_per_dev_params[configNr].ack( - rndis_per_dev_params[configNr].dev); - - return 0; -} - -static int rndis_query_response(int configNr, rndis_query_msg_type *buf) -{ - rndis_query_cmplt_type *resp; - rndis_resp_t *r; - - debug("%s: OID = %08X\n", __func__, get_unaligned_le32(&buf->OID)); - if (!rndis_per_dev_params[configNr].dev) - return -ENOTSUPP; - - /* - * we need more memory: - * gen_ndis_query_resp expects enough space for - * rndis_query_cmplt_type followed by data. - * oid_supported_list is the largest data reply - */ - r = rndis_add_response(configNr, - sizeof(oid_supported_list) + sizeof(rndis_query_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_query_cmplt_type *) r->buf; - - resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_QUERY_CMPLT); - resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */ - - if (gen_ndis_query_resp(configNr, get_unaligned_le32(&buf->OID), - get_unaligned_le32(&buf->InformationBufferOffset) - + 8 + (u8 *) buf, - get_unaligned_le32(&buf->InformationBufferLength), - r)) { - /* OID not supported */ - resp->Status = __constant_cpu_to_le32( - RNDIS_STATUS_NOT_SUPPORTED); - resp->MessageLength = __constant_cpu_to_le32(sizeof *resp); - resp->InformationBufferLength = __constant_cpu_to_le32(0); - resp->InformationBufferOffset = __constant_cpu_to_le32(0); - } else - resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS); - - if (rndis_per_dev_params[configNr].ack) - rndis_per_dev_params[configNr].ack( - rndis_per_dev_params[configNr].dev); - return 0; -} - -static int rndis_set_response(int configNr, rndis_set_msg_type *buf) -{ - u32 BufLength, BufOffset; - rndis_set_cmplt_type *resp; - rndis_resp_t *r; - - r = rndis_add_response(configNr, sizeof(rndis_set_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_set_cmplt_type *) r->buf; - - BufLength = get_unaligned_le32(&buf->InformationBufferLength); - BufOffset = get_unaligned_le32(&buf->InformationBufferOffset); - -#ifdef VERBOSE - debug("%s: Length: %d\n", __func__, BufLength); - debug("%s: Offset: %d\n", __func__, BufOffset); - debug("%s: InfoBuffer: ", __func__); - - for (i = 0; i < BufLength; i++) - debug("%02x ", *(((u8 *) buf) + i + 8 + BufOffset)); - - debug("\n"); -#endif - - resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_SET_CMPLT); - resp->MessageLength = __constant_cpu_to_le32(16); - resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */ - if (gen_ndis_set_resp(configNr, get_unaligned_le32(&buf->OID), - ((u8 *) buf) + 8 + BufOffset, BufLength, r)) - resp->Status = __constant_cpu_to_le32( - RNDIS_STATUS_NOT_SUPPORTED); - else - resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS); - - if (rndis_per_dev_params[configNr].ack) - rndis_per_dev_params[configNr].ack( - rndis_per_dev_params[configNr].dev); - - return 0; -} - -static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf) -{ - rndis_reset_cmplt_type *resp; - rndis_resp_t *r; - - r = rndis_add_response(configNr, sizeof(rndis_reset_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_reset_cmplt_type *) r->buf; - - resp->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_RESET_CMPLT); - resp->MessageLength = __constant_cpu_to_le32(16); - resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS); - /* resent information */ - resp->AddressingReset = __constant_cpu_to_le32(1); - - if (rndis_per_dev_params[configNr].ack) - rndis_per_dev_params[configNr].ack( - rndis_per_dev_params[configNr].dev); - - return 0; -} - -static int rndis_keepalive_response(int configNr, - rndis_keepalive_msg_type *buf) -{ - rndis_keepalive_cmplt_type *resp; - rndis_resp_t *r; - - /* host "should" check only in RNDIS_DATA_INITIALIZED state */ - - r = rndis_add_response(configNr, sizeof(rndis_keepalive_cmplt_type)); - if (!r) - return -ENOMEM; - resp = (rndis_keepalive_cmplt_type *) r->buf; - - resp->MessageType = __constant_cpu_to_le32( - REMOTE_NDIS_KEEPALIVE_CMPLT); - resp->MessageLength = __constant_cpu_to_le32(16); - resp->RequestID = get_unaligned(&buf->RequestID); /* Still LE in msg buffer */ - resp->Status = __constant_cpu_to_le32(RNDIS_STATUS_SUCCESS); - - if (rndis_per_dev_params[configNr].ack) - rndis_per_dev_params[configNr].ack( - rndis_per_dev_params[configNr].dev); - - return 0; -} - - -/* - * Device to Host Comunication - */ -static int rndis_indicate_status_msg(int configNr, u32 status) -{ - rndis_indicate_status_msg_type *resp; - rndis_resp_t *r; - - if (rndis_per_dev_params[configNr].state == RNDIS_UNINITIALIZED) - return -ENOTSUPP; - - r = rndis_add_response(configNr, - sizeof(rndis_indicate_status_msg_type)); - if (!r) - return -ENOMEM; - resp = (rndis_indicate_status_msg_type *) r->buf; - - resp->MessageType = __constant_cpu_to_le32( - REMOTE_NDIS_INDICATE_STATUS_MSG); - resp->MessageLength = __constant_cpu_to_le32(20); - resp->Status = cpu_to_le32(status); - resp->StatusBufferLength = __constant_cpu_to_le32(0); - resp->StatusBufferOffset = __constant_cpu_to_le32(0); - - if (rndis_per_dev_params[configNr].ack) - rndis_per_dev_params[configNr].ack( - rndis_per_dev_params[configNr].dev); - return 0; -} - -int rndis_signal_connect(int configNr) -{ - rndis_per_dev_params[configNr].media_state - = NDIS_MEDIA_STATE_CONNECTED; - return rndis_indicate_status_msg(configNr, - RNDIS_STATUS_MEDIA_CONNECT); -} - -int rndis_signal_disconnect(int configNr) -{ - rndis_per_dev_params[configNr].media_state - = NDIS_MEDIA_STATE_DISCONNECTED; - -#ifdef RNDIS_COMPLETE_SIGNAL_DISCONNECT - return rndis_indicate_status_msg(configNr, - RNDIS_STATUS_MEDIA_DISCONNECT); -#else - return 0; -#endif -} - -void rndis_uninit(int configNr) -{ - u8 *buf; - u32 length; - - if (configNr >= RNDIS_MAX_CONFIGS) - return; - rndis_per_dev_params[configNr].used = 0; - rndis_per_dev_params[configNr].state = RNDIS_UNINITIALIZED; - - /* drain the response queue */ - while ((buf = rndis_get_next_response(configNr, &length))) - rndis_free_response(configNr, buf); -} - -void rndis_set_host_mac(int configNr, const u8 *addr) -{ - rndis_per_dev_params[configNr].host_mac = addr; -} - -enum rndis_state rndis_get_state(int configNr) -{ - if (configNr >= RNDIS_MAX_CONFIGS || configNr < 0) - return -ENOTSUPP; - return rndis_per_dev_params[configNr].state; -} - -/* - * Message Parser - */ -int rndis_msg_parser(u8 configNr, u8 *buf) -{ - u32 MsgType, MsgLength; - __le32 *tmp; - struct rndis_params *params; - - debug("%s: configNr = %d, %p\n", __func__, configNr, buf); - - if (!buf) - return -ENOMEM; - - tmp = (__le32 *) buf; - MsgType = get_unaligned_le32(tmp++); - MsgLength = get_unaligned_le32(tmp++); - - if (configNr >= RNDIS_MAX_CONFIGS) - return -ENOTSUPP; - params = &rndis_per_dev_params[configNr]; - - /* - * NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for - * rx/tx statistics and link status, in addition to KEEPALIVE traffic - * and normal HC level polling to see if there's any IN traffic. - */ - - /* For USB: responses may take up to 10 seconds */ - switch (MsgType) { - case REMOTE_NDIS_INITIALIZE_MSG: - debug("%s: REMOTE_NDIS_INITIALIZE_MSG\n", __func__); - params->state = RNDIS_INITIALIZED; - return rndis_init_response(configNr, - (rndis_init_msg_type *) buf); - - case REMOTE_NDIS_HALT_MSG: - debug("%s: REMOTE_NDIS_HALT_MSG\n", __func__); - params->state = RNDIS_UNINITIALIZED; - return 0; - - case REMOTE_NDIS_QUERY_MSG: - return rndis_query_response(configNr, - (rndis_query_msg_type *) buf); - - case REMOTE_NDIS_SET_MSG: - return rndis_set_response(configNr, - (rndis_set_msg_type *) buf); - - case REMOTE_NDIS_RESET_MSG: - debug("%s: REMOTE_NDIS_RESET_MSG\n", __func__); - return rndis_reset_response(configNr, - (rndis_reset_msg_type *) buf); - - case REMOTE_NDIS_KEEPALIVE_MSG: - /* For USB: host does this every 5 seconds */ -#if defined(DEBUG) && defined(DEBUG_VERBOSE) - debug("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", __func__); -#endif - return rndis_keepalive_response(configNr, - (rndis_keepalive_msg_type *) buf); - - default: - /* - * At least Windows XP emits some undefined RNDIS messages. - * In one case those messages seemed to relate to the host - * suspending itself. - */ - debug("%s: unknown RNDIS message 0x%08X len %d\n", - __func__ , MsgType, MsgLength); - { - unsigned i; - for (i = 0; i < MsgLength; i += 16) { - debug("%03d: " - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - " %02x %02x %02x %02x" - "\n", - i, - buf[i], buf[i+1], - buf[i+2], buf[i+3], - buf[i+4], buf[i+5], - buf[i+6], buf[i+7], - buf[i+8], buf[i+9], - buf[i+10], buf[i+11], - buf[i+12], buf[i+13], - buf[i+14], buf[i+15]); - } - } - break; - } - - return -ENOTSUPP; -} - -int rndis_register(int (*rndis_control_ack)(struct eth_device *)) -{ - u8 i; - - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { - if (!rndis_per_dev_params[i].used) { - rndis_per_dev_params[i].used = 1; - rndis_per_dev_params[i].ack = rndis_control_ack; - debug("%s: configNr = %d\n", __func__, i); - return i; - } - } - debug("%s failed\n", __func__); - - return -1; -} - -void rndis_deregister(int configNr) -{ - debug("%s: configNr = %d\n", __func__, configNr); - - if (configNr >= RNDIS_MAX_CONFIGS) - return; - rndis_per_dev_params[configNr].used = 0; - - return; -} - -int rndis_set_param_dev(u8 configNr, struct eth_device *dev, int mtu, - struct net_device_stats *stats, u16 *cdc_filter) -{ - debug("%s: configNr = %d\n", __func__, configNr); - if (!dev || !stats) - return -1; - if (configNr >= RNDIS_MAX_CONFIGS) - return -1; - - rndis_per_dev_params[configNr].dev = dev; - rndis_per_dev_params[configNr].stats = stats; - rndis_per_dev_params[configNr].mtu = mtu; - rndis_per_dev_params[configNr].filter = cdc_filter; - - return 0; -} - -int rndis_set_param_vendor(u8 configNr, u32 vendorID, const char *vendorDescr) -{ - debug("%s: configNr = %d\n", __func__, configNr); - if (!vendorDescr) - return -1; - if (configNr >= RNDIS_MAX_CONFIGS) - return -1; - - rndis_per_dev_params[configNr].vendorID = vendorID; - rndis_per_dev_params[configNr].vendorDescr = vendorDescr; - - return 0; -} - -int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed) -{ - debug("%s: configNr = %d, %u %u\n", __func__, configNr, medium, speed); - if (configNr >= RNDIS_MAX_CONFIGS) - return -1; - - rndis_per_dev_params[configNr].medium = medium; - rndis_per_dev_params[configNr].speed = speed; - - return 0; -} - -void rndis_add_hdr(void *buf, int length) -{ - struct rndis_packet_msg_type *header; - - header = buf; - memset(header, 0, sizeof *header); - header->MessageType = __constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG); - header->MessageLength = cpu_to_le32(length + sizeof *header); - header->DataOffset = __constant_cpu_to_le32(36); - header->DataLength = cpu_to_le32(length); -} - -void rndis_free_response(int configNr, u8 *buf) -{ - rndis_resp_t *r; - struct list_head *act, *tmp; - - list_for_each_safe(act, tmp, - &(rndis_per_dev_params[configNr].resp_queue)) - { - r = list_entry(act, rndis_resp_t, list); - if (r && r->buf == buf) { - list_del(&r->list); - free(r); - } - } -} - -u8 *rndis_get_next_response(int configNr, u32 *length) -{ - rndis_resp_t *r; - struct list_head *act, *tmp; - - if (!length) - return NULL; - - list_for_each_safe(act, tmp, - &(rndis_per_dev_params[configNr].resp_queue)) - { - r = list_entry(act, rndis_resp_t, list); - if (!r->send) { - r->send = 1; - *length = r->length; - return r->buf; - } - } - - return NULL; -} - -static rndis_resp_t *rndis_add_response(int configNr, u32 length) -{ - rndis_resp_t *r; - - /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */ - r = malloc(sizeof(rndis_resp_t) + length); - if (!r) - return NULL; - - r->buf = (u8 *) (r + 1); - r->length = length; - r->send = 0; - - list_add_tail(&r->list, - &(rndis_per_dev_params[configNr].resp_queue)); - return r; -} - -int rndis_rm_hdr(void *buf, int length) -{ - /* tmp points to a struct rndis_packet_msg_type */ - __le32 *tmp = buf; - int offs, len; - - /* MessageType, MessageLength */ - if (__constant_cpu_to_le32(REMOTE_NDIS_PACKET_MSG) - != get_unaligned(tmp++)) - return -EINVAL; - tmp++; - - /* DataOffset, DataLength */ - offs = get_unaligned_le32(tmp++) + 8 /* offset of DataOffset */; - if (offs != sizeof(struct rndis_packet_msg_type)) - debug("%s: unexpected DataOffset: %d\n", __func__, offs); - if (offs >= length) - return -EOVERFLOW; - - len = get_unaligned_le32(tmp++); - if (len + sizeof(struct rndis_packet_msg_type) != length) - debug("%s: unexpected DataLength: %d, packet length=%d\n", - __func__, len, length); - - memmove(buf, buf + offs, len); - - return offs; -} - -int rndis_init(void) -{ - u8 i; - - for (i = 0; i < RNDIS_MAX_CONFIGS; i++) { - rndis_per_dev_params[i].confignr = i; - rndis_per_dev_params[i].used = 0; - rndis_per_dev_params[i].state = RNDIS_UNINITIALIZED; - rndis_per_dev_params[i].media_state - = NDIS_MEDIA_STATE_DISCONNECTED; - INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue)); - } - - return 0; -} - -void rndis_exit(void) -{ - /* Nothing to do */ -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/rndis.h b/qemu/roms/u-boot/drivers/usb/gadget/rndis.h deleted file mode 100644 index d9e3a7528..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/rndis.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - * RNDIS Definitions for Remote NDIS - * - * Authors: Benedikt Spranger, Pengutronix - * Robert Schwebel, Pengutronix - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2, as published by the Free Software Foundation. - * - * This software was originally developed in conformance with - * Microsoft's Remote NDIS Specification License Agreement. - */ - -#ifndef _USBGADGET_RNDIS_H -#define _USBGADGET_RNDIS_H - -#include "ndis.h" - -/* - * By default rndis_signal_disconnect does not send status message about - * RNDIS disconnection to USB host (indicated as cable disconnected). - * Define RNDIS_COMPLETE_SIGNAL_DISCONNECT to send it. - * However, this will cause 1 sec delay on Ethernet device halt. - * Usually you do not need to define it. Mostly usable for debugging. - */ - -#define RNDIS_MAXIMUM_FRAME_SIZE 1518 -#define RNDIS_MAX_TOTAL_SIZE 1558 - -/* Remote NDIS Versions */ -#define RNDIS_MAJOR_VERSION 1 -#define RNDIS_MINOR_VERSION 0 - -/* Status Values */ -#define RNDIS_STATUS_SUCCESS 0x00000000U /* Success */ -#define RNDIS_STATUS_FAILURE 0xC0000001U /* Unspecified error */ -#define RNDIS_STATUS_INVALID_DATA 0xC0010015U /* Invalid data */ -#define RNDIS_STATUS_NOT_SUPPORTED 0xC00000BBU /* Unsupported request */ -#define RNDIS_STATUS_MEDIA_CONNECT 0x4001000BU /* Device connected */ -#define RNDIS_STATUS_MEDIA_DISCONNECT 0x4001000CU /* Device disconnected */ -/* - * For all not specified status messages: - * RNDIS_STATUS_Xxx -> NDIS_STATUS_Xxx - */ - -/* Message Set for Connectionless (802.3) Devices */ -#define REMOTE_NDIS_PACKET_MSG 0x00000001U -#define REMOTE_NDIS_INITIALIZE_MSG 0x00000002U /* Initialize device */ -#define REMOTE_NDIS_HALT_MSG 0x00000003U -#define REMOTE_NDIS_QUERY_MSG 0x00000004U -#define REMOTE_NDIS_SET_MSG 0x00000005U -#define REMOTE_NDIS_RESET_MSG 0x00000006U -#define REMOTE_NDIS_INDICATE_STATUS_MSG 0x00000007U -#define REMOTE_NDIS_KEEPALIVE_MSG 0x00000008U - -/* Message completion */ -#define REMOTE_NDIS_INITIALIZE_CMPLT 0x80000002U -#define REMOTE_NDIS_QUERY_CMPLT 0x80000004U -#define REMOTE_NDIS_SET_CMPLT 0x80000005U -#define REMOTE_NDIS_RESET_CMPLT 0x80000006U -#define REMOTE_NDIS_KEEPALIVE_CMPLT 0x80000008U - -/* Device Flags */ -#define RNDIS_DF_CONNECTIONLESS 0x00000001U -#define RNDIS_DF_CONNECTION_ORIENTED 0x00000002U - -#define RNDIS_MEDIUM_802_3 0x00000000U - -/* from drivers/net/sk98lin/h/skgepnmi.h */ -#define OID_PNP_CAPABILITIES 0xFD010100 -#define OID_PNP_SET_POWER 0xFD010101 -#define OID_PNP_QUERY_POWER 0xFD010102 -#define OID_PNP_ADD_WAKE_UP_PATTERN 0xFD010103 -#define OID_PNP_REMOVE_WAKE_UP_PATTERN 0xFD010104 -#define OID_PNP_ENABLE_WAKE_UP 0xFD010106 - - -typedef struct rndis_init_msg_type { - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 MajorVersion; - __le32 MinorVersion; - __le32 MaxTransferSize; -} rndis_init_msg_type; - -typedef struct rndis_init_cmplt_type { - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 Status; - __le32 MajorVersion; - __le32 MinorVersion; - __le32 DeviceFlags; - __le32 Medium; - __le32 MaxPacketsPerTransfer; - __le32 MaxTransferSize; - __le32 PacketAlignmentFactor; - __le32 AFListOffset; - __le32 AFListSize; -} rndis_init_cmplt_type; - -typedef struct rndis_halt_msg_type { - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; -} rndis_halt_msg_type; - -typedef struct rndis_query_msg_type { - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 OID; - __le32 InformationBufferLength; - __le32 InformationBufferOffset; - __le32 DeviceVcHandle; -} rndis_query_msg_type; - -typedef struct rndis_query_cmplt_type { - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 Status; - __le32 InformationBufferLength; - __le32 InformationBufferOffset; -} rndis_query_cmplt_type; - -typedef struct rndis_set_msg_type { - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 OID; - __le32 InformationBufferLength; - __le32 InformationBufferOffset; - __le32 DeviceVcHandle; -} rndis_set_msg_type; - -typedef struct rndis_set_cmplt_type { - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 Status; -} rndis_set_cmplt_type; - -typedef struct rndis_reset_msg_type { - __le32 MessageType; - __le32 MessageLength; - __le32 Reserved; -} rndis_reset_msg_type; - -typedef struct rndis_reset_cmplt_type { - __le32 MessageType; - __le32 MessageLength; - __le32 Status; - __le32 AddressingReset; -} rndis_reset_cmplt_type; - -typedef struct rndis_indicate_status_msg_type { - __le32 MessageType; - __le32 MessageLength; - __le32 Status; - __le32 StatusBufferLength; - __le32 StatusBufferOffset; -} rndis_indicate_status_msg_type; - -typedef struct rndis_keepalive_msg_type { - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; -} rndis_keepalive_msg_type; - -typedef struct rndis_keepalive_cmplt_type { - __le32 MessageType; - __le32 MessageLength; - __le32 RequestID; - __le32 Status; -} rndis_keepalive_cmplt_type; - -struct rndis_packet_msg_type { - __le32 MessageType; - __le32 MessageLength; - __le32 DataOffset; - __le32 DataLength; - __le32 OOBDataOffset; - __le32 OOBDataLength; - __le32 NumOOBDataElements; - __le32 PerPacketInfoOffset; - __le32 PerPacketInfoLength; - __le32 VcHandle; - __le32 Reserved; -} __attribute__ ((packed)); - -struct rndis_config_parameter { - __le32 ParameterNameOffset; - __le32 ParameterNameLength; - __le32 ParameterType; - __le32 ParameterValueOffset; - __le32 ParameterValueLength; -}; - -/* implementation specific */ -enum rndis_state { - RNDIS_UNINITIALIZED, - RNDIS_INITIALIZED, - RNDIS_DATA_INITIALIZED, -}; - -typedef struct rndis_resp_t { - struct list_head list; - u8 *buf; - u32 length; - int send; -} rndis_resp_t; - -typedef struct rndis_params { - u8 confignr; - u8 used; - u16 saved_filter; - enum rndis_state state; - u32 medium; - u32 speed; - u32 media_state; - - const u8 *host_mac; - u16 *filter; - struct eth_device *dev; - struct net_device_stats *stats; - int mtu; - - u32 vendorID; - const char *vendorDescr; - int (*ack)(struct eth_device *); - struct list_head resp_queue; -} rndis_params; - -/* RNDIS Message parser and other useless functions */ -int rndis_msg_parser(u8 configNr, u8 *buf); -enum rndis_state rndis_get_state(int configNr); -int rndis_register(int (*rndis_control_ack)(struct eth_device *)); -void rndis_deregister(int configNr); -int rndis_set_param_dev(u8 configNr, struct eth_device *dev, int mtu, - struct net_device_stats *stats, u16 *cdc_filter); -int rndis_set_param_vendor(u8 configNr, u32 vendorID, - const char *vendorDescr); -int rndis_set_param_medium(u8 configNr, u32 medium, u32 speed); -void rndis_add_hdr(void *bug, int length); -int rndis_rm_hdr(void *bug, int length); -u8 *rndis_get_next_response(int configNr, u32 *length); -void rndis_free_response(int configNr, u8 *buf); - -void rndis_uninit(int configNr); -int rndis_signal_connect(int configNr); -int rndis_signal_disconnect(int configNr); -extern void rndis_set_host_mac(int configNr, const u8 *addr); - -int rndis_init(void); -void rndis_exit(void); - -#endif /* _USBGADGET_RNDIS_H */ diff --git a/qemu/roms/u-boot/drivers/usb/gadget/s3c_udc_otg.c b/qemu/roms/u-boot/drivers/usb/gadget/s3c_udc_otg.c deleted file mode 100644 index 63d4487a9..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/s3c_udc_otg.c +++ /dev/null @@ -1,890 +0,0 @@ -/* - * drivers/usb/gadget/s3c_udc_otg.c - * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers - * - * Copyright (C) 2008 for Samsung Electronics - * - * BSP Support for Samsung's UDC driver - * available at: - * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git - * - * State machine bugfixes: - * Marek Szyprowski <m.szyprowski@samsung.com> - * - * Ported to u-boot: - * Marek Szyprowski <m.szyprowski@samsung.com> - * Lukasz Majewski <l.majewski@samsumg.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ -#undef DEBUG -#include <common.h> -#include <asm/errno.h> -#include <linux/list.h> -#include <malloc.h> - -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - -#include <asm/byteorder.h> -#include <asm/unaligned.h> -#include <asm/io.h> - -#include <asm/mach-types.h> -#include <asm/arch/gpio.h> - -#include "regs-otg.h" -#include <usb/lin_gadget_compat.h> - -/***********************************************************/ - -#define OTG_DMA_MODE 1 - -#define DEBUG_SETUP 0 -#define DEBUG_EP0 0 -#define DEBUG_ISR 0 -#define DEBUG_OUT_EP 0 -#define DEBUG_IN_EP 0 - -#include <usb/s3c_udc.h> - -#define EP0_CON 0 -#define EP_MASK 0xF - -static char *state_names[] = { - "WAIT_FOR_SETUP", - "DATA_STATE_XMIT", - "DATA_STATE_NEED_ZLP", - "WAIT_FOR_OUT_STATUS", - "DATA_STATE_RECV", - "WAIT_FOR_COMPLETE", - "WAIT_FOR_OUT_COMPLETE", - "WAIT_FOR_IN_COMPLETE", - "WAIT_FOR_NULL_COMPLETE", -}; - -#define DRIVER_DESC "S3C HS USB OTG Device Driver, (c) Samsung Electronics" -#define DRIVER_VERSION "15 March 2009" - -struct s3c_udc *the_controller; - -static const char driver_name[] = "s3c-udc"; -static const char driver_desc[] = DRIVER_DESC; -static const char ep0name[] = "ep0-control"; - -/* Max packet size*/ -static unsigned int ep0_fifo_size = 64; -static unsigned int ep_fifo_size = 512; -static unsigned int ep_fifo_size2 = 1024; -static int reset_available = 1; - -static struct usb_ctrlrequest *usb_ctrl; -static dma_addr_t usb_ctrl_dma_addr; - -/* - Local declarations. -*/ -static int s3c_ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *); -static int s3c_ep_disable(struct usb_ep *ep); -static struct usb_request *s3c_alloc_request(struct usb_ep *ep, - gfp_t gfp_flags); -static void s3c_free_request(struct usb_ep *ep, struct usb_request *); - -static int s3c_queue(struct usb_ep *ep, struct usb_request *, gfp_t gfp_flags); -static int s3c_dequeue(struct usb_ep *ep, struct usb_request *); -static int s3c_fifo_status(struct usb_ep *ep); -static void s3c_fifo_flush(struct usb_ep *ep); -static void s3c_ep0_read(struct s3c_udc *dev); -static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep); -static void s3c_handle_ep0(struct s3c_udc *dev); -static int s3c_ep0_write(struct s3c_udc *dev); -static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req); -static void done(struct s3c_ep *ep, struct s3c_request *req, int status); -static void stop_activity(struct s3c_udc *dev, - struct usb_gadget_driver *driver); -static int udc_enable(struct s3c_udc *dev); -static void udc_set_address(struct s3c_udc *dev, unsigned char address); -static void reconfig_usbd(void); -static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed); -static void nuke(struct s3c_ep *ep, int status); -static int s3c_udc_set_halt(struct usb_ep *_ep, int value); -static void s3c_udc_set_nak(struct s3c_ep *ep); - -void set_udc_gadget_private_data(void *p) -{ - debug_cond(DEBUG_SETUP != 0, - "%s: the_controller: 0x%p, p: 0x%p\n", __func__, - the_controller, p); - the_controller->gadget.dev.device_data = p; -} - -void *get_udc_gadget_private_data(struct usb_gadget *gadget) -{ - return gadget->dev.device_data; -} - -static struct usb_ep_ops s3c_ep_ops = { - .enable = s3c_ep_enable, - .disable = s3c_ep_disable, - - .alloc_request = s3c_alloc_request, - .free_request = s3c_free_request, - - .queue = s3c_queue, - .dequeue = s3c_dequeue, - - .set_halt = s3c_udc_set_halt, - .fifo_status = s3c_fifo_status, - .fifo_flush = s3c_fifo_flush, -}; - -#define create_proc_files() do {} while (0) -#define remove_proc_files() do {} while (0) - -/***********************************************************/ - -void __iomem *regs_otg; -struct s3c_usbotg_reg *reg; -struct s3c_usbotg_phy *phy; -static unsigned int usb_phy_ctrl; - -void otg_phy_init(struct s3c_udc *dev) -{ - dev->pdata->phy_control(1); - - /*USB PHY0 Enable */ - printf("USB PHY0 Enable\n"); - - /* Enable PHY */ - writel(readl(usb_phy_ctrl) | USB_PHY_CTRL_EN0, usb_phy_ctrl); - - if (dev->pdata->usb_flags == PHY0_SLEEP) /* C210 Universal */ - writel((readl(&phy->phypwr) - &~(PHY_0_SLEEP | OTG_DISABLE_0 | ANALOG_PWRDOWN) - &~FORCE_SUSPEND_0), &phy->phypwr); - else /* C110 GONI */ - writel((readl(&phy->phypwr) &~(OTG_DISABLE_0 | ANALOG_PWRDOWN) - &~FORCE_SUSPEND_0), &phy->phypwr); - - if (s5p_cpu_id == 0x4412) - writel((readl(&phy->phyclk) & ~(EXYNOS4X12_ID_PULLUP0 | - EXYNOS4X12_COMMON_ON_N0)) | EXYNOS4X12_CLK_SEL_24MHZ, - &phy->phyclk); /* PLL 24Mhz */ - else - writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)) | - CLK_SEL_24MHZ, &phy->phyclk); /* PLL 24Mhz */ - - writel((readl(&phy->rstcon) &~(LINK_SW_RST | PHYLNK_SW_RST)) - | PHY_SW_RST0, &phy->rstcon); - udelay(10); - writel(readl(&phy->rstcon) - &~(PHY_SW_RST0 | LINK_SW_RST | PHYLNK_SW_RST), &phy->rstcon); - udelay(10); -} - -void otg_phy_off(struct s3c_udc *dev) -{ - /* reset controller just in case */ - writel(PHY_SW_RST0, &phy->rstcon); - udelay(20); - writel(readl(&phy->phypwr) &~PHY_SW_RST0, &phy->rstcon); - udelay(20); - - writel(readl(&phy->phypwr) | OTG_DISABLE_0 | ANALOG_PWRDOWN - | FORCE_SUSPEND_0, &phy->phypwr); - - writel(readl(usb_phy_ctrl) &~USB_PHY_CTRL_EN0, usb_phy_ctrl); - - writel((readl(&phy->phyclk) & ~(ID_PULLUP0 | COMMON_ON_N0)), - &phy->phyclk); - - udelay(10000); - - dev->pdata->phy_control(0); -} - -/***********************************************************/ - -#include "s3c_udc_otg_xfer_dma.c" - -/* - * udc_disable - disable USB device controller - */ -static void udc_disable(struct s3c_udc *dev) -{ - debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); - - udc_set_address(dev, 0); - - dev->ep0state = WAIT_FOR_SETUP; - dev->gadget.speed = USB_SPEED_UNKNOWN; - dev->usb_address = 0; - - otg_phy_off(dev); -} - -/* - * udc_reinit - initialize software state - */ -static void udc_reinit(struct s3c_udc *dev) -{ - unsigned int i; - - debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); - - /* device/ep0 records init */ - INIT_LIST_HEAD(&dev->gadget.ep_list); - INIT_LIST_HEAD(&dev->gadget.ep0->ep_list); - dev->ep0state = WAIT_FOR_SETUP; - - /* basic endpoint records init */ - for (i = 0; i < S3C_MAX_ENDPOINTS; i++) { - struct s3c_ep *ep = &dev->ep[i]; - - if (i != 0) - list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); - - ep->desc = 0; - ep->stopped = 0; - INIT_LIST_HEAD(&ep->queue); - ep->pio_irqs = 0; - } - - /* the rest was statically initialized, and is read-only */ -} - -#define BYTES2MAXP(x) (x / 8) -#define MAXP2BYTES(x) (x * 8) - -/* until it's enabled, this UDC should be completely invisible - * to any USB host. - */ -static int udc_enable(struct s3c_udc *dev) -{ - debug_cond(DEBUG_SETUP != 0, "%s: %p\n", __func__, dev); - - otg_phy_init(dev); - reconfig_usbd(); - - debug_cond(DEBUG_SETUP != 0, - "S3C USB 2.0 OTG Controller Core Initialized : 0x%x\n", - readl(®->gintmsk)); - - dev->gadget.speed = USB_SPEED_UNKNOWN; - - return 0; -} - -/* - Register entry point for the peripheral controller driver. -*/ -int usb_gadget_register_driver(struct usb_gadget_driver *driver) -{ - struct s3c_udc *dev = the_controller; - int retval = 0; - unsigned long flags; - - debug_cond(DEBUG_SETUP != 0, "%s: %s\n", __func__, "no name"); - - if (!driver - || (driver->speed != USB_SPEED_FULL - && driver->speed != USB_SPEED_HIGH) - || !driver->bind || !driver->disconnect || !driver->setup) - return -EINVAL; - if (!dev) - return -ENODEV; - if (dev->driver) - return -EBUSY; - - spin_lock_irqsave(&dev->lock, flags); - /* first hook up the driver ... */ - dev->driver = driver; - spin_unlock_irqrestore(&dev->lock, flags); - - if (retval) { /* TODO */ - printf("target device_add failed, error %d\n", retval); - return retval; - } - - retval = driver->bind(&dev->gadget); - if (retval) { - debug_cond(DEBUG_SETUP != 0, - "%s: bind to driver --> error %d\n", - dev->gadget.name, retval); - dev->driver = 0; - return retval; - } - - enable_irq(IRQ_OTG); - - debug_cond(DEBUG_SETUP != 0, - "Registered gadget driver %s\n", dev->gadget.name); - udc_enable(dev); - - return 0; -} - -/* - * Unregister entry point for the peripheral controller driver. - */ -int usb_gadget_unregister_driver(struct usb_gadget_driver *driver) -{ - struct s3c_udc *dev = the_controller; - unsigned long flags; - - if (!dev) - return -ENODEV; - if (!driver || driver != dev->driver) - return -EINVAL; - - spin_lock_irqsave(&dev->lock, flags); - dev->driver = 0; - stop_activity(dev, driver); - spin_unlock_irqrestore(&dev->lock, flags); - - driver->unbind(&dev->gadget); - - disable_irq(IRQ_OTG); - - udc_disable(dev); - return 0; -} - -/* - * done - retire a request; caller blocked irqs - */ -static void done(struct s3c_ep *ep, struct s3c_request *req, int status) -{ - unsigned int stopped = ep->stopped; - - debug("%s: %s %p, req = %p, stopped = %d\n", - __func__, ep->ep.name, ep, &req->req, stopped); - - list_del_init(&req->queue); - - if (likely(req->req.status == -EINPROGRESS)) - req->req.status = status; - else - status = req->req.status; - - if (status && status != -ESHUTDOWN) { - debug("complete %s req %p stat %d len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - } - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - -#ifdef DEBUG - printf("calling complete callback\n"); - { - int i, len = req->req.length; - - printf("pkt[%d] = ", req->req.length); - if (len > 64) - len = 64; - for (i = 0; i < len; i++) { - printf("%02x", ((u8 *)req->req.buf)[i]); - if ((i & 7) == 7) - printf(" "); - } - printf("\n"); - } -#endif - spin_unlock(&ep->dev->lock); - req->req.complete(&ep->ep, &req->req); - spin_lock(&ep->dev->lock); - - debug("callback completed\n"); - - ep->stopped = stopped; -} - -/* - * nuke - dequeue ALL requests - */ -static void nuke(struct s3c_ep *ep, int status) -{ - struct s3c_request *req; - - debug("%s: %s %p\n", __func__, ep->ep.name, ep); - - /* called with irqs blocked */ - while (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct s3c_request, queue); - done(ep, req, status); - } -} - -static void stop_activity(struct s3c_udc *dev, - struct usb_gadget_driver *driver) -{ - int i; - - /* don't disconnect drivers more than once */ - if (dev->gadget.speed == USB_SPEED_UNKNOWN) - driver = 0; - dev->gadget.speed = USB_SPEED_UNKNOWN; - - /* prevent new request submissions, kill any outstanding requests */ - for (i = 0; i < S3C_MAX_ENDPOINTS; i++) { - struct s3c_ep *ep = &dev->ep[i]; - ep->stopped = 1; - nuke(ep, -ESHUTDOWN); - } - - /* report disconnect; the driver is already quiesced */ - if (driver) { - spin_unlock(&dev->lock); - driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - - /* re-init driver-visible data structures */ - udc_reinit(dev); -} - -static void reconfig_usbd(void) -{ - /* 2. Soft-reset OTG Core and then unreset again. */ - int i; - unsigned int uTemp = writel(CORE_SOFT_RESET, ®->grstctl); - - debug("Reseting OTG controller\n"); - - writel(0<<15 /* PHY Low Power Clock sel*/ - |1<<14 /* Non-Periodic TxFIFO Rewind Enable*/ - |0x5<<10 /* Turnaround time*/ - |0<<9 | 0<<8 /* [0:HNP disable,1:HNP enable][ 0:SRP disable*/ - /* 1:SRP enable] H1= 1,1*/ - |0<<7 /* Ulpi DDR sel*/ - |0<<6 /* 0: high speed utmi+, 1: full speed serial*/ - |0<<4 /* 0: utmi+, 1:ulpi*/ - |1<<3 /* phy i/f 0:8bit, 1:16bit*/ - |0x7<<0, /* HS/FS Timeout**/ - ®->gusbcfg); - - /* 3. Put the OTG device core in the disconnected state.*/ - uTemp = readl(®->dctl); - uTemp |= SOFT_DISCONNECT; - writel(uTemp, ®->dctl); - - udelay(20); - - /* 4. Make the OTG device core exit from the disconnected state.*/ - uTemp = readl(®->dctl); - uTemp = uTemp & ~SOFT_DISCONNECT; - writel(uTemp, ®->dctl); - - /* 5. Configure OTG Core to initial settings of device mode.*/ - /* [][1: full speed(30Mhz) 0:high speed]*/ - writel(EP_MISS_CNT(1) | DEV_SPEED_HIGH_SPEED_20, ®->dcfg); - - mdelay(1); - - /* 6. Unmask the core interrupts*/ - writel(GINTMSK_INIT, ®->gintmsk); - - /* 7. Set NAK bit of EP0, EP1, EP2*/ - writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[EP0_CON].doepctl); - writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[EP0_CON].diepctl); - - for (i = 1; i < S3C_MAX_ENDPOINTS; i++) { - writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->out_endp[i].doepctl); - writel(DEPCTL_EPDIS|DEPCTL_SNAK, ®->in_endp[i].diepctl); - } - - /* 8. Unmask EPO interrupts*/ - writel(((1 << EP0_CON) << DAINT_OUT_BIT) - | (1 << EP0_CON), ®->daintmsk); - - /* 9. Unmask device OUT EP common interrupts*/ - writel(DOEPMSK_INIT, ®->doepmsk); - - /* 10. Unmask device IN EP common interrupts*/ - writel(DIEPMSK_INIT, ®->diepmsk); - - /* 11. Set Rx FIFO Size (in 32-bit words) */ - writel(RX_FIFO_SIZE >> 2, ®->grxfsiz); - - /* 12. Set Non Periodic Tx FIFO Size */ - writel((NPTX_FIFO_SIZE >> 2) << 16 | ((RX_FIFO_SIZE >> 2)) << 0, - ®->gnptxfsiz); - - for (i = 1; i < S3C_MAX_HW_ENDPOINTS; i++) - writel((PTX_FIFO_SIZE >> 2) << 16 | - ((RX_FIFO_SIZE + NPTX_FIFO_SIZE + - PTX_FIFO_SIZE*(i-1)) >> 2) << 0, - ®->dieptxf[i-1]); - - /* Flush the RX FIFO */ - writel(RX_FIFO_FLUSH, ®->grstctl); - while (readl(®->grstctl) & RX_FIFO_FLUSH) - debug("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__); - - /* Flush all the Tx FIFO's */ - writel(TX_FIFO_FLUSH_ALL, ®->grstctl); - writel(TX_FIFO_FLUSH_ALL | TX_FIFO_FLUSH, ®->grstctl); - while (readl(®->grstctl) & TX_FIFO_FLUSH) - debug("%s: waiting for S3C_UDC_OTG_GRSTCTL\n", __func__); - - /* 13. Clear NAK bit of EP0, EP1, EP2*/ - /* For Slave mode*/ - /* EP0: Control OUT */ - writel(DEPCTL_EPDIS | DEPCTL_CNAK, - ®->out_endp[EP0_CON].doepctl); - - /* 14. Initialize OTG Link Core.*/ - writel(GAHBCFG_INIT, ®->gahbcfg); -} - -static void set_max_pktsize(struct s3c_udc *dev, enum usb_device_speed speed) -{ - unsigned int ep_ctrl; - int i; - - if (speed == USB_SPEED_HIGH) { - ep0_fifo_size = 64; - ep_fifo_size = 512; - ep_fifo_size2 = 1024; - dev->gadget.speed = USB_SPEED_HIGH; - } else { - ep0_fifo_size = 64; - ep_fifo_size = 64; - ep_fifo_size2 = 64; - dev->gadget.speed = USB_SPEED_FULL; - } - - dev->ep[0].ep.maxpacket = ep0_fifo_size; - for (i = 1; i < S3C_MAX_ENDPOINTS; i++) - dev->ep[i].ep.maxpacket = ep_fifo_size; - - /* EP0 - Control IN (64 bytes)*/ - ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); - writel(ep_ctrl|(0<<0), ®->in_endp[EP0_CON].diepctl); - - /* EP0 - Control OUT (64 bytes)*/ - ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); - writel(ep_ctrl|(0<<0), ®->out_endp[EP0_CON].doepctl); -} - -static int s3c_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct s3c_ep *ep; - struct s3c_udc *dev; - unsigned long flags; - - debug("%s: %p\n", __func__, _ep); - - ep = container_of(_ep, struct s3c_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name - || desc->bDescriptorType != USB_DT_ENDPOINT - || ep->bEndpointAddress != desc->bEndpointAddress - || ep_maxpacket(ep) < - le16_to_cpu(get_unaligned(&desc->wMaxPacketSize))) { - - debug("%s: bad ep or descriptor\n", __func__); - return -EINVAL; - } - - /* xfer types must match, except that interrupt ~= bulk */ - if (ep->bmAttributes != desc->bmAttributes - && ep->bmAttributes != USB_ENDPOINT_XFER_BULK - && desc->bmAttributes != USB_ENDPOINT_XFER_INT) { - - debug("%s: %s type mismatch\n", __func__, _ep->name); - return -EINVAL; - } - - /* hardware _could_ do smaller, but driver doesn't */ - if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK - && le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)) != - ep_maxpacket(ep)) || !get_unaligned(&desc->wMaxPacketSize)) { - - debug("%s: bad %s maxpacket\n", __func__, _ep->name); - return -ERANGE; - } - - dev = ep->dev; - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) { - - debug("%s: bogus device state\n", __func__); - return -ESHUTDOWN; - } - - ep->stopped = 0; - ep->desc = desc; - ep->pio_irqs = 0; - ep->ep.maxpacket = le16_to_cpu(get_unaligned(&desc->wMaxPacketSize)); - - /* Reset halt state */ - s3c_udc_set_nak(ep); - s3c_udc_set_halt(_ep, 0); - - spin_lock_irqsave(&ep->dev->lock, flags); - s3c_udc_ep_activate(ep); - spin_unlock_irqrestore(&ep->dev->lock, flags); - - debug("%s: enabled %s, stopped = %d, maxpacket = %d\n", - __func__, _ep->name, ep->stopped, ep->ep.maxpacket); - return 0; -} - -/* - * Disable EP - */ -static int s3c_ep_disable(struct usb_ep *_ep) -{ - struct s3c_ep *ep; - unsigned long flags; - - debug("%s: %p\n", __func__, _ep); - - ep = container_of(_ep, struct s3c_ep, ep); - if (!_ep || !ep->desc) { - debug("%s: %s not enabled\n", __func__, - _ep ? ep->ep.name : NULL); - return -EINVAL; - } - - spin_lock_irqsave(&ep->dev->lock, flags); - - /* Nuke all pending requests */ - nuke(ep, -ESHUTDOWN); - - ep->desc = 0; - ep->stopped = 1; - - spin_unlock_irqrestore(&ep->dev->lock, flags); - - debug("%s: disabled %s\n", __func__, _ep->name); - return 0; -} - -static struct usb_request *s3c_alloc_request(struct usb_ep *ep, - gfp_t gfp_flags) -{ - struct s3c_request *req; - - debug("%s: %s %p\n", __func__, ep->name, ep); - - req = memalign(CONFIG_SYS_CACHELINE_SIZE, sizeof(*req)); - if (!req) - return 0; - - memset(req, 0, sizeof *req); - INIT_LIST_HEAD(&req->queue); - - return &req->req; -} - -static void s3c_free_request(struct usb_ep *ep, struct usb_request *_req) -{ - struct s3c_request *req; - - debug("%s: %p\n", __func__, ep); - - req = container_of(_req, struct s3c_request, req); - WARN_ON(!list_empty(&req->queue)); - kfree(req); -} - -/* dequeue JUST ONE request */ -static int s3c_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct s3c_ep *ep; - struct s3c_request *req; - unsigned long flags; - - debug("%s: %p\n", __func__, _ep); - - ep = container_of(_ep, struct s3c_ep, ep); - if (!_ep || ep->ep.name == ep0name) - return -EINVAL; - - spin_lock_irqsave(&ep->dev->lock, flags); - - /* make sure it's actually queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - if (&req->req != _req) { - spin_unlock_irqrestore(&ep->dev->lock, flags); - return -EINVAL; - } - - done(ep, req, -ECONNRESET); - - spin_unlock_irqrestore(&ep->dev->lock, flags); - return 0; -} - -/* - * Return bytes in EP FIFO - */ -static int s3c_fifo_status(struct usb_ep *_ep) -{ - int count = 0; - struct s3c_ep *ep; - - ep = container_of(_ep, struct s3c_ep, ep); - if (!_ep) { - debug("%s: bad ep\n", __func__); - return -ENODEV; - } - - debug("%s: %d\n", __func__, ep_index(ep)); - - /* LPD can't report unclaimed bytes from IN fifos */ - if (ep_is_in(ep)) - return -EOPNOTSUPP; - - return count; -} - -/* - * Flush EP FIFO - */ -static void s3c_fifo_flush(struct usb_ep *_ep) -{ - struct s3c_ep *ep; - - ep = container_of(_ep, struct s3c_ep, ep); - if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { - debug("%s: bad ep\n", __func__); - return; - } - - debug("%s: %d\n", __func__, ep_index(ep)); -} - -static const struct usb_gadget_ops s3c_udc_ops = { - /* current versions must always be self-powered */ -}; - -static struct s3c_udc memory = { - .usb_address = 0, - .gadget = { - .ops = &s3c_udc_ops, - .ep0 = &memory.ep[0].ep, - .name = driver_name, - }, - - /* control endpoint */ - .ep[0] = { - .ep = { - .name = ep0name, - .ops = &s3c_ep_ops, - .maxpacket = EP0_FIFO_SIZE, - }, - .dev = &memory, - - .bEndpointAddress = 0, - .bmAttributes = 0, - - .ep_type = ep_control, - }, - - /* first group of endpoints */ - .ep[1] = { - .ep = { - .name = "ep1in-bulk", - .ops = &s3c_ep_ops, - .maxpacket = EP_FIFO_SIZE, - }, - .dev = &memory, - - .bEndpointAddress = USB_DIR_IN | 1, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - - .ep_type = ep_bulk_out, - .fifo_num = 1, - }, - - .ep[2] = { - .ep = { - .name = "ep2out-bulk", - .ops = &s3c_ep_ops, - .maxpacket = EP_FIFO_SIZE, - }, - .dev = &memory, - - .bEndpointAddress = USB_DIR_OUT | 2, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - - .ep_type = ep_bulk_in, - .fifo_num = 2, - }, - - .ep[3] = { - .ep = { - .name = "ep3in-int", - .ops = &s3c_ep_ops, - .maxpacket = EP_FIFO_SIZE, - }, - .dev = &memory, - - .bEndpointAddress = USB_DIR_IN | 3, - .bmAttributes = USB_ENDPOINT_XFER_INT, - - .ep_type = ep_interrupt, - .fifo_num = 3, - }, -}; - -/* - * probe - binds to the platform device - */ - -int s3c_udc_probe(struct s3c_plat_otg_data *pdata) -{ - struct s3c_udc *dev = &memory; - int retval = 0; - - debug("%s: %p\n", __func__, pdata); - - dev->pdata = pdata; - - phy = (struct s3c_usbotg_phy *)pdata->regs_phy; - reg = (struct s3c_usbotg_reg *)pdata->regs_otg; - usb_phy_ctrl = pdata->usb_phy_ctrl; - - /* regs_otg = (void *)pdata->regs_otg; */ - - dev->gadget.is_dualspeed = 1; /* Hack only*/ - dev->gadget.is_otg = 0; - dev->gadget.is_a_peripheral = 0; - dev->gadget.b_hnp_enable = 0; - dev->gadget.a_hnp_support = 0; - dev->gadget.a_alt_hnp_support = 0; - - the_controller = dev; - - usb_ctrl = memalign(CONFIG_SYS_CACHELINE_SIZE, - ROUND(sizeof(struct usb_ctrlrequest), - CONFIG_SYS_CACHELINE_SIZE)); - if (!usb_ctrl) { - error("No memory available for UDC!\n"); - return -ENOMEM; - } - - usb_ctrl_dma_addr = (dma_addr_t) usb_ctrl; - - udc_reinit(dev); - - return retval; -} - -int usb_gadget_handle_interrupts() -{ - u32 intr_status = readl(®->gintsts); - u32 gintmsk = readl(®->gintmsk); - - if (intr_status & gintmsk) - return s3c_udc_irq(1, (void *)the_controller); - return 0; -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c b/qemu/roms/u-boot/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c deleted file mode 100644 index 06dfeed90..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/s3c_udc_otg_xfer_dma.c +++ /dev/null @@ -1,1480 +0,0 @@ -/* - * drivers/usb/gadget/s3c_udc_otg_xfer_dma.c - * Samsung S3C on-chip full/high speed USB OTG 2.0 device controllers - * - * Copyright (C) 2009 for Samsung Electronics - * - * BSP Support for Samsung's UDC driver - * available at: - * git://git.kernel.org/pub/scm/linux/kernel/git/kki_ap/linux-2.6-samsung.git - * - * State machine bugfixes: - * Marek Szyprowski <m.szyprowski@samsung.com> - * - * Ported to u-boot: - * Marek Szyprowski <m.szyprowski@samsung.com> - * Lukasz Majewski <l.majewski@samsumg.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - -static u8 clear_feature_num; -int clear_feature_flag; - -/* Bulk-Only Mass Storage Reset (class-specific request) */ -#define GET_MAX_LUN_REQUEST 0xFE -#define BOT_RESET_REQUEST 0xFF - -static inline void s3c_udc_ep0_zlp(struct s3c_udc *dev) -{ - u32 ep_ctrl; - - writel(usb_ctrl_dma_addr, ®->in_endp[EP0_CON].diepdma); - writel(DIEPT_SIZ_PKT_CNT(1), ®->in_endp[EP0_CON].dieptsiz); - - ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); - writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, - ®->in_endp[EP0_CON].diepctl); - - debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", - __func__, readl(®->in_endp[EP0_CON].diepctl)); - dev->ep0state = WAIT_FOR_IN_COMPLETE; -} - -void s3c_udc_pre_setup(void) -{ - u32 ep_ctrl; - - debug_cond(DEBUG_IN_EP, - "%s : Prepare Setup packets.\n", __func__); - - writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest), - ®->out_endp[EP0_CON].doeptsiz); - writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma); - - ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); - writel(ep_ctrl|DEPCTL_EPENA, ®->out_endp[EP0_CON].doepctl); - - debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", - __func__, readl(®->in_endp[EP0_CON].diepctl)); - debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", - __func__, readl(®->out_endp[EP0_CON].doepctl)); - -} - -static inline void s3c_ep0_complete_out(void) -{ - u32 ep_ctrl; - - debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", - __func__, readl(®->in_endp[EP0_CON].diepctl)); - debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", - __func__, readl(®->out_endp[EP0_CON].doepctl)); - - debug_cond(DEBUG_IN_EP, - "%s : Prepare Complete Out packet.\n", __func__); - - writel(DOEPT_SIZ_PKT_CNT(1) | sizeof(struct usb_ctrlrequest), - ®->out_endp[EP0_CON].doeptsiz); - writel(usb_ctrl_dma_addr, ®->out_endp[EP0_CON].doepdma); - - ep_ctrl = readl(®->out_endp[EP0_CON].doepctl); - writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, - ®->out_endp[EP0_CON].doepctl); - - debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DIEPCTL0 = 0x%x\n", - __func__, readl(®->in_endp[EP0_CON].diepctl)); - debug_cond(DEBUG_EP0 != 0, "%s:EP0 ZLP DOEPCTL0 = 0x%x\n", - __func__, readl(®->out_endp[EP0_CON].doepctl)); - -} - - -static int setdma_rx(struct s3c_ep *ep, struct s3c_request *req) -{ - u32 *buf, ctrl; - u32 length, pktcnt; - u32 ep_num = ep_index(ep); - - buf = req->req.buf + req->req.actual; - length = min(req->req.length - req->req.actual, - ep_num ? DMA_BUFFER_SIZE : ep->ep.maxpacket); - - ep->len = length; - ep->dma_buf = buf; - - if (ep_num == EP0_CON || length == 0) - pktcnt = 1; - else - pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; - - ctrl = readl(®->out_endp[ep_num].doepctl); - - writel((unsigned int) ep->dma_buf, ®->out_endp[ep_num].doepdma); - writel(DOEPT_SIZ_PKT_CNT(pktcnt) | DOEPT_SIZ_XFER_SIZE(length), - ®->out_endp[ep_num].doeptsiz); - writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->out_endp[ep_num].doepctl); - - debug_cond(DEBUG_OUT_EP != 0, - "%s: EP%d RX DMA start : DOEPDMA = 0x%x," - "DOEPTSIZ = 0x%x, DOEPCTL = 0x%x\n" - "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", - __func__, ep_num, - readl(®->out_endp[ep_num].doepdma), - readl(®->out_endp[ep_num].doeptsiz), - readl(®->out_endp[ep_num].doepctl), - buf, pktcnt, length); - return 0; - -} - -int setdma_tx(struct s3c_ep *ep, struct s3c_request *req) -{ - u32 *buf, ctrl = 0; - u32 length, pktcnt; - u32 ep_num = ep_index(ep); - - buf = req->req.buf + req->req.actual; - length = req->req.length - req->req.actual; - - if (ep_num == EP0_CON) - length = min(length, (u32)ep_maxpacket(ep)); - - ep->len = length; - ep->dma_buf = buf; - - flush_dcache_range((unsigned long) ep->dma_buf, - (unsigned long) ep->dma_buf + - ROUND(ep->len, CONFIG_SYS_CACHELINE_SIZE)); - - if (length == 0) - pktcnt = 1; - else - pktcnt = (length - 1)/(ep->ep.maxpacket) + 1; - - /* Flush the endpoint's Tx FIFO */ - writel(TX_FIFO_NUMBER(ep->fifo_num), ®->grstctl); - writel(TX_FIFO_NUMBER(ep->fifo_num) | TX_FIFO_FLUSH, ®->grstctl); - while (readl(®->grstctl) & TX_FIFO_FLUSH) - ; - - writel((unsigned long) ep->dma_buf, ®->in_endp[ep_num].diepdma); - writel(DIEPT_SIZ_PKT_CNT(pktcnt) | DIEPT_SIZ_XFER_SIZE(length), - ®->in_endp[ep_num].dieptsiz); - - ctrl = readl(®->in_endp[ep_num].diepctl); - - /* Write the FIFO number to be used for this endpoint */ - ctrl &= DIEPCTL_TX_FIFO_NUM_MASK; - ctrl |= DIEPCTL_TX_FIFO_NUM(ep->fifo_num); - - /* Clear reserved (Next EP) bits */ - ctrl = (ctrl&~(EP_MASK<<DEPCTL_NEXT_EP_BIT)); - - writel(DEPCTL_EPENA|DEPCTL_CNAK|ctrl, ®->in_endp[ep_num].diepctl); - - debug_cond(DEBUG_IN_EP, - "%s:EP%d TX DMA start : DIEPDMA0 = 0x%x," - "DIEPTSIZ0 = 0x%x, DIEPCTL0 = 0x%x\n" - "\tbuf = 0x%p, pktcnt = %d, xfersize = %d\n", - __func__, ep_num, - readl(®->in_endp[ep_num].diepdma), - readl(®->in_endp[ep_num].dieptsiz), - readl(®->in_endp[ep_num].diepctl), - buf, pktcnt, length); - - return length; -} - -static void complete_rx(struct s3c_udc *dev, u8 ep_num) -{ - struct s3c_ep *ep = &dev->ep[ep_num]; - struct s3c_request *req = NULL; - u32 ep_tsr = 0, xfer_size = 0, is_short = 0; - - if (list_empty(&ep->queue)) { - debug_cond(DEBUG_OUT_EP != 0, - "%s: RX DMA done : NULL REQ on OUT EP-%d\n", - __func__, ep_num); - return; - - } - - req = list_entry(ep->queue.next, struct s3c_request, queue); - ep_tsr = readl(®->out_endp[ep_num].doeptsiz); - - if (ep_num == EP0_CON) - xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP0); - else - xfer_size = (ep_tsr & DOEPT_SIZ_XFER_SIZE_MAX_EP); - - xfer_size = ep->len - xfer_size; - - /* - * NOTE: - * - * Please be careful with proper buffer allocation for USB request, - * which needs to be aligned to CONFIG_SYS_CACHELINE_SIZE, not only - * with starting address, but also its size shall be a cache line - * multiplication. - * - * This will prevent from corruption of data allocated immediatelly - * before or after the buffer. - * - * For armv7, the cache_v7.c provides proper code to emit "ERROR" - * message to warn users. - */ - invalidate_dcache_range((unsigned long) ep->dma_buf, - (unsigned long) ep->dma_buf + - ROUND(xfer_size, CONFIG_SYS_CACHELINE_SIZE)); - - req->req.actual += min(xfer_size, req->req.length - req->req.actual); - is_short = (xfer_size < ep->ep.maxpacket); - - debug_cond(DEBUG_OUT_EP != 0, - "%s: RX DMA done : ep = %d, rx bytes = %d/%d, " - "is_short = %d, DOEPTSIZ = 0x%x, remained bytes = %d\n", - __func__, ep_num, req->req.actual, req->req.length, - is_short, ep_tsr, xfer_size); - - if (is_short || req->req.actual == req->req.length) { - if (ep_num == EP0_CON && dev->ep0state == DATA_STATE_RECV) { - debug_cond(DEBUG_OUT_EP != 0, " => Send ZLP\n"); - s3c_udc_ep0_zlp(dev); - /* packet will be completed in complete_tx() */ - dev->ep0state = WAIT_FOR_IN_COMPLETE; - } else { - done(ep, req, 0); - - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, - struct s3c_request, queue); - debug_cond(DEBUG_OUT_EP != 0, - "%s: Next Rx request start...\n", - __func__); - setdma_rx(ep, req); - } - } - } else - setdma_rx(ep, req); -} - -static void complete_tx(struct s3c_udc *dev, u8 ep_num) -{ - struct s3c_ep *ep = &dev->ep[ep_num]; - struct s3c_request *req; - u32 ep_tsr = 0, xfer_size = 0, is_short = 0; - u32 last; - - if (dev->ep0state == WAIT_FOR_NULL_COMPLETE) { - dev->ep0state = WAIT_FOR_OUT_COMPLETE; - s3c_ep0_complete_out(); - return; - } - - if (list_empty(&ep->queue)) { - debug_cond(DEBUG_IN_EP, - "%s: TX DMA done : NULL REQ on IN EP-%d\n", - __func__, ep_num); - return; - - } - - req = list_entry(ep->queue.next, struct s3c_request, queue); - - ep_tsr = readl(®->in_endp[ep_num].dieptsiz); - - xfer_size = ep->len; - is_short = (xfer_size < ep->ep.maxpacket); - req->req.actual += min(xfer_size, req->req.length - req->req.actual); - - debug_cond(DEBUG_IN_EP, - "%s: TX DMA done : ep = %d, tx bytes = %d/%d, " - "is_short = %d, DIEPTSIZ = 0x%x, remained bytes = %d\n", - __func__, ep_num, req->req.actual, req->req.length, - is_short, ep_tsr, xfer_size); - - if (ep_num == 0) { - if (dev->ep0state == DATA_STATE_XMIT) { - debug_cond(DEBUG_IN_EP, - "%s: ep_num = %d, ep0stat ==" - "DATA_STATE_XMIT\n", - __func__, ep_num); - last = write_fifo_ep0(ep, req); - if (last) - dev->ep0state = WAIT_FOR_COMPLETE; - } else if (dev->ep0state == WAIT_FOR_IN_COMPLETE) { - debug_cond(DEBUG_IN_EP, - "%s: ep_num = %d, completing request\n", - __func__, ep_num); - done(ep, req, 0); - dev->ep0state = WAIT_FOR_SETUP; - } else if (dev->ep0state == WAIT_FOR_COMPLETE) { - debug_cond(DEBUG_IN_EP, - "%s: ep_num = %d, completing request\n", - __func__, ep_num); - done(ep, req, 0); - dev->ep0state = WAIT_FOR_OUT_COMPLETE; - s3c_ep0_complete_out(); - } else { - debug_cond(DEBUG_IN_EP, - "%s: ep_num = %d, invalid ep state\n", - __func__, ep_num); - } - return; - } - - if (req->req.actual == req->req.length) - done(ep, req, 0); - - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct s3c_request, queue); - debug_cond(DEBUG_IN_EP, - "%s: Next Tx request start...\n", __func__); - setdma_tx(ep, req); - } -} - -static inline void s3c_udc_check_tx_queue(struct s3c_udc *dev, u8 ep_num) -{ - struct s3c_ep *ep = &dev->ep[ep_num]; - struct s3c_request *req; - - debug_cond(DEBUG_IN_EP, - "%s: Check queue, ep_num = %d\n", __func__, ep_num); - - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct s3c_request, queue); - debug_cond(DEBUG_IN_EP, - "%s: Next Tx request(0x%p) start...\n", - __func__, req); - - if (ep_is_in(ep)) - setdma_tx(ep, req); - else - setdma_rx(ep, req); - } else { - debug_cond(DEBUG_IN_EP, - "%s: NULL REQ on IN EP-%d\n", __func__, ep_num); - - return; - } - -} - -static void process_ep_in_intr(struct s3c_udc *dev) -{ - u32 ep_intr, ep_intr_status; - u8 ep_num = 0; - - ep_intr = readl(®->daint); - debug_cond(DEBUG_IN_EP, - "*** %s: EP In interrupt : DAINT = 0x%x\n", __func__, ep_intr); - - ep_intr &= DAINT_MASK; - - while (ep_intr) { - if (ep_intr & DAINT_IN_EP_INT(1)) { - ep_intr_status = readl(®->in_endp[ep_num].diepint); - debug_cond(DEBUG_IN_EP, - "\tEP%d-IN : DIEPINT = 0x%x\n", - ep_num, ep_intr_status); - - /* Interrupt Clear */ - writel(ep_intr_status, ®->in_endp[ep_num].diepint); - - if (ep_intr_status & TRANSFER_DONE) { - complete_tx(dev, ep_num); - - if (ep_num == 0) { - if (dev->ep0state == - WAIT_FOR_IN_COMPLETE) - dev->ep0state = WAIT_FOR_SETUP; - - if (dev->ep0state == WAIT_FOR_SETUP) - s3c_udc_pre_setup(); - - /* continue transfer after - set_clear_halt for DMA mode */ - if (clear_feature_flag == 1) { - s3c_udc_check_tx_queue(dev, - clear_feature_num); - clear_feature_flag = 0; - } - } - } - } - ep_num++; - ep_intr >>= 1; - } -} - -static void process_ep_out_intr(struct s3c_udc *dev) -{ - u32 ep_intr, ep_intr_status; - u8 ep_num = 0; - - ep_intr = readl(®->daint); - debug_cond(DEBUG_OUT_EP != 0, - "*** %s: EP OUT interrupt : DAINT = 0x%x\n", - __func__, ep_intr); - - ep_intr = (ep_intr >> DAINT_OUT_BIT) & DAINT_MASK; - - while (ep_intr) { - if (ep_intr & 0x1) { - ep_intr_status = readl(®->out_endp[ep_num].doepint); - debug_cond(DEBUG_OUT_EP != 0, - "\tEP%d-OUT : DOEPINT = 0x%x\n", - ep_num, ep_intr_status); - - /* Interrupt Clear */ - writel(ep_intr_status, ®->out_endp[ep_num].doepint); - - if (ep_num == 0) { - if (ep_intr_status & TRANSFER_DONE) { - if (dev->ep0state != - WAIT_FOR_OUT_COMPLETE) - complete_rx(dev, ep_num); - else { - dev->ep0state = WAIT_FOR_SETUP; - s3c_udc_pre_setup(); - } - } - - if (ep_intr_status & - CTRL_OUT_EP_SETUP_PHASE_DONE) { - debug_cond(DEBUG_OUT_EP != 0, - "SETUP packet arrived\n"); - s3c_handle_ep0(dev); - } - } else { - if (ep_intr_status & TRANSFER_DONE) - complete_rx(dev, ep_num); - } - } - ep_num++; - ep_intr >>= 1; - } -} - -/* - * usb client interrupt handler. - */ -static int s3c_udc_irq(int irq, void *_dev) -{ - struct s3c_udc *dev = _dev; - u32 intr_status; - u32 usb_status, gintmsk; - unsigned long flags; - - spin_lock_irqsave(&dev->lock, flags); - - intr_status = readl(®->gintsts); - gintmsk = readl(®->gintmsk); - - debug_cond(DEBUG_ISR, - "\n*** %s : GINTSTS=0x%x(on state %s), GINTMSK : 0x%x," - "DAINT : 0x%x, DAINTMSK : 0x%x\n", - __func__, intr_status, state_names[dev->ep0state], gintmsk, - readl(®->daint), readl(®->daintmsk)); - - if (!intr_status) { - spin_unlock_irqrestore(&dev->lock, flags); - return IRQ_HANDLED; - } - - if (intr_status & INT_ENUMDONE) { - debug_cond(DEBUG_ISR, "\tSpeed Detection interrupt\n"); - - writel(INT_ENUMDONE, ®->gintsts); - usb_status = (readl(®->dsts) & 0x6); - - if (usb_status & (USB_FULL_30_60MHZ | USB_FULL_48MHZ)) { - debug_cond(DEBUG_ISR, - "\t\tFull Speed Detection\n"); - set_max_pktsize(dev, USB_SPEED_FULL); - - } else { - debug_cond(DEBUG_ISR, - "\t\tHigh Speed Detection : 0x%x\n", - usb_status); - set_max_pktsize(dev, USB_SPEED_HIGH); - } - } - - if (intr_status & INT_EARLY_SUSPEND) { - debug_cond(DEBUG_ISR, "\tEarly suspend interrupt\n"); - writel(INT_EARLY_SUSPEND, ®->gintsts); - } - - if (intr_status & INT_SUSPEND) { - usb_status = readl(®->dsts); - debug_cond(DEBUG_ISR, - "\tSuspend interrupt :(DSTS):0x%x\n", usb_status); - writel(INT_SUSPEND, ®->gintsts); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver) { - if (dev->driver->suspend) - dev->driver->suspend(&dev->gadget); - - /* HACK to let gadget detect disconnected state */ - if (dev->driver->disconnect) { - spin_unlock_irqrestore(&dev->lock, flags); - dev->driver->disconnect(&dev->gadget); - spin_lock_irqsave(&dev->lock, flags); - } - } - } - - if (intr_status & INT_RESUME) { - debug_cond(DEBUG_ISR, "\tResume interrupt\n"); - writel(INT_RESUME, ®->gintsts); - - if (dev->gadget.speed != USB_SPEED_UNKNOWN - && dev->driver - && dev->driver->resume) { - - dev->driver->resume(&dev->gadget); - } - } - - if (intr_status & INT_RESET) { - usb_status = readl(®->gotgctl); - debug_cond(DEBUG_ISR, - "\tReset interrupt - (GOTGCTL):0x%x\n", usb_status); - writel(INT_RESET, ®->gintsts); - - if ((usb_status & 0xc0000) == (0x3 << 18)) { - if (reset_available) { - debug_cond(DEBUG_ISR, - "\t\tOTG core got reset (%d)!!\n", - reset_available); - reconfig_usbd(); - dev->ep0state = WAIT_FOR_SETUP; - reset_available = 0; - s3c_udc_pre_setup(); - } else - reset_available = 1; - - } else { - reset_available = 1; - debug_cond(DEBUG_ISR, - "\t\tRESET handling skipped\n"); - } - } - - if (intr_status & INT_IN_EP) - process_ep_in_intr(dev); - - if (intr_status & INT_OUT_EP) - process_ep_out_intr(dev); - - spin_unlock_irqrestore(&dev->lock, flags); - - return IRQ_HANDLED; -} - -/** Queue one request - * Kickstart transfer if needed - */ -static int s3c_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct s3c_request *req; - struct s3c_ep *ep; - struct s3c_udc *dev; - unsigned long flags; - u32 ep_num, gintsts; - - req = container_of(_req, struct s3c_request, req); - if (unlikely(!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue))) { - - debug("%s: bad params\n", __func__); - return -EINVAL; - } - - ep = container_of(_ep, struct s3c_ep, ep); - - if (unlikely(!_ep || (!ep->desc && ep->ep.name != ep0name))) { - - debug("%s: bad ep: %s, %d, %p\n", __func__, - ep->ep.name, !ep->desc, _ep); - return -EINVAL; - } - - ep_num = ep_index(ep); - dev = ep->dev; - if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) { - - debug("%s: bogus device state %p\n", __func__, dev->driver); - return -ESHUTDOWN; - } - - spin_lock_irqsave(&dev->lock, flags); - - _req->status = -EINPROGRESS; - _req->actual = 0; - - /* kickstart this i/o queue? */ - debug("\n*** %s: %s-%s req = %p, len = %d, buf = %p" - "Q empty = %d, stopped = %d\n", - __func__, _ep->name, ep_is_in(ep) ? "in" : "out", - _req, _req->length, _req->buf, - list_empty(&ep->queue), ep->stopped); - -#ifdef DEBUG - { - int i, len = _req->length; - - printf("pkt = "); - if (len > 64) - len = 64; - for (i = 0; i < len; i++) { - printf("%02x", ((u8 *)_req->buf)[i]); - if ((i & 7) == 7) - printf(" "); - } - printf("\n"); - } -#endif - - if (list_empty(&ep->queue) && !ep->stopped) { - - if (ep_num == 0) { - /* EP0 */ - list_add_tail(&req->queue, &ep->queue); - s3c_ep0_kick(dev, ep); - req = 0; - - } else if (ep_is_in(ep)) { - gintsts = readl(®->gintsts); - debug_cond(DEBUG_IN_EP, - "%s: ep_is_in, S3C_UDC_OTG_GINTSTS=0x%x\n", - __func__, gintsts); - - setdma_tx(ep, req); - } else { - gintsts = readl(®->gintsts); - debug_cond(DEBUG_OUT_EP != 0, - "%s:ep_is_out, S3C_UDC_OTG_GINTSTS=0x%x\n", - __func__, gintsts); - - setdma_rx(ep, req); - } - } - - /* pio or dma irq handler advances the queue. */ - if (likely(req != 0)) - list_add_tail(&req->queue, &ep->queue); - - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -/****************************************************************/ -/* End Point 0 related functions */ -/****************************************************************/ - -/* return: 0 = still running, 1 = completed, negative = errno */ -static int write_fifo_ep0(struct s3c_ep *ep, struct s3c_request *req) -{ - u32 max; - unsigned count; - int is_last; - - max = ep_maxpacket(ep); - - debug_cond(DEBUG_EP0 != 0, "%s: max = %d\n", __func__, max); - - count = setdma_tx(ep, req); - - /* last packet is usually short (or a zlp) */ - if (likely(count != max)) - is_last = 1; - else { - if (likely(req->req.length != req->req.actual + count) - || req->req.zero) - is_last = 0; - else - is_last = 1; - } - - debug_cond(DEBUG_EP0 != 0, - "%s: wrote %s %d bytes%s %d left %p\n", __func__, - ep->ep.name, count, - is_last ? "/L" : "", - req->req.length - req->req.actual - count, req); - - /* requests complete when all IN data is in the FIFO */ - if (is_last) { - ep->dev->ep0state = WAIT_FOR_SETUP; - return 1; - } - - return 0; -} - -int s3c_fifo_read(struct s3c_ep *ep, u32 *cp, int max) -{ - invalidate_dcache_range((unsigned long)cp, (unsigned long)cp + - ROUND(max, CONFIG_SYS_CACHELINE_SIZE)); - - debug_cond(DEBUG_EP0 != 0, - "%s: bytes=%d, ep_index=%d 0x%p\n", __func__, - max, ep_index(ep), cp); - - return max; -} - -/** - * udc_set_address - set the USB address for this device - * @address: - * - * Called from control endpoint function - * after it decodes a set address setup packet. - */ -static void udc_set_address(struct s3c_udc *dev, unsigned char address) -{ - u32 ctrl = readl(®->dcfg); - writel(DEVICE_ADDRESS(address) | ctrl, ®->dcfg); - - s3c_udc_ep0_zlp(dev); - - debug_cond(DEBUG_EP0 != 0, - "%s: USB OTG 2.0 Device address=%d, DCFG=0x%x\n", - __func__, address, readl(®->dcfg)); - - dev->usb_address = address; -} - -static inline void s3c_udc_ep0_set_stall(struct s3c_ep *ep) -{ - struct s3c_udc *dev; - u32 ep_ctrl = 0; - - dev = ep->dev; - ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); - - /* set the disable and stall bits */ - if (ep_ctrl & DEPCTL_EPENA) - ep_ctrl |= DEPCTL_EPDIS; - - ep_ctrl |= DEPCTL_STALL; - - writel(ep_ctrl, ®->in_endp[EP0_CON].diepctl); - - debug_cond(DEBUG_EP0 != 0, - "%s: set ep%d stall, DIEPCTL0 = 0x%p\n", - __func__, ep_index(ep), ®->in_endp[EP0_CON].diepctl); - /* - * The application can only set this bit, and the core clears it, - * when a SETUP token is received for this endpoint - */ - dev->ep0state = WAIT_FOR_SETUP; - - s3c_udc_pre_setup(); -} - -static void s3c_ep0_read(struct s3c_udc *dev) -{ - struct s3c_request *req; - struct s3c_ep *ep = &dev->ep[0]; - - if (!list_empty(&ep->queue)) { - req = list_entry(ep->queue.next, struct s3c_request, queue); - - } else { - debug("%s: ---> BUG\n", __func__); - BUG(); - return; - } - - debug_cond(DEBUG_EP0 != 0, - "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", - __func__, req, req->req.length, req->req.actual); - - if (req->req.length == 0) { - /* zlp for Set_configuration, Set_interface, - * or Bulk-Only mass storge reset */ - - ep->len = 0; - s3c_udc_ep0_zlp(dev); - - debug_cond(DEBUG_EP0 != 0, - "%s: req.length = 0, bRequest = %d\n", - __func__, usb_ctrl->bRequest); - return; - } - - setdma_rx(ep, req); -} - -/* - * DATA_STATE_XMIT - */ -static int s3c_ep0_write(struct s3c_udc *dev) -{ - struct s3c_request *req; - struct s3c_ep *ep = &dev->ep[0]; - int ret, need_zlp = 0; - - if (list_empty(&ep->queue)) - req = 0; - else - req = list_entry(ep->queue.next, struct s3c_request, queue); - - if (!req) { - debug_cond(DEBUG_EP0 != 0, "%s: NULL REQ\n", __func__); - return 0; - } - - debug_cond(DEBUG_EP0 != 0, - "%s: req = %p, req.length = 0x%x, req.actual = 0x%x\n", - __func__, req, req->req.length, req->req.actual); - - if (req->req.length - req->req.actual == ep0_fifo_size) { - /* Next write will end with the packet size, */ - /* so we need Zero-length-packet */ - need_zlp = 1; - } - - ret = write_fifo_ep0(ep, req); - - if ((ret == 1) && !need_zlp) { - /* Last packet */ - dev->ep0state = WAIT_FOR_COMPLETE; - debug_cond(DEBUG_EP0 != 0, - "%s: finished, waiting for status\n", __func__); - - } else { - dev->ep0state = DATA_STATE_XMIT; - debug_cond(DEBUG_EP0 != 0, - "%s: not finished\n", __func__); - } - - return 1; -} - -int s3c_udc_get_status(struct s3c_udc *dev, - struct usb_ctrlrequest *crq) -{ - u8 ep_num = crq->wIndex & 0x7F; - u16 g_status = 0; - u32 ep_ctrl; - - debug_cond(DEBUG_SETUP != 0, - "%s: *** USB_REQ_GET_STATUS\n", __func__); - printf("crq->brequest:0x%x\n", crq->bRequestType & USB_RECIP_MASK); - switch (crq->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_INTERFACE: - g_status = 0; - debug_cond(DEBUG_SETUP != 0, - "\tGET_STATUS:USB_RECIP_INTERFACE, g_stauts = %d\n", - g_status); - break; - - case USB_RECIP_DEVICE: - g_status = 0x1; /* Self powered */ - debug_cond(DEBUG_SETUP != 0, - "\tGET_STATUS: USB_RECIP_DEVICE, g_stauts = %d\n", - g_status); - break; - - case USB_RECIP_ENDPOINT: - if (crq->wLength > 2) { - debug_cond(DEBUG_SETUP != 0, - "\tGET_STATUS:Not support EP or wLength\n"); - return 1; - } - - g_status = dev->ep[ep_num].stopped; - debug_cond(DEBUG_SETUP != 0, - "\tGET_STATUS: USB_RECIP_ENDPOINT, g_stauts = %d\n", - g_status); - - break; - - default: - return 1; - } - - memcpy(usb_ctrl, &g_status, sizeof(g_status)); - - flush_dcache_range((unsigned long) usb_ctrl, - (unsigned long) usb_ctrl + - ROUND(sizeof(g_status), CONFIG_SYS_CACHELINE_SIZE)); - - writel(usb_ctrl_dma_addr, ®->in_endp[EP0_CON].diepdma); - writel(DIEPT_SIZ_PKT_CNT(1) | DIEPT_SIZ_XFER_SIZE(2), - ®->in_endp[EP0_CON].dieptsiz); - - ep_ctrl = readl(®->in_endp[EP0_CON].diepctl); - writel(ep_ctrl|DEPCTL_EPENA|DEPCTL_CNAK, - ®->in_endp[EP0_CON].diepctl); - dev->ep0state = WAIT_FOR_NULL_COMPLETE; - - return 0; -} - -static void s3c_udc_set_nak(struct s3c_ep *ep) -{ - u8 ep_num; - u32 ep_ctrl = 0; - - ep_num = ep_index(ep); - debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); - - if (ep_is_in(ep)) { - ep_ctrl = readl(®->in_endp[ep_num].diepctl); - ep_ctrl |= DEPCTL_SNAK; - writel(ep_ctrl, ®->in_endp[ep_num].diepctl); - debug("%s: set NAK, DIEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); - } else { - ep_ctrl = readl(®->out_endp[ep_num].doepctl); - ep_ctrl |= DEPCTL_SNAK; - writel(ep_ctrl, ®->out_endp[ep_num].doepctl); - debug("%s: set NAK, DOEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); - } - - return; -} - - -void s3c_udc_ep_set_stall(struct s3c_ep *ep) -{ - u8 ep_num; - u32 ep_ctrl = 0; - - ep_num = ep_index(ep); - debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); - - if (ep_is_in(ep)) { - ep_ctrl = readl(®->in_endp[ep_num].diepctl); - - /* set the disable and stall bits */ - if (ep_ctrl & DEPCTL_EPENA) - ep_ctrl |= DEPCTL_EPDIS; - - ep_ctrl |= DEPCTL_STALL; - - writel(ep_ctrl, ®->in_endp[ep_num].diepctl); - debug("%s: set stall, DIEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); - - } else { - ep_ctrl = readl(®->out_endp[ep_num].doepctl); - - /* set the stall bit */ - ep_ctrl |= DEPCTL_STALL; - - writel(ep_ctrl, ®->out_endp[ep_num].doepctl); - debug("%s: set stall, DOEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); - } - - return; -} - -void s3c_udc_ep_clear_stall(struct s3c_ep *ep) -{ - u8 ep_num; - u32 ep_ctrl = 0; - - ep_num = ep_index(ep); - debug("%s: ep_num = %d, ep_type = %d\n", __func__, ep_num, ep->ep_type); - - if (ep_is_in(ep)) { - ep_ctrl = readl(®->in_endp[ep_num].diepctl); - - /* clear stall bit */ - ep_ctrl &= ~DEPCTL_STALL; - - /* - * USB Spec 9.4.5: For endpoints using data toggle, regardless - * of whether an endpoint has the Halt feature set, a - * ClearFeature(ENDPOINT_HALT) request always results in the - * data toggle being reinitialized to DATA0. - */ - if (ep->bmAttributes == USB_ENDPOINT_XFER_INT - || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { - ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */ - } - - writel(ep_ctrl, ®->in_endp[ep_num].diepctl); - debug("%s: cleared stall, DIEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->in_endp[ep_num].diepctl)); - - } else { - ep_ctrl = readl(®->out_endp[ep_num].doepctl); - - /* clear stall bit */ - ep_ctrl &= ~DEPCTL_STALL; - - if (ep->bmAttributes == USB_ENDPOINT_XFER_INT - || ep->bmAttributes == USB_ENDPOINT_XFER_BULK) { - ep_ctrl |= DEPCTL_SETD0PID; /* DATA0 */ - } - - writel(ep_ctrl, ®->out_endp[ep_num].doepctl); - debug("%s: cleared stall, DOEPCTL%d = 0x%x\n", - __func__, ep_num, readl(®->out_endp[ep_num].doepctl)); - } - - return; -} - -static int s3c_udc_set_halt(struct usb_ep *_ep, int value) -{ - struct s3c_ep *ep; - struct s3c_udc *dev; - unsigned long flags; - u8 ep_num; - - ep = container_of(_ep, struct s3c_ep, ep); - ep_num = ep_index(ep); - - if (unlikely(!_ep || !ep->desc || ep_num == EP0_CON || - ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC)) { - debug("%s: %s bad ep or descriptor\n", __func__, ep->ep.name); - return -EINVAL; - } - - /* Attempt to halt IN ep will fail if any transfer requests - * are still queue */ - if (value && ep_is_in(ep) && !list_empty(&ep->queue)) { - debug("%s: %s queue not empty, req = %p\n", - __func__, ep->ep.name, - list_entry(ep->queue.next, struct s3c_request, queue)); - - return -EAGAIN; - } - - dev = ep->dev; - debug("%s: ep_num = %d, value = %d\n", __func__, ep_num, value); - - spin_lock_irqsave(&dev->lock, flags); - - if (value == 0) { - ep->stopped = 0; - s3c_udc_ep_clear_stall(ep); - } else { - if (ep_num == 0) - dev->ep0state = WAIT_FOR_SETUP; - - ep->stopped = 1; - s3c_udc_ep_set_stall(ep); - } - - spin_unlock_irqrestore(&dev->lock, flags); - - return 0; -} - -void s3c_udc_ep_activate(struct s3c_ep *ep) -{ - u8 ep_num; - u32 ep_ctrl = 0, daintmsk = 0; - - ep_num = ep_index(ep); - - /* Read DEPCTLn register */ - if (ep_is_in(ep)) { - ep_ctrl = readl(®->in_endp[ep_num].diepctl); - daintmsk = 1 << ep_num; - } else { - ep_ctrl = readl(®->out_endp[ep_num].doepctl); - daintmsk = (1 << ep_num) << DAINT_OUT_BIT; - } - - debug("%s: EPCTRL%d = 0x%x, ep_is_in = %d\n", - __func__, ep_num, ep_ctrl, ep_is_in(ep)); - - /* If the EP is already active don't change the EP Control - * register. */ - if (!(ep_ctrl & DEPCTL_USBACTEP)) { - ep_ctrl = (ep_ctrl & ~DEPCTL_TYPE_MASK) | - (ep->bmAttributes << DEPCTL_TYPE_BIT); - ep_ctrl = (ep_ctrl & ~DEPCTL_MPS_MASK) | - (ep->ep.maxpacket << DEPCTL_MPS_BIT); - ep_ctrl |= (DEPCTL_SETD0PID | DEPCTL_USBACTEP | DEPCTL_SNAK); - - if (ep_is_in(ep)) { - writel(ep_ctrl, ®->in_endp[ep_num].diepctl); - debug("%s: USB Ative EP%d, DIEPCTRL%d = 0x%x\n", - __func__, ep_num, ep_num, - readl(®->in_endp[ep_num].diepctl)); - } else { - writel(ep_ctrl, ®->out_endp[ep_num].doepctl); - debug("%s: USB Ative EP%d, DOEPCTRL%d = 0x%x\n", - __func__, ep_num, ep_num, - readl(®->out_endp[ep_num].doepctl)); - } - } - - /* Unmask EP Interrtupt */ - writel(readl(®->daintmsk)|daintmsk, ®->daintmsk); - debug("%s: DAINTMSK = 0x%x\n", __func__, readl(®->daintmsk)); - -} - -static int s3c_udc_clear_feature(struct usb_ep *_ep) -{ - struct s3c_udc *dev; - struct s3c_ep *ep; - u8 ep_num; - - ep = container_of(_ep, struct s3c_ep, ep); - ep_num = ep_index(ep); - - dev = ep->dev; - debug_cond(DEBUG_SETUP != 0, - "%s: ep_num = %d, is_in = %d, clear_feature_flag = %d\n", - __func__, ep_num, ep_is_in(ep), clear_feature_flag); - - if (usb_ctrl->wLength != 0) { - debug_cond(DEBUG_SETUP != 0, - "\tCLEAR_FEATURE: wLength is not zero.....\n"); - return 1; - } - - switch (usb_ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - switch (usb_ctrl->wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - debug_cond(DEBUG_SETUP != 0, - "\tOFF:USB_DEVICE_REMOTE_WAKEUP\n"); - break; - - case USB_DEVICE_TEST_MODE: - debug_cond(DEBUG_SETUP != 0, - "\tCLEAR_FEATURE: USB_DEVICE_TEST_MODE\n"); - /** @todo Add CLEAR_FEATURE for TEST modes. */ - break; - } - - s3c_udc_ep0_zlp(dev); - break; - - case USB_RECIP_ENDPOINT: - debug_cond(DEBUG_SETUP != 0, - "\tCLEAR_FEATURE:USB_RECIP_ENDPOINT, wValue = %d\n", - usb_ctrl->wValue); - - if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { - if (ep_num == 0) { - s3c_udc_ep0_set_stall(ep); - return 0; - } - - s3c_udc_ep0_zlp(dev); - - s3c_udc_ep_clear_stall(ep); - s3c_udc_ep_activate(ep); - ep->stopped = 0; - - clear_feature_num = ep_num; - clear_feature_flag = 1; - } - break; - } - - return 0; -} - -static int s3c_udc_set_feature(struct usb_ep *_ep) -{ - struct s3c_udc *dev; - struct s3c_ep *ep; - u8 ep_num; - - ep = container_of(_ep, struct s3c_ep, ep); - ep_num = ep_index(ep); - dev = ep->dev; - - debug_cond(DEBUG_SETUP != 0, - "%s: *** USB_REQ_SET_FEATURE , ep_num = %d\n", - __func__, ep_num); - - if (usb_ctrl->wLength != 0) { - debug_cond(DEBUG_SETUP != 0, - "\tSET_FEATURE: wLength is not zero.....\n"); - return 1; - } - - switch (usb_ctrl->bRequestType & USB_RECIP_MASK) { - case USB_RECIP_DEVICE: - switch (usb_ctrl->wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - debug_cond(DEBUG_SETUP != 0, - "\tSET_FEATURE:USB_DEVICE_REMOTE_WAKEUP\n"); - break; - case USB_DEVICE_B_HNP_ENABLE: - debug_cond(DEBUG_SETUP != 0, - "\tSET_FEATURE: USB_DEVICE_B_HNP_ENABLE\n"); - break; - - case USB_DEVICE_A_HNP_SUPPORT: - /* RH port supports HNP */ - debug_cond(DEBUG_SETUP != 0, - "\tSET_FEATURE:USB_DEVICE_A_HNP_SUPPORT\n"); - break; - - case USB_DEVICE_A_ALT_HNP_SUPPORT: - /* other RH port does */ - debug_cond(DEBUG_SETUP != 0, - "\tSET: USB_DEVICE_A_ALT_HNP_SUPPORT\n"); - break; - } - - s3c_udc_ep0_zlp(dev); - return 0; - - case USB_RECIP_INTERFACE: - debug_cond(DEBUG_SETUP != 0, - "\tSET_FEATURE: USB_RECIP_INTERFACE\n"); - break; - - case USB_RECIP_ENDPOINT: - debug_cond(DEBUG_SETUP != 0, - "\tSET_FEATURE: USB_RECIP_ENDPOINT\n"); - if (usb_ctrl->wValue == USB_ENDPOINT_HALT) { - if (ep_num == 0) { - s3c_udc_ep0_set_stall(ep); - return 0; - } - ep->stopped = 1; - s3c_udc_ep_set_stall(ep); - } - - s3c_udc_ep0_zlp(dev); - return 0; - } - - return 1; -} - -/* - * WAIT_FOR_SETUP (OUT_PKT_RDY) - */ -void s3c_ep0_setup(struct s3c_udc *dev) -{ - struct s3c_ep *ep = &dev->ep[0]; - int i; - u8 ep_num; - - /* Nuke all previous transfers */ - nuke(ep, -EPROTO); - - /* read control req from fifo (8 bytes) */ - s3c_fifo_read(ep, (u32 *)usb_ctrl, 8); - - debug_cond(DEBUG_SETUP != 0, - "%s: bRequestType = 0x%x(%s), bRequest = 0x%x" - "\twLength = 0x%x, wValue = 0x%x, wIndex= 0x%x\n", - __func__, usb_ctrl->bRequestType, - (usb_ctrl->bRequestType & USB_DIR_IN) ? "IN" : "OUT", - usb_ctrl->bRequest, - usb_ctrl->wLength, usb_ctrl->wValue, usb_ctrl->wIndex); - -#ifdef DEBUG - { - int i, len = sizeof(*usb_ctrl); - char *p = (char *)usb_ctrl; - - printf("pkt = "); - for (i = 0; i < len; i++) { - printf("%02x", ((u8 *)p)[i]); - if ((i & 7) == 7) - printf(" "); - } - printf("\n"); - } -#endif - - if (usb_ctrl->bRequest == GET_MAX_LUN_REQUEST && - usb_ctrl->wLength != 1) { - debug_cond(DEBUG_SETUP != 0, - "\t%s:GET_MAX_LUN_REQUEST:invalid", - __func__); - debug_cond(DEBUG_SETUP != 0, - "wLength = %d, setup returned\n", - usb_ctrl->wLength); - - s3c_udc_ep0_set_stall(ep); - dev->ep0state = WAIT_FOR_SETUP; - - return; - } else if (usb_ctrl->bRequest == BOT_RESET_REQUEST && - usb_ctrl->wLength != 0) { - /* Bulk-Only *mass storge reset of class-specific request */ - debug_cond(DEBUG_SETUP != 0, - "%s:BOT Rest:invalid wLength =%d, setup returned\n", - __func__, usb_ctrl->wLength); - - s3c_udc_ep0_set_stall(ep); - dev->ep0state = WAIT_FOR_SETUP; - - return; - } - - /* Set direction of EP0 */ - if (likely(usb_ctrl->bRequestType & USB_DIR_IN)) { - ep->bEndpointAddress |= USB_DIR_IN; - } else { - ep->bEndpointAddress &= ~USB_DIR_IN; - } - /* cope with automagic for some standard requests. */ - dev->req_std = (usb_ctrl->bRequestType & USB_TYPE_MASK) - == USB_TYPE_STANDARD; - - dev->req_pending = 1; - - /* Handle some SETUP packets ourselves */ - if (dev->req_std) { - switch (usb_ctrl->bRequest) { - case USB_REQ_SET_ADDRESS: - debug_cond(DEBUG_SETUP != 0, - "%s: *** USB_REQ_SET_ADDRESS (%d)\n", - __func__, usb_ctrl->wValue); - if (usb_ctrl->bRequestType - != (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) - break; - - udc_set_address(dev, usb_ctrl->wValue); - return; - - case USB_REQ_SET_CONFIGURATION: - debug_cond(DEBUG_SETUP != 0, - "=====================================\n"); - debug_cond(DEBUG_SETUP != 0, - "%s: USB_REQ_SET_CONFIGURATION (%d)\n", - __func__, usb_ctrl->wValue); - - if (usb_ctrl->bRequestType == USB_RECIP_DEVICE) - reset_available = 1; - - break; - - case USB_REQ_GET_DESCRIPTOR: - debug_cond(DEBUG_SETUP != 0, - "%s: *** USB_REQ_GET_DESCRIPTOR\n", - __func__); - break; - - case USB_REQ_SET_INTERFACE: - debug_cond(DEBUG_SETUP != 0, - "%s: *** USB_REQ_SET_INTERFACE (%d)\n", - __func__, usb_ctrl->wValue); - - if (usb_ctrl->bRequestType == USB_RECIP_INTERFACE) - reset_available = 1; - - break; - - case USB_REQ_GET_CONFIGURATION: - debug_cond(DEBUG_SETUP != 0, - "%s: *** USB_REQ_GET_CONFIGURATION\n", - __func__); - break; - - case USB_REQ_GET_STATUS: - if (!s3c_udc_get_status(dev, usb_ctrl)) - return; - - break; - - case USB_REQ_CLEAR_FEATURE: - ep_num = usb_ctrl->wIndex & 0x7f; - - if (!s3c_udc_clear_feature(&dev->ep[ep_num].ep)) - return; - - break; - - case USB_REQ_SET_FEATURE: - ep_num = usb_ctrl->wIndex & 0x7f; - - if (!s3c_udc_set_feature(&dev->ep[ep_num].ep)) - return; - - break; - - default: - debug_cond(DEBUG_SETUP != 0, - "%s: *** Default of usb_ctrl->bRequest=0x%x" - "happened.\n", __func__, usb_ctrl->bRequest); - break; - } - } - - - if (likely(dev->driver)) { - /* device-2-host (IN) or no data setup command, - * process immediately */ - debug_cond(DEBUG_SETUP != 0, - "%s:usb_ctrlreq will be passed to fsg_setup()\n", - __func__); - - spin_unlock(&dev->lock); - i = dev->driver->setup(&dev->gadget, usb_ctrl); - spin_lock(&dev->lock); - - if (i < 0) { - /* setup processing failed, force stall */ - s3c_udc_ep0_set_stall(ep); - dev->ep0state = WAIT_FOR_SETUP; - - debug_cond(DEBUG_SETUP != 0, - "\tdev->driver->setup failed (%d)," - " bRequest = %d\n", - i, usb_ctrl->bRequest); - - - } else if (dev->req_pending) { - dev->req_pending = 0; - debug_cond(DEBUG_SETUP != 0, - "\tdev->req_pending...\n"); - } - - debug_cond(DEBUG_SETUP != 0, - "\tep0state = %s\n", state_names[dev->ep0state]); - - } -} - -/* - * handle ep0 interrupt - */ -static void s3c_handle_ep0(struct s3c_udc *dev) -{ - if (dev->ep0state == WAIT_FOR_SETUP) { - debug_cond(DEBUG_OUT_EP != 0, - "%s: WAIT_FOR_SETUP\n", __func__); - s3c_ep0_setup(dev); - - } else { - debug_cond(DEBUG_OUT_EP != 0, - "%s: strange state!!(state = %s)\n", - __func__, state_names[dev->ep0state]); - } -} - -static void s3c_ep0_kick(struct s3c_udc *dev, struct s3c_ep *ep) -{ - debug_cond(DEBUG_EP0 != 0, - "%s: ep_is_in = %d\n", __func__, ep_is_in(ep)); - if (ep_is_in(ep)) { - dev->ep0state = DATA_STATE_XMIT; - s3c_ep0_write(dev); - - } else { - dev->ep0state = DATA_STATE_RECV; - s3c_ep0_read(dev); - } -} diff --git a/qemu/roms/u-boot/drivers/usb/gadget/storage_common.c b/qemu/roms/u-boot/drivers/usb/gadget/storage_common.c deleted file mode 100644 index 74300746b..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/storage_common.c +++ /dev/null @@ -1,624 +0,0 @@ -/* - * storage_common.c -- Common definitions for mass storage functionality - * - * Copyright (C) 2003-2008 Alan Stern - * Copyeight (C) 2009 Samsung Electronics - * Author: Michal Nazarewicz (m.nazarewicz@samsung.com) - * - * Ported to u-boot: - * Andrzej Pietrasiewicz <andrzej.p@samsung.com> - * - * Code refactoring & cleanup: - * Ćukasz Majewski <l.majewski@samsung.com> - * - * SPDX-License-Identifier: GPL-2.0+ - */ - - -/* - * This file requires the following identifiers used in USB strings to - * be defined (each of type pointer to char): - * - fsg_string_manufacturer -- name of the manufacturer - * - fsg_string_product -- name of the product - * - fsg_string_serial -- product's serial - * - fsg_string_config -- name of the configuration - * - fsg_string_interface -- name of the interface - * The first four are only needed when FSG_DESCRIPTORS_DEVICE_STRINGS - * macro is defined prior to including this file. - */ - -/* - * When FSG_NO_INTR_EP is defined fsg_fs_intr_in_desc and - * fsg_hs_intr_in_desc objects as well as - * FSG_FS_FUNCTION_PRE_EP_ENTRIES and FSG_HS_FUNCTION_PRE_EP_ENTRIES - * macros are not defined. - * - * When FSG_NO_DEVICE_STRINGS is defined FSG_STRING_MANUFACTURER, - * FSG_STRING_PRODUCT, FSG_STRING_SERIAL and FSG_STRING_CONFIG are not - * defined (as well as corresponding entries in string tables are - * missing) and FSG_STRING_INTERFACE has value of zero. - * - * When FSG_NO_OTG is defined fsg_otg_desc won't be defined. - */ - -/* - * When FSG_BUFFHD_STATIC_BUFFER is defined when this file is included - * the fsg_buffhd structure's buf field will be an array of FSG_BUFLEN - * characters rather then a pointer to void. - */ - - -/* #include <asm/unaligned.h> */ - - -/* - * Thanks to NetChip Technologies for donating this product ID. - * - * DO NOT REUSE THESE IDs with any other driver!! Ever!! - * Instead: allocate your own, using normal USB-IF procedures. - */ -#define FSG_VENDOR_ID 0x0525 /* NetChip */ -#define FSG_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ - -/*-------------------------------------------------------------------------*/ - -#ifndef DEBUG -#undef VERBOSE_DEBUG -#undef DUMP_MSGS -#endif /* !DEBUG */ - -#ifdef VERBOSE_DEBUG -#define VLDBG LDBG -#else -#define VLDBG(lun, fmt, args...) do { } while (0) -#endif /* VERBOSE_DEBUG */ - -/* -#define LDBG(lun, fmt, args...) dev_dbg (&(lun)->dev, fmt, ## args) -#define LERROR(lun, fmt, args...) dev_err (&(lun)->dev, fmt, ## args) -#define LWARN(lun, fmt, args...) dev_warn(&(lun)->dev, fmt, ## args) -#define LINFO(lun, fmt, args...) dev_info(&(lun)->dev, fmt, ## args) -*/ - -#define LDBG(lun, fmt, args...) do { } while (0) -#define LERROR(lun, fmt, args...) do { } while (0) -#define LWARN(lun, fmt, args...) do { } while (0) -#define LINFO(lun, fmt, args...) do { } while (0) - -/* - * Keep those macros in sync with those in - * include/linux/usb/composite.h or else GCC will complain. If they - * are identical (the same names of arguments, white spaces in the - * same places) GCC will allow redefinition otherwise (even if some - * white space is removed or added) warning will be issued. - * - * Those macros are needed here because File Storage Gadget does not - * include the composite.h header. For composite gadgets those macros - * are redundant since composite.h is included any way. - * - * One could check whether those macros are already defined (which - * would indicate composite.h had been included) or not (which would - * indicate we were in FSG) but this is not done because a warning is - * desired if definitions here differ from the ones in composite.h. - * - * We want the definitions to match and be the same in File Storage - * Gadget as well as Mass Storage Function (and so composite gadgets - * using MSF). If someone changes them in composite.h it will produce - * a warning in this file when building MSF. - */ - -#define DBG(d, fmt, args...) debug(fmt , ## args) -#define VDBG(d, fmt, args...) debug(fmt , ## args) -/* #define ERROR(d, fmt, args...) printf(fmt , ## args) */ -/* #define WARNING(d, fmt, args...) printf(fmt , ## args) */ -/* #define INFO(d, fmt, args...) printf(fmt , ## args) */ - -/* #define DBG(d, fmt, args...) do { } while (0) */ -/* #define VDBG(d, fmt, args...) do { } while (0) */ -#define ERROR(d, fmt, args...) do { } while (0) -#define WARNING(d, fmt, args...) do { } while (0) -#define INFO(d, fmt, args...) do { } while (0) - -#ifdef DUMP_MSGS - -/* dump_msg(fsg, const char * label, const u8 * buf, unsigned length); */ -# define dump_msg(fsg, label, buf, length) do { \ - if (length < 512) { \ - DBG(fsg, "%s, length %u:\n", label, length); \ - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, \ - 16, 1, buf, length, 0); \ - } \ -} while (0) - -# define dump_cdb(fsg) do { } while (0) - -#else - -# define dump_msg(fsg, /* const char * */ label, \ - /* const u8 * */ buf, /* unsigned */ length) do { } while (0) - -# ifdef VERBOSE_DEBUG - -# define dump_cdb(fsg) \ - print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE, \ - 16, 1, (fsg)->cmnd, (fsg)->cmnd_size, 0) \ - -# else - -# define dump_cdb(fsg) do { } while (0) - -# endif /* VERBOSE_DEBUG */ - -#endif /* DUMP_MSGS */ - -/*-------------------------------------------------------------------------*/ - -/* SCSI device types */ -#define TYPE_DISK 0x00 -#define TYPE_CDROM 0x05 - -/* USB protocol value = the transport method */ -#define USB_PR_CBI 0x00 /* Control/Bulk/Interrupt */ -#define USB_PR_CB 0x01 /* Control/Bulk w/o interrupt */ -#define USB_PR_BULK 0x50 /* Bulk-only */ - -/* USB subclass value = the protocol encapsulation */ -#define USB_SC_RBC 0x01 /* Reduced Block Commands (flash) */ -#define USB_SC_8020 0x02 /* SFF-8020i, MMC-2, ATAPI (CD-ROM) */ -#define USB_SC_QIC 0x03 /* QIC-157 (tape) */ -#define USB_SC_UFI 0x04 /* UFI (floppy) */ -#define USB_SC_8070 0x05 /* SFF-8070i (removable) */ -#define USB_SC_SCSI 0x06 /* Transparent SCSI */ - -/* Bulk-only data structures */ - -/* Command Block Wrapper */ -struct fsg_bulk_cb_wrap { - __le32 Signature; /* Contains 'USBC' */ - u32 Tag; /* Unique per command id */ - __le32 DataTransferLength; /* Size of the data */ - u8 Flags; /* Direction in bit 7 */ - u8 Lun; /* LUN (normally 0) */ - u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */ - u8 CDB[16]; /* Command Data Block */ -}; - -#define USB_BULK_CB_WRAP_LEN 31 -#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */ -#define USB_BULK_IN_FLAG 0x80 - -/* Command Status Wrapper */ -struct bulk_cs_wrap { - __le32 Signature; /* Should = 'USBS' */ - u32 Tag; /* Same as original command */ - __le32 Residue; /* Amount not transferred */ - u8 Status; /* See below */ -}; - -#define USB_BULK_CS_WRAP_LEN 13 -#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */ -#define USB_STATUS_PASS 0 -#define USB_STATUS_FAIL 1 -#define USB_STATUS_PHASE_ERROR 2 - -/* Bulk-only class specific requests */ -#define USB_BULK_RESET_REQUEST 0xff -#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe - -/* CBI Interrupt data structure */ -struct interrupt_data { - u8 bType; - u8 bValue; -}; - -#define CBI_INTERRUPT_DATA_LEN 2 - -/* CBI Accept Device-Specific Command request */ -#define USB_CBI_ADSC_REQUEST 0x00 - -/* Length of a SCSI Command Data Block */ -#define MAX_COMMAND_SIZE 16 - -/* SCSI commands that we recognize */ -#define SC_FORMAT_UNIT 0x04 -#define SC_INQUIRY 0x12 -#define SC_MODE_SELECT_6 0x15 -#define SC_MODE_SELECT_10 0x55 -#define SC_MODE_SENSE_6 0x1a -#define SC_MODE_SENSE_10 0x5a -#define SC_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e -#define SC_READ_6 0x08 -#define SC_READ_10 0x28 -#define SC_READ_12 0xa8 -#define SC_READ_CAPACITY 0x25 -#define SC_READ_FORMAT_CAPACITIES 0x23 -#define SC_READ_HEADER 0x44 -#define SC_READ_TOC 0x43 -#define SC_RELEASE 0x17 -#define SC_REQUEST_SENSE 0x03 -#define SC_RESERVE 0x16 -#define SC_SEND_DIAGNOSTIC 0x1d -#define SC_START_STOP_UNIT 0x1b -#define SC_SYNCHRONIZE_CACHE 0x35 -#define SC_TEST_UNIT_READY 0x00 -#define SC_VERIFY 0x2f -#define SC_WRITE_6 0x0a -#define SC_WRITE_10 0x2a -#define SC_WRITE_12 0xaa - -/* SCSI Sense Key/Additional Sense Code/ASC Qualifier values */ -#define SS_NO_SENSE 0 -#define SS_COMMUNICATION_FAILURE 0x040800 -#define SS_INVALID_COMMAND 0x052000 -#define SS_INVALID_FIELD_IN_CDB 0x052400 -#define SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x052100 -#define SS_LOGICAL_UNIT_NOT_SUPPORTED 0x052500 -#define SS_MEDIUM_NOT_PRESENT 0x023a00 -#define SS_MEDIUM_REMOVAL_PREVENTED 0x055302 -#define SS_NOT_READY_TO_READY_TRANSITION 0x062800 -#define SS_RESET_OCCURRED 0x062900 -#define SS_SAVING_PARAMETERS_NOT_SUPPORTED 0x053900 -#define SS_UNRECOVERED_READ_ERROR 0x031100 -#define SS_WRITE_ERROR 0x030c02 -#define SS_WRITE_PROTECTED 0x072700 - -#define SK(x) ((u8) ((x) >> 16)) /* Sense Key byte, etc. */ -#define ASC(x) ((u8) ((x) >> 8)) -#define ASCQ(x) ((u8) (x)) - -struct device_attribute { int i; }; -struct rw_semaphore { int i; }; -#define down_write(...) do { } while (0) -#define up_write(...) do { } while (0) -#define down_read(...) do { } while (0) -#define up_read(...) do { } while (0) -#define ETOOSMALL 525 - -#include <usb_mass_storage.h> - -/*-------------------------------------------------------------------------*/ - -struct fsg_lun { - loff_t file_length; - loff_t num_sectors; - - unsigned int initially_ro:1; - unsigned int ro:1; - unsigned int removable:1; - unsigned int cdrom:1; - unsigned int prevent_medium_removal:1; - unsigned int registered:1; - unsigned int info_valid:1; - unsigned int nofua:1; - - u32 sense_data; - u32 sense_data_info; - u32 unit_attention_data; - - struct device dev; -}; - -#define fsg_lun_is_open(curlun) ((curlun)->filp != NULL) -#if 0 -static struct fsg_lun *fsg_lun_from_dev(struct device *dev) -{ - return container_of(dev, struct fsg_lun, dev); -} -#endif - -/* Big enough to hold our biggest descriptor */ -#define EP0_BUFSIZE 256 -#define DELAYED_STATUS (EP0_BUFSIZE + 999) /* An impossibly large value */ - -/* Number of buffers we will use. 2 is enough for double-buffering */ -#ifndef CONFIG_CI_UDC -#define FSG_NUM_BUFFERS 2 -#else -#define FSG_NUM_BUFFERS 1 /* ci_udc only allows 1 req per ep at present */ -#endif - -/* Default size of buffer length. */ -#define FSG_BUFLEN ((u32)16384) - -/* Maximal number of LUNs supported in mass storage function */ -#define FSG_MAX_LUNS 8 - -enum fsg_buffer_state { - BUF_STATE_EMPTY = 0, - BUF_STATE_FULL, - BUF_STATE_BUSY -}; - -struct fsg_buffhd { -#ifdef FSG_BUFFHD_STATIC_BUFFER - char buf[FSG_BUFLEN]; -#else - void *buf; -#endif - enum fsg_buffer_state state; - struct fsg_buffhd *next; - - /* - * The NetChip 2280 is faster, and handles some protocol faults - * better, if we don't submit any short bulk-out read requests. - * So we will record the intended request length here. - */ - unsigned int bulk_out_intended_length; - - struct usb_request *inreq; - int inreq_busy; - struct usb_request *outreq; - int outreq_busy; -}; - -enum fsg_state { - /* This one isn't used anywhere */ - FSG_STATE_COMMAND_PHASE = -10, - FSG_STATE_DATA_PHASE, - FSG_STATE_STATUS_PHASE, - - FSG_STATE_IDLE = 0, - FSG_STATE_ABORT_BULK_OUT, - FSG_STATE_RESET, - FSG_STATE_INTERFACE_CHANGE, - FSG_STATE_CONFIG_CHANGE, - FSG_STATE_DISCONNECT, - FSG_STATE_EXIT, - FSG_STATE_TERMINATED -}; - -enum data_direction { - DATA_DIR_UNKNOWN = 0, - DATA_DIR_FROM_HOST, - DATA_DIR_TO_HOST, - DATA_DIR_NONE -}; - -/*-------------------------------------------------------------------------*/ - -static inline u32 get_unaligned_be24(u8 *buf) -{ - return 0xffffff & (u32) get_unaligned_be32(buf - 1); -} - -/*-------------------------------------------------------------------------*/ - -enum { -#ifndef FSG_NO_DEVICE_STRINGS - FSG_STRING_MANUFACTURER = 1, - FSG_STRING_PRODUCT, - FSG_STRING_SERIAL, - FSG_STRING_CONFIG, -#endif - FSG_STRING_INTERFACE -}; - -#ifndef FSG_NO_OTG -static struct usb_otg_descriptor -fsg_otg_desc = { - .bLength = sizeof fsg_otg_desc, - .bDescriptorType = USB_DT_OTG, - - .bmAttributes = USB_OTG_SRP, -}; -#endif - -/* There is only one interface. */ - -static struct usb_interface_descriptor -fsg_intf_desc = { - .bLength = sizeof fsg_intf_desc, - .bDescriptorType = USB_DT_INTERFACE, - - .bNumEndpoints = 2, /* Adjusted during fsg_bind() */ - .bInterfaceClass = USB_CLASS_MASS_STORAGE, - .bInterfaceSubClass = USB_SC_SCSI, /* Adjusted during fsg_bind() */ - .bInterfaceProtocol = USB_PR_BULK, /* Adjusted during fsg_bind() */ - .iInterface = FSG_STRING_INTERFACE, -}; - -/* - * Three full-speed endpoint descriptors: bulk-in, bulk-out, and - * interrupt-in. - */ - -static struct usb_endpoint_descriptor -fsg_fs_bulk_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - /* wMaxPacketSize set by autoconfiguration */ -}; - -static struct usb_endpoint_descriptor -fsg_fs_bulk_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_BULK, - /* wMaxPacketSize set by autoconfiguration */ -}; - -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_fs_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 32, /* frames -> 32 ms */ -}; - -#ifndef FSG_NO_OTG -# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_FS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif - -static struct usb_descriptor_header *fsg_fs_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif - (struct usb_descriptor_header *) &fsg_intf_desc, - (struct usb_descriptor_header *) &fsg_fs_bulk_in_desc, - (struct usb_descriptor_header *) &fsg_fs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_fs_intr_in_desc, -#endif - NULL, -}; - -/* - * USB 2.0 devices need to expose both high speed and full speed - * descriptors, unless they only run at full speed. - * - * That means alternate endpoint descriptors (bigger packets) - * and a "device qualifier" ... plus more construction options - * for the configuration descriptor. - */ -static struct usb_endpoint_descriptor -fsg_hs_bulk_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_bulk_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), -}; - -static struct usb_endpoint_descriptor -fsg_hs_bulk_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_bulk_out_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_BULK, - .wMaxPacketSize = cpu_to_le16(512), - .bInterval = 1, /* NAK every 1 uframe */ -}; - -#ifndef FSG_NO_INTR_EP - -static struct usb_endpoint_descriptor -fsg_hs_intr_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - /* bEndpointAddress copied from fs_intr_in_desc during fsg_bind() */ - .bmAttributes = USB_ENDPOINT_XFER_INT, - .wMaxPacketSize = cpu_to_le16(2), - .bInterval = 9, /* 2**(9-1) = 256 uframes -> 32 ms */ -}; - -#ifndef FSG_NO_OTG -# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 2 -#else -# define FSG_HS_FUNCTION_PRE_EP_ENTRIES 1 -#endif - -#endif - -static struct usb_descriptor_header *fsg_hs_function[] = { -#ifndef FSG_NO_OTG - (struct usb_descriptor_header *) &fsg_otg_desc, -#endif - (struct usb_descriptor_header *) &fsg_intf_desc, - (struct usb_descriptor_header *) &fsg_hs_bulk_in_desc, - (struct usb_descriptor_header *) &fsg_hs_bulk_out_desc, -#ifndef FSG_NO_INTR_EP - (struct usb_descriptor_header *) &fsg_hs_intr_in_desc, -#endif - NULL, -}; - -/* Maxpacket and other transfer characteristics vary by speed. */ -static struct usb_endpoint_descriptor * -fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs, - struct usb_endpoint_descriptor *hs) -{ - if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) - return hs; - return fs; -} - -/* Static strings, in UTF-8 (for simplicity we use only ASCII characters) */ -static struct usb_string fsg_strings[] = { -#ifndef FSG_NO_DEVICE_STRINGS - {FSG_STRING_MANUFACTURER, fsg_string_manufacturer}, - {FSG_STRING_PRODUCT, fsg_string_product}, - {FSG_STRING_SERIAL, fsg_string_serial}, - {FSG_STRING_CONFIG, fsg_string_config}, -#endif - {FSG_STRING_INTERFACE, fsg_string_interface}, - {} -}; - -static struct usb_gadget_strings fsg_stringtab = { - .language = 0x0409, /* en-us */ - .strings = fsg_strings, -}; - -/*-------------------------------------------------------------------------*/ - -/* - * If the next two routines are called while the gadget is registered, - * the caller must own fsg->filesem for writing. - */ - -static int fsg_lun_open(struct fsg_lun *curlun, const char *filename) -{ - int ro; - - /* R/W if we can, R/O if we must */ - ro = curlun->initially_ro; - - curlun->ro = ro; - curlun->file_length = ums->num_sectors << 9; - curlun->num_sectors = ums->num_sectors; - debug("open backing file: %s\n", filename); - - return 0; -} - -static void fsg_lun_close(struct fsg_lun *curlun) -{ -} - -/*-------------------------------------------------------------------------*/ - -/* - * Sync the file data, don't bother with the metadata. - * This code was copied from fs/buffer.c:sys_fdatasync(). - */ -static int fsg_lun_fsync_sub(struct fsg_lun *curlun) -{ - return 0; -} - -static void store_cdrom_address(u8 *dest, int msf, u32 addr) -{ - if (msf) { - /* Convert to Minutes-Seconds-Frames */ - addr >>= 2; /* Convert to 2048-byte frames */ - addr += 2*75; /* Lead-in occupies 2 seconds */ - dest[3] = addr % 75; /* Frames */ - addr /= 75; - dest[2] = addr % 60; /* Seconds */ - addr /= 60; - dest[1] = addr; /* Minutes */ - dest[0] = 0; /* Reserved */ - } else { - /* Absolute sector */ - put_unaligned_be32(addr, dest); - } -} - -/*-------------------------------------------------------------------------*/ diff --git a/qemu/roms/u-boot/drivers/usb/gadget/usbstring.c b/qemu/roms/u-boot/drivers/usb/gadget/usbstring.c deleted file mode 100644 index 8c3ff64fe..000000000 --- a/qemu/roms/u-boot/drivers/usb/gadget/usbstring.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2003 David Brownell - * - * SPDX-License-Identifier: LGPL-2.1+ - * - * Ported to U-boot by: Thomas Smits <ts.smits@gmail.com> and - * Remy Bohmer <linux@bohmer.net> - */ - -#include <common.h> -#include <asm/errno.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> - -#include <asm/unaligned.h> - - -static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len) -{ - int count = 0; - u8 c; - u16 uchar; - - /* - * this insists on correct encodings, though not minimal ones. - * BUT it currently rejects legit 4-byte UTF-8 code points, - * which need surrogate pairs. (Unicode 3.1 can use them.) - */ - while (len != 0 && (c = (u8) *s++) != 0) { - if ((c & 0x80)) { - /* - * 2-byte sequence: - * 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx - */ - if ((c & 0xe0) == 0xc0) { - uchar = (c & 0x1f) << 6; - - c = (u8) *s++; - if ((c & 0xc0) != 0x80) - goto fail; - c &= 0x3f; - uchar |= c; - - /* - * 3-byte sequence (most CJKV characters): - * zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx - */ - } else if ((c & 0xf0) == 0xe0) { - uchar = (c & 0x0f) << 12; - - c = (u8) *s++; - if ((c & 0xc0) != 0x80) - goto fail; - c &= 0x3f; - uchar |= c << 6; - - c = (u8) *s++; - if ((c & 0xc0) != 0x80) - goto fail; - c &= 0x3f; - uchar |= c; - - /* no bogus surrogates */ - if (0xd800 <= uchar && uchar <= 0xdfff) - goto fail; - - /* - * 4-byte sequence (surrogate pairs, currently rare): - * 11101110wwwwzzzzyy + 110111yyyyxxxxxx - * = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx - * (uuuuu = wwww + 1) - * FIXME accept the surrogate code points (only) - */ - } else - goto fail; - } else - uchar = c; - put_unaligned_le16(uchar, cp++); - count++; - len--; - } - return count; -fail: - return -1; -} - - -/** - * usb_gadget_get_string - fill out a string descriptor - * @table: of c strings encoded using UTF-8 - * @id: string id, from low byte of wValue in get string descriptor - * @buf: at least 256 bytes - * - * Finds the UTF-8 string matching the ID, and converts it into a - * string descriptor in utf16-le. - * Returns length of descriptor (always even) or negative errno - * - * If your driver needs stings in multiple languages, you'll probably - * "switch (wIndex) { ... }" in your ep0 string descriptor logic, - * using this routine after choosing which set of UTF-8 strings to use. - * Note that US-ASCII is a strict subset of UTF-8; any string bytes with - * the eighth bit set will be multibyte UTF-8 characters, not ISO-8859/1 - * characters (which are also widely used in C strings). - */ -int -usb_gadget_get_string(struct usb_gadget_strings *table, int id, u8 *buf) -{ - struct usb_string *s; - int len; - - if (!table) - return -EINVAL; - - /* descriptor 0 has the language id */ - if (id == 0) { - buf[0] = 4; - buf[1] = USB_DT_STRING; - buf[2] = (u8) table->language; - buf[3] = (u8) (table->language >> 8); - return 4; - } - for (s = table->strings; s && s->s; s++) - if (s->id == id) - break; - - /* unrecognized: stall. */ - if (!s || !s->s) - return -EINVAL; - - /* string descriptors have length, tag, then UTF16-LE text */ - len = min((size_t) 126, strlen(s->s)); - memset(buf + 2, 0, 2 * len); /* zero all the bytes */ - len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len); - if (len < 0) - return -EINVAL; - buf[0] = (len + 1) * 2; - buf[1] = USB_DT_STRING; - return buf[0]; -} |