diff options
Diffstat (limited to 'drivers/usb')
252 files changed, 19458 insertions, 13463 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index 76316a33061b..a7773a3e02b1 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -133,6 +133,8 @@ source "drivers/usb/host/Kconfig" source "drivers/usb/musb/Kconfig" +source "drivers/usb/chipidea/Kconfig" + source "drivers/usb/renesas_usbhs/Kconfig" source "drivers/usb/class/Kconfig" @@ -177,6 +179,8 @@ source "drivers/usb/serial/Kconfig" source "drivers/usb/misc/Kconfig" +source "drivers/usb/phy/Kconfig" + source "drivers/usb/atm/Kconfig" source "drivers/usb/gadget/Kconfig" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index 53a7bc07dd8d..c691eea51537 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -46,12 +46,14 @@ obj-$(CONFIG_USB_MICROTEK) += image/ obj-$(CONFIG_USB_SERIAL) += serial/ obj-$(CONFIG_USB) += misc/ +obj-$(CONFIG_USB) += phy/ obj-$(CONFIG_EARLY_PRINTK_DBGP) += early/ obj-$(CONFIG_USB_ATM) += atm/ obj-$(CONFIG_USB_SPEEDTOUCH) += atm/ obj-$(CONFIG_USB_MUSB_HDRC) += musb/ +obj-$(CONFIG_USB_CHIPIDEA) += chipidea/ obj-$(CONFIG_USB_RENESAS_USBHS) += renesas_usbhs/ obj-$(CONFIG_USB_GADGET) += gadget/ diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 98b89fe19867..b7eb86ad6bf2 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -674,7 +674,7 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, } ret = offd; - dbg("cm %#x", cm); + usb_dbg(instance->usbatm, "cm %#x\n", cm); fail: mutex_unlock(&instance->cm_serialize); err: @@ -733,7 +733,7 @@ static int cxacru_card_status(struct cxacru_data *instance) { int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0); if (ret < 0) { /* firmware not loaded */ - dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret); + usb_dbg(instance->usbatm, "cxacru_adsl_start: CARD_GET_STATUS returned %d\n", ret); return ret; } return 0; @@ -758,7 +758,7 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance, int ret; int start_polling = 1; - dbg("cxacru_atm_start"); + dev_dbg(&intf->dev, "%s\n", __func__); /* Read MAC address */ ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0, @@ -962,13 +962,13 @@ static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw, ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD), buf, offb, NULL, CMD_TIMEOUT); if (ret < 0) { - dbg("sending fw %#x failed", fw); + dev_dbg(&usb_dev->dev, "sending fw %#x failed\n", fw); goto cleanup; } offb = 0; } } while (offd < size); - dbg("sent fw %#x", fw); + dev_dbg(&usb_dev->dev, "sent fw %#x\n", fw); ret = 0; @@ -988,7 +988,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance, usb_dev->descriptor.idProduct }; __le32 val; - dbg("cxacru_upload_firmware"); + usb_dbg(usbatm, "%s\n", __func__); /* FirmwarePllFClkValue */ val = cpu_to_le32(instance->modem_type->pll_f_clk); @@ -1074,7 +1074,7 @@ static int cxacru_find_firmware(struct cxacru_data *instance, char buf[16]; sprintf(buf, "cxacru-%s.bin", phase); - dbg("cxacru_find_firmware: looking for %s", buf); + usb_dbg(usbatm, "cxacru_find_firmware: looking for %s\n", buf); if (request_firmware(fw_p, buf, dev)) { usb_dbg(usbatm, "no stage %s firmware found\n", phase); @@ -1115,9 +1115,9 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance, ret = cxacru_card_status(instance); if (ret) - dbg("modem initialisation failed"); + usb_dbg(usbatm_instance, "modem initialisation failed\n"); else - dbg("done setting up the modem"); + usb_dbg(usbatm_instance, "done setting up the modem\n"); return ret; } @@ -1133,7 +1133,7 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, /* instance init */ instance = kzalloc(sizeof(*instance), GFP_KERNEL); if (!instance) { - dbg("cxacru_bind: no memory for instance data"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for instance data\n"); return -ENOMEM; } @@ -1149,31 +1149,31 @@ static int cxacru_bind(struct usbatm_data *usbatm_instance, instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL); if (!instance->rcv_buf) { - dbg("cxacru_bind: no memory for rcv_buf"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_buf\n"); ret = -ENOMEM; goto fail; } instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL); if (!instance->snd_buf) { - dbg("cxacru_bind: no memory for snd_buf"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_buf\n"); ret = -ENOMEM; goto fail; } instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL); if (!instance->rcv_urb) { - dbg("cxacru_bind: no memory for rcv_urb"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for rcv_urb\n"); ret = -ENOMEM; goto fail; } instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL); if (!instance->snd_urb) { - dbg("cxacru_bind: no memory for snd_urb"); + usb_dbg(usbatm_instance, "cxacru_bind: no memory for snd_urb\n"); ret = -ENOMEM; goto fail; } if (!cmd_ep) { - dbg("cxacru_bind: no command endpoint"); + usb_dbg(usbatm_instance, "cxacru_bind: no command endpoint\n"); ret = -ENODEV; goto fail; } @@ -1227,10 +1227,10 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance, struct cxacru_data *instance = usbatm_instance->driver_data; int is_polling = 1; - dbg("cxacru_unbind entered"); + usb_dbg(usbatm_instance, "cxacru_unbind entered\n"); if (!instance) { - dbg("cxacru_unbind: NULL instance!"); + usb_dbg(usbatm_instance, "cxacru_unbind: NULL instance!\n"); return; } diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 98dd9e49b684..975e9c6691d6 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -170,7 +170,7 @@ static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int sta "%sabling SW buffering: usb_control_msg returned %d\n", state ? "En" : "Dis", ret); else - dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis"); + usb_dbg(usbatm, "speedtch_set_swbuff: %sbled SW buffering\n", state ? "En" : "Dis"); } static void speedtch_test_sequence(struct speedtch_instance_data *instance) diff --git a/drivers/usb/atm/ueagle-atm.c b/drivers/usb/atm/ueagle-atm.c index 01ea5d7421d4..d7e422dc0ef7 100644 --- a/drivers/usb/atm/ueagle-atm.c +++ b/drivers/usb/atm/ueagle-atm.c @@ -1357,10 +1357,8 @@ static int uea_stat_e1(struct uea_softc *sc) /* release the dsp firmware as it is not needed until * the next failure */ - if (sc->dsp_firm) { - release_firmware(sc->dsp_firm); - sc->dsp_firm = NULL; - } + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; } /* always update it as atm layer could not be init when we switch to @@ -1496,10 +1494,8 @@ static int uea_stat_e4(struct uea_softc *sc) /* release the dsp firmware as it is not needed until * the next failure */ - if (sc->dsp_firm) { - release_firmware(sc->dsp_firm); - sc->dsp_firm = NULL; - } + release_firmware(sc->dsp_firm); + sc->dsp_firm = NULL; } /* always update it as atm layer could not be init when we switch to @@ -2240,8 +2236,7 @@ static void uea_stop(struct uea_softc *sc) /* flush the work item, when no one can schedule it */ flush_work_sync(&sc->task); - if (sc->dsp_firm) - release_firmware(sc->dsp_firm); + release_firmware(sc->dsp_firm); uea_leaves(INS_TO_USBDEV(sc)); } diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index d3448ca110ce..ee62b3576f94 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -86,7 +86,7 @@ #ifdef VERBOSE_DEBUG static int usbatm_print_packet(const unsigned char *data, int len); #define PACKETDEBUG(arg...) usbatm_print_packet(arg) -#define vdbg(arg...) dbg(arg) +#define vdbg(arg...) dev_dbg(arg) #else #define PACKETDEBUG(arg...) #define vdbg(arg...) @@ -714,7 +714,7 @@ static void usbatm_destroy_instance(struct kref *kref) { struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount); - dbg("%s", __func__); + usb_dbg(instance, "%s\n", __func__); tasklet_kill(&instance->rx_channel.tasklet); tasklet_kill(&instance->tx_channel.tasklet); @@ -724,14 +724,14 @@ static void usbatm_destroy_instance(struct kref *kref) static void usbatm_get_instance(struct usbatm_data *instance) { - dbg("%s", __func__); + usb_dbg(instance, "%s\n", __func__); kref_get(&instance->refcount); } static void usbatm_put_instance(struct usbatm_data *instance) { - dbg("%s", __func__); + usb_dbg(instance, "%s\n", __func__); kref_put(&instance->refcount, usbatm_destroy_instance); } @@ -745,11 +745,10 @@ static void usbatm_atm_dev_close(struct atm_dev *atm_dev) { struct usbatm_data *instance = atm_dev->dev_data; - dbg("%s", __func__); - if (!instance) return; + usb_dbg(instance, "%s\n", __func__); atm_dev->dev_data = NULL; /* catch bugs */ usbatm_put_instance(instance); /* taken in usbatm_atm_init */ } @@ -759,10 +758,8 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *pag struct usbatm_data *instance = atm_dev->dev_data; int left = *pos; - if (!instance) { - dbg("%s: NULL instance!", __func__); + if (!instance) return -ENODEV; - } if (!left--) return sprintf(page, "%s\n", instance->description); @@ -804,10 +801,8 @@ static int usbatm_atm_open(struct atm_vcc *vcc) int vci = vcc->vci; short vpi = vcc->vpi; - if (!instance) { - dbg("%s: NULL data!", __func__); + if (!instance) return -ENODEV; - } atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci); @@ -884,10 +879,8 @@ static void usbatm_atm_close(struct atm_vcc *vcc) struct usbatm_data *instance = vcc->dev->dev_data; struct usbatm_vcc_data *vcc_data = vcc->dev_data; - if (!instance || !vcc_data) { - dbg("%s: NULL data!", __func__); + if (!instance || !vcc_data) return; - } atm_dbg(instance, "%s entered\n", __func__); @@ -929,10 +922,8 @@ static int usbatm_atm_ioctl(struct atm_dev *atm_dev, unsigned int cmd, { struct usbatm_data *instance = atm_dev->dev_data; - if (!instance || instance->disconnected) { - dbg("%s: %s!", __func__, instance ? "disconnected" : "NULL instance"); + if (!instance || instance->disconnected) return -ENODEV; - } switch (cmd) { case ATM_QUERYLOOP: @@ -1336,8 +1327,6 @@ EXPORT_SYMBOL_GPL(usbatm_usb_disconnect); static int __init usbatm_usb_init(void) { - dbg("%s: driver version %s", __func__, DRIVER_VERSION); - if (sizeof(struct usbatm_control) > FIELD_SIZEOF(struct sk_buff, cb)) { printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name); return -EIO; @@ -1357,7 +1346,6 @@ module_init(usbatm_usb_init); static void __exit usbatm_usb_exit(void) { - dbg("%s", __func__); } module_exit(usbatm_usb_exit); diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c index 48ee0c5ff282..14ec9f0c5924 100644 --- a/drivers/usb/atm/xusbatm.c +++ b/drivers/usb/atm/xusbatm.c @@ -187,8 +187,6 @@ static int __init xusbatm_init(void) { int i; - dbg("xusbatm_init"); - if (!num_vendor || num_vendor != num_product || num_vendor != num_rx_endpoint || @@ -221,8 +219,6 @@ module_init(xusbatm_init); static void __exit xusbatm_exit(void) { - dbg("xusbatm_exit entered"); - usb_deregister(&xusbatm_usb_driver); } module_exit(xusbatm_exit); diff --git a/drivers/usb/chipidea/Kconfig b/drivers/usb/chipidea/Kconfig new file mode 100644 index 000000000000..fd36dc8b889b --- /dev/null +++ b/drivers/usb/chipidea/Kconfig @@ -0,0 +1,32 @@ +config USB_CHIPIDEA + tristate "ChipIdea Highspeed Dual Role Controller" + depends on USB + help + Say Y here if your system has a dual role high speed USB + controller based on ChipIdea silicon IP. Currently, only the + peripheral mode is supported. + + When compiled dynamically, the module will be called ci-hdrc.ko. + +if USB_CHIPIDEA + +config USB_CHIPIDEA_UDC + bool "ChipIdea device controller" + depends on USB_GADGET + select USB_GADGET_DUALSPEED + help + Say Y here to enable device controller functionality of the + ChipIdea driver. + +config USB_CHIPIDEA_HOST + bool "ChipIdea host controller" + help + Say Y here to enable host controller functionality of the + ChipIdea driver. + +config USB_CHIPIDEA_DEBUG + bool "ChipIdea driver debug" + help + Say Y here to enable debugging output of the ChipIdea driver. + +endif diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile new file mode 100644 index 000000000000..cc3493769724 --- /dev/null +++ b/drivers/usb/chipidea/Makefile @@ -0,0 +1,14 @@ +obj-$(CONFIG_USB_CHIPIDEA) += ci_hdrc.o + +ci_hdrc-y := core.o +ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC) += udc.o +ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST) += host.o +ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG) += debug.o + +ifneq ($(CONFIG_PCI),) + obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_pci.o +endif + +ifneq ($(CONFIG_ARCH_MSM),) + obj-$(CONFIG_USB_CHIPIDEA) += ci13xxx_msm.o +endif diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h new file mode 100644 index 000000000000..050de8562a04 --- /dev/null +++ b/drivers/usb/chipidea/bits.h @@ -0,0 +1,90 @@ +/* + * bits.h - register bits of the ChipIdea USB IP core + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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. + */ + +#ifndef __DRIVERS_USB_CHIPIDEA_BITS_H +#define __DRIVERS_USB_CHIPIDEA_BITS_H + +#include <linux/usb/ehci_def.h> + +/* HCCPARAMS */ +#define HCCPARAMS_LEN BIT(17) + +/* DCCPARAMS */ +#define DCCPARAMS_DEN (0x1F << 0) +#define DCCPARAMS_DC BIT(7) +#define DCCPARAMS_HC BIT(8) + +/* TESTMODE */ +#define TESTMODE_FORCE BIT(0) + +/* USBCMD */ +#define USBCMD_RS BIT(0) +#define USBCMD_RST BIT(1) +#define USBCMD_SUTW BIT(13) +#define USBCMD_ATDTW BIT(14) + +/* USBSTS & USBINTR */ +#define USBi_UI BIT(0) +#define USBi_UEI BIT(1) +#define USBi_PCI BIT(2) +#define USBi_URI BIT(6) +#define USBi_SLI BIT(8) + +/* DEVICEADDR */ +#define DEVICEADDR_USBADRA BIT(24) +#define DEVICEADDR_USBADR (0x7FUL << 25) + +/* PORTSC */ +#define PORTSC_FPR BIT(6) +#define PORTSC_SUSP BIT(7) +#define PORTSC_HSP BIT(9) +#define PORTSC_PTC (0x0FUL << 16) + +/* DEVLC */ +#define DEVLC_PSPD (0x03UL << 25) +#define DEVLC_PSPD_HS (0x02UL << 25) + +/* OTGSC */ +#define OTGSC_IDPU BIT(5) +#define OTGSC_ID BIT(8) +#define OTGSC_AVV BIT(9) +#define OTGSC_ASV BIT(10) +#define OTGSC_BSV BIT(11) +#define OTGSC_BSE BIT(12) +#define OTGSC_IDIS BIT(16) +#define OTGSC_AVVIS BIT(17) +#define OTGSC_ASVIS BIT(18) +#define OTGSC_BSVIS BIT(19) +#define OTGSC_BSEIS BIT(20) +#define OTGSC_IDIE BIT(24) +#define OTGSC_AVVIE BIT(25) +#define OTGSC_ASVIE BIT(26) +#define OTGSC_BSVIE BIT(27) +#define OTGSC_BSEIE BIT(28) + +/* USBMODE */ +#define USBMODE_CM (0x03UL << 0) +#define USBMODE_CM_DC (0x02UL << 0) +#define USBMODE_SLOM BIT(3) +#define USBMODE_CI_SDIS BIT(4) + +/* ENDPTCTRL */ +#define ENDPTCTRL_RXS BIT(0) +#define ENDPTCTRL_RXT (0x03UL << 2) +#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */ +#define ENDPTCTRL_RXE BIT(7) +#define ENDPTCTRL_TXS BIT(16) +#define ENDPTCTRL_TXT (0x03UL << 18) +#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */ +#define ENDPTCTRL_TXE BIT(23) + +#endif /* __DRIVERS_USB_CHIPIDEA_BITS_H */ diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h new file mode 100644 index 000000000000..50911f8490d4 --- /dev/null +++ b/drivers/usb/chipidea/ci.h @@ -0,0 +1,313 @@ +/* + * ci.h - common structures, functions, and macros of the ChipIdea driver + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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. + */ + +#ifndef __DRIVERS_USB_CHIPIDEA_CI_H +#define __DRIVERS_USB_CHIPIDEA_CI_H + +#include <linux/list.h> +#include <linux/irqreturn.h> +#include <linux/usb.h> +#include <linux/usb/gadget.h> + +/****************************************************************************** + * DEFINE + *****************************************************************************/ +#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */ +#define ENDPT_MAX 32 + +/****************************************************************************** + * STRUCTURES + *****************************************************************************/ +/** + * struct ci13xxx_ep - endpoint representation + * @ep: endpoint structure for gadget drivers + * @dir: endpoint direction (TX/RX) + * @num: endpoint number + * @type: endpoint type + * @name: string description of the endpoint + * @qh: queue head for this endpoint + * @wedge: is the endpoint wedged + * @udc: pointer to the controller + * @lock: pointer to controller's spinlock + * @td_pool: pointer to controller's TD pool + */ +struct ci13xxx_ep { + struct usb_ep ep; + u8 dir; + u8 num; + u8 type; + char name[16]; + struct { + struct list_head queue; + struct ci13xxx_qh *ptr; + dma_addr_t dma; + } qh; + int wedge; + + /* global resources */ + struct ci13xxx *udc; + spinlock_t *lock; + struct dma_pool *td_pool; +}; + +enum ci_role { + CI_ROLE_HOST = 0, + CI_ROLE_GADGET, + CI_ROLE_END, +}; + +/** + * struct ci_role_driver - host/gadget role driver + * start: start this role + * stop: stop this role + * irq: irq handler for this role + * name: role name string (host/gadget) + */ +struct ci_role_driver { + int (*start)(struct ci13xxx *); + void (*stop)(struct ci13xxx *); + irqreturn_t (*irq)(struct ci13xxx *); + const char *name; +}; + +/** + * struct hw_bank - hardware register mapping representation + * @lpm: set if the device is LPM capable + * @phys: physical address of the controller's registers + * @abs: absolute address of the beginning of register window + * @cap: capability registers + * @op: operational registers + * @size: size of the register window + * @regmap: register lookup table + */ +struct hw_bank { + unsigned lpm; + resource_size_t phys; + void __iomem *abs; + void __iomem *cap; + void __iomem *op; + size_t size; + void __iomem **regmap; +}; + +/** + * struct ci13xxx - chipidea device representation + * @dev: pointer to parent device + * @lock: access synchronization + * @hw_bank: hardware register mapping + * @irq: IRQ number + * @roles: array of supported roles for this controller + * @role: current role + * @is_otg: if the device is otg-capable + * @work: work for role changing + * @wq: workqueue thread + * @qh_pool: allocation pool for queue heads + * @td_pool: allocation pool for transfer descriptors + * @gadget: device side representation for peripheral controller + * @driver: gadget driver + * @hw_ep_max: total number of endpoints supported by hardware + * @ci13xxx_ep: array of endpoints + * @ep0_dir: ep0 direction + * @ep0out: pointer to ep0 OUT endpoint + * @ep0in: pointer to ep0 IN endpoint + * @status: ep0 status request + * @setaddr: if we should set the address on status completion + * @address: usb address received from the host + * @remote_wakeup: host-enabled remote wakeup + * @suspended: suspended by host + * @test_mode: the selected test mode + * @udc_driver: platform specific information supplied by parent device + * @vbus_active: is VBUS active + * @transceiver: pointer to USB PHY, if any + * @hcd: pointer to usb_hcd for ehci host driver + */ +struct ci13xxx { + struct device *dev; + spinlock_t lock; + struct hw_bank hw_bank; + int irq; + struct ci_role_driver *roles[CI_ROLE_END]; + enum ci_role role; + bool is_otg; + struct work_struct work; + struct workqueue_struct *wq; + + struct dma_pool *qh_pool; + struct dma_pool *td_pool; + + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + unsigned hw_ep_max; + struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; + u32 ep0_dir; + struct ci13xxx_ep *ep0out, *ep0in; + + struct usb_request *status; + bool setaddr; + u8 address; + u8 remote_wakeup; + u8 suspended; + u8 test_mode; + + struct ci13xxx_udc_driver *udc_driver; + int vbus_active; + struct usb_phy *transceiver; + struct usb_hcd *hcd; +}; + +static inline struct ci_role_driver *ci_role(struct ci13xxx *ci) +{ + BUG_ON(ci->role >= CI_ROLE_END || !ci->roles[ci->role]); + return ci->roles[ci->role]; +} + +static inline int ci_role_start(struct ci13xxx *ci, enum ci_role role) +{ + int ret; + + if (role >= CI_ROLE_END) + return -EINVAL; + + if (!ci->roles[role]) + return -ENXIO; + + ret = ci->roles[role]->start(ci); + if (!ret) + ci->role = role; + return ret; +} + +static inline void ci_role_stop(struct ci13xxx *ci) +{ + enum ci_role role = ci->role; + + if (role == CI_ROLE_END) + return; + + ci->role = CI_ROLE_END; + + ci->roles[role]->stop(ci); +} + +/****************************************************************************** + * REGISTERS + *****************************************************************************/ +/* register size */ +#define REG_BITS (32) + +/* register indices */ +enum ci13xxx_regs { + CAP_CAPLENGTH, + CAP_HCCPARAMS, + CAP_DCCPARAMS, + CAP_TESTMODE, + CAP_LAST = CAP_TESTMODE, + OP_USBCMD, + OP_USBSTS, + OP_USBINTR, + OP_DEVICEADDR, + OP_ENDPTLISTADDR, + OP_PORTSC, + OP_DEVLC, + OP_OTGSC, + OP_USBMODE, + OP_ENDPTSETUPSTAT, + OP_ENDPTPRIME, + OP_ENDPTFLUSH, + OP_ENDPTSTAT, + OP_ENDPTCOMPLETE, + OP_ENDPTCTRL, + /* endptctrl1..15 follow */ + OP_LAST = OP_ENDPTCTRL + ENDPT_MAX / 2, +}; + +/** + * ffs_nr: find first (least significant) bit set + * @x: the word to search + * + * This function returns bit number (instead of position) + */ +static inline int ffs_nr(u32 x) +{ + int n = ffs(x); + + return n ? n-1 : 32; +} + +/** + * hw_read: reads from a hw register + * @reg: register index + * @mask: bitfield mask + * + * This function returns register contents + */ +static inline u32 hw_read(struct ci13xxx *udc, enum ci13xxx_regs reg, u32 mask) +{ + return ioread32(udc->hw_bank.regmap[reg]) & mask; +} + +/** + * hw_write: writes to a hw register + * @reg: register index + * @mask: bitfield mask + * @data: new value + */ +static inline void hw_write(struct ci13xxx *udc, enum ci13xxx_regs reg, + u32 mask, u32 data) +{ + if (~mask) + data = (ioread32(udc->hw_bank.regmap[reg]) & ~mask) + | (data & mask); + + iowrite32(data, udc->hw_bank.regmap[reg]); +} + +/** + * hw_test_and_clear: tests & clears a hw register + * @reg: register index + * @mask: bitfield mask + * + * This function returns register contents + */ +static inline u32 hw_test_and_clear(struct ci13xxx *udc, enum ci13xxx_regs reg, + u32 mask) +{ + u32 val = ioread32(udc->hw_bank.regmap[reg]) & mask; + + iowrite32(val, udc->hw_bank.regmap[reg]); + return val; +} + +/** + * hw_test_and_write: tests & writes a hw register + * @reg: register index + * @mask: bitfield mask + * @data: new value + * + * This function returns register contents + */ +static inline u32 hw_test_and_write(struct ci13xxx *udc, enum ci13xxx_regs reg, + u32 mask, u32 data) +{ + u32 val = hw_read(udc, reg, ~0); + + hw_write(udc, reg, mask, data); + return (val & mask) >> ffs_nr(mask); +} + +int hw_device_reset(struct ci13xxx *ci, u32 mode); + +int hw_port_test_set(struct ci13xxx *ci, u8 mode); + +u8 hw_port_test_get(struct ci13xxx *ci); + +#endif /* __DRIVERS_USB_CHIPIDEA_CI_H */ diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/chipidea/ci13xxx_msm.c index d07e44c05e9b..958069ef95e3 100644 --- a/drivers/usb/gadget/ci13xxx_msm.c +++ b/drivers/usb/chipidea/ci13xxx_msm.c @@ -10,15 +10,12 @@ #include <linux/pm_runtime.h> #include <linux/usb/msm_hsusb_hw.h> #include <linux/usb/ulpi.h> +#include <linux/usb/gadget.h> +#include <linux/usb/chipidea.h> -#include "ci13xxx_udc.c" +#include "ci.h" -#define MSM_USB_BASE (udc->regs) - -static irqreturn_t msm_udc_irq(int irq, void *data) -{ - return udc_irq(); -} +#define MSM_USB_BASE (udc->hw_bank.abs) static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event) { @@ -60,53 +57,40 @@ static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = { static int ci13xxx_msm_probe(struct platform_device *pdev) { - struct resource *res; - void __iomem *regs; - int irq; + struct platform_device *plat_ci; int ret; dev_dbg(&pdev->dev, "ci13xxx_msm_probe\n"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "failed to get platform resource mem\n"); - return -ENXIO; - } - - regs = ioremap(res->start, resource_size(res)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); + plat_ci = platform_device_alloc("ci_hdrc", -1); + if (!plat_ci) { + dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n"); return -ENOMEM; } - ret = udc_probe(&ci13xxx_msm_udc_driver, &pdev->dev, regs); - if (ret < 0) { - dev_err(&pdev->dev, "udc_probe failed\n"); - goto iounmap; + ret = platform_device_add_resources(plat_ci, pdev->resource, + pdev->num_resources); + if (ret) { + dev_err(&pdev->dev, "can't add resources to platform device\n"); + goto put_platform; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "IRQ not found\n"); - ret = -ENXIO; - goto udc_remove; - } + ret = platform_device_add_data(plat_ci, &ci13xxx_msm_udc_driver, + sizeof(ci13xxx_msm_udc_driver)); + if (ret) + goto put_platform; - ret = request_irq(irq, msm_udc_irq, IRQF_SHARED, pdev->name, pdev); - if (ret < 0) { - dev_err(&pdev->dev, "request_irq failed\n"); - goto udc_remove; - } + ret = platform_device_add(plat_ci); + if (ret) + goto put_platform; pm_runtime_no_callbacks(&pdev->dev); pm_runtime_enable(&pdev->dev); return 0; -udc_remove: - udc_remove(); -iounmap: - iounmap(regs); +put_platform: + platform_device_put(plat_ci); return ret; } diff --git a/drivers/usb/gadget/ci13xxx_pci.c b/drivers/usb/chipidea/ci13xxx_pci.c index 883ab5e832d1..e3dab27f5c75 100644 --- a/drivers/usb/gadget/ci13xxx_pci.c +++ b/drivers/usb/chipidea/ci13xxx_pci.c @@ -10,10 +10,12 @@ * published by the Free Software Foundation. */ +#include <linux/platform_device.h> #include <linux/module.h> #include <linux/pci.h> - -#include "ci13xxx_udc.c" +#include <linux/interrupt.h> +#include <linux/usb/gadget.h> +#include <linux/usb/chipidea.h> /* driver name */ #define UDC_DRIVER_NAME "ci13xxx_pci" @@ -21,25 +23,20 @@ /****************************************************************************** * PCI block *****************************************************************************/ -/** - * ci13xxx_pci_irq: interrut handler - * @irq: irq number - * @pdev: USB Device Controller interrupt source - * - * This function returns IRQ_HANDLED if the IRQ has been handled - * This is an ISR don't trace, use attribute interface instead - */ -static irqreturn_t ci13xxx_pci_irq(int irq, void *pdev) -{ - if (irq == 0) { - dev_err(&((struct pci_dev *)pdev)->dev, "Invalid IRQ0 usage!"); - return IRQ_HANDLED; - } - return udc_irq(); -} +struct ci13xxx_udc_driver pci_driver = { + .name = UDC_DRIVER_NAME, + .capoffset = DEF_CAPOFFSET, +}; -static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = { +struct ci13xxx_udc_driver langwell_pci_driver = { .name = UDC_DRIVER_NAME, + .capoffset = 0, +}; + +struct ci13xxx_udc_driver penwell_pci_driver = { + .name = UDC_DRIVER_NAME, + .capoffset = 0, + .power_budget = 200, }; /** @@ -54,11 +51,15 @@ static struct ci13xxx_udc_driver ci13xxx_pci_udc_driver = { static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { - void __iomem *regs = NULL; - int retval = 0; - - if (id == NULL) - return -EINVAL; + struct ci13xxx_udc_driver *driver = (void *)id->driver_data; + struct platform_device *plat_ci; + struct resource res[3]; + int retval = 0, nres = 2; + + if (!driver) { + dev_err(&pdev->dev, "device doesn't provide driver data\n"); + return -ENODEV; + } retval = pci_enable_device(pdev); if (retval) @@ -70,41 +71,50 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev, goto disable_device; } - retval = pci_request_regions(pdev, UDC_DRIVER_NAME); - if (retval) - goto disable_device; + pci_set_power_state(pdev, PCI_D0); + pci_set_master(pdev); + pci_try_set_mwi(pdev); - /* BAR 0 holds all the registers */ - regs = pci_iomap(pdev, 0, 0); - if (!regs) { - dev_err(&pdev->dev, "Error mapping memory!"); - retval = -EFAULT; - goto release_regions; + plat_ci = platform_device_alloc("ci_hdrc", -1); + if (!plat_ci) { + dev_err(&pdev->dev, "can't allocate ci_hdrc platform device\n"); + retval = -ENOMEM; + goto disable_device; } - pci_set_drvdata(pdev, (__force void *)regs); - pci_set_master(pdev); - pci_try_set_mwi(pdev); + memset(res, 0, sizeof(res)); + res[0].start = pci_resource_start(pdev, 0); + res[0].end = pci_resource_end(pdev, 0); + res[0].flags = IORESOURCE_MEM; + res[1].start = pdev->irq; + res[1].flags = IORESOURCE_IRQ; + + retval = platform_device_add_resources(plat_ci, res, nres); + if (retval) { + dev_err(&pdev->dev, "can't add resources to platform device\n"); + goto put_platform; + } - retval = udc_probe(&ci13xxx_pci_udc_driver, &pdev->dev, regs); + retval = platform_device_add_data(plat_ci, driver, sizeof(*driver)); if (retval) - goto iounmap; + goto put_platform; + + dma_set_coherent_mask(&plat_ci->dev, pdev->dev.coherent_dma_mask); + plat_ci->dev.dma_mask = pdev->dev.dma_mask; + plat_ci->dev.dma_parms = pdev->dev.dma_parms; + plat_ci->dev.parent = &pdev->dev; - /* our device does not have MSI capability */ + pci_set_drvdata(pdev, plat_ci); - retval = request_irq(pdev->irq, ci13xxx_pci_irq, IRQF_SHARED, - UDC_DRIVER_NAME, pdev); + retval = platform_device_add(plat_ci); if (retval) - goto gadget_remove; + goto put_platform; return 0; - gadget_remove: - udc_remove(); - iounmap: - pci_iounmap(pdev, regs); - release_regions: - pci_release_regions(pdev); + put_platform: + pci_set_drvdata(pdev, NULL); + platform_device_put(plat_ci); disable_device: pci_disable_device(pdev); done: @@ -121,10 +131,10 @@ static int __devinit ci13xxx_pci_probe(struct pci_dev *pdev, */ static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev) { - free_irq(pdev->irq, pdev); - udc_remove(); - pci_iounmap(pdev, (__force void __iomem *)pci_get_drvdata(pdev)); - pci_release_regions(pdev); + struct platform_device *plat_ci = pci_get_drvdata(pdev); + + platform_device_unregister(plat_ci); + pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); } @@ -135,8 +145,22 @@ static void __devexit ci13xxx_pci_remove(struct pci_dev *pdev) * Check "pci.h" for details */ static DEFINE_PCI_DEVICE_TABLE(ci13xxx_pci_id_table) = { - { PCI_DEVICE(0x153F, 0x1004) }, - { PCI_DEVICE(0x153F, 0x1006) }, + { + PCI_DEVICE(0x153F, 0x1004), + .driver_data = (kernel_ulong_t)&pci_driver, + }, + { + PCI_DEVICE(0x153F, 0x1006), + .driver_data = (kernel_ulong_t)&pci_driver, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811), + .driver_data = (kernel_ulong_t)&langwell_pci_driver, + }, + { + PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829), + .driver_data = (kernel_ulong_t)&penwell_pci_driver, + }, { 0, 0, 0, 0, 0, 0, 0 /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(pci, ci13xxx_pci_id_table); @@ -148,27 +172,7 @@ static struct pci_driver ci13xxx_pci_driver = { .remove = __devexit_p(ci13xxx_pci_remove), }; -/** - * ci13xxx_pci_init: module init - * - * Driver load - */ -static int __init ci13xxx_pci_init(void) -{ - return pci_register_driver(&ci13xxx_pci_driver); -} -module_init(ci13xxx_pci_init); - -/** - * ci13xxx_pci_exit: module exit - * - * Driver unload - */ -static void __exit ci13xxx_pci_exit(void) -{ - pci_unregister_driver(&ci13xxx_pci_driver); -} -module_exit(ci13xxx_pci_exit); +module_pci_driver(ci13xxx_pci_driver); MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>"); MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c new file mode 100644 index 000000000000..15e03b308f8a --- /dev/null +++ b/drivers/usb/chipidea/core.c @@ -0,0 +1,474 @@ +/* + * core.c - ChipIdea USB IP core family device controller + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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. + */ + +/* + * Description: ChipIdea USB IP core family device controller + * + * This driver is composed of several blocks: + * - HW: hardware interface + * - DBG: debug facilities (optional) + * - UTIL: utilities + * - ISR: interrupts handling + * - ENDPT: endpoint operations (Gadget API) + * - GADGET: gadget operations (Gadget API) + * - BUS: bus glue code, bus abstraction layer + * + * Compile Options + * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities + * - STALL_IN: non-empty bulk-in pipes cannot be halted + * if defined mass storage compliance succeeds but with warnings + * => case 4: Hi > Dn + * => case 5: Hi > Di + * => case 8: Hi <> Do + * if undefined usbtest 13 fails + * - TRACE: enable function tracing (depends on DEBUG) + * + * Main Features + * - Chapter 9 & Mass Storage Compliance with Gadget File Storage + * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined) + * - Normal & LPM support + * + * USBTEST Report + * - OK: 0-12, 13 (STALL_IN defined) & 14 + * - Not Supported: 15 & 16 (ISO) + * + * TODO List + * - OTG + * - Isochronous & Interrupt Traffic + * - Handle requests which spawns into several TDs + * - GET_STATUS(device) - always reports 0 + * - Gadget API (majority of optional features) + * - Suspend & Remote Wakeup + */ +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dmapool.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> +#include <linux/usb/chipidea.h> + +#include "ci.h" +#include "udc.h" +#include "bits.h" +#include "host.h" +#include "debug.h" + +/* Controller register map */ +static uintptr_t ci_regs_nolpm[] = { + [CAP_CAPLENGTH] = 0x000UL, + [CAP_HCCPARAMS] = 0x008UL, + [CAP_DCCPARAMS] = 0x024UL, + [CAP_TESTMODE] = 0x038UL, + [OP_USBCMD] = 0x000UL, + [OP_USBSTS] = 0x004UL, + [OP_USBINTR] = 0x008UL, + [OP_DEVICEADDR] = 0x014UL, + [OP_ENDPTLISTADDR] = 0x018UL, + [OP_PORTSC] = 0x044UL, + [OP_DEVLC] = 0x084UL, + [OP_OTGSC] = 0x064UL, + [OP_USBMODE] = 0x068UL, + [OP_ENDPTSETUPSTAT] = 0x06CUL, + [OP_ENDPTPRIME] = 0x070UL, + [OP_ENDPTFLUSH] = 0x074UL, + [OP_ENDPTSTAT] = 0x078UL, + [OP_ENDPTCOMPLETE] = 0x07CUL, + [OP_ENDPTCTRL] = 0x080UL, +}; + +static uintptr_t ci_regs_lpm[] = { + [CAP_CAPLENGTH] = 0x000UL, + [CAP_HCCPARAMS] = 0x008UL, + [CAP_DCCPARAMS] = 0x024UL, + [CAP_TESTMODE] = 0x0FCUL, + [OP_USBCMD] = 0x000UL, + [OP_USBSTS] = 0x004UL, + [OP_USBINTR] = 0x008UL, + [OP_DEVICEADDR] = 0x014UL, + [OP_ENDPTLISTADDR] = 0x018UL, + [OP_PORTSC] = 0x044UL, + [OP_DEVLC] = 0x084UL, + [OP_OTGSC] = 0x0C4UL, + [OP_USBMODE] = 0x0C8UL, + [OP_ENDPTSETUPSTAT] = 0x0D8UL, + [OP_ENDPTPRIME] = 0x0DCUL, + [OP_ENDPTFLUSH] = 0x0E0UL, + [OP_ENDPTSTAT] = 0x0E4UL, + [OP_ENDPTCOMPLETE] = 0x0E8UL, + [OP_ENDPTCTRL] = 0x0ECUL, +}; + +static int hw_alloc_regmap(struct ci13xxx *ci, bool is_lpm) +{ + int i; + + kfree(ci->hw_bank.regmap); + + ci->hw_bank.regmap = kzalloc((OP_LAST + 1) * sizeof(void *), + GFP_KERNEL); + if (!ci->hw_bank.regmap) + return -ENOMEM; + + for (i = 0; i < OP_ENDPTCTRL; i++) + ci->hw_bank.regmap[i] = + (i <= CAP_LAST ? ci->hw_bank.cap : ci->hw_bank.op) + + (is_lpm ? ci_regs_lpm[i] : ci_regs_nolpm[i]); + + for (; i <= OP_LAST; i++) + ci->hw_bank.regmap[i] = ci->hw_bank.op + + 4 * (i - OP_ENDPTCTRL) + + (is_lpm + ? ci_regs_lpm[OP_ENDPTCTRL] + : ci_regs_nolpm[OP_ENDPTCTRL]); + + return 0; +} + +/** + * hw_port_test_set: writes port test mode (execute without interruption) + * @mode: new value + * + * This function returns an error code + */ +int hw_port_test_set(struct ci13xxx *ci, u8 mode) +{ + const u8 TEST_MODE_MAX = 7; + + if (mode > TEST_MODE_MAX) + return -EINVAL; + + hw_write(ci, OP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); + return 0; +} + +/** + * hw_port_test_get: reads port test mode value + * + * This function returns port test mode value + */ +u8 hw_port_test_get(struct ci13xxx *ci) +{ + return hw_read(ci, OP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); +} + +static int hw_device_init(struct ci13xxx *ci, void __iomem *base) +{ + u32 reg; + + /* bank is a module variable */ + ci->hw_bank.abs = base; + + ci->hw_bank.cap = ci->hw_bank.abs; + ci->hw_bank.cap += ci->udc_driver->capoffset; + ci->hw_bank.op = ci->hw_bank.cap + ioread8(ci->hw_bank.cap); + + hw_alloc_regmap(ci, false); + reg = hw_read(ci, CAP_HCCPARAMS, HCCPARAMS_LEN) >> + ffs_nr(HCCPARAMS_LEN); + ci->hw_bank.lpm = reg; + hw_alloc_regmap(ci, !!reg); + ci->hw_bank.size = ci->hw_bank.op - ci->hw_bank.abs; + ci->hw_bank.size += OP_LAST; + ci->hw_bank.size /= sizeof(u32); + + reg = hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DEN) >> + ffs_nr(DCCPARAMS_DEN); + ci->hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ + + if (ci->hw_ep_max > ENDPT_MAX) + return -ENODEV; + + dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n", + ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op); + + /* setup lock mode ? */ + + /* ENDPTSETUPSTAT is '0' by default */ + + /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ + + return 0; +} + +/** + * hw_device_reset: resets chip (execute without interruption) + * @ci: the controller + * + * This function returns an error code + */ +int hw_device_reset(struct ci13xxx *ci, u32 mode) +{ + /* should flush & stop before reset */ + hw_write(ci, OP_ENDPTFLUSH, ~0, ~0); + hw_write(ci, OP_USBCMD, USBCMD_RS, 0); + + hw_write(ci, OP_USBCMD, USBCMD_RST, USBCMD_RST); + while (hw_read(ci, OP_USBCMD, USBCMD_RST)) + udelay(10); /* not RTOS friendly */ + + + if (ci->udc_driver->notify_event) + ci->udc_driver->notify_event(ci, + CI13XXX_CONTROLLER_RESET_EVENT); + + if (ci->udc_driver->flags & CI13XXX_DISABLE_STREAMING) + hw_write(ci, OP_USBMODE, USBMODE_CI_SDIS, USBMODE_CI_SDIS); + + /* USBMODE should be configured step by step */ + hw_write(ci, OP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); + hw_write(ci, OP_USBMODE, USBMODE_CM, mode); + /* HW >= 2.3 */ + hw_write(ci, OP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); + + if (hw_read(ci, OP_USBMODE, USBMODE_CM) != mode) { + pr_err("cannot enter in %s mode", ci_role(ci)->name); + pr_err("lpm = %i", ci->hw_bank.lpm); + return -ENODEV; + } + + return 0; +} + +/** + * ci_otg_role - pick role based on ID pin state + * @ci: the controller + */ +static enum ci_role ci_otg_role(struct ci13xxx *ci) +{ + u32 sts = hw_read(ci, OP_OTGSC, ~0); + enum ci_role role = sts & OTGSC_ID + ? CI_ROLE_GADGET + : CI_ROLE_HOST; + + return role; +} + +/** + * ci_role_work - perform role changing based on ID pin + * @work: work struct + */ +static void ci_role_work(struct work_struct *work) +{ + struct ci13xxx *ci = container_of(work, struct ci13xxx, work); + enum ci_role role = ci_otg_role(ci); + + hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS); + + if (role != ci->role) { + dev_dbg(ci->dev, "switching from %s to %s\n", + ci_role(ci)->name, ci->roles[role]->name); + + ci_role_stop(ci); + ci_role_start(ci, role); + } +} + +static ssize_t show_role(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *ci = dev_get_drvdata(dev); + + return sprintf(buf, "%s\n", ci_role(ci)->name); +} + +static ssize_t store_role(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci13xxx *ci = dev_get_drvdata(dev); + enum ci_role role; + int ret; + + for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) + if (ci->roles[role] && !strcmp(buf, ci->roles[role]->name)) + break; + + if (role == CI_ROLE_END || role == ci->role) + return -EINVAL; + + ci_role_stop(ci); + ret = ci_role_start(ci, role); + if (ret) + return ret; + + return count; +} + +static DEVICE_ATTR(role, S_IRUSR | S_IWUSR, show_role, store_role); + +static irqreturn_t ci_irq(int irq, void *data) +{ + struct ci13xxx *ci = data; + irqreturn_t ret = IRQ_NONE; + + if (ci->is_otg) { + u32 sts = hw_read(ci, OP_OTGSC, ~0); + + if (sts & OTGSC_IDIS) { + queue_work(ci->wq, &ci->work); + ret = IRQ_HANDLED; + } + } + + return ci->role == CI_ROLE_END ? ret : ci_role(ci)->irq(ci); +} + +static int __devinit ci_hdrc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct ci13xxx *ci; + struct resource *res; + void __iomem *base; + int ret; + + if (!dev->platform_data) { + dev_err(dev, "platform data missing\n"); + return -ENODEV; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing resource\n"); + return -ENODEV; + } + + base = devm_request_and_ioremap(dev, res); + if (!res) { + dev_err(dev, "can't request and ioremap resource\n"); + return -ENOMEM; + } + + ci = devm_kzalloc(dev, sizeof(*ci), GFP_KERNEL); + if (!ci) { + dev_err(dev, "can't allocate device\n"); + return -ENOMEM; + } + + ci->dev = dev; + ci->udc_driver = dev->platform_data; + + ret = hw_device_init(ci, base); + if (ret < 0) { + dev_err(dev, "can't initialize hardware\n"); + return -ENODEV; + } + + ci->hw_bank.phys = res->start; + + ci->irq = platform_get_irq(pdev, 0); + if (ci->irq < 0) { + dev_err(dev, "missing IRQ\n"); + return -ENODEV; + } + + INIT_WORK(&ci->work, ci_role_work); + ci->wq = create_singlethread_workqueue("ci_otg"); + if (!ci->wq) { + dev_err(dev, "can't create workqueue\n"); + return -ENODEV; + } + + /* initialize role(s) before the interrupt is requested */ + ret = ci_hdrc_host_init(ci); + if (ret) + dev_info(dev, "doesn't support host\n"); + + ret = ci_hdrc_gadget_init(ci); + if (ret) + dev_info(dev, "doesn't support gadget\n"); + + if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { + dev_err(dev, "no supported roles\n"); + ret = -ENODEV; + goto rm_wq; + } + + if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) { + ci->is_otg = true; + ci->role = ci_otg_role(ci); + } else { + ci->role = ci->roles[CI_ROLE_HOST] + ? CI_ROLE_HOST + : CI_ROLE_GADGET; + } + + ret = ci_role_start(ci, ci->role); + if (ret) { + dev_err(dev, "can't start %s role\n", ci_role(ci)->name); + ret = -ENODEV; + goto rm_wq; + } + + platform_set_drvdata(pdev, ci); + ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->udc_driver->name, + ci); + if (ret) + goto stop; + + ret = device_create_file(dev, &dev_attr_role); + if (ret) + goto rm_attr; + + if (ci->is_otg) + hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE); + + return ret; + +rm_attr: + device_remove_file(dev, &dev_attr_role); +stop: + ci_role_stop(ci); +rm_wq: + flush_workqueue(ci->wq); + destroy_workqueue(ci->wq); + + return ret; +} + +static int __devexit ci_hdrc_remove(struct platform_device *pdev) +{ + struct ci13xxx *ci = platform_get_drvdata(pdev); + + flush_workqueue(ci->wq); + destroy_workqueue(ci->wq); + device_remove_file(ci->dev, &dev_attr_role); + free_irq(ci->irq, ci); + ci_role_stop(ci); + + return 0; +} + +static struct platform_driver ci_hdrc_driver = { + .probe = ci_hdrc_probe, + .remove = __devexit_p(ci_hdrc_remove), + .driver = { + .name = "ci_hdrc", + }, +}; + +module_platform_driver(ci_hdrc_driver); + +MODULE_ALIAS("platform:ci_hdrc"); +MODULE_ALIAS("platform:ci13xxx"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("David Lopo <dlopo@chipidea.mips.com>"); +MODULE_DESCRIPTION("ChipIdea HDRC Driver"); diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c new file mode 100644 index 000000000000..c4b3e15532db --- /dev/null +++ b/drivers/usb/chipidea/debug.c @@ -0,0 +1,804 @@ +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dmapool.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> +#include <linux/usb/chipidea.h> + +#include "ci.h" +#include "udc.h" +#include "bits.h" +#include "debug.h" + +/* Interrupt statistics */ +#define ISR_MASK 0x1F +static struct isr_statistics { + u32 test; + u32 ui; + u32 uei; + u32 pci; + u32 uri; + u32 sli; + u32 none; + struct { + u32 cnt; + u32 buf[ISR_MASK+1]; + u32 idx; + } hndl; +} isr_statistics; + +void dbg_interrupt(u32 intmask) +{ + if (!intmask) { + isr_statistics.none++; + return; + } + + isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intmask; + isr_statistics.hndl.idx &= ISR_MASK; + isr_statistics.hndl.cnt++; + + if (USBi_URI & intmask) + isr_statistics.uri++; + if (USBi_PCI & intmask) + isr_statistics.pci++; + if (USBi_UEI & intmask) + isr_statistics.uei++; + if (USBi_UI & intmask) + isr_statistics.ui++; + if (USBi_SLI & intmask) + isr_statistics.sli++; +} + +/** + * hw_register_read: reads all device registers (execute without interruption) + * @buf: destination buffer + * @size: buffer size + * + * This function returns number of registers read + */ +static size_t hw_register_read(struct ci13xxx *udc, u32 *buf, size_t size) +{ + unsigned i; + + if (size > udc->hw_bank.size) + size = udc->hw_bank.size; + + for (i = 0; i < size; i++) + buf[i] = hw_read(udc, i * sizeof(u32), ~0); + + return size; +} + +/** + * hw_register_write: writes to register + * @addr: register address + * @data: register value + * + * This function returns an error code + */ +static int hw_register_write(struct ci13xxx *udc, u16 addr, u32 data) +{ + /* align */ + addr /= sizeof(u32); + + if (addr >= udc->hw_bank.size) + return -EINVAL; + + /* align */ + addr *= sizeof(u32); + + hw_write(udc, addr, ~0, data); + return 0; +} + +/** + * hw_intr_clear: disables interrupt & clears interrupt status (execute without + * interruption) + * @n: interrupt bit + * + * This function returns an error code + */ +static int hw_intr_clear(struct ci13xxx *udc, int n) +{ + if (n >= REG_BITS) + return -EINVAL; + + hw_write(udc, OP_USBINTR, BIT(n), 0); + hw_write(udc, OP_USBSTS, BIT(n), BIT(n)); + return 0; +} + +/** + * hw_intr_force: enables interrupt & forces interrupt status (execute without + * interruption) + * @n: interrupt bit + * + * This function returns an error code + */ +static int hw_intr_force(struct ci13xxx *udc, int n) +{ + if (n >= REG_BITS) + return -EINVAL; + + hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); + hw_write(udc, OP_USBINTR, BIT(n), BIT(n)); + hw_write(udc, OP_USBSTS, BIT(n), BIT(n)); + hw_write(udc, CAP_TESTMODE, TESTMODE_FORCE, 0); + return 0; +} + +/** + * show_device: prints information about device capabilities and status + * + * Check "device.h" for details + */ +static ssize_t show_device(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + struct usb_gadget *gadget = &udc->gadget; + int n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", + gadget->speed); + n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", + gadget->max_speed); + /* TODO: Scheduled for removal in 3.8. */ + n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", + gadget_is_dualspeed(gadget)); + n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", + gadget->is_otg); + n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", + gadget->is_a_peripheral); + n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n", + gadget->b_hnp_enable); + n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n", + gadget->a_hnp_support); + n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n", + gadget->a_alt_hnp_support); + n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n", + (gadget->name ? gadget->name : "")); + + return n; +} +static DEVICE_ATTR(device, S_IRUSR, show_device, NULL); + +/** + * show_driver: prints information about attached gadget (if any) + * + * Check "device.h" for details + */ +static ssize_t show_driver(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + struct usb_gadget_driver *driver = udc->driver; + int n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(dev, "[%s] EINVAL\n", __func__); + return 0; + } + + if (driver == NULL) + return scnprintf(buf, PAGE_SIZE, + "There is no gadget attached!\n"); + + n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", + (driver->function ? driver->function : "")); + n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", + driver->max_speed); + + return n; +} +static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL); + +/* Maximum event message length */ +#define DBG_DATA_MSG 64UL + +/* Maximum event messages */ +#define DBG_DATA_MAX 128UL + +/* Event buffer descriptor */ +static struct { + char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */ + unsigned idx; /* index */ + unsigned tty; /* print to console? */ + rwlock_t lck; /* lock */ +} dbg_data = { + .idx = 0, + .tty = 0, + .lck = __RW_LOCK_UNLOCKED(lck) +}; + +/** + * dbg_dec: decrements debug event index + * @idx: buffer index + */ +static void dbg_dec(unsigned *idx) +{ + *idx = (*idx - 1) & (DBG_DATA_MAX-1); +} + +/** + * dbg_inc: increments debug event index + * @idx: buffer index + */ +static void dbg_inc(unsigned *idx) +{ + *idx = (*idx + 1) & (DBG_DATA_MAX-1); +} + +/** + * dbg_print: prints the common part of the event + * @addr: endpoint address + * @name: event name + * @status: status + * @extra: extra information + */ +static void dbg_print(u8 addr, const char *name, int status, const char *extra) +{ + struct timeval tval; + unsigned int stamp; + unsigned long flags; + + write_lock_irqsave(&dbg_data.lck, flags); + + do_gettimeofday(&tval); + stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */ + stamp = stamp * 1000000 + tval.tv_usec; + + scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, + "%04X\t? %02X %-7.7s %4i ?\t%s\n", + stamp, addr, name, status, extra); + + dbg_inc(&dbg_data.idx); + + write_unlock_irqrestore(&dbg_data.lck, flags); + + if (dbg_data.tty != 0) + pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n", + stamp, addr, name, status, extra); +} + +/** + * dbg_done: prints a DONE event + * @addr: endpoint address + * @td: transfer descriptor + * @status: status + */ +void dbg_done(u8 addr, const u32 token, int status) +{ + char msg[DBG_DATA_MSG]; + + scnprintf(msg, sizeof(msg), "%d %02X", + (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES), + (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS)); + dbg_print(addr, "DONE", status, msg); +} + +/** + * dbg_event: prints a generic event + * @addr: endpoint address + * @name: event name + * @status: status + */ +void dbg_event(u8 addr, const char *name, int status) +{ + if (name != NULL) + dbg_print(addr, name, status, ""); +} + +/* + * dbg_queue: prints a QUEUE event + * @addr: endpoint address + * @req: USB request + * @status: status + */ +void dbg_queue(u8 addr, const struct usb_request *req, int status) +{ + char msg[DBG_DATA_MSG]; + + if (req != NULL) { + scnprintf(msg, sizeof(msg), + "%d %d", !req->no_interrupt, req->length); + dbg_print(addr, "QUEUE", status, msg); + } +} + +/** + * dbg_setup: prints a SETUP event + * @addr: endpoint address + * @req: setup request + */ +void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) +{ + char msg[DBG_DATA_MSG]; + + if (req != NULL) { + scnprintf(msg, sizeof(msg), + "%02X %02X %04X %04X %d", req->bRequestType, + req->bRequest, le16_to_cpu(req->wValue), + le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); + dbg_print(addr, "SETUP", 0, msg); + } +} + +/** + * show_events: displays the event buffer + * + * Check "device.h" for details + */ +static ssize_t show_events(struct device *dev, struct device_attribute *attr, + char *buf) +{ + unsigned long flags; + unsigned i, j, n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(dev->parent, "[%s] EINVAL\n", __func__); + return 0; + } + + read_lock_irqsave(&dbg_data.lck, flags); + + i = dbg_data.idx; + for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) { + n += strlen(dbg_data.buf[i]); + if (n >= PAGE_SIZE) { + n -= strlen(dbg_data.buf[i]); + break; + } + } + for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i)) + j += scnprintf(buf + j, PAGE_SIZE - j, + "%s", dbg_data.buf[i]); + + read_unlock_irqrestore(&dbg_data.lck, flags); + + return n; +} + +/** + * store_events: configure if events are going to be also printed to console + * + * Check "device.h" for details + */ +static ssize_t store_events(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + unsigned tty; + + if (attr == NULL || buf == NULL) { + dev_err(dev, "[%s] EINVAL\n", __func__); + goto done; + } + + if (sscanf(buf, "%u", &tty) != 1 || tty > 1) { + dev_err(dev, "<1|0>: enable|disable console log\n"); + goto done; + } + + dbg_data.tty = tty; + dev_info(dev, "tty = %u", dbg_data.tty); + + done: + return count; +} +static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); + +/** + * show_inters: interrupt status, enable status and historic + * + * Check "device.h" for details + */ +static ssize_t show_inters(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + u32 intr; + unsigned i, j, n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + + /*n += scnprintf(buf + n, PAGE_SIZE - n, + "status = %08x\n", hw_read_intr_status(udc)); + n += scnprintf(buf + n, PAGE_SIZE - n, + "enable = %08x\n", hw_read_intr_enable(udc));*/ + + n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", + isr_statistics.test); + n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n", + isr_statistics.ui); + n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n", + isr_statistics.uei); + n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n", + isr_statistics.pci); + n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n", + isr_statistics.uri); + n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n", + isr_statistics.sli); + n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", + isr_statistics.none); + n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n", + isr_statistics.hndl.cnt); + + for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) { + i &= ISR_MASK; + intr = isr_statistics.hndl.buf[i]; + + if (USBi_UI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "ui "); + intr &= ~USBi_UI; + if (USBi_UEI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "uei "); + intr &= ~USBi_UEI; + if (USBi_PCI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "pci "); + intr &= ~USBi_PCI; + if (USBi_URI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "uri "); + intr &= ~USBi_URI; + if (USBi_SLI & intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "sli "); + intr &= ~USBi_SLI; + if (intr) + n += scnprintf(buf + n, PAGE_SIZE - n, "??? "); + if (isr_statistics.hndl.buf[i]) + n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return n; +} + +/** + * store_inters: enable & force or disable an individual interrutps + * (to be used for test purposes only) + * + * Check "device.h" for details + */ +static ssize_t store_inters(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + unsigned en, bit; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "EINVAL\n"); + goto done; + } + + if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) { + dev_err(udc->dev, "<1|0> <bit>: enable|disable interrupt\n"); + goto done; + } + + spin_lock_irqsave(&udc->lock, flags); + if (en) { + if (hw_intr_force(udc, bit)) + dev_err(dev, "invalid bit number\n"); + else + isr_statistics.test++; + } else { + if (hw_intr_clear(udc, bit)) + dev_err(dev, "invalid bit number\n"); + } + spin_unlock_irqrestore(&udc->lock, flags); + + done: + return count; +} +static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); + +/** + * show_port_test: reads port test mode + * + * Check "device.h" for details + */ +static ssize_t show_port_test(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + unsigned mode; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "EINVAL\n"); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + mode = hw_port_test_get(udc); + spin_unlock_irqrestore(&udc->lock, flags); + + return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); +} + +/** + * store_port_test: writes port test mode + * + * Check "device.h" for details + */ +static ssize_t store_port_test(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + unsigned mode; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + goto done; + } + + if (sscanf(buf, "%u", &mode) != 1) { + dev_err(udc->dev, "<mode>: set port test mode"); + goto done; + } + + spin_lock_irqsave(&udc->lock, flags); + if (hw_port_test_set(udc, mode)) + dev_err(udc->dev, "invalid mode\n"); + spin_unlock_irqrestore(&udc->lock, flags); + + done: + return count; +} +static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, + show_port_test, store_port_test); + +/** + * show_qheads: DMA contents of all queue heads + * + * Check "device.h" for details + */ +static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + unsigned i, j, n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + for (i = 0; i < udc->hw_ep_max/2; i++) { + struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i]; + struct ci13xxx_ep *mEpTx = + &udc->ci13xxx_ep[i + udc->hw_ep_max/2]; + n += scnprintf(buf + n, PAGE_SIZE - n, + "EP=%02i: RX=%08X TX=%08X\n", + i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); + for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { + n += scnprintf(buf + n, PAGE_SIZE - n, + " %04X: %08X %08X\n", j, + *((u32 *)mEpRx->qh.ptr + j), + *((u32 *)mEpTx->qh.ptr + j)); + } + } + spin_unlock_irqrestore(&udc->lock, flags); + + return n; +} +static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); + +/** + * show_registers: dumps all registers + * + * Check "device.h" for details + */ +#define DUMP_ENTRIES 512 +static ssize_t show_registers(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + u32 *dump; + unsigned i, k, n = 0; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); + if (!dump) { + dev_err(udc->dev, "%s: out of memory\n", __func__); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + k = hw_register_read(udc, dump, DUMP_ENTRIES); + spin_unlock_irqrestore(&udc->lock, flags); + + for (i = 0; i < k; i++) { + n += scnprintf(buf + n, PAGE_SIZE - n, + "reg[0x%04X] = 0x%08X\n", + i * (unsigned)sizeof(u32), dump[i]); + } + kfree(dump); + + return n; +} + +/** + * store_registers: writes value to register address + * + * Check "device.h" for details + */ +static ssize_t store_registers(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long addr, data, flags; + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + goto done; + } + + if (sscanf(buf, "%li %li", &addr, &data) != 2) { + dev_err(udc->dev, + "<addr> <data>: write data to register address\n"); + goto done; + } + + spin_lock_irqsave(&udc->lock, flags); + if (hw_register_write(udc, addr, data)) + dev_err(udc->dev, "invalid address range\n"); + spin_unlock_irqrestore(&udc->lock, flags); + + done: + return count; +} +static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, + show_registers, store_registers); + +/** + * show_requests: DMA contents of all requests currently queued (all endpts) + * + * Check "device.h" for details + */ +static ssize_t show_requests(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); + unsigned long flags; + struct list_head *ptr = NULL; + struct ci13xxx_req *req = NULL; + unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); + + if (attr == NULL || buf == NULL) { + dev_err(udc->dev, "[%s] EINVAL\n", __func__); + return 0; + } + + spin_lock_irqsave(&udc->lock, flags); + for (i = 0; i < udc->hw_ep_max; i++) + list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) + { + req = list_entry(ptr, struct ci13xxx_req, queue); + + n += scnprintf(buf + n, PAGE_SIZE - n, + "EP=%02i: TD=%08X %s\n", + i % udc->hw_ep_max/2, (u32)req->dma, + ((i < udc->hw_ep_max/2) ? "RX" : "TX")); + + for (j = 0; j < qSize; j++) + n += scnprintf(buf + n, PAGE_SIZE - n, + " %04X: %08X\n", j, + *((u32 *)req->ptr + j)); + } + spin_unlock_irqrestore(&udc->lock, flags); + + return n; +} +static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); + +/** + * dbg_create_files: initializes the attribute interface + * @dev: device + * + * This function returns an error code + */ +int dbg_create_files(struct device *dev) +{ + int retval = 0; + + if (dev == NULL) + return -EINVAL; + retval = device_create_file(dev, &dev_attr_device); + if (retval) + goto done; + retval = device_create_file(dev, &dev_attr_driver); + if (retval) + goto rm_device; + retval = device_create_file(dev, &dev_attr_events); + if (retval) + goto rm_driver; + retval = device_create_file(dev, &dev_attr_inters); + if (retval) + goto rm_events; + retval = device_create_file(dev, &dev_attr_port_test); + if (retval) + goto rm_inters; + retval = device_create_file(dev, &dev_attr_qheads); + if (retval) + goto rm_port_test; + retval = device_create_file(dev, &dev_attr_registers); + if (retval) + goto rm_qheads; + retval = device_create_file(dev, &dev_attr_requests); + if (retval) + goto rm_registers; + return 0; + + rm_registers: + device_remove_file(dev, &dev_attr_registers); + rm_qheads: + device_remove_file(dev, &dev_attr_qheads); + rm_port_test: + device_remove_file(dev, &dev_attr_port_test); + rm_inters: + device_remove_file(dev, &dev_attr_inters); + rm_events: + device_remove_file(dev, &dev_attr_events); + rm_driver: + device_remove_file(dev, &dev_attr_driver); + rm_device: + device_remove_file(dev, &dev_attr_device); + done: + return retval; +} + +/** + * dbg_remove_files: destroys the attribute interface + * @dev: device + * + * This function returns an error code + */ +int dbg_remove_files(struct device *dev) +{ + if (dev == NULL) + return -EINVAL; + device_remove_file(dev, &dev_attr_requests); + device_remove_file(dev, &dev_attr_registers); + device_remove_file(dev, &dev_attr_qheads); + device_remove_file(dev, &dev_attr_port_test); + device_remove_file(dev, &dev_attr_inters); + device_remove_file(dev, &dev_attr_events); + device_remove_file(dev, &dev_attr_driver); + device_remove_file(dev, &dev_attr_device); + return 0; +} diff --git a/drivers/usb/chipidea/debug.h b/drivers/usb/chipidea/debug.h new file mode 100644 index 000000000000..80d96865775c --- /dev/null +++ b/drivers/usb/chipidea/debug.h @@ -0,0 +1,56 @@ +/* + * debug.h - ChipIdea USB driver debug interfaces + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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. + */ + +#ifndef __DRIVERS_USB_CHIPIDEA_DEBUG_H +#define __DRIVERS_USB_CHIPIDEA_DEBUG_H + +#ifdef CONFIG_USB_CHIPIDEA_DEBUG +void dbg_interrupt(u32 intmask); +void dbg_done(u8 addr, const u32 token, int status); +void dbg_event(u8 addr, const char *name, int status); +void dbg_queue(u8 addr, const struct usb_request *req, int status); +void dbg_setup(u8 addr, const struct usb_ctrlrequest *req); +int dbg_create_files(struct device *dev); +int dbg_remove_files(struct device *dev); +#else +static inline void dbg_interrupt(u32 intmask) +{ +} + +static inline void dbg_done(u8 addr, const u32 token, int status) +{ +} + +static inline void dbg_event(u8 addr, const char *name, int status) +{ +} + +static inline void dbg_queue(u8 addr, const struct usb_request *req, int status) +{ +} + +static inline void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) +{ +} + +static inline int dbg_create_files(struct device *dev) +{ + return 0; +} + +static inline int dbg_remove_files(struct device *dev) +{ + return 0; +} +#endif + +#endif /* __DRIVERS_USB_CHIPIDEA_DEBUG_H */ diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c new file mode 100644 index 000000000000..9eacd21c0cd9 --- /dev/null +++ b/drivers/usb/chipidea/host.c @@ -0,0 +1,160 @@ +/* + * host.c - ChipIdea USB host controller driver + * + * Copyright (c) 2012 Intel Corporation + * + * Author: Alexander Shishkin + * + * 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 program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/kernel.h> +#include <linux/usb.h> +#include <linux/usb/hcd.h> +#include <linux/usb/chipidea.h> + +#define CHIPIDEA_EHCI +#include "../host/ehci-hcd.c" + +#include "ci.h" +#include "bits.h" +#include "host.h" + +static int ci_ehci_setup(struct usb_hcd *hcd) +{ + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + int ret; + + hcd->has_tt = 1; + + ret = ehci_setup(hcd); + if (ret) + return ret; + + ehci_port_power(ehci, 0); + + return ret; +} + +static const struct hc_driver ci_ehci_hc_driver = { + .description = "ehci_hcd", + .product_desc = "ChipIdea HDRC EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + */ + .reset = ci_ehci_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +}; + +static irqreturn_t host_irq(struct ci13xxx *ci) +{ + return usb_hcd_irq(ci->irq, ci->hcd); +} + +static int host_start(struct ci13xxx *ci) +{ + struct usb_hcd *hcd; + struct ehci_hcd *ehci; + int ret; + + if (usb_disabled()) + return -ENODEV; + + hcd = usb_create_hcd(&ci_ehci_hc_driver, ci->dev, dev_name(ci->dev)); + if (!hcd) + return -ENOMEM; + + dev_set_drvdata(ci->dev, ci); + hcd->rsrc_start = ci->hw_bank.phys; + hcd->rsrc_len = ci->hw_bank.size; + hcd->regs = ci->hw_bank.abs; + hcd->has_tt = 1; + + hcd->power_budget = ci->udc_driver->power_budget; + + ehci = hcd_to_ehci(hcd); + ehci->caps = ci->hw_bank.cap; + ehci->has_hostpc = ci->hw_bank.lpm; + + ret = usb_add_hcd(hcd, 0, 0); + if (ret) + usb_put_hcd(hcd); + else + ci->hcd = hcd; + + return ret; +} + +static void host_stop(struct ci13xxx *ci) +{ + struct usb_hcd *hcd = ci->hcd; + + usb_remove_hcd(hcd); + usb_put_hcd(hcd); +} + +int ci_hdrc_host_init(struct ci13xxx *ci) +{ + struct ci_role_driver *rdrv; + + if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_HC)) + return -ENXIO; + + rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL); + if (!rdrv) + return -ENOMEM; + + rdrv->start = host_start; + rdrv->stop = host_stop; + rdrv->irq = host_irq; + rdrv->name = "host"; + ci->roles[CI_ROLE_HOST] = rdrv; + + return 0; +} diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h new file mode 100644 index 000000000000..761fb1fd6d99 --- /dev/null +++ b/drivers/usb/chipidea/host.h @@ -0,0 +1,17 @@ +#ifndef __DRIVERS_USB_CHIPIDEA_HOST_H +#define __DRIVERS_USB_CHIPIDEA_HOST_H + +#ifdef CONFIG_USB_CHIPIDEA_HOST + +int ci_hdrc_host_init(struct ci13xxx *ci); + +#else + +static inline int ci_hdrc_host_init(struct ci13xxx *ci) +{ + return -ENXIO; +} + +#endif + +#endif /* __DRIVERS_USB_CHIPIDEA_HOST_H */ diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c new file mode 100644 index 000000000000..51f96942dc5e --- /dev/null +++ b/drivers/usb/chipidea/udc.c @@ -0,0 +1,1809 @@ +/* + * udc.c - ChipIdea UDC driver + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dmapool.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pm_runtime.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/usb/otg.h> +#include <linux/usb/chipidea.h> + +#include "ci.h" +#include "udc.h" +#include "bits.h" +#include "debug.h" + +/* control endpoint description */ +static const struct usb_endpoint_descriptor +ctrl_endpt_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), +}; + +static const struct usb_endpoint_descriptor +ctrl_endpt_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_CONTROL, + .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), +}; + +/** + * hw_ep_bit: calculates the bit number + * @num: endpoint number + * @dir: endpoint direction + * + * This function returns bit number + */ +static inline int hw_ep_bit(int num, int dir) +{ + return num + (dir ? 16 : 0); +} + +static inline int ep_to_bit(struct ci13xxx *udc, int n) +{ + int fill = 16 - udc->hw_ep_max / 2; + + if (n >= udc->hw_ep_max / 2) + n += fill; + + return n; +} + +/** + * hw_device_state: enables/disables interrupts & starts/stops device (execute + * without interruption) + * @dma: 0 => disable, !0 => enable and set dma engine + * + * This function returns an error code + */ +static int hw_device_state(struct ci13xxx *udc, u32 dma) +{ + if (dma) { + hw_write(udc, OP_ENDPTLISTADDR, ~0, dma); + /* interrupt, error, port change, reset, sleep/suspend */ + hw_write(udc, OP_USBINTR, ~0, + USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); + hw_write(udc, OP_USBCMD, USBCMD_RS, USBCMD_RS); + } else { + hw_write(udc, OP_USBCMD, USBCMD_RS, 0); + hw_write(udc, OP_USBINTR, ~0, 0); + } + return 0; +} + +/** + * hw_ep_flush: flush endpoint fifo (execute without interruption) + * @num: endpoint number + * @dir: endpoint direction + * + * This function returns an error code + */ +static int hw_ep_flush(struct ci13xxx *udc, int num, int dir) +{ + int n = hw_ep_bit(num, dir); + + do { + /* flush any pending transfer */ + hw_write(udc, OP_ENDPTFLUSH, BIT(n), BIT(n)); + while (hw_read(udc, OP_ENDPTFLUSH, BIT(n))) + cpu_relax(); + } while (hw_read(udc, OP_ENDPTSTAT, BIT(n))); + + return 0; +} + +/** + * hw_ep_disable: disables endpoint (execute without interruption) + * @num: endpoint number + * @dir: endpoint direction + * + * This function returns an error code + */ +static int hw_ep_disable(struct ci13xxx *udc, int num, int dir) +{ + hw_ep_flush(udc, num, dir); + hw_write(udc, OP_ENDPTCTRL + num, + dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); + return 0; +} + +/** + * hw_ep_enable: enables endpoint (execute without interruption) + * @num: endpoint number + * @dir: endpoint direction + * @type: endpoint type + * + * This function returns an error code + */ +static int hw_ep_enable(struct ci13xxx *udc, int num, int dir, int type) +{ + u32 mask, data; + + if (dir) { + mask = ENDPTCTRL_TXT; /* type */ + data = type << ffs_nr(mask); + + mask |= ENDPTCTRL_TXS; /* unstall */ + mask |= ENDPTCTRL_TXR; /* reset data toggle */ + data |= ENDPTCTRL_TXR; + mask |= ENDPTCTRL_TXE; /* enable */ + data |= ENDPTCTRL_TXE; + } else { + mask = ENDPTCTRL_RXT; /* type */ + data = type << ffs_nr(mask); + + mask |= ENDPTCTRL_RXS; /* unstall */ + mask |= ENDPTCTRL_RXR; /* reset data toggle */ + data |= ENDPTCTRL_RXR; + mask |= ENDPTCTRL_RXE; /* enable */ + data |= ENDPTCTRL_RXE; + } + hw_write(udc, OP_ENDPTCTRL + num, mask, data); + return 0; +} + +/** + * hw_ep_get_halt: return endpoint halt status + * @num: endpoint number + * @dir: endpoint direction + * + * This function returns 1 if endpoint halted + */ +static int hw_ep_get_halt(struct ci13xxx *udc, int num, int dir) +{ + u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; + + return hw_read(udc, OP_ENDPTCTRL + num, mask) ? 1 : 0; +} + +/** + * hw_test_and_clear_setup_status: test & clear setup status (execute without + * interruption) + * @n: endpoint number + * + * This function returns setup status + */ +static int hw_test_and_clear_setup_status(struct ci13xxx *udc, int n) +{ + n = ep_to_bit(udc, n); + return hw_test_and_clear(udc, OP_ENDPTSETUPSTAT, BIT(n)); +} + +/** + * hw_ep_prime: primes endpoint (execute without interruption) + * @num: endpoint number + * @dir: endpoint direction + * @is_ctrl: true if control endpoint + * + * This function returns an error code + */ +static int hw_ep_prime(struct ci13xxx *udc, int num, int dir, int is_ctrl) +{ + int n = hw_ep_bit(num, dir); + + if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num))) + return -EAGAIN; + + hw_write(udc, OP_ENDPTPRIME, BIT(n), BIT(n)); + + while (hw_read(udc, OP_ENDPTPRIME, BIT(n))) + cpu_relax(); + if (is_ctrl && dir == RX && hw_read(udc, OP_ENDPTSETUPSTAT, BIT(num))) + return -EAGAIN; + + /* status shoult be tested according with manual but it doesn't work */ + return 0; +} + +/** + * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute + * without interruption) + * @num: endpoint number + * @dir: endpoint direction + * @value: true => stall, false => unstall + * + * This function returns an error code + */ +static int hw_ep_set_halt(struct ci13xxx *udc, int num, int dir, int value) +{ + if (value != 0 && value != 1) + return -EINVAL; + + do { + enum ci13xxx_regs reg = OP_ENDPTCTRL + num; + u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; + u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; + + /* data toggle - reserved for EP0 but it's in ESS */ + hw_write(udc, reg, mask_xs|mask_xr, + value ? mask_xs : mask_xr); + } while (value != hw_ep_get_halt(udc, num, dir)); + + return 0; +} + +/** + * hw_is_port_high_speed: test if port is high speed + * + * This function returns true if high speed port + */ +static int hw_port_is_high_speed(struct ci13xxx *udc) +{ + return udc->hw_bank.lpm ? hw_read(udc, OP_DEVLC, DEVLC_PSPD) : + hw_read(udc, OP_PORTSC, PORTSC_HSP); +} + +/** + * hw_read_intr_enable: returns interrupt enable register + * + * This function returns register data + */ +static u32 hw_read_intr_enable(struct ci13xxx *udc) +{ + return hw_read(udc, OP_USBINTR, ~0); +} + +/** + * hw_read_intr_status: returns interrupt status register + * + * This function returns register data + */ +static u32 hw_read_intr_status(struct ci13xxx *udc) +{ + return hw_read(udc, OP_USBSTS, ~0); +} + +/** + * hw_test_and_clear_complete: test & clear complete status (execute without + * interruption) + * @n: endpoint number + * + * This function returns complete status + */ +static int hw_test_and_clear_complete(struct ci13xxx *udc, int n) +{ + n = ep_to_bit(udc, n); + return hw_test_and_clear(udc, OP_ENDPTCOMPLETE, BIT(n)); +} + +/** + * hw_test_and_clear_intr_active: test & clear active interrupts (execute + * without interruption) + * + * This function returns active interrutps + */ +static u32 hw_test_and_clear_intr_active(struct ci13xxx *udc) +{ + u32 reg = hw_read_intr_status(udc) & hw_read_intr_enable(udc); + + hw_write(udc, OP_USBSTS, ~0, reg); + return reg; +} + +/** + * hw_test_and_clear_setup_guard: test & clear setup guard (execute without + * interruption) + * + * This function returns guard value + */ +static int hw_test_and_clear_setup_guard(struct ci13xxx *udc) +{ + return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, 0); +} + +/** + * hw_test_and_set_setup_guard: test & set setup guard (execute without + * interruption) + * + * This function returns guard value + */ +static int hw_test_and_set_setup_guard(struct ci13xxx *udc) +{ + return hw_test_and_write(udc, OP_USBCMD, USBCMD_SUTW, USBCMD_SUTW); +} + +/** + * hw_usb_set_address: configures USB address (execute without interruption) + * @value: new USB address + * + * This function explicitly sets the address, without the "USBADRA" (advance) + * feature, which is not supported by older versions of the controller. + */ +static void hw_usb_set_address(struct ci13xxx *udc, u8 value) +{ + hw_write(udc, OP_DEVICEADDR, DEVICEADDR_USBADR, + value << ffs_nr(DEVICEADDR_USBADR)); +} + +/** + * hw_usb_reset: restart device after a bus reset (execute without + * interruption) + * + * This function returns an error code + */ +static int hw_usb_reset(struct ci13xxx *udc) +{ + hw_usb_set_address(udc, 0); + + /* ESS flushes only at end?!? */ + hw_write(udc, OP_ENDPTFLUSH, ~0, ~0); + + /* clear setup token semaphores */ + hw_write(udc, OP_ENDPTSETUPSTAT, 0, 0); + + /* clear complete status */ + hw_write(udc, OP_ENDPTCOMPLETE, 0, 0); + + /* wait until all bits cleared */ + while (hw_read(udc, OP_ENDPTPRIME, ~0)) + udelay(10); /* not RTOS friendly */ + + /* reset all endpoints ? */ + + /* reset internal status and wait for further instructions + no need to verify the port reset status (ESS does it) */ + + return 0; +} + +/****************************************************************************** + * UTIL block + *****************************************************************************/ +/** + * _usb_addr: calculates endpoint address from direction & number + * @ep: endpoint + */ +static inline u8 _usb_addr(struct ci13xxx_ep *ep) +{ + return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num; +} + +/** + * _hardware_queue: configures a request at hardware level + * @gadget: gadget + * @mEp: endpoint + * + * This function returns an error code + */ +static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) +{ + struct ci13xxx *udc = mEp->udc; + unsigned i; + int ret = 0; + unsigned length = mReq->req.length; + + /* don't queue twice */ + if (mReq->req.status == -EALREADY) + return -EALREADY; + + mReq->req.status = -EALREADY; + + if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) { + mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC, + &mReq->zdma); + if (mReq->zptr == NULL) + return -ENOMEM; + + memset(mReq->zptr, 0, sizeof(*mReq->zptr)); + mReq->zptr->next = TD_TERMINATE; + mReq->zptr->token = TD_STATUS_ACTIVE; + if (!mReq->req.no_interrupt) + mReq->zptr->token |= TD_IOC; + } + ret = usb_gadget_map_request(&udc->gadget, &mReq->req, mEp->dir); + if (ret) + return ret; + + /* + * TD configuration + * TODO - handle requests which spawns into several TDs + */ + memset(mReq->ptr, 0, sizeof(*mReq->ptr)); + mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES); + mReq->ptr->token &= TD_TOTAL_BYTES; + mReq->ptr->token |= TD_STATUS_ACTIVE; + if (mReq->zptr) { + mReq->ptr->next = mReq->zdma; + } else { + mReq->ptr->next = TD_TERMINATE; + if (!mReq->req.no_interrupt) + mReq->ptr->token |= TD_IOC; + } + mReq->ptr->page[0] = mReq->req.dma; + for (i = 1; i < 5; i++) + mReq->ptr->page[i] = + (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; + + if (!list_empty(&mEp->qh.queue)) { + struct ci13xxx_req *mReqPrev; + int n = hw_ep_bit(mEp->num, mEp->dir); + int tmp_stat; + + mReqPrev = list_entry(mEp->qh.queue.prev, + struct ci13xxx_req, queue); + if (mReqPrev->zptr) + mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK; + else + mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK; + wmb(); + if (hw_read(udc, OP_ENDPTPRIME, BIT(n))) + goto done; + do { + hw_write(udc, OP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW); + tmp_stat = hw_read(udc, OP_ENDPTSTAT, BIT(n)); + } while (!hw_read(udc, OP_USBCMD, USBCMD_ATDTW)); + hw_write(udc, OP_USBCMD, USBCMD_ATDTW, 0); + if (tmp_stat) + goto done; + } + + /* QH configuration */ + mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ + mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ + mEp->qh.ptr->cap |= QH_ZLT; + + wmb(); /* synchronize before ep prime */ + + ret = hw_ep_prime(udc, mEp->num, mEp->dir, + mEp->type == USB_ENDPOINT_XFER_CONTROL); +done: + return ret; +} + +/** + * _hardware_dequeue: handles a request at hardware level + * @gadget: gadget + * @mEp: endpoint + * + * This function returns an error code + */ +static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) +{ + if (mReq->req.status != -EALREADY) + return -EINVAL; + + if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0) + return -EBUSY; + + if (mReq->zptr) { + if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0) + return -EBUSY; + dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); + mReq->zptr = NULL; + } + + mReq->req.status = 0; + + usb_gadget_unmap_request(&mEp->udc->gadget, &mReq->req, mEp->dir); + + mReq->req.status = mReq->ptr->token & TD_STATUS; + if ((TD_STATUS_HALTED & mReq->req.status) != 0) + mReq->req.status = -1; + else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) + mReq->req.status = -1; + else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0) + mReq->req.status = -1; + + mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES; + mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); + mReq->req.actual = mReq->req.length - mReq->req.actual; + mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual; + + return mReq->req.actual; +} + +/** + * _ep_nuke: dequeues all endpoint requests + * @mEp: endpoint + * + * This function returns an error code + * Caller must hold lock + */ +static int _ep_nuke(struct ci13xxx_ep *mEp) +__releases(mEp->lock) +__acquires(mEp->lock) +{ + if (mEp == NULL) + return -EINVAL; + + hw_ep_flush(mEp->udc, mEp->num, mEp->dir); + + while (!list_empty(&mEp->qh.queue)) { + + /* pop oldest request */ + struct ci13xxx_req *mReq = \ + list_entry(mEp->qh.queue.next, + struct ci13xxx_req, queue); + list_del_init(&mReq->queue); + mReq->req.status = -ESHUTDOWN; + + if (mReq->req.complete != NULL) { + spin_unlock(mEp->lock); + mReq->req.complete(&mEp->ep, &mReq->req); + spin_lock(mEp->lock); + } + } + return 0; +} + +/** + * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts + * @gadget: gadget + * + * This function returns an error code + */ +static int _gadget_stop_activity(struct usb_gadget *gadget) +{ + struct usb_ep *ep; + struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->remote_wakeup = 0; + udc->suspended = 0; + spin_unlock_irqrestore(&udc->lock, flags); + + /* flush all endpoints */ + gadget_for_each_ep(ep, gadget) { + usb_ep_fifo_flush(ep); + } + usb_ep_fifo_flush(&udc->ep0out->ep); + usb_ep_fifo_flush(&udc->ep0in->ep); + + if (udc->driver) + udc->driver->disconnect(gadget); + + /* make sure to disable all endpoints */ + gadget_for_each_ep(ep, gadget) { + usb_ep_disable(ep); + } + + if (udc->status != NULL) { + usb_ep_free_request(&udc->ep0in->ep, udc->status); + udc->status = NULL; + } + + return 0; +} + +/****************************************************************************** + * ISR block + *****************************************************************************/ +/** + * isr_reset_handler: USB reset interrupt handler + * @udc: UDC device + * + * This function resets USB engine after a bus reset occurred + */ +static void isr_reset_handler(struct ci13xxx *udc) +__releases(udc->lock) +__acquires(udc->lock) +{ + int retval; + + dbg_event(0xFF, "BUS RST", 0); + + spin_unlock(&udc->lock); + retval = _gadget_stop_activity(&udc->gadget); + if (retval) + goto done; + + retval = hw_usb_reset(udc); + if (retval) + goto done; + + udc->status = usb_ep_alloc_request(&udc->ep0in->ep, GFP_ATOMIC); + if (udc->status == NULL) + retval = -ENOMEM; + +done: + spin_lock(&udc->lock); + + if (retval) + dev_err(udc->dev, "error: %i\n", retval); +} + +/** + * isr_get_status_complete: get_status request complete function + * @ep: endpoint + * @req: request handled + * + * Caller must release lock + */ +static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) +{ + if (ep == NULL || req == NULL) + return; + + kfree(req->buf); + usb_ep_free_request(ep, req); +} + +/** + * isr_get_status_response: get_status request response + * @udc: udc struct + * @setup: setup request packet + * + * This function returns an error code + */ +static int isr_get_status_response(struct ci13xxx *udc, + struct usb_ctrlrequest *setup) +__releases(mEp->lock) +__acquires(mEp->lock) +{ + struct ci13xxx_ep *mEp = udc->ep0in; + struct usb_request *req = NULL; + gfp_t gfp_flags = GFP_ATOMIC; + int dir, num, retval; + + if (mEp == NULL || setup == NULL) + return -EINVAL; + + spin_unlock(mEp->lock); + req = usb_ep_alloc_request(&mEp->ep, gfp_flags); + spin_lock(mEp->lock); + if (req == NULL) + return -ENOMEM; + + req->complete = isr_get_status_complete; + req->length = 2; + req->buf = kzalloc(req->length, gfp_flags); + if (req->buf == NULL) { + retval = -ENOMEM; + goto err_free_req; + } + + if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { + /* Assume that device is bus powered for now. */ + *(u16 *)req->buf = udc->remote_wakeup << 1; + retval = 0; + } else if ((setup->bRequestType & USB_RECIP_MASK) \ + == USB_RECIP_ENDPOINT) { + dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? + TX : RX; + num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK; + *(u16 *)req->buf = hw_ep_get_halt(udc, num, dir); + } + /* else do nothing; reserved for future use */ + + spin_unlock(mEp->lock); + retval = usb_ep_queue(&mEp->ep, req, gfp_flags); + spin_lock(mEp->lock); + if (retval) + goto err_free_buf; + + return 0; + + err_free_buf: + kfree(req->buf); + err_free_req: + spin_unlock(mEp->lock); + usb_ep_free_request(&mEp->ep, req); + spin_lock(mEp->lock); + return retval; +} + +/** + * isr_setup_status_complete: setup_status request complete function + * @ep: endpoint + * @req: request handled + * + * Caller must release lock. Put the port in test mode if test mode + * feature is selected. + */ +static void +isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct ci13xxx *udc = req->context; + unsigned long flags; + + if (udc->setaddr) { + hw_usb_set_address(udc, udc->address); + udc->setaddr = false; + } + + spin_lock_irqsave(&udc->lock, flags); + if (udc->test_mode) + hw_port_test_set(udc, udc->test_mode); + spin_unlock_irqrestore(&udc->lock, flags); +} + +/** + * isr_setup_status_phase: queues the status phase of a setup transation + * @udc: udc struct + * + * This function returns an error code + */ +static int isr_setup_status_phase(struct ci13xxx *udc) +__releases(mEp->lock) +__acquires(mEp->lock) +{ + int retval; + struct ci13xxx_ep *mEp; + + mEp = (udc->ep0_dir == TX) ? udc->ep0out : udc->ep0in; + udc->status->context = udc; + udc->status->complete = isr_setup_status_complete; + + spin_unlock(mEp->lock); + retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC); + spin_lock(mEp->lock); + + return retval; +} + +/** + * isr_tr_complete_low: transaction complete low level handler + * @mEp: endpoint + * + * This function returns an error code + * Caller must hold lock + */ +static int isr_tr_complete_low(struct ci13xxx_ep *mEp) +__releases(mEp->lock) +__acquires(mEp->lock) +{ + struct ci13xxx_req *mReq, *mReqTemp; + struct ci13xxx_ep *mEpTemp = mEp; + int uninitialized_var(retval); + + if (list_empty(&mEp->qh.queue)) + return -EINVAL; + + list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue, + queue) { + retval = _hardware_dequeue(mEp, mReq); + if (retval < 0) + break; + list_del_init(&mReq->queue); + dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); + if (mReq->req.complete != NULL) { + spin_unlock(mEp->lock); + if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) && + mReq->req.length) + mEpTemp = mEp->udc->ep0in; + mReq->req.complete(&mEpTemp->ep, &mReq->req); + spin_lock(mEp->lock); + } + } + + if (retval == -EBUSY) + retval = 0; + if (retval < 0) + dbg_event(_usb_addr(mEp), "DONE", retval); + + return retval; +} + +/** + * isr_tr_complete_handler: transaction complete interrupt handler + * @udc: UDC descriptor + * + * This function handles traffic events + */ +static void isr_tr_complete_handler(struct ci13xxx *udc) +__releases(udc->lock) +__acquires(udc->lock) +{ + unsigned i; + u8 tmode = 0; + + for (i = 0; i < udc->hw_ep_max; i++) { + struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; + int type, num, dir, err = -EINVAL; + struct usb_ctrlrequest req; + + if (mEp->ep.desc == NULL) + continue; /* not configured */ + + if (hw_test_and_clear_complete(udc, i)) { + err = isr_tr_complete_low(mEp); + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { + if (err > 0) /* needs status phase */ + err = isr_setup_status_phase(udc); + if (err < 0) { + dbg_event(_usb_addr(mEp), + "ERROR", err); + spin_unlock(&udc->lock); + if (usb_ep_set_halt(&mEp->ep)) + dev_err(udc->dev, + "error: ep_set_halt\n"); + spin_lock(&udc->lock); + } + } + } + + if (mEp->type != USB_ENDPOINT_XFER_CONTROL || + !hw_test_and_clear_setup_status(udc, i)) + continue; + + if (i != 0) { + dev_warn(udc->dev, "ctrl traffic at endpoint %d\n", i); + continue; + } + + /* + * Flush data and handshake transactions of previous + * setup packet. + */ + _ep_nuke(udc->ep0out); + _ep_nuke(udc->ep0in); + + /* read_setup_packet */ + do { + hw_test_and_set_setup_guard(udc); + memcpy(&req, &mEp->qh.ptr->setup, sizeof(req)); + } while (!hw_test_and_clear_setup_guard(udc)); + + type = req.bRequestType; + + udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX; + + dbg_setup(_usb_addr(mEp), &req); + + switch (req.bRequest) { + case USB_REQ_CLEAR_FEATURE: + if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && + le16_to_cpu(req.wValue) == + USB_ENDPOINT_HALT) { + if (req.wLength != 0) + break; + num = le16_to_cpu(req.wIndex); + dir = num & USB_ENDPOINT_DIR_MASK; + num &= USB_ENDPOINT_NUMBER_MASK; + if (dir) /* TX */ + num += udc->hw_ep_max/2; + if (!udc->ci13xxx_ep[num].wedge) { + spin_unlock(&udc->lock); + err = usb_ep_clear_halt( + &udc->ci13xxx_ep[num].ep); + spin_lock(&udc->lock); + if (err) + break; + } + err = isr_setup_status_phase(udc); + } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && + le16_to_cpu(req.wValue) == + USB_DEVICE_REMOTE_WAKEUP) { + if (req.wLength != 0) + break; + udc->remote_wakeup = 0; + err = isr_setup_status_phase(udc); + } else { + goto delegate; + } + break; + case USB_REQ_GET_STATUS: + if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && + type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && + type != (USB_DIR_IN|USB_RECIP_INTERFACE)) + goto delegate; + if (le16_to_cpu(req.wLength) != 2 || + le16_to_cpu(req.wValue) != 0) + break; + err = isr_get_status_response(udc, &req); + break; + case USB_REQ_SET_ADDRESS: + if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) + goto delegate; + if (le16_to_cpu(req.wLength) != 0 || + le16_to_cpu(req.wIndex) != 0) + break; + udc->address = (u8)le16_to_cpu(req.wValue); + udc->setaddr = true; + err = isr_setup_status_phase(udc); + break; + case USB_REQ_SET_FEATURE: + if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && + le16_to_cpu(req.wValue) == + USB_ENDPOINT_HALT) { + if (req.wLength != 0) + break; + num = le16_to_cpu(req.wIndex); + dir = num & USB_ENDPOINT_DIR_MASK; + num &= USB_ENDPOINT_NUMBER_MASK; + if (dir) /* TX */ + num += udc->hw_ep_max/2; + + spin_unlock(&udc->lock); + err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); + spin_lock(&udc->lock); + if (!err) + isr_setup_status_phase(udc); + } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { + if (req.wLength != 0) + break; + switch (le16_to_cpu(req.wValue)) { + case USB_DEVICE_REMOTE_WAKEUP: + udc->remote_wakeup = 1; + err = isr_setup_status_phase(udc); + break; + case USB_DEVICE_TEST_MODE: + tmode = le16_to_cpu(req.wIndex) >> 8; + switch (tmode) { + case TEST_J: + case TEST_K: + case TEST_SE0_NAK: + case TEST_PACKET: + case TEST_FORCE_EN: + udc->test_mode = tmode; + err = isr_setup_status_phase( + udc); + break; + default: + break; + } + default: + goto delegate; + } + } else { + goto delegate; + } + break; + default: +delegate: + if (req.wLength == 0) /* no data phase */ + udc->ep0_dir = TX; + + spin_unlock(&udc->lock); + err = udc->driver->setup(&udc->gadget, &req); + spin_lock(&udc->lock); + break; + } + + if (err < 0) { + dbg_event(_usb_addr(mEp), "ERROR", err); + + spin_unlock(&udc->lock); + if (usb_ep_set_halt(&mEp->ep)) + dev_err(udc->dev, "error: ep_set_halt\n"); + spin_lock(&udc->lock); + } + } +} + +/****************************************************************************** + * ENDPT block + *****************************************************************************/ +/** + * ep_enable: configure endpoint, making it usable + * + * Check usb_ep_enable() at "usb_gadget.h" for details + */ +static int ep_enable(struct usb_ep *ep, + const struct usb_endpoint_descriptor *desc) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + int retval = 0; + unsigned long flags; + + if (ep == NULL || desc == NULL) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + + /* only internal SW should enable ctrl endpts */ + + mEp->ep.desc = desc; + + if (!list_empty(&mEp->qh.queue)) + dev_warn(mEp->udc->dev, "enabling a non-empty endpoint!\n"); + + mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX; + mEp->num = usb_endpoint_num(desc); + mEp->type = usb_endpoint_type(desc); + + mEp->ep.maxpacket = usb_endpoint_maxp(desc); + + dbg_event(_usb_addr(mEp), "ENABLE", 0); + + mEp->qh.ptr->cap = 0; + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) + mEp->qh.ptr->cap |= QH_IOS; + else if (mEp->type == USB_ENDPOINT_XFER_ISOC) + mEp->qh.ptr->cap &= ~QH_MULT; + else + mEp->qh.ptr->cap &= ~QH_ZLT; + + mEp->qh.ptr->cap |= + (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; + mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */ + + /* + * Enable endpoints in the HW other than ep0 as ep0 + * is always enabled + */ + if (mEp->num) + retval |= hw_ep_enable(mEp->udc, mEp->num, mEp->dir, mEp->type); + + spin_unlock_irqrestore(mEp->lock, flags); + return retval; +} + +/** + * ep_disable: endpoint is no longer usable + * + * Check usb_ep_disable() at "usb_gadget.h" for details + */ +static int ep_disable(struct usb_ep *ep) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + int direction, retval = 0; + unsigned long flags; + + if (ep == NULL) + return -EINVAL; + else if (mEp->ep.desc == NULL) + return -EBUSY; + + spin_lock_irqsave(mEp->lock, flags); + + /* only internal SW should disable ctrl endpts */ + + direction = mEp->dir; + do { + dbg_event(_usb_addr(mEp), "DISABLE", 0); + + retval |= _ep_nuke(mEp); + retval |= hw_ep_disable(mEp->udc, mEp->num, mEp->dir); + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) + mEp->dir = (mEp->dir == TX) ? RX : TX; + + } while (mEp->dir != direction); + + mEp->ep.desc = NULL; + + spin_unlock_irqrestore(mEp->lock, flags); + return retval; +} + +/** + * ep_alloc_request: allocate a request object to use with this endpoint + * + * Check usb_ep_alloc_request() at "usb_gadget.h" for details + */ +static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = NULL; + + if (ep == NULL) + return NULL; + + mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags); + if (mReq != NULL) { + INIT_LIST_HEAD(&mReq->queue); + + mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags, + &mReq->dma); + if (mReq->ptr == NULL) { + kfree(mReq); + mReq = NULL; + } + } + + dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); + + return (mReq == NULL) ? NULL : &mReq->req; +} + +/** + * ep_free_request: frees a request object + * + * Check usb_ep_free_request() at "usb_gadget.h" for details + */ +static void ep_free_request(struct usb_ep *ep, struct usb_request *req) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); + unsigned long flags; + + if (ep == NULL || req == NULL) { + return; + } else if (!list_empty(&mReq->queue)) { + dev_err(mEp->udc->dev, "freeing queued request\n"); + return; + } + + spin_lock_irqsave(mEp->lock, flags); + + if (mReq->ptr) + dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma); + kfree(mReq); + + dbg_event(_usb_addr(mEp), "FREE", 0); + + spin_unlock_irqrestore(mEp->lock, flags); +} + +/** + * ep_queue: queues (submits) an I/O request to an endpoint + * + * Check usb_ep_queue()* at usb_gadget.h" for details + */ +static int ep_queue(struct usb_ep *ep, struct usb_request *req, + gfp_t __maybe_unused gfp_flags) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); + struct ci13xxx *udc = mEp->udc; + int retval = 0; + unsigned long flags; + + if (ep == NULL || req == NULL || mEp->ep.desc == NULL) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { + if (req->length) + mEp = (udc->ep0_dir == RX) ? + udc->ep0out : udc->ep0in; + if (!list_empty(&mEp->qh.queue)) { + _ep_nuke(mEp); + retval = -EOVERFLOW; + dev_warn(mEp->udc->dev, "endpoint ctrl %X nuked\n", + _usb_addr(mEp)); + } + } + + /* first nuke then test link, e.g. previous status has not sent */ + if (!list_empty(&mReq->queue)) { + retval = -EBUSY; + dev_err(mEp->udc->dev, "request already in queue\n"); + goto done; + } + + if (req->length > 4 * CI13XXX_PAGE_SIZE) { + req->length = 4 * CI13XXX_PAGE_SIZE; + retval = -EMSGSIZE; + dev_warn(mEp->udc->dev, "request length truncated\n"); + } + + dbg_queue(_usb_addr(mEp), req, retval); + + /* push request */ + mReq->req.status = -EINPROGRESS; + mReq->req.actual = 0; + + retval = _hardware_enqueue(mEp, mReq); + + if (retval == -EALREADY) { + dbg_event(_usb_addr(mEp), "QUEUE", retval); + retval = 0; + } + if (!retval) + list_add_tail(&mReq->queue, &mEp->qh.queue); + + done: + spin_unlock_irqrestore(mEp->lock, flags); + return retval; +} + +/** + * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint + * + * Check usb_ep_dequeue() at "usb_gadget.h" for details + */ +static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); + unsigned long flags; + + if (ep == NULL || req == NULL || mReq->req.status != -EALREADY || + mEp->ep.desc == NULL || list_empty(&mReq->queue) || + list_empty(&mEp->qh.queue)) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + + dbg_event(_usb_addr(mEp), "DEQUEUE", 0); + + hw_ep_flush(mEp->udc, mEp->num, mEp->dir); + + /* pop request */ + list_del_init(&mReq->queue); + + usb_gadget_unmap_request(&mEp->udc->gadget, req, mEp->dir); + + req->status = -ECONNRESET; + + if (mReq->req.complete != NULL) { + spin_unlock(mEp->lock); + mReq->req.complete(&mEp->ep, &mReq->req); + spin_lock(mEp->lock); + } + + spin_unlock_irqrestore(mEp->lock, flags); + return 0; +} + +/** + * ep_set_halt: sets the endpoint halt feature + * + * Check usb_ep_set_halt() at "usb_gadget.h" for details + */ +static int ep_set_halt(struct usb_ep *ep, int value) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + int direction, retval = 0; + unsigned long flags; + + if (ep == NULL || mEp->ep.desc == NULL) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + +#ifndef STALL_IN + /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ + if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX && + !list_empty(&mEp->qh.queue)) { + spin_unlock_irqrestore(mEp->lock, flags); + return -EAGAIN; + } +#endif + + direction = mEp->dir; + do { + dbg_event(_usb_addr(mEp), "HALT", value); + retval |= hw_ep_set_halt(mEp->udc, mEp->num, mEp->dir, value); + + if (!value) + mEp->wedge = 0; + + if (mEp->type == USB_ENDPOINT_XFER_CONTROL) + mEp->dir = (mEp->dir == TX) ? RX : TX; + + } while (mEp->dir != direction); + + spin_unlock_irqrestore(mEp->lock, flags); + return retval; +} + +/** + * ep_set_wedge: sets the halt feature and ignores clear requests + * + * Check usb_ep_set_wedge() at "usb_gadget.h" for details + */ +static int ep_set_wedge(struct usb_ep *ep) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + unsigned long flags; + + if (ep == NULL || mEp->ep.desc == NULL) + return -EINVAL; + + spin_lock_irqsave(mEp->lock, flags); + + dbg_event(_usb_addr(mEp), "WEDGE", 0); + mEp->wedge = 1; + + spin_unlock_irqrestore(mEp->lock, flags); + + return usb_ep_set_halt(ep); +} + +/** + * ep_fifo_flush: flushes contents of a fifo + * + * Check usb_ep_fifo_flush() at "usb_gadget.h" for details + */ +static void ep_fifo_flush(struct usb_ep *ep) +{ + struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); + unsigned long flags; + + if (ep == NULL) { + dev_err(mEp->udc->dev, "%02X: -EINVAL\n", _usb_addr(mEp)); + return; + } + + spin_lock_irqsave(mEp->lock, flags); + + dbg_event(_usb_addr(mEp), "FFLUSH", 0); + hw_ep_flush(mEp->udc, mEp->num, mEp->dir); + + spin_unlock_irqrestore(mEp->lock, flags); +} + +/** + * Endpoint-specific part of the API to the USB controller hardware + * Check "usb_gadget.h" for details + */ +static const struct usb_ep_ops usb_ep_ops = { + .enable = ep_enable, + .disable = ep_disable, + .alloc_request = ep_alloc_request, + .free_request = ep_free_request, + .queue = ep_queue, + .dequeue = ep_dequeue, + .set_halt = ep_set_halt, + .set_wedge = ep_set_wedge, + .fifo_flush = ep_fifo_flush, +}; + +/****************************************************************************** + * GADGET block + *****************************************************************************/ +static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) +{ + struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); + unsigned long flags; + int gadget_ready = 0; + + if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS)) + return -EOPNOTSUPP; + + spin_lock_irqsave(&udc->lock, flags); + udc->vbus_active = is_active; + if (udc->driver) + gadget_ready = 1; + spin_unlock_irqrestore(&udc->lock, flags); + + if (gadget_ready) { + if (is_active) { + pm_runtime_get_sync(&_gadget->dev); + hw_device_reset(udc, USBMODE_CM_DC); + hw_device_state(udc, udc->ep0out->qh.dma); + } else { + hw_device_state(udc, 0); + if (udc->udc_driver->notify_event) + udc->udc_driver->notify_event(udc, + CI13XXX_CONTROLLER_STOPPED_EVENT); + _gadget_stop_activity(&udc->gadget); + pm_runtime_put_sync(&_gadget->dev); + } + } + + return 0; +} + +static int ci13xxx_wakeup(struct usb_gadget *_gadget) +{ + struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&udc->lock, flags); + if (!udc->remote_wakeup) { + ret = -EOPNOTSUPP; + goto out; + } + if (!hw_read(udc, OP_PORTSC, PORTSC_SUSP)) { + ret = -EINVAL; + goto out; + } + hw_write(udc, OP_PORTSC, PORTSC_FPR, PORTSC_FPR); +out: + spin_unlock_irqrestore(&udc->lock, flags); + return ret; +} + +static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) +{ + struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); + + if (udc->transceiver) + return usb_phy_set_power(udc->transceiver, mA); + return -ENOTSUPP; +} + +static int ci13xxx_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int ci13xxx_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +/** + * Device operations part of the API to the USB controller hardware, + * which don't involve endpoints (or i/o) + * Check "usb_gadget.h" for details + */ +static const struct usb_gadget_ops usb_gadget_ops = { + .vbus_session = ci13xxx_vbus_session, + .wakeup = ci13xxx_wakeup, + .vbus_draw = ci13xxx_vbus_draw, + .udc_start = ci13xxx_start, + .udc_stop = ci13xxx_stop, +}; + +static int init_eps(struct ci13xxx *udc) +{ + int retval = 0, i, j; + + for (i = 0; i < udc->hw_ep_max/2; i++) + for (j = RX; j <= TX; j++) { + int k = i + j * udc->hw_ep_max/2; + struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k]; + + scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i, + (j == TX) ? "in" : "out"); + + mEp->udc = udc; + mEp->lock = &udc->lock; + mEp->td_pool = udc->td_pool; + + mEp->ep.name = mEp->name; + mEp->ep.ops = &usb_ep_ops; + mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; + + INIT_LIST_HEAD(&mEp->qh.queue); + mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL, + &mEp->qh.dma); + if (mEp->qh.ptr == NULL) + retval = -ENOMEM; + else + memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr)); + + /* + * set up shorthands for ep0 out and in endpoints, + * don't add to gadget's ep_list + */ + if (i == 0) { + if (j == RX) + udc->ep0out = mEp; + else + udc->ep0in = mEp; + + continue; + } + + list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); + } + + return retval; +} + +/** + * ci13xxx_start: register a gadget driver + * @gadget: our gadget + * @driver: the driver being registered + * + * Interrupts are enabled here. + */ +static int ci13xxx_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); + unsigned long flags; + int retval = -ENOMEM; + + if (driver->disconnect == NULL) + return -EINVAL; + + + udc->ep0out->ep.desc = &ctrl_endpt_out_desc; + retval = usb_ep_enable(&udc->ep0out->ep); + if (retval) + return retval; + + udc->ep0in->ep.desc = &ctrl_endpt_in_desc; + retval = usb_ep_enable(&udc->ep0in->ep); + if (retval) + return retval; + spin_lock_irqsave(&udc->lock, flags); + + udc->driver = driver; + pm_runtime_get_sync(&udc->gadget.dev); + if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { + if (udc->vbus_active) { + if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) + hw_device_reset(udc, USBMODE_CM_DC); + } else { + pm_runtime_put_sync(&udc->gadget.dev); + goto done; + } + } + + retval = hw_device_state(udc, udc->ep0out->qh.dma); + if (retval) + pm_runtime_put_sync(&udc->gadget.dev); + + done: + spin_unlock_irqrestore(&udc->lock, flags); + return retval; +} + +/** + * ci13xxx_stop: unregister a gadget driver + */ +static int ci13xxx_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) +{ + struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); + unsigned long flags; + + spin_lock_irqsave(&udc->lock, flags); + + if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) || + udc->vbus_active) { + hw_device_state(udc, 0); + if (udc->udc_driver->notify_event) + udc->udc_driver->notify_event(udc, + CI13XXX_CONTROLLER_STOPPED_EVENT); + udc->driver = NULL; + spin_unlock_irqrestore(&udc->lock, flags); + _gadget_stop_activity(&udc->gadget); + spin_lock_irqsave(&udc->lock, flags); + pm_runtime_put(&udc->gadget.dev); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/****************************************************************************** + * BUS block + *****************************************************************************/ +/** + * udc_irq: udc interrupt handler + * + * This function returns IRQ_HANDLED if the IRQ has been handled + * It locks access to registers + */ +static irqreturn_t udc_irq(struct ci13xxx *udc) +{ + irqreturn_t retval; + u32 intr; + + if (udc == NULL) + return IRQ_HANDLED; + + spin_lock(&udc->lock); + + if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) { + if (hw_read(udc, OP_USBMODE, USBMODE_CM) != + USBMODE_CM_DC) { + spin_unlock(&udc->lock); + return IRQ_NONE; + } + } + intr = hw_test_and_clear_intr_active(udc); + dbg_interrupt(intr); + + if (intr) { + /* order defines priority - do NOT change it */ + if (USBi_URI & intr) + isr_reset_handler(udc); + + if (USBi_PCI & intr) { + udc->gadget.speed = hw_port_is_high_speed(udc) ? + USB_SPEED_HIGH : USB_SPEED_FULL; + if (udc->suspended && udc->driver->resume) { + spin_unlock(&udc->lock); + udc->driver->resume(&udc->gadget); + spin_lock(&udc->lock); + udc->suspended = 0; + } + } + + if (USBi_UI & intr) + isr_tr_complete_handler(udc); + + if (USBi_SLI & intr) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN && + udc->driver->suspend) { + udc->suspended = 1; + spin_unlock(&udc->lock); + udc->driver->suspend(&udc->gadget); + spin_lock(&udc->lock); + } + } + retval = IRQ_HANDLED; + } else { + retval = IRQ_NONE; + } + spin_unlock(&udc->lock); + + return retval; +} + +/** + * udc_release: driver release function + * @dev: device + * + * Currently does nothing + */ +static void udc_release(struct device *dev) +{ +} + +/** + * udc_start: initialize gadget role + * @udc: chipidea controller + */ +static int udc_start(struct ci13xxx *udc) +{ + struct device *dev = udc->dev; + int retval = 0; + + if (!udc) + return -EINVAL; + + spin_lock_init(&udc->lock); + + udc->gadget.ops = &usb_gadget_ops; + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.max_speed = USB_SPEED_HIGH; + udc->gadget.is_otg = 0; + udc->gadget.name = udc->udc_driver->name; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + + dev_set_name(&udc->gadget.dev, "gadget"); + udc->gadget.dev.dma_mask = dev->dma_mask; + udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask; + udc->gadget.dev.parent = dev; + udc->gadget.dev.release = udc_release; + + /* alloc resources */ + udc->qh_pool = dma_pool_create("ci13xxx_qh", dev, + sizeof(struct ci13xxx_qh), + 64, CI13XXX_PAGE_SIZE); + if (udc->qh_pool == NULL) + return -ENOMEM; + + udc->td_pool = dma_pool_create("ci13xxx_td", dev, + sizeof(struct ci13xxx_td), + 64, CI13XXX_PAGE_SIZE); + if (udc->td_pool == NULL) { + retval = -ENOMEM; + goto free_qh_pool; + } + + retval = init_eps(udc); + if (retval) + goto free_pools; + + udc->gadget.ep0 = &udc->ep0in->ep; + + udc->transceiver = usb_get_transceiver(); + + if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) { + if (udc->transceiver == NULL) { + retval = -ENODEV; + goto free_pools; + } + } + + if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) { + retval = hw_device_reset(udc, USBMODE_CM_DC); + if (retval) + goto put_transceiver; + } + + retval = device_register(&udc->gadget.dev); + if (retval) { + put_device(&udc->gadget.dev); + goto put_transceiver; + } + + retval = dbg_create_files(&udc->gadget.dev); + if (retval) + goto unreg_device; + + if (udc->transceiver) { + retval = otg_set_peripheral(udc->transceiver->otg, + &udc->gadget); + if (retval) + goto remove_dbg; + } + + retval = usb_add_gadget_udc(dev, &udc->gadget); + if (retval) + goto remove_trans; + + pm_runtime_no_callbacks(&udc->gadget.dev); + pm_runtime_enable(&udc->gadget.dev); + + return retval; + +remove_trans: + if (udc->transceiver) { + otg_set_peripheral(udc->transceiver->otg, &udc->gadget); + usb_put_transceiver(udc->transceiver); + } + + dev_err(dev, "error = %i\n", retval); +remove_dbg: + dbg_remove_files(&udc->gadget.dev); +unreg_device: + device_unregister(&udc->gadget.dev); +put_transceiver: + if (udc->transceiver) + usb_put_transceiver(udc->transceiver); +free_pools: + dma_pool_destroy(udc->td_pool); +free_qh_pool: + dma_pool_destroy(udc->qh_pool); + return retval; +} + +/** + * udc_remove: parent remove must call this to remove UDC + * + * No interrupts active, the IRQ has been released + */ +static void udc_stop(struct ci13xxx *udc) +{ + int i; + + if (udc == NULL) + return; + + usb_del_gadget_udc(&udc->gadget); + + for (i = 0; i < udc->hw_ep_max; i++) { + struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; + + dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); + } + + dma_pool_destroy(udc->td_pool); + dma_pool_destroy(udc->qh_pool); + + if (udc->transceiver) { + otg_set_peripheral(udc->transceiver->otg, NULL); + usb_put_transceiver(udc->transceiver); + } + dbg_remove_files(&udc->gadget.dev); + device_unregister(&udc->gadget.dev); + /* my kobject is dynamic, I swear! */ + memset(&udc->gadget, 0, sizeof(udc->gadget)); +} + +/** + * ci_hdrc_gadget_init - initialize device related bits + * ci: the controller + * + * This function enables the gadget role, if the device is "device capable". + */ +int ci_hdrc_gadget_init(struct ci13xxx *ci) +{ + struct ci_role_driver *rdrv; + + if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC)) + return -ENXIO; + + rdrv = devm_kzalloc(ci->dev, sizeof(struct ci_role_driver), GFP_KERNEL); + if (!rdrv) + return -ENOMEM; + + rdrv->start = udc_start; + rdrv->stop = udc_stop; + rdrv->irq = udc_irq; + rdrv->name = "gadget"; + ci->roles[CI_ROLE_GADGET] = rdrv; + + return 0; +} diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h new file mode 100644 index 000000000000..4ff2384d7ca8 --- /dev/null +++ b/drivers/usb/chipidea/udc.h @@ -0,0 +1,93 @@ +/* + * udc.h - ChipIdea UDC structures + * + * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. + * + * Author: David Lopo + * + * 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. + */ + +#ifndef __DRIVERS_USB_CHIPIDEA_UDC_H +#define __DRIVERS_USB_CHIPIDEA_UDC_H + +#include <linux/list.h> + +#define CTRL_PAYLOAD_MAX 64 +#define RX 0 /* similar to USB_DIR_OUT but can be used as an index */ +#define TX 1 /* similar to USB_DIR_IN but can be used as an index */ + +/* DMA layout of transfer descriptors */ +struct ci13xxx_td { + /* 0 */ + u32 next; +#define TD_TERMINATE BIT(0) +#define TD_ADDR_MASK (0xFFFFFFEUL << 5) + /* 1 */ + u32 token; +#define TD_STATUS (0x00FFUL << 0) +#define TD_STATUS_TR_ERR BIT(3) +#define TD_STATUS_DT_ERR BIT(5) +#define TD_STATUS_HALTED BIT(6) +#define TD_STATUS_ACTIVE BIT(7) +#define TD_MULTO (0x0003UL << 10) +#define TD_IOC BIT(15) +#define TD_TOTAL_BYTES (0x7FFFUL << 16) + /* 2 */ + u32 page[5]; +#define TD_CURR_OFFSET (0x0FFFUL << 0) +#define TD_FRAME_NUM (0x07FFUL << 0) +#define TD_RESERVED_MASK (0x0FFFUL << 0) +} __attribute__ ((packed)); + +/* DMA layout of queue heads */ +struct ci13xxx_qh { + /* 0 */ + u32 cap; +#define QH_IOS BIT(15) +#define QH_MAX_PKT (0x07FFUL << 16) +#define QH_ZLT BIT(29) +#define QH_MULT (0x0003UL << 30) + /* 1 */ + u32 curr; + /* 2 - 8 */ + struct ci13xxx_td td; + /* 9 */ + u32 RESERVED; + struct usb_ctrlrequest setup; +} __attribute__ ((packed)); + +/** + * struct ci13xxx_req - usb request representation + * @req: request structure for gadget drivers + * @queue: link to QH list + * @ptr: transfer descriptor for this request + * @dma: dma address for the transfer descriptor + * @zptr: transfer descriptor for the zero packet + * @zdma: dma address of the zero packet's transfer descriptor + */ +struct ci13xxx_req { + struct usb_request req; + struct list_head queue; + struct ci13xxx_td *ptr; + dma_addr_t dma; + struct ci13xxx_td *zptr; + dma_addr_t zdma; +}; + +#ifdef CONFIG_USB_CHIPIDEA_UDC + +int ci_hdrc_gadget_init(struct ci13xxx *ci); + +#else + +static inline int ci_hdrc_gadget_init(struct ci13xxx *ci) +{ + return -ENXIO; +} + +#endif + +#endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */ diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c index b32ccb461019..f2a120eea9d4 100644 --- a/drivers/usb/class/cdc-acm.c +++ b/drivers/usb/class/cdc-acm.c @@ -1664,6 +1664,7 @@ static struct usb_driver acm_driver = { #ifdef CONFIG_PM .supports_autosuspend = 1, #endif + .disable_hub_initiated_lpm = 1, }; /* diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 0bb2b3248dad..ea8b304f0e85 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -309,9 +309,6 @@ static void free_urbs(struct wdm_device *desc) static void cleanup(struct wdm_device *desc) { - spin_lock(&wdm_device_list_lock); - list_del(&desc->device_list); - spin_unlock(&wdm_device_list_lock); kfree(desc->sbuf); kfree(desc->inbuf); kfree(desc->orq); @@ -369,6 +366,7 @@ static ssize_t wdm_write r = usb_autopm_get_interface(desc->intf); if (r < 0) { kfree(buf); + rv = usb_translate_errors(r); goto outnp; } @@ -384,6 +382,7 @@ static ssize_t wdm_write if (r < 0) { kfree(buf); + rv = r; goto out; } @@ -415,6 +414,7 @@ static ssize_t wdm_write desc->outbuf = NULL; clear_bit(WDM_IN_USE, &desc->flags); dev_err(&desc->intf->dev, "Tx URB error: %d\n", rv); + rv = usb_translate_errors(rv); } else { dev_dbg(&desc->intf->dev, "Tx URB has been submitted index=%d", req->wIndex); @@ -530,11 +530,13 @@ static int wdm_flush(struct file *file, fl_owner_t id) struct wdm_device *desc = file->private_data; wait_event(desc->wait, !test_bit(WDM_IN_USE, &desc->flags)); - if (desc->werr < 0) + + /* cannot dereference desc->intf if WDM_DISCONNECTING */ + if (desc->werr < 0 && !test_bit(WDM_DISCONNECTING, &desc->flags)) dev_err(&desc->intf->dev, "Error in flush path: %d\n", desc->werr); - return desc->werr; + return usb_translate_errors(desc->werr); } static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) @@ -545,7 +547,7 @@ static unsigned int wdm_poll(struct file *file, struct poll_table_struct *wait) spin_lock_irqsave(&desc->iuspin, flags); if (test_bit(WDM_DISCONNECTING, &desc->flags)) { - mask = POLLERR; + mask = POLLHUP | POLLERR; spin_unlock_irqrestore(&desc->iuspin, flags); goto desc_out; } @@ -596,6 +598,7 @@ static int wdm_open(struct inode *inode, struct file *file) desc->count--; dev_err(&desc->intf->dev, "Error submitting int urb - %d\n", rv); + rv = usb_translate_errors(rv); } } else { rv = 0; @@ -621,10 +624,15 @@ static int wdm_release(struct inode *inode, struct file *file) mutex_unlock(&desc->wlock); if (!desc->count) { - dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); - kill_urbs(desc); - if (!test_bit(WDM_DISCONNECTING, &desc->flags)) + if (!test_bit(WDM_DISCONNECTING, &desc->flags)) { + dev_dbg(&desc->intf->dev, "wdm_release: cleanup"); + kill_urbs(desc); desc->manage_power(desc->intf, 0); + } else { + /* must avoid dev_printk here as desc->intf is invalid */ + pr_debug(KBUILD_MODNAME " %s: device gone - cleaning up\n", __func__); + cleanup(desc); + } } mutex_unlock(&wdm_mutex); return 0; @@ -771,6 +779,9 @@ static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor out: return rv; err: + spin_lock(&wdm_device_list_lock); + list_del(&desc->device_list); + spin_unlock(&wdm_device_list_lock); cleanup(desc); return rv; } @@ -896,8 +907,16 @@ static void wdm_disconnect(struct usb_interface *intf) cancel_work_sync(&desc->rxwork); mutex_unlock(&desc->wlock); mutex_unlock(&desc->rlock); + + /* the desc->intf pointer used as list key is now invalid */ + spin_lock(&wdm_device_list_lock); + list_del(&desc->device_list); + spin_unlock(&wdm_device_list_lock); + if (!desc->count) cleanup(desc); + else + dev_dbg(&intf->dev, "%s: %d open files - postponing cleanup\n", __func__, desc->count); mutex_unlock(&wdm_mutex); } @@ -1015,6 +1034,7 @@ static struct usb_driver wdm_driver = { .post_reset = wdm_post_reset, .id_table = wdm_ids, .supports_autosuspend = 1, + .disable_hub_initiated_lpm = 1, }; module_usb_driver(wdm_driver); diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index a68c1a63dc65..d4c47d5d7625 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -172,27 +172,31 @@ struct usblp { #ifdef DEBUG static void usblp_dump(struct usblp *usblp) { + struct device *dev = &usblp->intf->dev; int p; - dbg("usblp=0x%p", usblp); - dbg("dev=0x%p", usblp->dev); - dbg("present=%d", usblp->present); - dbg("readbuf=0x%p", usblp->readbuf); - dbg("readcount=%d", usblp->readcount); - dbg("ifnum=%d", usblp->ifnum); - for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { - dbg("protocol[%d].alt_setting=%d", p, usblp->protocol[p].alt_setting); - dbg("protocol[%d].epwrite=%p", p, usblp->protocol[p].epwrite); - dbg("protocol[%d].epread=%p", p, usblp->protocol[p].epread); - } - dbg("current_protocol=%d", usblp->current_protocol); - dbg("minor=%d", usblp->minor); - dbg("wstatus=%d", usblp->wstatus); - dbg("rstatus=%d", usblp->rstatus); - dbg("quirks=%d", usblp->quirks); - dbg("used=%d", usblp->used); - dbg("bidir=%d", usblp->bidir); - dbg("device_id_string=\"%s\"", + dev_dbg(dev, "usblp=0x%p\n", usblp); + dev_dbg(dev, "dev=0x%p\n", usblp->dev); + dev_dbg(dev, "present=%d\n", usblp->present); + dev_dbg(dev, "readbuf=0x%p\n", usblp->readbuf); + dev_dbg(dev, "readcount=%d\n", usblp->readcount); + dev_dbg(dev, "ifnum=%d\n", usblp->ifnum); + for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) { + dev_dbg(dev, "protocol[%d].alt_setting=%d\n", p, + usblp->protocol[p].alt_setting); + dev_dbg(dev, "protocol[%d].epwrite=%p\n", p, + usblp->protocol[p].epwrite); + dev_dbg(dev, "protocol[%d].epread=%p\n", p, + usblp->protocol[p].epread); + } + dev_dbg(dev, "current_protocol=%d\n", usblp->current_protocol); + dev_dbg(dev, "minor=%d\n", usblp->minor); + dev_dbg(dev, "wstatus=%d\n", usblp->wstatus); + dev_dbg(dev, "rstatus=%d\n", usblp->rstatus); + dev_dbg(dev, "quirks=%d\n", usblp->quirks); + dev_dbg(dev, "used=%d\n", usblp->used); + dev_dbg(dev, "bidir=%d\n", usblp->bidir); + dev_dbg(dev, "device_id_string=\"%s\"\n", usblp->device_id_string ? usblp->device_id_string + 2 : (unsigned char *)"(null)"); @@ -262,7 +266,8 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i retval = usb_control_msg(usblp->dev, dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0), request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT); - dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d", + dev_dbg(&usblp->intf->dev, + "usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d\n", request, !!dir, recip, value, index, len, retval); return retval < 0 ? retval : 0; } @@ -500,8 +505,9 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } - dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd), - _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd)); + dev_dbg(&usblp->intf->dev, + "usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)\n", cmd, + _IOC_TYPE(cmd), _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd)); if (_IOC_TYPE(cmd) == 'P') /* new-style ioctl number */ @@ -594,7 +600,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } - dbg("usblp%d requested/got HP channel %ld/%d", + dev_dbg(&usblp->intf->dev, + "usblp%d requested/got HP channel %ld/%d\n", usblp->minor, arg, newChannel); break; @@ -614,7 +621,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } - dbg("usblp%d is bus=%d, device=%d", + dev_dbg(&usblp->intf->dev, + "usblp%d is bus=%d, device=%d\n", usblp->minor, twoints[0], twoints[1]); break; @@ -634,7 +642,8 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg) goto done; } - dbg("usblp%d is VID=0x%4.4X, PID=0x%4.4X", + dev_dbg(&usblp->intf->dev, + "usblp%d is VID=0x%4.4X, PID=0x%4.4X\n", usblp->minor, twoints[0], twoints[1]); break; @@ -987,7 +996,7 @@ static int usblp_submit_read(struct usblp *usblp) usblp->rcomplete = 0; spin_unlock_irqrestore(&usblp->lock, flags); if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) { - dbg("error submitting urb (%d)", rc); + dev_dbg(&usblp->intf->dev, "error submitting urb (%d)\n", rc); spin_lock_irqsave(&usblp->lock, flags); usblp->rstatus = rc; usblp->rcomplete = 1; @@ -1129,7 +1138,8 @@ static int usblp_probe(struct usb_interface *intf, /* Analyze and pick initial alternate settings and endpoints. */ protocol = usblp_select_alts(usblp); if (protocol < 0) { - dbg("incompatible printer-class device 0x%4.4X/0x%4.4X", + dev_dbg(&intf->dev, + "incompatible printer-class device 0x%4.4X/0x%4.4X\n", le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); retval = -ENODEV; @@ -1158,14 +1168,14 @@ static int usblp_probe(struct usb_interface *intf, retval = usb_register_dev(intf, &usblp_class); if (retval) { - printk(KERN_ERR "usblp: Not able to get a minor" - " (base %u, slice default): %d\n", - USBLP_MINOR_BASE, retval); + dev_err(&intf->dev, + "usblp: Not able to get a minor (base %u, slice default): %d\n", + USBLP_MINOR_BASE, retval); goto abort_intfdata; } usblp->minor = intf->minor; - printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d " - "if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n", + dev_info(&intf->dev, + "usblp%d: USB %sdirectional printer dev %d if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n", usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum, usblp->ifnum, usblp->protocol[usblp->current_protocol].alt_setting, @@ -1302,7 +1312,8 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol) usblp->bidir = (usblp->protocol[protocol].epread != NULL); usblp->current_protocol = protocol; - dbg("usblp%d set protocol %d", usblp->minor, protocol); + dev_dbg(&usblp->intf->dev, "usblp%d set protocol %d\n", + usblp->minor, protocol); return 0; } @@ -1315,7 +1326,8 @@ static int usblp_cache_device_id_string(struct usblp *usblp) err = usblp_get_id(usblp, 0, usblp->device_id_string, USBLP_DEVICE_ID_SIZE - 1); if (err < 0) { - dbg("usblp%d: error = %d reading IEEE-1284 Device ID string", + dev_dbg(&usblp->intf->dev, + "usblp%d: error = %d reading IEEE-1284 Device ID string\n", usblp->minor, err); usblp->device_id_string[0] = usblp->device_id_string[1] = '\0'; return -EIO; @@ -1331,7 +1343,7 @@ static int usblp_cache_device_id_string(struct usblp *usblp) length = USBLP_DEVICE_ID_SIZE - 1; usblp->device_id_string[length] = '\0'; - dbg("usblp%d Device ID string [len=%d]=\"%s\"", + dev_dbg(&usblp->intf->dev, "usblp%d Device ID string [len=%d]=\"%s\"\n", usblp->minor, length, &usblp->device_id_string[2]); return length; diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig index 18d02e32a3d5..9981984b365b 100644 --- a/drivers/usb/core/Kconfig +++ b/drivers/usb/core/Kconfig @@ -27,58 +27,6 @@ config USB_ANNOUNCE_NEW_DEVICES comment "Miscellaneous USB options" depends on USB -config USB_DEVICEFS - bool "USB device filesystem (DEPRECATED)" - depends on USB - ---help--- - If you say Y here (and to "/proc file system support" in the "File - systems" section, above), you will get a file /proc/bus/usb/devices - which lists the devices currently connected to your USB bus or - busses, and for every connected device a file named - "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the - device number; the latter files can be used by user space programs - to talk directly to the device. These files are "virtual", meaning - they are generated on the fly and not stored on the hard drive. - - You may need to mount the usbfs file system to see the files, use - mount -t usbfs none /proc/bus/usb - - For the format of the various /proc/bus/usb/ files, please read - <file:Documentation/usb/proc_usb_info.txt>. - - Modern Linux systems do not use this. - - Usbfs entries are files and not character devices; usbfs can't - handle Access Control Lists (ACL) which are the default way to - grant access to USB devices for untrusted users of a desktop - system. - - The usbfs functionality is replaced by real device-nodes managed by - udev. These nodes lived in /dev/bus/usb and are used by libusb. - -config USB_DEVICE_CLASS - bool "USB device class-devices (DEPRECATED)" - depends on USB - default y - ---help--- - Userspace access to USB devices is granted by device-nodes exported - directly from the usbdev in sysfs. Old versions of the driver - core and udev needed additional class devices to export device nodes. - - These additional devices are difficult to handle in userspace, if - information about USB interfaces must be available. One device - contains the device node, the other device contains the interface - data. Both devices are at the same level in sysfs (siblings) and one - can't access the other. The device node created directly by the - usb device is the parent device of the interface and therefore - easily accessible from the interface event. - - This option provides backward compatibility for libusb device - nodes (lsusb) when usbfs is not used, and the following udev rule - doesn't exist: - SUBSYSTEM=="usb", ACTION=="add", ENV{DEVTYPE}=="usb_device", \ - NAME="bus/usb/$env{BUSNUM}/$env{DEVNUM}", MODE="0644" - config USB_DYNAMIC_MINORS bool "Dynamic USB minor allocation" depends on USB @@ -125,7 +73,6 @@ config USB_OTG_WHITELIST bool "Rely on OTG Targeted Peripherals List" depends on USB_OTG || EXPERT default y if USB_OTG - default n if EXPERT help If you say Y here, the "otg_whitelist.h" file will be used as a product whitelist, so USB peripherals not listed there will be diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile index 507a4e1b6360..26059b93dbf4 100644 --- a/drivers/usb/core/Makefile +++ b/drivers/usb/core/Makefile @@ -9,6 +9,6 @@ usbcore-y += config.o file.o buffer.o sysfs.o endpoint.o usbcore-y += devio.o notify.o generic.o quirks.o devices.o usbcore-$(CONFIG_PCI) += hcd-pci.o -usbcore-$(CONFIG_USB_DEVICEFS) += inode.o +usbcore-$(CONFIG_ACPI) += usb-acpi.o obj-$(CONFIG_USB) += usbcore.o diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 8df4b76465ac..e0f107948eba 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -333,17 +333,14 @@ static struct async *async_getcompleted(struct dev_state *ps) static struct async *async_getpending(struct dev_state *ps, void __user *userurb) { - unsigned long flags; struct async *as; - spin_lock_irqsave(&ps->lock, flags); list_for_each_entry(as, &ps->async_pending, asynclist) if (as->userurb == userurb) { list_del_init(&as->asynclist); - spin_unlock_irqrestore(&ps->lock, flags); return as; } - spin_unlock_irqrestore(&ps->lock, flags); + return NULL; } @@ -398,6 +395,7 @@ static void cancel_bulk_urbs(struct dev_state *ps, unsigned bulk_addr) __releases(ps->lock) __acquires(ps->lock) { + struct urb *urb; struct async *as; /* Mark all the pending URBs that match bulk_addr, up to but not @@ -420,8 +418,11 @@ __acquires(ps->lock) list_for_each_entry(as, &ps->async_pending, asynclist) { if (as->bulk_status == AS_UNLINK) { as->bulk_status = 0; /* Only once */ + urb = as->urb; + usb_get_urb(urb); spin_unlock(&ps->lock); /* Allow completions */ - usb_unlink_urb(as->urb); + usb_unlink_urb(urb); + usb_put_urb(urb); spin_lock(&ps->lock); goto rescan; } @@ -472,6 +473,7 @@ static void async_completed(struct urb *urb) static void destroy_async(struct dev_state *ps, struct list_head *list) { + struct urb *urb; struct async *as; unsigned long flags; @@ -479,10 +481,13 @@ static void destroy_async(struct dev_state *ps, struct list_head *list) while (!list_empty(list)) { as = list_entry(list->next, struct async, asynclist); list_del_init(&as->asynclist); + urb = as->urb; + usb_get_urb(urb); /* drop the spinlock so the completion handler can run */ spin_unlock_irqrestore(&ps->lock, flags); - usb_kill_urb(as->urb); + usb_kill_urb(urb); + usb_put_urb(urb); spin_lock_irqsave(&ps->lock, flags); } spin_unlock_irqrestore(&ps->lock, flags); @@ -727,17 +732,6 @@ static int usbdev_open(struct inode *inode, struct file *file) if (imajor(inode) == USB_DEVICE_MAJOR) dev = usbdev_lookup_by_devt(inode->i_rdev); -#ifdef CONFIG_USB_DEVICEFS - /* procfs file */ - if (!dev) { - dev = inode->i_private; - if (dev && dev->usbfs_dentry && - dev->usbfs_dentry->d_inode == inode) - usb_get_dev(dev); - else - dev = NULL; - } -#endif mutex_unlock(&usbfs_mutex); if (!dev) @@ -1410,12 +1404,24 @@ static int proc_submiturb(struct dev_state *ps, void __user *arg) static int proc_unlinkurb(struct dev_state *ps, void __user *arg) { + struct urb *urb; struct async *as; + unsigned long flags; + spin_lock_irqsave(&ps->lock, flags); as = async_getpending(ps, arg); - if (!as) + if (!as) { + spin_unlock_irqrestore(&ps->lock, flags); return -EINVAL; - usb_kill_urb(as->urb); + } + + urb = as->urb; + usb_get_urb(urb); + spin_unlock_irqrestore(&ps->lock, flags); + + usb_kill_urb(urb); + usb_put_urb(urb); + return 0; } @@ -2062,44 +2068,13 @@ static void usbdev_remove(struct usb_device *udev) } } -#ifdef CONFIG_USB_DEVICE_CLASS -static struct class *usb_classdev_class; - -static int usb_classdev_add(struct usb_device *dev) -{ - struct device *cldev; - - cldev = device_create(usb_classdev_class, &dev->dev, dev->dev.devt, - NULL, "usbdev%d.%d", dev->bus->busnum, - dev->devnum); - if (IS_ERR(cldev)) - return PTR_ERR(cldev); - dev->usb_classdev = cldev; - return 0; -} - -static void usb_classdev_remove(struct usb_device *dev) -{ - if (dev->usb_classdev) - device_unregister(dev->usb_classdev); -} - -#else -#define usb_classdev_add(dev) 0 -#define usb_classdev_remove(dev) do {} while (0) - -#endif - static int usbdev_notify(struct notifier_block *self, unsigned long action, void *dev) { switch (action) { case USB_DEVICE_ADD: - if (usb_classdev_add(dev)) - return NOTIFY_BAD; break; case USB_DEVICE_REMOVE: - usb_classdev_remove(dev); usbdev_remove(dev); break; } @@ -2129,21 +2104,6 @@ int __init usb_devio_init(void) USB_DEVICE_MAJOR); goto error_cdev; } -#ifdef CONFIG_USB_DEVICE_CLASS - usb_classdev_class = class_create(THIS_MODULE, "usb_device"); - if (IS_ERR(usb_classdev_class)) { - printk(KERN_ERR "Unable to register usb_device class\n"); - retval = PTR_ERR(usb_classdev_class); - cdev_del(&usb_device_cdev); - usb_classdev_class = NULL; - goto out; - } - /* devices of this class shadow the major:minor of their parent - * device, so clear ->dev_kobj to prevent adding duplicate entries - * to /sys/dev - */ - usb_classdev_class->dev_kobj = NULL; -#endif usb_register_notify(&usbdev_nb); out: return retval; @@ -2156,9 +2116,6 @@ error_cdev: void usb_devio_cleanup(void) { usb_unregister_notify(&usbdev_nb); -#ifdef CONFIG_USB_DEVICE_CLASS - class_destroy(usb_classdev_class); -#endif cdev_del(&usb_device_cdev); unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX); } diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index 9a56635dc19c..f536aebc958e 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -79,6 +79,30 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids, } EXPORT_SYMBOL_GPL(usb_store_new_id); +ssize_t usb_show_dynids(struct usb_dynids *dynids, char *buf) +{ + struct usb_dynid *dynid; + size_t count = 0; + + list_for_each_entry(dynid, &dynids->list, node) + if (dynid->id.bInterfaceClass != 0) + count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x %02x\n", + dynid->id.idVendor, dynid->id.idProduct, + dynid->id.bInterfaceClass); + else + count += scnprintf(&buf[count], PAGE_SIZE - count, "%04x %04x\n", + dynid->id.idVendor, dynid->id.idProduct); + return count; +} +EXPORT_SYMBOL_GPL(usb_show_dynids); + +static ssize_t show_dynids(struct device_driver *driver, char *buf) +{ + struct usb_driver *usb_drv = to_usb_driver(driver); + + return usb_show_dynids(&usb_drv->dynids, buf); +} + static ssize_t store_new_id(struct device_driver *driver, const char *buf, size_t count) { @@ -86,7 +110,7 @@ static ssize_t store_new_id(struct device_driver *driver, return usb_store_new_id(&usb_drv->dynids, driver, buf, count); } -static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); +static DRIVER_ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id); /** * store_remove_id - remove a USB device ID from this driver @@ -127,7 +151,7 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count) return retval; return count; } -static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id); +static DRIVER_ATTR(remove_id, S_IRUGO | S_IWUSR, show_dynids, store_remove_id); static int usb_create_newid_files(struct usb_driver *usb_drv) { @@ -264,6 +288,7 @@ static int usb_probe_interface(struct device *dev) struct usb_device *udev = interface_to_usbdev(intf); const struct usb_device_id *id; int error = -ENODEV; + int lpm_disable_error; dev_dbg(dev, "%s\n", __func__); @@ -300,6 +325,25 @@ static int usb_probe_interface(struct device *dev) if (driver->supports_autosuspend) pm_runtime_enable(dev); + /* If the new driver doesn't allow hub-initiated LPM, and we can't + * disable hub-initiated LPM, then fail the probe. + * + * Otherwise, leaving LPM enabled should be harmless, because the + * endpoint intervals should remain the same, and the U1/U2 timeouts + * should remain the same. + * + * If we need to install alt setting 0 before probe, or another alt + * setting during probe, that should also be fine. usb_set_interface() + * will attempt to disable LPM, and fail if it can't disable it. + */ + lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (lpm_disable_error && driver->disable_hub_initiated_lpm) { + dev_err(&intf->dev, "%s Failed to disable LPM for driver %s\n.", + __func__, driver->name); + error = lpm_disable_error; + goto err; + } + /* Carry out a deferred switch to altsetting 0 */ if (intf->needs_altsetting0) { error = usb_set_interface(udev, intf->altsetting[0]. @@ -314,6 +358,11 @@ static int usb_probe_interface(struct device *dev) goto err; intf->condition = USB_INTERFACE_BOUND; + + /* If the LPM disable succeeded, balance the ref counts. */ + if (!lpm_disable_error) + usb_unlocked_enable_lpm(udev); + usb_autosuspend_device(udev); return error; @@ -337,7 +386,7 @@ static int usb_unbind_interface(struct device *dev) struct usb_driver *driver = to_usb_driver(dev->driver); struct usb_interface *intf = to_usb_interface(dev); struct usb_device *udev; - int error, r; + int error, r, lpm_disable_error; intf->condition = USB_INTERFACE_UNBINDING; @@ -345,6 +394,13 @@ static int usb_unbind_interface(struct device *dev) udev = interface_to_usbdev(intf); error = usb_autoresume_device(udev); + /* Hub-initiated LPM policy may change, so attempt to disable LPM until + * the driver is unbound. If LPM isn't disabled, that's fine because it + * wouldn't be enabled unless all the bound interfaces supported + * hub-initiated LPM. + */ + lpm_disable_error = usb_unlocked_disable_lpm(udev); + /* Terminate all URBs for this interface unless the driver * supports "soft" unbinding. */ @@ -378,6 +434,10 @@ static int usb_unbind_interface(struct device *dev) intf->condition = USB_INTERFACE_UNBOUND; intf->needs_remote_wakeup = 0; + /* Attempt to re-enable USB3 LPM, if the disable succeeded. */ + if (!lpm_disable_error) + usb_unlocked_enable_lpm(udev); + /* Unbound interfaces are always runtime-PM-disabled and -suspended */ if (driver->supports_autosuspend) pm_runtime_disable(dev); @@ -418,17 +478,29 @@ int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv) { struct device *dev = &iface->dev; + struct usb_device *udev; int retval = 0; + int lpm_disable_error; if (dev->driver) return -EBUSY; + udev = interface_to_usbdev(iface); + dev->driver = &driver->drvwrap.driver; usb_set_intfdata(iface, priv); iface->needs_binding = 0; iface->condition = USB_INTERFACE_BOUND; + /* Disable LPM until this driver is bound. */ + lpm_disable_error = usb_unlocked_disable_lpm(udev); + if (lpm_disable_error && driver->disable_hub_initiated_lpm) { + dev_err(&iface->dev, "%s Failed to disable LPM for driver %s\n.", + __func__, driver->name); + return -ENOMEM; + } + /* Claimed interfaces are initially inactive (suspended) and * runtime-PM-enabled, but only if the driver has autosuspend * support. Otherwise they are marked active, to prevent the @@ -447,6 +519,10 @@ int usb_driver_claim_interface(struct usb_driver *driver, if (device_is_registered(dev)) retval = device_bind_driver(dev); + /* Attempt to re-enable USB3 LPM, if the disable was successful. */ + if (!lpm_disable_error) + usb_unlocked_enable_lpm(udev); + return retval; } EXPORT_SYMBOL_GPL(usb_driver_claim_interface); @@ -726,16 +802,6 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENODEV; } -#ifdef CONFIG_USB_DEVICEFS - /* If this is available, userspace programs can directly read - * all the device descriptors we don't tell them about. Or - * act as usermode drivers. - */ - if (add_uevent_var(env, "DEVICE=/proc/bus/usb/%03d/%03d", - usb_dev->bus->busnum, usb_dev->devnum)) - return -ENOMEM; -#endif - /* per-device configurations are common */ if (add_uevent_var(env, "PRODUCT=%x/%x/%x", le16_to_cpu(usb_dev->descriptor.idVendor), @@ -788,15 +854,13 @@ int usb_register_device_driver(struct usb_device_driver *new_udriver, retval = driver_register(&new_udriver->drvwrap.driver); - if (!retval) { + if (!retval) pr_info("%s: registered new device driver %s\n", usbcore_name, new_udriver->name); - usbfs_update_special(); - } else { + else printk(KERN_ERR "%s: error %d registering device " " driver %s\n", usbcore_name, retval, new_udriver->name); - } return retval; } @@ -815,7 +879,6 @@ void usb_deregister_device_driver(struct usb_device_driver *udriver) usbcore_name, udriver->name); driver_unregister(&udriver->drvwrap.driver); - usbfs_update_special(); } EXPORT_SYMBOL_GPL(usb_deregister_device_driver); @@ -856,8 +919,6 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner, if (retval) goto out; - usbfs_update_special(); - retval = usb_create_newid_files(new_driver); if (retval) goto out_newid; @@ -897,8 +958,6 @@ void usb_deregister(struct usb_driver *driver) usb_remove_newid_files(driver); driver_unregister(&driver->drvwrap.driver); usb_free_dynids(driver); - - usbfs_update_special(); } EXPORT_SYMBOL_GPL(usb_deregister); diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c index d95760de9e8b..e673b26e598f 100644 --- a/drivers/usb/core/file.c +++ b/drivers/usb/core/file.c @@ -183,7 +183,7 @@ int usb_register_dev(struct usb_interface *intf, if (retval) return retval; - dev_dbg(&intf->dev, "looking for a minor, starting at %d", minor_base); + dev_dbg(&intf->dev, "looking for a minor, starting at %d\n", minor_base); down_write(&minor_rwsem); for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) { @@ -239,7 +239,7 @@ void usb_deregister_dev(struct usb_interface *intf, if (intf->minor == -1) return; - dbg ("removing %d minor", intf->minor); + dev_dbg(&intf->dev, "removing %d minor\n", intf->minor); down_write(&minor_rwsem); usb_minors[intf->minor] = NULL; diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 140d3e11f212..190b1ec7bdcb 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -138,7 +138,7 @@ static const u8 usb3_rh_dev_descriptor[18] = { 0x03, /* __u8 bDeviceProtocol; USB 3.0 hub */ 0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */ - 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */ 0x03, 0x00, /* __le16 idProduct; device 0x0003 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ @@ -159,7 +159,7 @@ static const u8 usb2_rh_dev_descriptor [18] = { 0x00, /* __u8 bDeviceProtocol; [ usb 2.0 no TT ] */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */ 0x02, 0x00, /* __le16 idProduct; device 0x0002 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ @@ -182,7 +182,7 @@ static const u8 usb11_rh_dev_descriptor [18] = { 0x00, /* __u8 bDeviceProtocol; [ low/full speeds only ] */ 0x40, /* __u8 bMaxPacketSize0; 64 Bytes */ - 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */ + 0x6b, 0x1d, /* __le16 idVendor; Linux Foundation 0x1d6b */ 0x01, 0x00, /* __le16 idProduct; device 0x0001 */ KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */ @@ -997,6 +997,15 @@ static int register_root_hub(struct usb_hcd *hcd) dev_name(&usb_dev->dev), retval); return (retval < 0) ? retval : -EMSGSIZE; } + if (usb_dev->speed == USB_SPEED_SUPER) { + retval = usb_get_bos_descriptor(usb_dev); + if (retval < 0) { + mutex_unlock(&usb_bus_list_lock); + dev_dbg(parent_dev, "can't read %s bos descriptor %d\n", + dev_name(&usb_dev->dev), retval); + return retval; + } + } retval = usb_new_device (usb_dev); if (retval) { diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index ec6c97dadbe4..04fb834c3fa1 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -177,6 +177,228 @@ static struct usb_hub *hdev_to_hub(struct usb_device *hdev) return usb_get_intfdata(hdev->actconfig->interface[0]); } +static int usb_device_supports_lpm(struct usb_device *udev) +{ + /* USB 2.1 (and greater) devices indicate LPM support through + * their USB 2.0 Extended Capabilities BOS descriptor. + */ + if (udev->speed == USB_SPEED_HIGH) { + if (udev->bos->ext_cap && + (USB_LPM_SUPPORT & + le32_to_cpu(udev->bos->ext_cap->bmAttributes))) + return 1; + return 0; + } + + /* All USB 3.0 must support LPM, but we need their max exit latency + * information from the SuperSpeed Extended Capabilities BOS descriptor. + */ + if (!udev->bos->ss_cap) { + dev_warn(&udev->dev, "No LPM exit latency info found. " + "Power management will be impacted.\n"); + return 0; + } + if (udev->parent->lpm_capable) + return 1; + + dev_warn(&udev->dev, "Parent hub missing LPM exit latency info. " + "Power management will be impacted.\n"); + return 0; +} + +/* + * Set the Maximum Exit Latency (MEL) for the host to initiate a transition from + * either U1 or U2. + */ +static void usb_set_lpm_mel(struct usb_device *udev, + struct usb3_lpm_parameters *udev_lpm_params, + unsigned int udev_exit_latency, + struct usb_hub *hub, + struct usb3_lpm_parameters *hub_lpm_params, + unsigned int hub_exit_latency) +{ + unsigned int total_mel; + unsigned int device_mel; + unsigned int hub_mel; + + /* + * Calculate the time it takes to transition all links from the roothub + * to the parent hub into U0. The parent hub must then decode the + * packet (hub header decode latency) to figure out which port it was + * bound for. + * + * The Hub Header decode latency is expressed in 0.1us intervals (0x1 + * means 0.1us). Multiply that by 100 to get nanoseconds. + */ + total_mel = hub_lpm_params->mel + + (hub->descriptor->u.ss.bHubHdrDecLat * 100); + + /* + * How long will it take to transition the downstream hub's port into + * U0? The greater of either the hub exit latency or the device exit + * latency. + * + * The BOS U1/U2 exit latencies are expressed in 1us intervals. + * Multiply that by 1000 to get nanoseconds. + */ + device_mel = udev_exit_latency * 1000; + hub_mel = hub_exit_latency * 1000; + if (device_mel > hub_mel) + total_mel += device_mel; + else + total_mel += hub_mel; + + udev_lpm_params->mel = total_mel; +} + +/* + * Set the maximum Device to Host Exit Latency (PEL) for the device to initiate + * a transition from either U1 or U2. + */ +static void usb_set_lpm_pel(struct usb_device *udev, + struct usb3_lpm_parameters *udev_lpm_params, + unsigned int udev_exit_latency, + struct usb_hub *hub, + struct usb3_lpm_parameters *hub_lpm_params, + unsigned int hub_exit_latency, + unsigned int port_to_port_exit_latency) +{ + unsigned int first_link_pel; + unsigned int hub_pel; + + /* + * First, the device sends an LFPS to transition the link between the + * device and the parent hub into U0. The exit latency is the bigger of + * the device exit latency or the hub exit latency. + */ + if (udev_exit_latency > hub_exit_latency) + first_link_pel = udev_exit_latency * 1000; + else + first_link_pel = hub_exit_latency * 1000; + + /* + * When the hub starts to receive the LFPS, there is a slight delay for + * it to figure out that one of the ports is sending an LFPS. Then it + * will forward the LFPS to its upstream link. The exit latency is the + * delay, plus the PEL that we calculated for this hub. + */ + hub_pel = port_to_port_exit_latency * 1000 + hub_lpm_params->pel; + + /* + * According to figure C-7 in the USB 3.0 spec, the PEL for this device + * is the greater of the two exit latencies. + */ + if (first_link_pel > hub_pel) + udev_lpm_params->pel = first_link_pel; + else + udev_lpm_params->pel = hub_pel; +} + +/* + * Set the System Exit Latency (SEL) to indicate the total worst-case time from + * when a device initiates a transition to U0, until when it will receive the + * first packet from the host controller. + * + * Section C.1.5.1 describes the four components to this: + * - t1: device PEL + * - t2: time for the ERDY to make it from the device to the host. + * - t3: a host-specific delay to process the ERDY. + * - t4: time for the packet to make it from the host to the device. + * + * t3 is specific to both the xHCI host and the platform the host is integrated + * into. The Intel HW folks have said it's negligible, FIXME if a different + * vendor says otherwise. + */ +static void usb_set_lpm_sel(struct usb_device *udev, + struct usb3_lpm_parameters *udev_lpm_params) +{ + struct usb_device *parent; + unsigned int num_hubs; + unsigned int total_sel; + + /* t1 = device PEL */ + total_sel = udev_lpm_params->pel; + /* How many external hubs are in between the device & the root port. */ + for (parent = udev->parent, num_hubs = 0; parent->parent; + parent = parent->parent) + num_hubs++; + /* t2 = 2.1us + 250ns * (num_hubs - 1) */ + if (num_hubs > 0) + total_sel += 2100 + 250 * (num_hubs - 1); + + /* t4 = 250ns * num_hubs */ + total_sel += 250 * num_hubs; + + udev_lpm_params->sel = total_sel; +} + +static void usb_set_lpm_parameters(struct usb_device *udev) +{ + struct usb_hub *hub; + unsigned int port_to_port_delay; + unsigned int udev_u1_del; + unsigned int udev_u2_del; + unsigned int hub_u1_del; + unsigned int hub_u2_del; + + if (!udev->lpm_capable || udev->speed != USB_SPEED_SUPER) + return; + + hub = hdev_to_hub(udev->parent); + /* It doesn't take time to transition the roothub into U0, since it + * doesn't have an upstream link. + */ + if (!hub) + return; + + udev_u1_del = udev->bos->ss_cap->bU1devExitLat; + udev_u2_del = udev->bos->ss_cap->bU2DevExitLat; + hub_u1_del = udev->parent->bos->ss_cap->bU1devExitLat; + hub_u2_del = udev->parent->bos->ss_cap->bU2DevExitLat; + + usb_set_lpm_mel(udev, &udev->u1_params, udev_u1_del, + hub, &udev->parent->u1_params, hub_u1_del); + + usb_set_lpm_mel(udev, &udev->u2_params, udev_u2_del, + hub, &udev->parent->u2_params, hub_u2_del); + + /* + * Appendix C, section C.2.2.2, says that there is a slight delay from + * when the parent hub notices the downstream port is trying to + * transition to U0 to when the hub initiates a U0 transition on its + * upstream port. The section says the delays are tPort2PortU1EL and + * tPort2PortU2EL, but it doesn't define what they are. + * + * The hub chapter, sections 10.4.2.4 and 10.4.2.5 seem to be talking + * about the same delays. Use the maximum delay calculations from those + * sections. For U1, it's tHubPort2PortExitLat, which is 1us max. For + * U2, it's tHubPort2PortExitLat + U2DevExitLat - U1DevExitLat. I + * assume the device exit latencies they are talking about are the hub + * exit latencies. + * + * What do we do if the U2 exit latency is less than the U1 exit + * latency? It's possible, although not likely... + */ + port_to_port_delay = 1; + + usb_set_lpm_pel(udev, &udev->u1_params, udev_u1_del, + hub, &udev->parent->u1_params, hub_u1_del, + port_to_port_delay); + + if (hub_u2_del > hub_u1_del) + port_to_port_delay = 1 + hub_u2_del - hub_u1_del; + else + port_to_port_delay = 1 + hub_u1_del; + + usb_set_lpm_pel(udev, &udev->u2_params, udev_u2_del, + hub, &udev->parent->u2_params, hub_u2_del, + port_to_port_delay); + + /* Now that we've got PEL, calculate SEL. */ + usb_set_lpm_sel(udev, &udev->u1_params); + usb_set_lpm_sel(udev, &udev->u2_params); +} + /* USB 2.0 spec Section 11.24.4.5 */ static int get_hub_descriptor(struct usb_device *hdev, void *data) { @@ -2480,6 +2702,12 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) if (udev->usb2_hw_lpm_enabled == 1) usb_set_usb2_hardware_lpm(udev, 0); + if (usb_unlocked_disable_lpm(udev)) { + dev_err(&udev->dev, "%s Failed to disable LPM before suspend\n.", + __func__); + return -ENOMEM; + } + /* see 7.1.7.6 */ if (hub_is_superspeed(hub->hdev)) status = set_port_feature(hub->hdev, @@ -2499,6 +2727,13 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg) NULL, 0, USB_CTRL_SET_TIMEOUT); + /* Try to enable USB2 hardware LPM again */ + if (udev->usb2_hw_lpm_capable == 1) + usb_set_usb2_hardware_lpm(udev, 1); + + /* Try to enable USB3 LPM again */ + usb_unlocked_enable_lpm(udev); + /* System sleep transitions should never fail */ if (!PMSG_IS_AUTO(msg)) status = 0; @@ -2696,6 +2931,9 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) /* Try to enable USB2 hardware LPM */ if (udev->usb2_hw_lpm_capable == 1) usb_set_usb2_hardware_lpm(udev, 1); + + /* Try to enable USB3 LPM */ + usb_unlocked_enable_lpm(udev); } return status; @@ -2824,11 +3062,429 @@ void usb_root_hub_lost_power(struct usb_device *rhdev) } EXPORT_SYMBOL_GPL(usb_root_hub_lost_power); +static const char * const usb3_lpm_names[] = { + "U0", + "U1", + "U2", + "U3", +}; + +/* + * Send a Set SEL control transfer to the device, prior to enabling + * device-initiated U1 or U2. This lets the device know the exit latencies from + * the time the device initiates a U1 or U2 exit, to the time it will receive a + * packet from the host. + * + * This function will fail if the SEL or PEL values for udev are greater than + * the maximum allowed values for the link state to be enabled. + */ +static int usb_req_set_sel(struct usb_device *udev, enum usb3_link_state state) +{ + struct usb_set_sel_req *sel_values; + unsigned long long u1_sel; + unsigned long long u1_pel; + unsigned long long u2_sel; + unsigned long long u2_pel; + int ret; + + /* Convert SEL and PEL stored in ns to us */ + u1_sel = DIV_ROUND_UP(udev->u1_params.sel, 1000); + u1_pel = DIV_ROUND_UP(udev->u1_params.pel, 1000); + u2_sel = DIV_ROUND_UP(udev->u2_params.sel, 1000); + u2_pel = DIV_ROUND_UP(udev->u2_params.pel, 1000); + + /* + * Make sure that the calculated SEL and PEL values for the link + * state we're enabling aren't bigger than the max SEL/PEL + * value that will fit in the SET SEL control transfer. + * Otherwise the device would get an incorrect idea of the exit + * latency for the link state, and could start a device-initiated + * U1/U2 when the exit latencies are too high. + */ + if ((state == USB3_LPM_U1 && + (u1_sel > USB3_LPM_MAX_U1_SEL_PEL || + u1_pel > USB3_LPM_MAX_U1_SEL_PEL)) || + (state == USB3_LPM_U2 && + (u2_sel > USB3_LPM_MAX_U2_SEL_PEL || + u2_pel > USB3_LPM_MAX_U2_SEL_PEL))) { + dev_dbg(&udev->dev, "Device-initiated %s disabled due " + "to long SEL %llu ms or PEL %llu ms\n", + usb3_lpm_names[state], u1_sel, u1_pel); + return -EINVAL; + } + + /* + * If we're enabling device-initiated LPM for one link state, + * but the other link state has a too high SEL or PEL value, + * just set those values to the max in the Set SEL request. + */ + if (u1_sel > USB3_LPM_MAX_U1_SEL_PEL) + u1_sel = USB3_LPM_MAX_U1_SEL_PEL; + + if (u1_pel > USB3_LPM_MAX_U1_SEL_PEL) + u1_pel = USB3_LPM_MAX_U1_SEL_PEL; + + if (u2_sel > USB3_LPM_MAX_U2_SEL_PEL) + u2_sel = USB3_LPM_MAX_U2_SEL_PEL; + + if (u2_pel > USB3_LPM_MAX_U2_SEL_PEL) + u2_pel = USB3_LPM_MAX_U2_SEL_PEL; + + /* + * usb_enable_lpm() can be called as part of a failed device reset, + * which may be initiated by an error path of a mass storage driver. + * Therefore, use GFP_NOIO. + */ + sel_values = kmalloc(sizeof *(sel_values), GFP_NOIO); + if (!sel_values) + return -ENOMEM; + + sel_values->u1_sel = u1_sel; + sel_values->u1_pel = u1_pel; + sel_values->u2_sel = cpu_to_le16(u2_sel); + sel_values->u2_pel = cpu_to_le16(u2_pel); + + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_SEL, + USB_RECIP_DEVICE, + 0, 0, + sel_values, sizeof *(sel_values), + USB_CTRL_SET_TIMEOUT); + kfree(sel_values); + return ret; +} + +/* + * Enable or disable device-initiated U1 or U2 transitions. + */ +static int usb_set_device_initiated_lpm(struct usb_device *udev, + enum usb3_link_state state, bool enable) +{ + int ret; + int feature; + + switch (state) { + case USB3_LPM_U1: + feature = USB_DEVICE_U1_ENABLE; + break; + case USB3_LPM_U2: + feature = USB_DEVICE_U2_ENABLE; + break; + default: + dev_warn(&udev->dev, "%s: Can't %s non-U1 or U2 state.\n", + __func__, enable ? "enable" : "disable"); + return -EINVAL; + } + + if (udev->state != USB_STATE_CONFIGURED) { + dev_dbg(&udev->dev, "%s: Can't %s %s state " + "for unconfigured device.\n", + __func__, enable ? "enable" : "disable", + usb3_lpm_names[state]); + return 0; + } + + if (enable) { + /* + * First, let the device know about the exit latencies + * associated with the link state we're about to enable. + */ + ret = usb_req_set_sel(udev, state); + if (ret < 0) { + dev_warn(&udev->dev, "Set SEL for device-initiated " + "%s failed.\n", usb3_lpm_names[state]); + return -EBUSY; + } + /* + * Now send the control transfer to enable device-initiated LPM + * for either U1 or U2. + */ + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_SET_FEATURE, + USB_RECIP_DEVICE, + feature, + 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + } else { + ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + USB_REQ_CLEAR_FEATURE, + USB_RECIP_DEVICE, + feature, + 0, NULL, 0, + USB_CTRL_SET_TIMEOUT); + } + if (ret < 0) { + dev_warn(&udev->dev, "%s of device-initiated %s failed.\n", + enable ? "Enable" : "Disable", + usb3_lpm_names[state]); + return -EBUSY; + } + return 0; +} + +static int usb_set_lpm_timeout(struct usb_device *udev, + enum usb3_link_state state, int timeout) +{ + int ret; + int feature; + + switch (state) { + case USB3_LPM_U1: + feature = USB_PORT_FEAT_U1_TIMEOUT; + break; + case USB3_LPM_U2: + feature = USB_PORT_FEAT_U2_TIMEOUT; + break; + default: + dev_warn(&udev->dev, "%s: Can't set timeout for non-U1 or U2 state.\n", + __func__); + return -EINVAL; + } + + if (state == USB3_LPM_U1 && timeout > USB3_LPM_U1_MAX_TIMEOUT && + timeout != USB3_LPM_DEVICE_INITIATED) { + dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x, " + "which is a reserved value.\n", + usb3_lpm_names[state], timeout); + return -EINVAL; + } + + ret = set_port_feature(udev->parent, + USB_PORT_LPM_TIMEOUT(timeout) | udev->portnum, + feature); + if (ret < 0) { + dev_warn(&udev->dev, "Failed to set %s timeout to 0x%x," + "error code %i\n", usb3_lpm_names[state], + timeout, ret); + return -EBUSY; + } + if (state == USB3_LPM_U1) + udev->u1_params.timeout = timeout; + else + udev->u2_params.timeout = timeout; + return 0; +} + +/* + * Enable the hub-initiated U1/U2 idle timeouts, and enable device-initiated + * U1/U2 entry. + * + * We will attempt to enable U1 or U2, but there are no guarantees that the + * control transfers to set the hub timeout or enable device-initiated U1/U2 + * will be successful. + * + * If we cannot set the parent hub U1/U2 timeout, we attempt to let the xHCI + * driver know about it. If that call fails, it should be harmless, and just + * take up more slightly more bus bandwidth for unnecessary U1/U2 exit latency. + */ +static void usb_enable_link_state(struct usb_hcd *hcd, struct usb_device *udev, + enum usb3_link_state state) +{ + int timeout; + + /* We allow the host controller to set the U1/U2 timeout internally + * first, so that it can change its schedule to account for the + * additional latency to send data to a device in a lower power + * link state. + */ + timeout = hcd->driver->enable_usb3_lpm_timeout(hcd, udev, state); + + /* xHCI host controller doesn't want to enable this LPM state. */ + if (timeout == 0) + return; + + if (timeout < 0) { + dev_warn(&udev->dev, "Could not enable %s link state, " + "xHCI error %i.\n", usb3_lpm_names[state], + timeout); + return; + } + + if (usb_set_lpm_timeout(udev, state, timeout)) + /* If we can't set the parent hub U1/U2 timeout, + * device-initiated LPM won't be allowed either, so let the xHCI + * host know that this link state won't be enabled. + */ + hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state); + + /* Only a configured device will accept the Set Feature U1/U2_ENABLE */ + else if (udev->actconfig) + usb_set_device_initiated_lpm(udev, state, true); + +} + +/* + * Disable the hub-initiated U1/U2 idle timeouts, and disable device-initiated + * U1/U2 entry. + * + * If this function returns -EBUSY, the parent hub will still allow U1/U2 entry. + * If zero is returned, the parent will not allow the link to go into U1/U2. + * + * If zero is returned, device-initiated U1/U2 entry may still be enabled, but + * it won't have an effect on the bus link state because the parent hub will + * still disallow device-initiated U1/U2 entry. + * + * If zero is returned, the xHCI host controller may still think U1/U2 entry is + * possible. The result will be slightly more bus bandwidth will be taken up + * (to account for U1/U2 exit latency), but it should be harmless. + */ +static int usb_disable_link_state(struct usb_hcd *hcd, struct usb_device *udev, + enum usb3_link_state state) +{ + int feature; + + switch (state) { + case USB3_LPM_U1: + feature = USB_PORT_FEAT_U1_TIMEOUT; + break; + case USB3_LPM_U2: + feature = USB_PORT_FEAT_U2_TIMEOUT; + break; + default: + dev_warn(&udev->dev, "%s: Can't disable non-U1 or U2 state.\n", + __func__); + return -EINVAL; + } + + if (usb_set_lpm_timeout(udev, state, 0)) + return -EBUSY; + + usb_set_device_initiated_lpm(udev, state, false); + + if (hcd->driver->disable_usb3_lpm_timeout(hcd, udev, state)) + dev_warn(&udev->dev, "Could not disable xHCI %s timeout, " + "bus schedule bandwidth may be impacted.\n", + usb3_lpm_names[state]); + return 0; +} + +/* + * Disable hub-initiated and device-initiated U1 and U2 entry. + * Caller must own the bandwidth_mutex. + * + * This will call usb_enable_lpm() on failure, which will decrement + * lpm_disable_count, and will re-enable LPM if lpm_disable_count reaches zero. + */ +int usb_disable_lpm(struct usb_device *udev) +{ + struct usb_hcd *hcd; + + if (!udev || !udev->parent || + udev->speed != USB_SPEED_SUPER || + !udev->lpm_capable) + return 0; + + hcd = bus_to_hcd(udev->bus); + if (!hcd || !hcd->driver->disable_usb3_lpm_timeout) + return 0; + + udev->lpm_disable_count++; + if ((udev->u1_params.timeout == 0 && udev->u1_params.timeout == 0)) + return 0; + + /* If LPM is enabled, attempt to disable it. */ + if (usb_disable_link_state(hcd, udev, USB3_LPM_U1)) + goto enable_lpm; + if (usb_disable_link_state(hcd, udev, USB3_LPM_U2)) + goto enable_lpm; + + return 0; + +enable_lpm: + usb_enable_lpm(udev); + return -EBUSY; +} +EXPORT_SYMBOL_GPL(usb_disable_lpm); + +/* Grab the bandwidth_mutex before calling usb_disable_lpm() */ +int usb_unlocked_disable_lpm(struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + int ret; + + if (!hcd) + return -EINVAL; + + mutex_lock(hcd->bandwidth_mutex); + ret = usb_disable_lpm(udev); + mutex_unlock(hcd->bandwidth_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm); + +/* + * Attempt to enable device-initiated and hub-initiated U1 and U2 entry. The + * xHCI host policy may prevent U1 or U2 from being enabled. + * + * Other callers may have disabled link PM, so U1 and U2 entry will be disabled + * until the lpm_disable_count drops to zero. Caller must own the + * bandwidth_mutex. + */ +void usb_enable_lpm(struct usb_device *udev) +{ + struct usb_hcd *hcd; + + if (!udev || !udev->parent || + udev->speed != USB_SPEED_SUPER || + !udev->lpm_capable) + return; + + udev->lpm_disable_count--; + hcd = bus_to_hcd(udev->bus); + /* Double check that we can both enable and disable LPM. + * Device must be configured to accept set feature U1/U2 timeout. + */ + if (!hcd || !hcd->driver->enable_usb3_lpm_timeout || + !hcd->driver->disable_usb3_lpm_timeout) + return; + + if (udev->lpm_disable_count > 0) + return; + + usb_enable_link_state(hcd, udev, USB3_LPM_U1); + usb_enable_link_state(hcd, udev, USB3_LPM_U2); +} +EXPORT_SYMBOL_GPL(usb_enable_lpm); + +/* Grab the bandwidth_mutex before calling usb_enable_lpm() */ +void usb_unlocked_enable_lpm(struct usb_device *udev) +{ + struct usb_hcd *hcd = bus_to_hcd(udev->bus); + + if (!hcd) + return; + + mutex_lock(hcd->bandwidth_mutex); + usb_enable_lpm(udev); + mutex_unlock(hcd->bandwidth_mutex); +} +EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm); + + #else /* CONFIG_PM */ #define hub_suspend NULL #define hub_resume NULL #define hub_reset_resume NULL + +int usb_disable_lpm(struct usb_device *udev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(usb_disable_lpm); + +void usb_enable_lpm(struct usb_device *udev) { } +EXPORT_SYMBOL_GPL(usb_enable_lpm); + +int usb_unlocked_disable_lpm(struct usb_device *udev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(usb_unlocked_disable_lpm); + +void usb_unlocked_enable_lpm(struct usb_device *udev) { } +EXPORT_SYMBOL_GPL(usb_unlocked_enable_lpm); #endif @@ -3208,9 +3864,8 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) { retval = usb_get_bos_descriptor(udev); if (!retval) { - if (udev->bos->ext_cap && (USB_LPM_SUPPORT & - le32_to_cpu(udev->bos->ext_cap->bmAttributes))) - udev->lpm_capable = 1; + udev->lpm_capable = usb_device_supports_lpm(udev); + usb_set_lpm_parameters(udev); } } @@ -4042,11 +4697,22 @@ static int usb_reset_and_verify_device(struct usb_device *udev) goto done; mutex_lock(hcd->bandwidth_mutex); + /* Disable LPM while we reset the device and reinstall the alt settings. + * Device-initiated LPM settings, and system exit latency settings are + * cleared when the device is reset, so we have to set them up again. + */ + ret = usb_disable_lpm(udev); + if (ret) { + dev_err(&udev->dev, "%s Failed to disable LPM\n.", __func__); + mutex_unlock(hcd->bandwidth_mutex); + goto done; + } ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL); if (ret < 0) { dev_warn(&udev->dev, "Busted HC? Not enough HCD resources for " "old configuration.\n"); + usb_enable_lpm(udev); mutex_unlock(hcd->bandwidth_mutex); goto re_enumerate; } @@ -4058,6 +4724,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev) dev_err(&udev->dev, "can't restore configuration #%d (error=%d)\n", udev->actconfig->desc.bConfigurationValue, ret); + usb_enable_lpm(udev); mutex_unlock(hcd->bandwidth_mutex); goto re_enumerate; } @@ -4096,10 +4763,13 @@ static int usb_reset_and_verify_device(struct usb_device *udev) desc->bInterfaceNumber, desc->bAlternateSetting, ret); + usb_unlocked_enable_lpm(udev); goto re_enumerate; } } + /* Now that the alt settings are re-installed, enable LPM. */ + usb_unlocked_enable_lpm(udev); done: return 0; diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c deleted file mode 100644 index d2b9af59cba9..000000000000 --- a/drivers/usb/core/inode.c +++ /dev/null @@ -1,748 +0,0 @@ -/*****************************************************************************/ - -/* - * inode.c -- Inode/Dentry functions for the USB device file system. - * - * Copyright (C) 2000 Thomas Sailer (sailer@ife.ee.ethz.ch) - * Copyright (C) 2001,2002,2004 Greg Kroah-Hartman (greg@kroah.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * History: - * 0.1 04.01.2000 Created - * 0.2 10.12.2001 converted to use the vfs layer better - */ - -/*****************************************************************************/ - -#include <linux/module.h> -#include <linux/fs.h> -#include <linux/mount.h> -#include <linux/pagemap.h> -#include <linux/init.h> -#include <linux/proc_fs.h> -#include <linux/usb.h> -#include <linux/namei.h> -#include <linux/usbdevice_fs.h> -#include <linux/parser.h> -#include <linux/notifier.h> -#include <linux/seq_file.h> -#include <linux/usb/hcd.h> -#include <asm/byteorder.h> -#include "usb.h" - -#define USBFS_DEFAULT_DEVMODE (S_IWUSR | S_IRUGO) -#define USBFS_DEFAULT_BUSMODE (S_IXUGO | S_IRUGO) -#define USBFS_DEFAULT_LISTMODE S_IRUGO - -static const struct file_operations default_file_operations; -static struct vfsmount *usbfs_mount; -static int usbfs_mount_count; /* = 0 */ - -static struct dentry *devices_usbfs_dentry; -static int num_buses; /* = 0 */ - -static uid_t devuid; /* = 0 */ -static uid_t busuid; /* = 0 */ -static uid_t listuid; /* = 0 */ -static gid_t devgid; /* = 0 */ -static gid_t busgid; /* = 0 */ -static gid_t listgid; /* = 0 */ -static umode_t devmode = USBFS_DEFAULT_DEVMODE; -static umode_t busmode = USBFS_DEFAULT_BUSMODE; -static umode_t listmode = USBFS_DEFAULT_LISTMODE; - -static int usbfs_show_options(struct seq_file *seq, struct dentry *root) -{ - if (devuid != 0) - seq_printf(seq, ",devuid=%u", devuid); - if (devgid != 0) - seq_printf(seq, ",devgid=%u", devgid); - if (devmode != USBFS_DEFAULT_DEVMODE) - seq_printf(seq, ",devmode=%o", devmode); - if (busuid != 0) - seq_printf(seq, ",busuid=%u", busuid); - if (busgid != 0) - seq_printf(seq, ",busgid=%u", busgid); - if (busmode != USBFS_DEFAULT_BUSMODE) - seq_printf(seq, ",busmode=%o", busmode); - if (listuid != 0) - seq_printf(seq, ",listuid=%u", listuid); - if (listgid != 0) - seq_printf(seq, ",listgid=%u", listgid); - if (listmode != USBFS_DEFAULT_LISTMODE) - seq_printf(seq, ",listmode=%o", listmode); - - return 0; -} - -enum { - Opt_devuid, Opt_devgid, Opt_devmode, - Opt_busuid, Opt_busgid, Opt_busmode, - Opt_listuid, Opt_listgid, Opt_listmode, - Opt_err, -}; - -static const match_table_t tokens = { - {Opt_devuid, "devuid=%u"}, - {Opt_devgid, "devgid=%u"}, - {Opt_devmode, "devmode=%o"}, - {Opt_busuid, "busuid=%u"}, - {Opt_busgid, "busgid=%u"}, - {Opt_busmode, "busmode=%o"}, - {Opt_listuid, "listuid=%u"}, - {Opt_listgid, "listgid=%u"}, - {Opt_listmode, "listmode=%o"}, - {Opt_err, NULL} -}; - -static int parse_options(struct super_block *s, char *data) -{ - char *p; - int option; - - /* (re)set to defaults. */ - devuid = 0; - busuid = 0; - listuid = 0; - devgid = 0; - busgid = 0; - listgid = 0; - devmode = USBFS_DEFAULT_DEVMODE; - busmode = USBFS_DEFAULT_BUSMODE; - listmode = USBFS_DEFAULT_LISTMODE; - - while ((p = strsep(&data, ",")) != NULL) { - substring_t args[MAX_OPT_ARGS]; - int token; - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_devuid: - if (match_int(&args[0], &option)) - return -EINVAL; - devuid = option; - break; - case Opt_devgid: - if (match_int(&args[0], &option)) - return -EINVAL; - devgid = option; - break; - case Opt_devmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - devmode = option & S_IRWXUGO; - break; - case Opt_busuid: - if (match_int(&args[0], &option)) - return -EINVAL; - busuid = option; - break; - case Opt_busgid: - if (match_int(&args[0], &option)) - return -EINVAL; - busgid = option; - break; - case Opt_busmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - busmode = option & S_IRWXUGO; - break; - case Opt_listuid: - if (match_int(&args[0], &option)) - return -EINVAL; - listuid = option; - break; - case Opt_listgid: - if (match_int(&args[0], &option)) - return -EINVAL; - listgid = option; - break; - case Opt_listmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - listmode = option & S_IRWXUGO; - break; - default: - printk(KERN_ERR "usbfs: unrecognised mount option " - "\"%s\" or missing value\n", p); - return -EINVAL; - } - } - - return 0; -} - -static void update_special(struct dentry *special) -{ - special->d_inode->i_uid = listuid; - special->d_inode->i_gid = listgid; - special->d_inode->i_mode = S_IFREG | listmode; -} - -static void update_dev(struct dentry *dev) -{ - dev->d_inode->i_uid = devuid; - dev->d_inode->i_gid = devgid; - dev->d_inode->i_mode = S_IFREG | devmode; -} - -static void update_bus(struct dentry *bus) -{ - struct dentry *dev = NULL; - - bus->d_inode->i_uid = busuid; - bus->d_inode->i_gid = busgid; - bus->d_inode->i_mode = S_IFDIR | busmode; - - mutex_lock(&bus->d_inode->i_mutex); - - list_for_each_entry(dev, &bus->d_subdirs, d_u.d_child) - if (dev->d_inode) - update_dev(dev); - - mutex_unlock(&bus->d_inode->i_mutex); -} - -static void update_sb(struct super_block *sb) -{ - struct dentry *root = sb->s_root; - struct dentry *bus = NULL; - - if (!root) - return; - - mutex_lock_nested(&root->d_inode->i_mutex, I_MUTEX_PARENT); - - list_for_each_entry(bus, &root->d_subdirs, d_u.d_child) { - if (bus->d_inode) { - switch (S_IFMT & bus->d_inode->i_mode) { - case S_IFDIR: - update_bus(bus); - break; - case S_IFREG: - update_special(bus); - break; - default: - printk(KERN_WARNING "usbfs: Unknown node %s " - "mode %x found on remount!\n", - bus->d_name.name, bus->d_inode->i_mode); - break; - } - } - } - - mutex_unlock(&root->d_inode->i_mutex); -} - -static int remount(struct super_block *sb, int *flags, char *data) -{ - /* If this is not a real mount, - * i.e. it's a simple_pin_fs from create_special_files, - * then ignore it. - */ - if (*flags & MS_KERNMOUNT) - return 0; - - if (parse_options(sb, data)) { - printk(KERN_WARNING "usbfs: mount parameter error.\n"); - return -EINVAL; - } - - if (usbfs_mount) - update_sb(usbfs_mount->mnt_sb); - - return 0; -} - -static struct inode *usbfs_get_inode (struct super_block *sb, umode_t mode, dev_t dev) -{ - struct inode *inode = new_inode(sb); - - if (inode) { - inode->i_ino = get_next_ino(); - inode_init_owner(inode, NULL, mode); - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - switch (mode & S_IFMT) { - default: - init_special_inode(inode, mode, dev); - break; - case S_IFREG: - inode->i_fop = &default_file_operations; - break; - case S_IFDIR: - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - - /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inc_nlink(inode); - break; - } - } - return inode; -} - -/* SMP-safe */ -static int usbfs_mknod (struct inode *dir, struct dentry *dentry, umode_t mode, - dev_t dev) -{ - struct inode *inode = usbfs_get_inode(dir->i_sb, mode, dev); - int error = -EPERM; - - if (dentry->d_inode) - return -EEXIST; - - if (inode) { - d_instantiate(dentry, inode); - dget(dentry); - error = 0; - } - return error; -} - -static int usbfs_mkdir (struct inode *dir, struct dentry *dentry, umode_t mode) -{ - int res; - - mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; - res = usbfs_mknod (dir, dentry, mode, 0); - if (!res) - inc_nlink(dir); - return res; -} - -static int usbfs_create (struct inode *dir, struct dentry *dentry, umode_t mode) -{ - mode = (mode & S_IALLUGO) | S_IFREG; - return usbfs_mknod (dir, dentry, mode, 0); -} - -static inline int usbfs_positive (struct dentry *dentry) -{ - return dentry->d_inode && !d_unhashed(dentry); -} - -static int usbfs_empty (struct dentry *dentry) -{ - struct list_head *list; - - spin_lock(&dentry->d_lock); - list_for_each(list, &dentry->d_subdirs) { - struct dentry *de = list_entry(list, struct dentry, d_u.d_child); - - spin_lock_nested(&de->d_lock, DENTRY_D_LOCK_NESTED); - if (usbfs_positive(de)) { - spin_unlock(&de->d_lock); - spin_unlock(&dentry->d_lock); - return 0; - } - spin_unlock(&de->d_lock); - } - spin_unlock(&dentry->d_lock); - return 1; -} - -static int usbfs_unlink (struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - mutex_lock(&inode->i_mutex); - drop_nlink(dentry->d_inode); - dput(dentry); - mutex_unlock(&inode->i_mutex); - d_delete(dentry); - return 0; -} - -static int usbfs_rmdir(struct inode *dir, struct dentry *dentry) -{ - int error = -ENOTEMPTY; - struct inode * inode = dentry->d_inode; - - mutex_lock(&inode->i_mutex); - dentry_unhash(dentry); - if (usbfs_empty(dentry)) { - dont_mount(dentry); - drop_nlink(dentry->d_inode); - drop_nlink(dentry->d_inode); - dput(dentry); - inode->i_flags |= S_DEAD; - drop_nlink(dir); - error = 0; - } - mutex_unlock(&inode->i_mutex); - if (!error) - d_delete(dentry); - return error; -} - - -/* default file operations */ -static ssize_t default_read_file (struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - return 0; -} - -static ssize_t default_write_file (struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return count; -} - -static loff_t default_file_lseek (struct file *file, loff_t offset, int orig) -{ - loff_t retval = -EINVAL; - - mutex_lock(&file->f_path.dentry->d_inode->i_mutex); - switch(orig) { - case 0: - if (offset > 0) { - file->f_pos = offset; - retval = file->f_pos; - } - break; - case 1: - if ((offset + file->f_pos) > 0) { - file->f_pos += offset; - retval = file->f_pos; - } - break; - default: - break; - } - mutex_unlock(&file->f_path.dentry->d_inode->i_mutex); - return retval; -} - -static const struct file_operations default_file_operations = { - .read = default_read_file, - .write = default_write_file, - .open = simple_open, - .llseek = default_file_lseek, -}; - -static const struct super_operations usbfs_ops = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, - .remount_fs = remount, - .show_options = usbfs_show_options, -}; - -static int usbfs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *inode; - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = USBDEVICE_SUPER_MAGIC; - sb->s_op = &usbfs_ops; - sb->s_time_gran = 1; - inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0); - sb->s_root = d_make_root(inode); - if (!sb->s_root) { - dbg("%s: could not get root dentry!",__func__); - return -ENOMEM; - } - return 0; -} - -/* - * fs_create_by_name - create a file, given a name - * @name: name of file - * @mode: type of file - * @parent: dentry of directory to create it in - * @dentry: resulting dentry of file - * - * This function handles both regular files and directories. - */ -static int fs_create_by_name (const char *name, umode_t mode, - struct dentry *parent, struct dentry **dentry) -{ - int error = 0; - - /* If the parent is not specified, we create it in the root. - * We need the root dentry to do this, which is in the super - * block. A pointer to that is in the struct vfsmount that we - * have around. - */ - if (!parent ) { - if (usbfs_mount) - parent = usbfs_mount->mnt_root; - } - - if (!parent) { - dbg("Ah! can not find a parent!"); - return -EFAULT; - } - - *dentry = NULL; - mutex_lock(&parent->d_inode->i_mutex); - *dentry = lookup_one_len(name, parent, strlen(name)); - if (!IS_ERR(*dentry)) { - if (S_ISDIR(mode)) - error = usbfs_mkdir (parent->d_inode, *dentry, mode); - else - error = usbfs_create (parent->d_inode, *dentry, mode); - } else - error = PTR_ERR(*dentry); - mutex_unlock(&parent->d_inode->i_mutex); - - return error; -} - -static struct dentry *fs_create_file (const char *name, umode_t mode, - struct dentry *parent, void *data, - const struct file_operations *fops, - uid_t uid, gid_t gid) -{ - struct dentry *dentry; - int error; - - dbg("creating file '%s'",name); - - error = fs_create_by_name (name, mode, parent, &dentry); - if (error) { - dentry = NULL; - } else { - if (dentry->d_inode) { - if (data) - dentry->d_inode->i_private = data; - if (fops) - dentry->d_inode->i_fop = fops; - dentry->d_inode->i_uid = uid; - dentry->d_inode->i_gid = gid; - } - } - - return dentry; -} - -static void fs_remove_file (struct dentry *dentry) -{ - struct dentry *parent = dentry->d_parent; - - if (!parent || !parent->d_inode) - return; - - mutex_lock_nested(&parent->d_inode->i_mutex, I_MUTEX_PARENT); - if (usbfs_positive(dentry)) { - if (dentry->d_inode) { - if (S_ISDIR(dentry->d_inode->i_mode)) - usbfs_rmdir(parent->d_inode, dentry); - else - usbfs_unlink(parent->d_inode, dentry); - dput(dentry); - } - } - mutex_unlock(&parent->d_inode->i_mutex); -} - -/* --------------------------------------------------------------------- */ - -static struct dentry *usb_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_single(fs_type, flags, data, usbfs_fill_super); -} - -static struct file_system_type usb_fs_type = { - .owner = THIS_MODULE, - .name = "usbfs", - .mount = usb_mount, - .kill_sb = kill_litter_super, -}; - -/* --------------------------------------------------------------------- */ - -static int create_special_files (void) -{ - struct dentry *parent; - int retval; - - /* create the devices special file */ - retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count); - if (retval) { - printk(KERN_ERR "Unable to get usbfs mount\n"); - goto exit; - } - - parent = usbfs_mount->mnt_root; - devices_usbfs_dentry = fs_create_file ("devices", - listmode | S_IFREG, parent, - NULL, &usbfs_devices_fops, - listuid, listgid); - if (devices_usbfs_dentry == NULL) { - printk(KERN_ERR "Unable to create devices usbfs file\n"); - retval = -ENODEV; - goto error_clean_mounts; - } - - goto exit; - -error_clean_mounts: - simple_release_fs(&usbfs_mount, &usbfs_mount_count); -exit: - return retval; -} - -static void remove_special_files (void) -{ - if (devices_usbfs_dentry) - fs_remove_file (devices_usbfs_dentry); - devices_usbfs_dentry = NULL; - simple_release_fs(&usbfs_mount, &usbfs_mount_count); -} - -void usbfs_update_special (void) -{ - struct inode *inode; - - if (devices_usbfs_dentry) { - inode = devices_usbfs_dentry->d_inode; - if (inode) - inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; - } -} - -static void usbfs_add_bus(struct usb_bus *bus) -{ - struct dentry *parent; - char name[8]; - int retval; - - /* create the special files if this is the first bus added */ - if (num_buses == 0) { - retval = create_special_files(); - if (retval) - return; - } - ++num_buses; - - sprintf (name, "%03d", bus->busnum); - - parent = usbfs_mount->mnt_root; - bus->usbfs_dentry = fs_create_file (name, busmode | S_IFDIR, parent, - bus, NULL, busuid, busgid); - if (bus->usbfs_dentry == NULL) { - printk(KERN_ERR "Error creating usbfs bus entry\n"); - return; - } -} - -static void usbfs_remove_bus(struct usb_bus *bus) -{ - if (bus->usbfs_dentry) { - fs_remove_file (bus->usbfs_dentry); - bus->usbfs_dentry = NULL; - } - - --num_buses; - if (num_buses <= 0) { - remove_special_files(); - num_buses = 0; - } -} - -static void usbfs_add_device(struct usb_device *dev) -{ - char name[8]; - int i; - int i_size; - - sprintf (name, "%03d", dev->devnum); - dev->usbfs_dentry = fs_create_file (name, devmode | S_IFREG, - dev->bus->usbfs_dentry, dev, - &usbdev_file_operations, - devuid, devgid); - if (dev->usbfs_dentry == NULL) { - printk(KERN_ERR "Error creating usbfs device entry\n"); - return; - } - - /* Set the size of the device's file to be - * equal to the size of the device descriptors. */ - i_size = sizeof (struct usb_device_descriptor); - for (i = 0; i < dev->descriptor.bNumConfigurations; ++i) { - struct usb_config_descriptor *config = - (struct usb_config_descriptor *)dev->rawdescriptors[i]; - i_size += le16_to_cpu(config->wTotalLength); - } - if (dev->usbfs_dentry->d_inode) - dev->usbfs_dentry->d_inode->i_size = i_size; -} - -static void usbfs_remove_device(struct usb_device *dev) -{ - if (dev->usbfs_dentry) { - fs_remove_file (dev->usbfs_dentry); - dev->usbfs_dentry = NULL; - } -} - -static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev) -{ - switch (action) { - case USB_DEVICE_ADD: - usbfs_add_device(dev); - break; - case USB_DEVICE_REMOVE: - usbfs_remove_device(dev); - break; - case USB_BUS_ADD: - usbfs_add_bus(dev); - break; - case USB_BUS_REMOVE: - usbfs_remove_bus(dev); - } - - usbfs_update_special(); - usbfs_conn_disc_event(); - return NOTIFY_OK; -} - -static struct notifier_block usbfs_nb = { - .notifier_call = usbfs_notify, -}; - -/* --------------------------------------------------------------------- */ - -static struct proc_dir_entry *usbdir = NULL; - -int __init usbfs_init(void) -{ - int retval; - - retval = register_filesystem(&usb_fs_type); - if (retval) - return retval; - - usb_register_notify(&usbfs_nb); - - /* create mount point for usbfs */ - usbdir = proc_mkdir("bus/usb", NULL); - - return 0; -} - -void usbfs_cleanup(void) -{ - usb_unregister_notify(&usbfs_nb); - unregister_filesystem(&usb_fs_type); - if (usbdir) - remove_proc_entry("bus/usb", NULL); -} - diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c index ca717da3be95..b548cf1dbc62 100644 --- a/drivers/usb/core/message.c +++ b/drivers/usb/core/message.c @@ -1308,10 +1308,19 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) * Remove the current alt setting and add the new alt setting. */ mutex_lock(hcd->bandwidth_mutex); + /* Disable LPM, and re-enable it once the new alt setting is installed, + * so that the xHCI driver can recalculate the U1/U2 timeouts. + */ + if (usb_disable_lpm(dev)) { + dev_err(&iface->dev, "%s Failed to disable LPM\n.", __func__); + mutex_unlock(hcd->bandwidth_mutex); + return -ENOMEM; + } ret = usb_hcd_alloc_bandwidth(dev, NULL, iface->cur_altsetting, alt); if (ret < 0) { dev_info(&dev->dev, "Not enough bandwidth for altsetting %d\n", alternate); + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); return ret; } @@ -1334,6 +1343,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) } else if (ret < 0) { /* Re-instate the old alt setting */ usb_hcd_alloc_bandwidth(dev, NULL, alt, iface->cur_altsetting); + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); return ret; } @@ -1354,6 +1364,9 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate) iface->cur_altsetting = alt; + /* Now that the interface is installed, re-enable LPM. */ + usb_unlocked_enable_lpm(dev); + /* If the interface only has one altsetting and the device didn't * accept the request, we attempt to carry out the equivalent action * by manually clearing the HALT feature for each endpoint in the @@ -1437,6 +1450,14 @@ int usb_reset_configuration(struct usb_device *dev) config = dev->actconfig; retval = 0; mutex_lock(hcd->bandwidth_mutex); + /* Disable LPM, and re-enable it once the configuration is reset, so + * that the xHCI driver can recalculate the U1/U2 timeouts. + */ + if (usb_disable_lpm(dev)) { + dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__); + mutex_unlock(hcd->bandwidth_mutex); + return -ENOMEM; + } /* Make sure we have enough bandwidth for each alternate setting 0 */ for (i = 0; i < config->desc.bNumInterfaces; i++) { struct usb_interface *intf = config->interface[i]; @@ -1465,6 +1486,7 @@ reset_old_alts: usb_hcd_alloc_bandwidth(dev, NULL, alt, intf->cur_altsetting); } + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); return retval; } @@ -1502,6 +1524,8 @@ reset_old_alts: create_intf_ep_devs(intf); } } + /* Now that the interfaces are installed, re-enable LPM. */ + usb_unlocked_enable_lpm(dev); return 0; } EXPORT_SYMBOL_GPL(usb_reset_configuration); @@ -1763,8 +1787,18 @@ free_interfaces: * this call fails, the device state is unchanged. */ mutex_lock(hcd->bandwidth_mutex); + /* Disable LPM, and re-enable it once the new configuration is + * installed, so that the xHCI driver can recalculate the U1/U2 + * timeouts. + */ + if (usb_disable_lpm(dev)) { + dev_err(&dev->dev, "%s Failed to disable LPM\n.", __func__); + mutex_unlock(hcd->bandwidth_mutex); + return -ENOMEM; + } ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL); if (ret < 0) { + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); usb_autosuspend_device(dev); goto free_interfaces; @@ -1784,6 +1818,7 @@ free_interfaces: if (!cp) { usb_set_device_state(dev, USB_STATE_ADDRESS); usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL); + usb_enable_lpm(dev); mutex_unlock(hcd->bandwidth_mutex); usb_autosuspend_device(dev); goto free_interfaces; @@ -1838,6 +1873,9 @@ free_interfaces: !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) cp->string = usb_cache_string(dev, cp->desc.iConfiguration); + /* Now that the interfaces are installed, re-enable LPM. */ + usb_unlocked_enable_lpm(dev); + /* Now that all the interfaces are set up, register them * to trigger binding of drivers to interfaces. probe() * routines may install different altsettings and may diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 4c65eb6a867a..32d3adc315f5 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -123,6 +123,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* Guillemot Webcam Hercules Dualpix Exchange*/ { USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME }, + /* Midiman M-Audio Keystation 88es */ + { USB_DEVICE(0x0763, 0x0192), .driver_info = USB_QUIRK_RESET_RESUME }, + /* M-Systems Flash Disk Pioneers */ { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c index 566d9f94f735..9a56e3adf476 100644 --- a/drivers/usb/core/sysfs.c +++ b/drivers/usb/core/sysfs.c @@ -73,7 +73,7 @@ set_bConfigurationValue(struct device *dev, struct device_attribute *attr, return (value < 0) ? value : count; } -static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR, +static DEVICE_ATTR_IGNORE_LOCKDEP(bConfigurationValue, S_IRUGO | S_IWUSR, show_bConfigurationValue, set_bConfigurationValue); /* String fields */ @@ -595,7 +595,7 @@ static ssize_t usb_dev_authorized_store(struct device *dev, return result < 0? result : size; } -static DEVICE_ATTR(authorized, 0644, +static DEVICE_ATTR_IGNORE_LOCKDEP(authorized, 0644, usb_dev_authorized_show, usb_dev_authorized_store); /* "Safely remove a device" */ @@ -618,7 +618,7 @@ static ssize_t usb_remove_store(struct device *dev, usb_unlock_device(udev); return rc; } -static DEVICE_ATTR(remove, 0200, NULL, usb_remove_store); +static DEVICE_ATTR_IGNORE_LOCKDEP(remove, 0200, NULL, usb_remove_store); static struct attribute *dev_attrs[] = { diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c index cd9b3a2cd8a7..9d912bfdcffe 100644 --- a/drivers/usb/core/urb.c +++ b/drivers/usb/core/urb.c @@ -681,6 +681,27 @@ void usb_unpoison_urb(struct urb *urb) EXPORT_SYMBOL_GPL(usb_unpoison_urb); /** + * usb_block_urb - reliably prevent further use of an URB + * @urb: pointer to URB to be blocked, may be NULL + * + * After the routine has run, attempts to resubmit the URB will fail + * with error -EPERM. Thus even if the URB's completion handler always + * tries to resubmit, it will not succeed and the URB will become idle. + * + * The URB must not be deallocated while this routine is running. In + * particular, when a driver calls this routine, it must insure that the + * completion handler cannot deallocate the URB. + */ +void usb_block_urb(struct urb *urb) +{ + if (!urb) + return; + + atomic_inc(&urb->reject); +} +EXPORT_SYMBOL_GPL(usb_block_urb); + +/** * usb_kill_anchored_urbs - cancel transfer requests en masse * @anchor: anchor the requests are bound to * diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c new file mode 100644 index 000000000000..8947b203d5a4 --- /dev/null +++ b/drivers/usb/core/usb-acpi.c @@ -0,0 +1,117 @@ +/* + * USB-ACPI glue code + * + * Copyright 2012 Red Hat <mjg@redhat.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, version 2. + * + */ +#include <linux/module.h> +#include <linux/usb.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/acpi.h> +#include <linux/pci.h> +#include <acpi/acpi_bus.h> + +#include "usb.h" + +static int usb_acpi_check_upc(struct usb_device *udev, acpi_handle handle) +{ + acpi_status status; + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; + union acpi_object *upc; + int ret = 0; + + status = acpi_evaluate_object(handle, "_UPC", NULL, &buffer); + + if (ACPI_FAILURE(status)) + return -ENODEV; + + upc = buffer.pointer; + + if (!upc || (upc->type != ACPI_TYPE_PACKAGE) + || upc->package.count != 4) { + ret = -EINVAL; + goto out; + } + + if (upc->package.elements[0].integer.value) + udev->removable = USB_DEVICE_REMOVABLE; + else + udev->removable = USB_DEVICE_FIXED; + +out: + kfree(upc); + return ret; +} + +static int usb_acpi_check_pld(struct usb_device *udev, acpi_handle handle) +{ + acpi_status status; + struct acpi_pld pld; + + status = acpi_get_physical_device_location(handle, &pld); + + if (ACPI_FAILURE(status)) + return -ENODEV; + + if (pld.user_visible) + udev->removable = USB_DEVICE_REMOVABLE; + else + udev->removable = USB_DEVICE_FIXED; + + return 0; +} + +static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) +{ + struct usb_device *udev; + struct device *parent; + acpi_handle *parent_handle; + + if (!is_usb_device(dev)) + return -ENODEV; + + udev = to_usb_device(dev); + parent = dev->parent; + parent_handle = DEVICE_ACPI_HANDLE(parent); + + if (!parent_handle) + return -ENODEV; + + *handle = acpi_get_child(parent_handle, udev->portnum); + + if (!*handle) + return -ENODEV; + + /* + * PLD will tell us whether a port is removable to the user or + * not. If we don't get an answer from PLD (it's not present + * or it's malformed) then try to infer it from UPC. If a + * device isn't connectable then it's probably not removable. + */ + if (usb_acpi_check_pld(udev, *handle) != 0) + usb_acpi_check_upc(udev, *handle); + + return 0; +} + +static struct acpi_bus_type usb_acpi_bus = { + .bus = &usb_bus_type, + .find_bridge = NULL, + .find_device = usb_acpi_find_device, +}; + +int usb_acpi_register(void) +{ + return register_acpi_bus_type(&usb_acpi_bus); +} + +void usb_acpi_unregister(void) +{ + unregister_acpi_bus_type(&usb_acpi_bus); +} diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index c74ba7bbc748..25d0c61c3f8a 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -1015,6 +1015,7 @@ static int __init usb_init(void) if (retval) goto out; + usb_acpi_register(); retval = bus_register(&usb_bus_type); if (retval) goto bus_register_failed; @@ -1030,9 +1031,6 @@ static int __init usb_init(void) retval = usb_devio_init(); if (retval) goto usb_devio_init_failed; - retval = usbfs_init(); - if (retval) - goto fs_init_failed; retval = usb_hub_init(); if (retval) goto hub_init_failed; @@ -1042,8 +1040,6 @@ static int __init usb_init(void) usb_hub_cleanup(); hub_init_failed: - usbfs_cleanup(); -fs_init_failed: usb_devio_cleanup(); usb_devio_init_failed: usb_deregister(&usbfs_driver); @@ -1054,6 +1050,7 @@ major_init_failed: bus_notifier_failed: bus_unregister(&usb_bus_type); bus_register_failed: + usb_acpi_unregister(); usb_debugfs_cleanup(); out: return retval; @@ -1070,12 +1067,12 @@ static void __exit usb_exit(void) usb_deregister_device_driver(&usb_generic_driver); usb_major_cleanup(); - usbfs_cleanup(); usb_deregister(&usbfs_driver); usb_devio_cleanup(); usb_hub_cleanup(); bus_unregister_notifier(&usb_bus_type, &usb_bus_nb); bus_unregister(&usb_bus_type); + usb_acpi_unregister(); usb_debugfs_cleanup(); } diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 71648dcbe438..5c5c538ea73d 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -156,3 +156,10 @@ extern void usb_notify_remove_device(struct usb_device *udev); extern void usb_notify_add_bus(struct usb_bus *ubus); extern void usb_notify_remove_bus(struct usb_bus *ubus); +#ifdef CONFIG_ACPI +extern int usb_acpi_register(void); +extern void usb_acpi_unregister(void); +#else +static inline int usb_acpi_register(void) { return 0; }; +static inline void usb_acpi_unregister(void) { }; +#endif diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index d8f741f9e56e..d13c60f42139 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -4,7 +4,7 @@ config USB_DWC3 select USB_OTG_UTILS select USB_GADGET_DUALSPEED select USB_GADGET_SUPERSPEED - select USB_XHCI_PLATFORM + select USB_XHCI_PLATFORM if USB_SUPPORT && USB_XHCI_HCD help Say Y or M here if your system has a Dual Role SuperSpeed USB controller based on the DesignWare USB3 IP Core. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 99b58d84553a..1040bdb8dc88 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -410,7 +410,6 @@ static int __devinit dwc3_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; int ret = -ENOMEM; - int irq; void __iomem *regs; void *mem; @@ -425,15 +424,28 @@ static int __devinit dwc3_probe(struct platform_device *pdev) dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1); dwc->mem = mem; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { - dev_err(dev, "missing resource\n"); + dev_err(dev, "missing IRQ\n"); return -ENODEV; } + dwc->xhci_resources[1] = *res; - dwc->res = res; - - res = devm_request_mem_region(dev, res->start, resource_size(res), + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing memory resource\n"); + return -ENODEV; + } + dwc->xhci_resources[0] = *res; + dwc->xhci_resources[0].end = dwc->xhci_resources[0].start + + DWC3_XHCI_REGS_END; + + /* + * Request memory region but exclude xHCI regs, + * since it will be requested by the xhci-plat driver. + */ + res = devm_request_mem_region(dev, res->start + DWC3_GLOBALS_REGS_START, + resource_size(res) - DWC3_GLOBALS_REGS_START, dev_name(dev)); if (!res) { dev_err(dev, "can't request mem region\n"); @@ -446,19 +458,12 @@ static int __devinit dwc3_probe(struct platform_device *pdev) return -ENOMEM; } - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(dev, "missing IRQ\n"); - return -ENODEV; - } - spin_lock_init(&dwc->lock); platform_set_drvdata(pdev, dwc); dwc->regs = regs; dwc->regs_size = resource_size(res); dwc->dev = dev; - dwc->irq = irq; if (!strncmp("super", maximum_speed, 5)) dwc->maximum_speed = DWC3_DCFG_SUPERSPEED; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 6c7945b4cad3..f69c877add09 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -51,7 +51,9 @@ #include <linux/usb/gadget.h> /* Global constants */ +#define DWC3_EP0_BOUNCE_SIZE 512 #define DWC3_ENDPOINTS_NUM 32 +#define DWC3_XHCI_RESOURCES_NUM 2 #define DWC3_EVENT_BUFFERS_SIZE PAGE_SIZE #define DWC3_EVENT_TYPE_MASK 0xfe @@ -75,6 +77,16 @@ #define DWC3_GSNPSID_MASK 0xffff0000 #define DWC3_GSNPSREV_MASK 0xffff +/* DWC3 registers memory space boundries */ +#define DWC3_XHCI_REGS_START 0x0 +#define DWC3_XHCI_REGS_END 0x7fff +#define DWC3_GLOBALS_REGS_START 0xc100 +#define DWC3_GLOBALS_REGS_END 0xc6ff +#define DWC3_DEVICE_REGS_START 0xc700 +#define DWC3_DEVICE_REGS_END 0xcbff +#define DWC3_OTG_REGS_START 0xcc00 +#define DWC3_OTG_REGS_END 0xccff + /* Global Registers */ #define DWC3_GSBUSCFG0 0xc100 #define DWC3_GSBUSCFG1 0xc104 @@ -183,6 +195,7 @@ #define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1 /* Device Configuration Register */ +#define DWC3_DCFG_LPM_CAP (1 << 22) #define DWC3_DCFG_DEVADDR(addr) ((addr) << 3) #define DWC3_DCFG_DEVADDR_MASK DWC3_DCFG_DEVADDR(0x7f) @@ -272,12 +285,14 @@ #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10 +#define DWC3_DGCMD_STATUS(n) (((n) >> 15) & 1) +#define DWC3_DGCMD_CMDACT (1 << 10) + /* Device Endpoint Command Register */ #define DWC3_DEPCMD_PARAM_SHIFT 16 #define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT) #define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f) -#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12) -#define DWC3_DEPCMD_STATUS(x) (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12) +#define DWC3_DEPCMD_STATUS(x) (((x) >> 15) & 1) #define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11) #define DWC3_DEPCMD_CMDACT (1 << 10) #define DWC3_DEPCMD_CMDIOC (1 << 8) @@ -361,7 +376,6 @@ struct dwc3_ep { dma_addr_t trb_pool_dma; u32 free_slot; u32 busy_slot; - const struct usb_endpoint_descriptor *desc; const struct usb_ss_ep_comp_descriptor *comp_desc; struct dwc3 *dwc; @@ -561,6 +575,11 @@ struct dwc3_request { * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround * @needs_fifo_resize: not all users might want fifo resizing, flag it * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes. + * @isoch_delay: wValue from Set Isochronous Delay request; + * @u2sel: parameter from Set SEL request. + * @u2pel: parameter from Set SEL request. + * @u1sel: parameter from Set SEL request. + * @u1pel: parameter from Set SEL request. * @ep0_next_event: hold the next expected event * @ep0state: state of endpoint zero * @link_state: link state @@ -583,7 +602,7 @@ struct dwc3 { struct device *dev; struct platform_device *xhci; - struct resource *res; + struct resource xhci_resources[DWC3_XHCI_RESOURCES_NUM]; struct dwc3_event_buffer **ev_buffs; struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; @@ -594,8 +613,6 @@ struct dwc3 { void __iomem *regs; size_t regs_size; - int irq; - u32 num_event_buffers; u32 u1u2; u32 maximum_speed; @@ -609,6 +626,10 @@ struct dwc3 { #define DWC3_REVISION_185A 0x5533185a #define DWC3_REVISION_188A 0x5533188a #define DWC3_REVISION_190A 0x5533190a +#define DWC3_REVISION_200A 0x5533200a +#define DWC3_REVISION_202A 0x5533202a +#define DWC3_REVISION_210A 0x5533210a +#define DWC3_REVISION_220A 0x5533220a unsigned is_selfpowered:1; unsigned three_stage_setup:1; @@ -625,7 +646,14 @@ struct dwc3 { enum dwc3_link_state link_state; enum dwc3_device_state dev_state; + u16 isoch_delay; + u16 u2sel; + u16 u2pel; + u8 u1sel; + u8 u1pel; + u8 speed; + void *mem; struct dwc3_hwparams hwparams; diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c index d7d9c0ec9515..479dc047da3a 100644 --- a/drivers/usb/dwc3/dwc3-omap.c +++ b/drivers/usb/dwc3/dwc3-omap.c @@ -49,7 +49,6 @@ #include <linux/of.h> #include "core.h" -#include "io.h" /* * All these registers belong to OMAP's Wrapper around the @@ -143,6 +142,17 @@ struct dwc3_omap { u32 dma_status:1; }; +static inline u32 dwc3_omap_readl(void __iomem *base, u32 offset) +{ + return readl(base + offset); +} + +static inline void dwc3_omap_writel(void __iomem *base, u32 offset, u32 value) +{ + writel(value, base + offset); +} + + static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) { struct dwc3_omap *omap = _omap; @@ -150,7 +160,7 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) spin_lock(&omap->lock); - reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1); + reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_1); if (reg & USBOTGSS_IRQ1_DMADISABLECLR) { dev_dbg(omap->dev, "DMA Disable was Cleared\n"); @@ -184,10 +194,10 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap) if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL) dev_dbg(omap->dev, "IDPULLUP Fall\n"); - dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg); + dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg); - reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0); - dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg); + reg = dwc3_omap_readl(omap->base, USBOTGSS_IRQSTATUS_0); + dwc3_omap_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg); spin_unlock(&omap->lock); @@ -270,7 +280,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) omap->base = base; omap->dwc3 = dwc3; - reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS); + reg = dwc3_omap_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS); utmi_mode = of_get_property(node, "utmi-mode", &size); if (utmi_mode && size == sizeof(*utmi_mode)) { @@ -293,10 +303,10 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) } } - dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg); + dwc3_omap_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg); /* check the DMA Status */ - reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG); + reg = dwc3_omap_readl(omap->base, USBOTGSS_SYSCONFIG); omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE); /* Set No-Idle and No-Standby */ @@ -306,7 +316,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY) | USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE)); - dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg); + dwc3_omap_writel(omap->base, USBOTGSS_SYSCONFIG, reg); ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0, "dwc3-omap", omap); @@ -318,7 +328,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) /* enable all IRQs */ reg = USBOTGSS_IRQO_COREIRQ_ST; - dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg); + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg); reg = (USBOTGSS_IRQ1_OEVT | USBOTGSS_IRQ1_DRVVBUS_RISE | @@ -330,7 +340,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) USBOTGSS_IRQ1_DISCHRGVBUS_FALL | USBOTGSS_IRQ1_IDPULLUP_FALL); - dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg); + dwc3_omap_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg); ret = platform_device_add_resources(dwc3, pdev->resource, pdev->num_resources); diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 3584a169886f..9e8a3dce69fd 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -179,7 +179,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int ret; spin_lock_irqsave(&dwc->lock, flags); - if (!dep->desc) { + if (!dep->endpoint.desc) { dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", request, dep->name); ret = -ESHUTDOWN; @@ -261,6 +261,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, { struct dwc3_ep *dep; u32 recip; + u32 reg; u16 usb_status = 0; __le16 *response_pkt; @@ -268,10 +269,18 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, switch (recip) { case USB_RECIP_DEVICE: /* - * We are self-powered. U1/U2/LTM will be set later - * once we handle this states. RemoteWakeup is 0 on SS + * LTM will be set once we know how to set this in HW. */ usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED; + + if (dwc->speed == DWC3_DSTS_SUPERSPEED) { + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (reg & DWC3_DCTL_INITU1ENA) + usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; + if (reg & DWC3_DCTL_INITU2ENA) + usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; + } + break; case USB_RECIP_INTERFACE: @@ -312,6 +321,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, u32 recip; u32 wValue; u32 wIndex; + u32 reg; int ret; wValue = le16_to_cpu(ctrl->wValue); @@ -320,29 +330,43 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc, switch (recip) { case USB_RECIP_DEVICE: + switch (wValue) { + case USB_DEVICE_REMOTE_WAKEUP: + break; /* * 9.4.1 says only only for SS, in AddressState only for * default control pipe */ - switch (wValue) { case USB_DEVICE_U1_ENABLE: - case USB_DEVICE_U2_ENABLE: - case USB_DEVICE_LTM_ENABLE: if (dwc->dev_state != DWC3_CONFIGURED_STATE) return -EINVAL; if (dwc->speed != DWC3_DSTS_SUPERSPEED) return -EINVAL; - } - /* XXX add U[12] & LTM */ - switch (wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - break; - case USB_DEVICE_U1_ENABLE: + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (set) + reg |= DWC3_DCTL_INITU1ENA; + else + reg &= ~DWC3_DCTL_INITU1ENA; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); break; + case USB_DEVICE_U2_ENABLE: + if (dwc->dev_state != DWC3_CONFIGURED_STATE) + return -EINVAL; + if (dwc->speed != DWC3_DSTS_SUPERSPEED) + return -EINVAL; + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (set) + reg |= DWC3_DCTL_INITU2ENA; + else + reg &= ~DWC3_DCTL_INITU2ENA; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); break; + case USB_DEVICE_LTM_ENABLE: + return -EINVAL; break; case USB_DEVICE_TEST_MODE: @@ -469,6 +493,107 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) return ret; } +static void dwc3_ep0_set_sel_cmpl(struct usb_ep *ep, struct usb_request *req) +{ + struct dwc3_ep *dep = to_dwc3_ep(ep); + struct dwc3 *dwc = dep->dwc; + + u32 param = 0; + u32 reg; + + struct timing { + u8 u1sel; + u8 u1pel; + u16 u2sel; + u16 u2pel; + } __packed timing; + + int ret; + + memcpy(&timing, req->buf, sizeof(timing)); + + dwc->u1sel = timing.u1sel; + dwc->u1pel = timing.u1pel; + dwc->u2sel = timing.u2sel; + dwc->u2pel = timing.u2pel; + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + if (reg & DWC3_DCTL_INITU2ENA) + param = dwc->u2pel; + if (reg & DWC3_DCTL_INITU1ENA) + param = dwc->u1pel; + + /* + * According to Synopsys Databook, if parameter is + * greater than 125, a value of zero should be + * programmed in the register. + */ + if (param > 125) + param = 0; + + /* now that we have the time, issue DGCMD Set Sel */ + ret = dwc3_send_gadget_generic_command(dwc, + DWC3_DGCMD_SET_PERIODIC_PAR, param); + WARN_ON(ret < 0); +} + +static int dwc3_ep0_set_sel(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) +{ + struct dwc3_ep *dep; + u16 wLength; + u16 wValue; + + if (dwc->dev_state == DWC3_DEFAULT_STATE) + return -EINVAL; + + wValue = le16_to_cpu(ctrl->wValue); + wLength = le16_to_cpu(ctrl->wLength); + + if (wLength != 6) { + dev_err(dwc->dev, "Set SEL should be 6 bytes, got %d\n", + wLength); + return -EINVAL; + } + + /* + * To handle Set SEL we need to receive 6 bytes from Host. So let's + * queue a usb_request for 6 bytes. + * + * Remember, though, this controller can't handle non-wMaxPacketSize + * aligned transfers on the OUT direction, so we queue a request for + * wMaxPacketSize instead. + */ + dep = dwc->eps[0]; + dwc->ep0_usb_req.dep = dep; + dwc->ep0_usb_req.request.length = dep->endpoint.maxpacket; + dwc->ep0_usb_req.request.buf = dwc->setup_buf; + dwc->ep0_usb_req.request.complete = dwc3_ep0_set_sel_cmpl; + + return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req); +} + +static int dwc3_ep0_set_isoch_delay(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) +{ + u16 wLength; + u16 wValue; + u16 wIndex; + + wValue = le16_to_cpu(ctrl->wValue); + wLength = le16_to_cpu(ctrl->wLength); + wIndex = le16_to_cpu(ctrl->wIndex); + + if (wIndex || wLength) + return -EINVAL; + + /* + * REVISIT It's unclear from Databook what to do with this + * value. For now, just cache it. + */ + dwc->isoch_delay = wValue; + + return 0; +} + static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) { int ret; @@ -494,6 +619,14 @@ static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n"); ret = dwc3_ep0_set_config(dwc, ctrl); break; + case USB_REQ_SET_SEL: + dev_vdbg(dwc->dev, "USB_REQ_SET_SEL\n"); + ret = dwc3_ep0_set_sel(dwc, ctrl); + break; + case USB_REQ_SET_ISOCH_DELAY: + dev_vdbg(dwc->dev, "USB_REQ_SET_ISOCH_DELAY\n"); + ret = dwc3_ep0_set_isoch_delay(dwc, ctrl); + break; default: dev_vdbg(dwc->dev, "Forwarding to gadget driver\n"); ret = dwc3_ep0_delegate_req(dwc, ctrl); diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 5255fe975ea1..3df1a1973b05 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -178,8 +178,8 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc) if (!(dep->flags & DWC3_EP_ENABLED)) continue; - if (usb_endpoint_xfer_bulk(dep->desc) - || usb_endpoint_xfer_isoc(dep->desc)) + if (usb_endpoint_xfer_bulk(dep->endpoint.desc) + || usb_endpoint_xfer_isoc(dep->endpoint.desc)) mult = 3; /* @@ -229,7 +229,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, * completed (not the LINK TRB). */ if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && - usb_endpoint_xfer_isoc(dep->desc)) + usb_endpoint_xfer_isoc(dep->endpoint.desc)) dep->busy_slot++; } list_del(&req->list); @@ -276,6 +276,33 @@ static const char *dwc3_gadget_ep_cmd_string(u8 cmd) } } +int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param) +{ + u32 timeout = 500; + u32 reg; + + dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); + dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); + + do { + reg = dwc3_readl(dwc->regs, DWC3_DGCMD); + if (!(reg & DWC3_DGCMD_CMDACT)) { + dev_vdbg(dwc->dev, "Command Complete --> %d\n", + DWC3_DGCMD_STATUS(reg)); + return 0; + } + + /* + * We can't sleep here, because it's also called from + * interrupt context. + */ + timeout--; + if (!timeout) + return -ETIMEDOUT; + udelay(1); + } while (1); +} + int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params) { @@ -470,7 +497,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, if (ret) return ret; - dep->desc = desc; + dep->endpoint.desc = desc; dep->comp_desc = comp_desc; dep->type = usb_endpoint_type(desc); dep->flags |= DWC3_EP_ENABLED; @@ -533,7 +560,6 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep) dwc3_writel(dwc->regs, DWC3_DALEPENA, reg); dep->stream_capable = false; - dep->desc = NULL; dep->endpoint.desc = NULL; dep->comp_desc = NULL; dep->type = 0; @@ -694,7 +720,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, /* Skip the LINK-TRB on ISOC */ if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) && - usb_endpoint_xfer_isoc(dep->desc)) + usb_endpoint_xfer_isoc(dep->endpoint.desc)) return; if (!req->trb) { @@ -707,7 +733,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->bpl = lower_32_bits(dma); trb->bph = upper_32_bits(dma); - switch (usb_endpoint_type(dep->desc)) { + switch (usb_endpoint_type(dep->endpoint.desc)) { case USB_ENDPOINT_XFER_CONTROL: trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP; break; @@ -732,7 +758,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, BUG(); } - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI; trb->ctrl |= DWC3_TRB_CTRL_CSP; } else { @@ -743,7 +769,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep, trb->ctrl |= DWC3_TRB_CTRL_LST; } - if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable) + if (usb_endpoint_xfer_bulk(dep->endpoint.desc) && dep->stream_capable) trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id); trb->ctrl |= DWC3_TRB_CTRL_HWO; @@ -771,7 +797,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK; /* Can't wrap around on a non-isoc EP since there's no link TRB */ - if (!usb_endpoint_xfer_isoc(dep->desc)) { + if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK); if (trbs_left > max) trbs_left = max; @@ -797,7 +823,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) * processed from the first TRB until the last one. Since we * don't wrap around we have to start at the beginning. */ - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dep->busy_slot = 1; dep->free_slot = 1; } else { @@ -807,7 +833,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting) } /* The last TRB is a link TRB, not used for xfer */ - if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc)) + if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->endpoint.desc)) return; list_for_each_entry_safe(req, n, &dep->request_list, list) { @@ -930,10 +956,12 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param, } dep->flags |= DWC3_EP_BUSY; - dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, - dep->number); - WARN_ON_ONCE(!dep->res_trans_idx); + if (start_new) { + dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc, + dep->number); + WARN_ON_ONCE(!dep->res_trans_idx); + } return 0; } @@ -967,28 +995,37 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req) list_add_tail(&req->list, &dep->request_list); + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && (dep->flags & DWC3_EP_BUSY)) + dep->flags |= DWC3_EP_PENDING_REQUEST; + /* - * There is one special case: XferNotReady with - * empty list of requests. We need to kick the - * transfer here in that situation, otherwise - * we will be NAKing forever. + * There are two special cases: + * + * 1. XferNotReady with empty list of requests. We need to kick the + * transfer here in that situation, otherwise we will be NAKing + * forever. If we get XferNotReady before gadget driver has a + * chance to queue a request, we will ACK the IRQ but won't be + * able to receive the data until the next request is queued. + * The following code is handling exactly that. * - * If we get XferNotReady before gadget driver - * has a chance to queue a request, we will ACK - * the IRQ but won't be able to receive the data - * until the next request is queued. The following - * code is handling exactly that. + * 2. XferInProgress on Isoc EP with an active transfer. We need to + * kick the transfer here after queuing a request, otherwise the + * core may not see the modified TRB(s). */ if (dep->flags & DWC3_EP_PENDING_REQUEST) { - int ret; - int start_trans; + int ret; + int start_trans = 1; + u8 trans_idx = dep->res_trans_idx; - start_trans = 1; - if (usb_endpoint_xfer_isoc(dep->desc) && - (dep->flags & DWC3_EP_BUSY)) + if (usb_endpoint_xfer_isoc(dep->endpoint.desc) && + (dep->flags & DWC3_EP_BUSY)) { start_trans = 0; + WARN_ON_ONCE(!trans_idx); + } else { + trans_idx = 0; + } - ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans); + ret = __dwc3_gadget_kick_transfer(dep, trans_idx, start_trans); if (ret && ret != -EBUSY) { struct dwc3 *dwc = dep->dwc; @@ -1011,7 +1048,7 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request, int ret; - if (!dep->desc) { + if (!dep->endpoint.desc) { dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n", request, ep->name); return -ESHUTDOWN; @@ -1125,7 +1162,7 @@ static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value) spin_lock_irqsave(&dwc->lock, flags); - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name); ret = -EINVAL; goto out; @@ -1356,7 +1393,24 @@ static int dwc3_gadget_start(struct usb_gadget *g, reg = dwc3_readl(dwc->regs, DWC3_DCFG); reg &= ~(DWC3_DCFG_SPEED_MASK); - reg |= dwc->maximum_speed; + + /** + * WORKAROUND: DWC3 revision < 2.20a have an issue + * which would cause metastability state on Run/Stop + * bit if we try to force the IP to USB2-only mode. + * + * Because of that, we cannot configure the IP to any + * speed other than the SuperSpeed + * + * Refers to: + * + * STAR#9000525659: Clock Domain Crossing on DCTL in + * USB 2.0 Mode + */ + if (dwc->revision < DWC3_REVISION_220A) + reg |= DWC3_DCFG_SUPERSPEED; + else + reg |= dwc->maximum_speed; dwc3_writel(dwc->regs, DWC3_DCFG, reg); dwc->start_config_issued = false; @@ -1681,7 +1735,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, case DWC3_DEPEVT_XFERCOMPLETE: dep->res_trans_idx = 0; - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n", dep->name); return; @@ -1690,7 +1744,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dwc3_endpoint_transfer_complete(dwc, dep, event, 1); break; case DWC3_DEPEVT_XFERINPROGRESS: - if (!usb_endpoint_xfer_isoc(dep->desc)) { + if (!usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n", dep->name); return; @@ -1699,7 +1753,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, dwc3_endpoint_transfer_complete(dwc, dep, event, 0); break; case DWC3_DEPEVT_XFERNOTREADY: - if (usb_endpoint_xfer_isoc(dep->desc)) { + if (usb_endpoint_xfer_isoc(dep->endpoint.desc)) { dwc3_gadget_start_isoc(dwc, dep, event); } else { int ret; @@ -1720,7 +1774,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc, break; case DWC3_DEPEVT_STREAMEVT: - if (!usb_endpoint_xfer_bulk(dep->desc)) { + if (!usb_endpoint_xfer_bulk(dep->endpoint.desc)) { dev_err(dwc->dev, "Stream event for non-Bulk %s\n", dep->name); return; @@ -1916,6 +1970,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg &= ~DWC3_DCTL_TSTCTRL_MASK; + reg &= ~(DWC3_DCTL_INITU1ENA | DWC3_DCTL_INITU2ENA); dwc3_writel(dwc->regs, DWC3_DCTL, reg); dwc->test_mode = false; @@ -2263,8 +2318,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) goto err1; } - dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2, - GFP_KERNEL); + dwc->setup_buf = kzalloc(DWC3_EP0_BOUNCE_SIZE, GFP_KERNEL); if (!dwc->setup_buf) { dev_err(dwc->dev, "failed to allocate setup buffer\n"); ret = -ENOMEM; @@ -2272,7 +2326,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) } dwc->ep0_bounce = dma_alloc_coherent(dwc->dev, - 512, &dwc->ep0_bounce_addr, GFP_KERNEL); + DWC3_EP0_BOUNCE_SIZE, &dwc->ep0_bounce_addr, + GFP_KERNEL); if (!dwc->ep0_bounce) { dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n"); ret = -ENOMEM; @@ -2313,6 +2368,14 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) goto err5; } + reg = dwc3_readl(dwc->regs, DWC3_DCFG); + reg |= DWC3_DCFG_LPM_CAP; + dwc3_writel(dwc->regs, DWC3_DCFG, reg); + + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= DWC3_DCTL_ACCEPTU1ENA | DWC3_DCTL_ACCEPTU2ENA; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + /* Enable all but Start and End of Frame IRQs */ reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN | DWC3_DEVTEN_EVNTOVERFLOWEN | @@ -2351,8 +2414,8 @@ err5: dwc3_gadget_free_endpoints(dwc); err4: - dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, - dwc->ep0_bounce_addr); + dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, + dwc->ep0_bounce, dwc->ep0_bounce_addr); err3: kfree(dwc->setup_buf); @@ -2381,8 +2444,8 @@ void dwc3_gadget_exit(struct dwc3 *dwc) dwc3_gadget_free_endpoints(dwc); - dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce, - dwc->ep0_bounce_addr); + dma_free_coherent(dwc->dev, DWC3_EP0_BOUNCE_SIZE, + dwc->ep0_bounce, dwc->ep0_bounce_addr); kfree(dwc->setup_buf); diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index a8600084348c..95ef6a2f7764 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -111,6 +111,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); +int dwc3_send_gadget_generic_command(struct dwc3 *dwc, int cmd, u32 param); /** * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index b108d18fd40d..56a62342884d 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -39,15 +39,6 @@ #include "core.h" -static struct resource generic_resources[] = { - { - .flags = IORESOURCE_IRQ, - }, - { - .flags = IORESOURCE_MEM, - }, -}; - int dwc3_host_init(struct dwc3 *dwc) { struct platform_device *xhci; @@ -68,14 +59,8 @@ int dwc3_host_init(struct dwc3 *dwc) dwc->xhci = xhci; - /* setup resources */ - generic_resources[0].start = dwc->irq; - - generic_resources[1].start = dwc->res->start; - generic_resources[1].end = dwc->res->start + 0x7fff; - - ret = platform_device_add_resources(xhci, generic_resources, - ARRAY_SIZE(generic_resources)); + ret = platform_device_add_resources(xhci, dwc->xhci_resources, + DWC3_XHCI_RESOURCES_NUM); if (ret) { dev_err(dwc->dev, "couldn't add resources to xHCI device\n"); goto err1; diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h index 071d561f3e68..a50f76b9d19b 100644 --- a/drivers/usb/dwc3/io.h +++ b/drivers/usb/dwc3/io.h @@ -41,14 +41,26 @@ #include <linux/io.h> +#include "core.h" + static inline u32 dwc3_readl(void __iomem *base, u32 offset) { - return readl(base + offset); + /* + * We requested the mem region starting from the Globals address + * space, see dwc3_probe in core.c. + * However, the offsets are given starting from xHCI address space. + */ + return readl(base + (offset - DWC3_GLOBALS_REGS_START)); } static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value) { - writel(value, base + offset); + /* + * We requested the mem region starting from the Globals address + * space, see dwc3_probe in core.c. + * However, the offsets are given starting from xHCI address space. + */ + writel(value, base + (offset - DWC3_GLOBALS_REGS_START)); } #endif /* __DRIVERS_USB_DWC3_IO_H */ diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2633f7595116..bddc8fd9a7be 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -123,13 +123,7 @@ config USB_GADGET_STORAGE_NUM_BUFFERS # - discrete ones (including all PCI-only controllers) # - debug/dummy gadget+hcd is last. # -choice - prompt "USB Peripheral Controller" - help - A USB device uses a controller to talk to its host. - Systems should have only one such upstream link. - Many controller drivers are platform-specific; these - often need board-specific hooks. +menu "USB Peripheral Controller" # # Integrated controllers @@ -147,6 +141,17 @@ config USB_AT91 dynamically linked module called "at91_udc" and force all gadget drivers to also be dynamically linked. +config USB_LPC32XX + tristate "LPC32XX USB Peripheral Controller" + depends on ARCH_LPC32XX + select USB_ISP1301 + help + This option selects the USB device controller in the LPC32xx SoC. + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "lpc32xx_udc" and force all + gadget drivers to also be dynamically linked. + config USB_ATMEL_USBA tristate "Atmel USBA" select USB_GADGET_DUALSPEED @@ -161,7 +166,7 @@ config USB_FSL_USB2 select USB_GADGET_DUALSPEED select USB_FSL_MPH_DR_OF if OF help - Some of Freescale PowerPC processors have a High Speed + Some of Freescale PowerPC and i.MX processors have a High Speed Dual-Role(DR) USB controller, which supports device mode. The number of programmable endpoints is different through @@ -373,18 +378,6 @@ config USB_FSL_QE Set CONFIG_USB_GADGET to "m" to build this driver as a dynamically linked module called "fsl_qe_udc". -config USB_CI13XXX_PCI - tristate "MIPS USB CI13xxx PCI UDC" - depends on PCI - select USB_GADGET_DUALSPEED - help - MIPS USB IP core family device controller - Currently it only supports IP part number CI13412 - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "ci13xxx_udc" and force all - gadget drivers to also be dynamically linked. - config USB_NET2272 tristate "PLX NET2272" select USB_GADGET_DUALSPEED @@ -438,22 +431,6 @@ config USB_GOKU dynamically linked module called "goku_udc" and to force all gadget drivers to also be dynamically linked. -config USB_LANGWELL - tristate "Intel Langwell USB Device Controller" - depends on PCI - depends on !PHYS_ADDR_T_64BIT - select USB_GADGET_DUALSPEED - help - Intel Langwell USB Device Controller is a High-Speed USB - On-The-Go device controller. - - The number of programmable endpoints is different through - controller revision. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "langwell_udc" and force all - gadget drivers to also be dynamically linked. - config USB_EG20T tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" depends on PCI @@ -477,23 +454,6 @@ config USB_EG20T ML7213/ML7831 is companion chip for Intel Atom E6xx series. ML7213/ML7831 is completely compatible for Intel EG20T PCH. -config USB_CI13XXX_MSM - tristate "MIPS USB CI13xxx for MSM" - depends on ARCH_MSM - select USB_GADGET_DUALSPEED - select USB_MSM_OTG - help - MSM SoC has chipidea USB controller. This driver uses - ci13xxx_udc core. - This driver depends on OTG driver for PHY initialization, - clock management, powering up VBUS, and power management. - This driver is not supported on boards like trout which - has an external PHY. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "ci13xxx_msm" and force all - gadget drivers to also be dynamically linked. - # # LAST -- dummy/emulated controller # @@ -525,7 +485,7 @@ config USB_DUMMY_HCD # NOTE: Please keep dummy_hcd LAST so that "real hardware" appears # first and will be selected by default. -endchoice +endmenu # Selected by UDC drivers that support high-speed operation. config USB_GADGET_DUALSPEED @@ -798,6 +758,16 @@ config USB_MASS_STORAGE Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_mass_storage". +config USB_GADGET_TARGET + tristate "USB Gadget Target Fabric Module" + depends on TARGET_CORE + help + This fabric is an USB gadget. Two USB protocols are supported that is + BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is + advertised on alternative interface 0 (primary) and UAS is on + alternative interface 1. Both protocols can work on USB2.0 and USB3.0. + UAS utilizes the USB 3.0 feature called streams support. + config USB_G_SERIAL tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" help diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index b7f6eefc3927..1811513f1c27 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -22,14 +22,12 @@ fsl_usb2_udc-$(CONFIG_ARCH_MXC) += fsl_mxc_udc.o obj-$(CONFIG_USB_M66592) += m66592-udc.o obj-$(CONFIG_USB_R8A66597) += r8a66597-udc.o obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o -obj-$(CONFIG_USB_CI13XXX_PCI) += ci13xxx_pci.o obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o obj-$(CONFIG_USB_S3C_HSUDC) += s3c-hsudc.o -obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o +obj-$(CONFIG_USB_LPC32XX) += lpc32xx_udc.o obj-$(CONFIG_USB_EG20T) += pch_udc.o obj-$(CONFIG_USB_MV_UDC) += mv_udc.o mv_udc-y := mv_udc_core.o -obj-$(CONFIG_USB_CI13XXX_MSM) += ci13xxx_msm.o obj-$(CONFIG_USB_FUSB300) += fusb300_udc.o # @@ -52,6 +50,7 @@ g_nokia-y := nokia.o g_webcam-y := webcam.o g_ncm-y := ncm.o g_acm_ms-y := acm_ms.o +g_tcm_usb_gadget-y := tcm_usb_gadget.o obj-$(CONFIG_USB_ZERO) += g_zero.o obj-$(CONFIG_USB_AUDIO) += g_audio.o @@ -71,3 +70,4 @@ obj-$(CONFIG_USB_G_NOKIA) += g_nokia.o obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o obj-$(CONFIG_USB_G_NCM) += g_ncm.o obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o +obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c index 77779271f487..187d21181cd5 100644 --- a/drivers/usb/gadget/amd5536udc.c +++ b/drivers/usb/gadget/amd5536udc.c @@ -333,7 +333,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc) return -ESHUTDOWN; spin_lock_irqsave(&dev->lock, iflags); - ep->desc = desc; + ep->ep.desc = desc; ep->halted = 0; @@ -442,7 +442,6 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep) u32 tmp; VDBG(ep->dev, "ep-%d reset\n", ep->num); - ep->desc = NULL; ep->ep.desc = NULL; ep->ep.ops = &udc_ep_ops; INIT_LIST_HEAD(&ep->queue); @@ -489,7 +488,7 @@ static int udc_ep_disable(struct usb_ep *usbep) return -EINVAL; ep = container_of(usbep, struct udc_ep, ep); - if (usbep->name == ep0_string || !ep->desc) + if (usbep->name == ep0_string || !ep->ep.desc) return -EINVAL; DBG(ep->dev, "Disable ep-%d\n", ep->num); @@ -1066,7 +1065,7 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp) return -EINVAL; ep = container_of(usbep, struct udc_ep, ep); - if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) + if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) return -EINVAL; VDBG(ep->dev, "udc_queue(): ep%d-in=%d\n", ep->num, ep->in); @@ -1257,7 +1256,7 @@ static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq) unsigned long iflags; ep = container_of(usbep, struct udc_ep, ep); - if (!usbep || !usbreq || (!ep->desc && (ep->num != 0 + if (!usbep || !usbreq || (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX))) return -EINVAL; @@ -1317,7 +1316,7 @@ udc_set_halt(struct usb_ep *usbep, int halt) pr_debug("set_halt %s: halt=%d\n", usbep->name, halt); ep = container_of(usbep, struct udc_ep, ep); - if (!ep->desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) + if (!ep->ep.desc && (ep->num != 0 && ep->num != UDC_EP0OUT_IX)) return -EINVAL; if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN) return -ESHUTDOWN; @@ -1539,7 +1538,7 @@ static void udc_setup_endpoints(struct udc *dev) * disabling ep interrupts when ENUM interrupt occurs but ep is * not enabled by gadget driver */ - if (!ep->desc) + if (!ep->ep.desc) ep_init(dev->regs, ep); if (use_dma) { @@ -3402,19 +3401,7 @@ static struct pci_driver udc_pci_driver = { .remove = udc_pci_remove, }; -/* Inits driver */ -static int __init init(void) -{ - return pci_register_driver(&udc_pci_driver); -} -module_init(init); - -/* Cleans driver */ -static void __exit cleanup(void) -{ - pci_unregister_driver(&udc_pci_driver); -} -module_exit(cleanup); +module_pci_driver(udc_pci_driver); MODULE_DESCRIPTION(UDC_MOD_DESCRIPTION); MODULE_AUTHOR("Thomas Dahlmann"); diff --git a/drivers/usb/gadget/amd5536udc.h b/drivers/usb/gadget/amd5536udc.h index f87e29c65325..14af87d65caa 100644 --- a/drivers/usb/gadget/amd5536udc.h +++ b/drivers/usb/gadget/amd5536udc.h @@ -512,7 +512,6 @@ struct udc_ep { /* queue for requests */ struct list_head queue; - const struct usb_endpoint_descriptor *desc; unsigned halted; unsigned cancel_transfer; unsigned num : 5, diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 9d7bcd910074..1a4430f315c3 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -212,7 +212,7 @@ static int proc_udc_show(struct seq_file *s, void *unused) if (udc->enabled && udc->vbus) { proc_ep_show(s, &udc->ep[0]); list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) + if (ep->ep.desc) proc_ep_show(s, ep); } } @@ -475,7 +475,7 @@ static int at91_ep_enable(struct usb_ep *_ep, unsigned long flags; if (!_ep || !ep - || !desc || ep->desc + || !desc || ep->ep.desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || (maxpacket = usb_endpoint_maxp(desc)) == 0 @@ -530,7 +530,7 @@ ok: tmp |= AT91_UDP_EPEDS; __raw_writel(tmp, ep->creg); - ep->desc = desc; + ep->ep.desc = desc; ep->ep.maxpacket = maxpacket; /* @@ -558,7 +558,6 @@ static int at91_ep_disable (struct usb_ep * _ep) nuke(ep, -ESHUTDOWN); /* restore the endpoint's pristine config */ - ep->desc = NULL; ep->ep.desc = NULL; ep->ep.maxpacket = ep->maxpacket; @@ -618,7 +617,7 @@ static int at91_ep_queue(struct usb_ep *_ep, return -EINVAL; } - if (!_ep || (!ep->desc && ep->ep.name != ep0name)) { + if (!_ep || (!ep->ep.desc && ep->ep.name != ep0name)) { DBG("invalid ep\n"); return -EINVAL; } @@ -833,7 +832,7 @@ static void udc_reinit(struct at91_udc *udc) if (i != 0) list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); - ep->desc = NULL; + ep->ep.desc = NULL; ep->stopped = 0; ep->fifo_bank = 0; ep->ep.maxpacket = ep->maxpacket; @@ -978,18 +977,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on) return 0; } -static int at91_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int at91_stop(struct usb_gadget_driver *driver); - +static int at91_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int at91_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops at91_udc_ops = { .get_frame = at91_get_frame, .wakeup = at91_wakeup, .set_selfpowered = at91_set_selfpowered, .vbus_session = at91_vbus_session, .pullup = at91_pullup, - .start = at91_start, - .stop = at91_stop, + .udc_start = at91_start, + .udc_stop = at91_stop, /* * VBUS-powered devices may also also want to support bigger @@ -1172,7 +1171,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) | USB_REQ_GET_STATUS: tmp = w_index & USB_ENDPOINT_NUMBER_MASK; ep = &udc->ep[tmp]; - if (tmp >= NUM_ENDPOINTS || (tmp && !ep->desc)) + if (tmp >= NUM_ENDPOINTS || (tmp && !ep->ep.desc)) goto stall; if (tmp) { @@ -1197,7 +1196,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) ep = &udc->ep[tmp]; if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS) goto stall; - if (!ep->desc || ep->is_iso) + if (!ep->ep.desc || ep->is_iso) goto stall; if ((w_index & USB_DIR_IN)) { if (!ep->is_in) @@ -1218,7 +1217,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr) goto stall; if (tmp == 0) goto succeed; - if (!ep->desc || ep->is_iso) + if (!ep->ep.desc || ep->is_iso) goto stall; if ((w_index & USB_DIR_IN)) { if (!ep->is_in) @@ -1627,66 +1626,34 @@ static void at91_vbus_timer(unsigned long data) schedule_work(&udc->vbus_timer_work); } -static int at91_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int at91_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct at91_udc *udc = &controller; - int retval; - unsigned long flags; - - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->setup) { - DBG("bad parameter.\n"); - return -EINVAL; - } - - if (udc->driver) { - DBG("UDC already has a gadget driver\n"); - return -EBUSY; - } + struct at91_udc *udc; + udc = container_of(gadget, struct at91_udc, gadget); udc->driver = driver; udc->gadget.dev.driver = &driver->driver; dev_set_drvdata(&udc->gadget.dev, &driver->driver); udc->enabled = 1; udc->selfpowered = 1; - retval = bind(&udc->gadget); - if (retval) { - DBG("bind() returned %d\n", retval); - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - dev_set_drvdata(&udc->gadget.dev, NULL); - udc->enabled = 0; - udc->selfpowered = 0; - return retval; - } - - spin_lock_irqsave(&udc->lock, flags); - pullup(udc, 1); - spin_unlock_irqrestore(&udc->lock, flags); - DBG("bound to %s\n", driver->driver.name); return 0; } -static int at91_stop(struct usb_gadget_driver *driver) +static int at91_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct at91_udc *udc = &controller; + struct at91_udc *udc; unsigned long flags; - if (!driver || driver != udc->driver || !driver->unbind) - return -EINVAL; - + udc = container_of(gadget, struct at91_udc, gadget); spin_lock_irqsave(&udc->lock, flags); udc->enabled = 0; at91_udp_write(udc, AT91_UDP_IDR, ~0); - pullup(udc, 0); spin_unlock_irqrestore(&udc->lock, flags); - driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; dev_set_drvdata(&udc->gadget.dev, NULL); udc->driver = NULL; diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h index 3c0315b86ace..e647d1c2ada4 100644 --- a/drivers/usb/gadget/at91_udc.h +++ b/drivers/usb/gadget/at91_udc.h @@ -105,9 +105,6 @@ struct at91_ep { unsigned is_in:1; unsigned is_iso:1; unsigned fifo_bank:1; - - const struct usb_endpoint_descriptor - *desc; }; /* diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c index 9f98508966d1..e23bf7984aaf 100644 --- a/drivers/usb/gadget/atmel_usba_udc.c +++ b/drivers/usb/gadget/atmel_usba_udc.c @@ -599,13 +599,13 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) spin_lock_irqsave(&ep->udc->lock, flags); - if (ep->desc) { + if (ep->ep.desc) { spin_unlock_irqrestore(&ep->udc->lock, flags); DBG(DBG_ERR, "ep%d already enabled\n", ep->index); return -EBUSY; } - ep->desc = desc; + ep->ep.desc = desc; ep->ep.maxpacket = maxpacket; usba_ep_writel(ep, CFG, ept_cfg); @@ -647,7 +647,7 @@ static int usba_ep_disable(struct usb_ep *_ep) spin_lock_irqsave(&udc->lock, flags); - if (!ep->desc) { + if (!ep->ep.desc) { spin_unlock_irqrestore(&udc->lock, flags); /* REVISIT because this driver disables endpoints in * reset_all_endpoints() before calling disconnect(), @@ -658,7 +658,6 @@ static int usba_ep_disable(struct usb_ep *_ep) ep->ep.name); return -EINVAL; } - ep->desc = NULL; ep->ep.desc = NULL; list_splice_init(&ep->queue, &req_list); @@ -752,7 +751,7 @@ static int queue_dma(struct usba_udc *udc, struct usba_ep *ep, */ ret = -ESHUTDOWN; spin_lock_irqsave(&udc->lock, flags); - if (ep->desc) { + if (ep->ep.desc) { if (list_empty(&ep->queue)) submit_request(ep, req); @@ -776,7 +775,8 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) 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) + if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || + !ep->ep.desc) return -ESHUTDOWN; req->submitted = 0; @@ -792,7 +792,7 @@ usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* May have received a reset since last time we checked */ ret = -ESHUTDOWN; spin_lock_irqsave(&udc->lock, flags); - if (ep->desc) { + if (ep->ep.desc) { list_add_tail(&req->queue, &ep->queue); if ((!ep_is_control(ep) && ep->is_in) || @@ -905,7 +905,7 @@ static int usba_ep_set_halt(struct usb_ep *_ep, int value) DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name, value ? "set" : "clear"); - if (!ep->desc) { + if (!ep->ep.desc) { DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n", ep->ep.name); return -ENODEV; @@ -1008,16 +1008,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered) return 0; } -static int atmel_usba_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int atmel_usba_stop(struct usb_gadget_driver *driver); - +static int atmel_usba_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int atmel_usba_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); 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, - .start = atmel_usba_start, - .stop = atmel_usba_stop, + .udc_start = atmel_usba_start, + .udc_stop = atmel_usba_stop, }; static struct usb_endpoint_descriptor usba_ep0_desc = { @@ -1071,7 +1071,7 @@ static void reset_all_endpoints(struct usba_udc *udc) * FIXME remove this code ... and retest thoroughly. */ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { + if (ep->ep.desc) { spin_unlock(&udc->lock); usba_ep_disable(&ep->ep); spin_lock(&udc->lock); @@ -1089,9 +1089,9 @@ static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex) list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { u8 bEndpointAddress; - if (!ep->desc) + if (!ep->ep.desc) continue; - bEndpointAddress = ep->desc->bEndpointAddress; + bEndpointAddress = ep->ep.desc->bEndpointAddress; if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) continue; if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) @@ -1727,7 +1727,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid) usb_speed_string(udc->gadget.speed)); ep0 = &usba_ep[0]; - ep0->desc = &usba_ep0_desc; + ep0->ep.desc = &usba_ep0_desc; ep0->state = WAIT_FOR_SETUP; usba_ep_writel(ep0, CFG, (USBA_BF(EPT_SIZE, EP0_EPT_SIZE) @@ -1795,21 +1795,13 @@ out: return IRQ_HANDLED; } -static int atmel_usba_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int atmel_usba_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct usba_udc *udc = &the_udc; + struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); unsigned long flags; - int ret; - - if (!udc->pdev) - return -ENODEV; spin_lock_irqsave(&udc->lock, flags); - if (udc->driver) { - spin_unlock_irqrestore(&udc->lock, flags); - return -EBUSY; - } udc->devstatus = 1 << USB_DEVICE_SELF_POWERED; udc->driver = driver; @@ -1819,13 +1811,6 @@ static int atmel_usba_start(struct usb_gadget_driver *driver, clk_enable(udc->pclk); clk_enable(udc->hclk); - ret = bind(&udc->gadget); - if (ret) { - DBG(DBG_ERR, "Could not bind to driver %s: error %d\n", - driver->driver.name, ret); - goto err_driver_bind; - } - DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name); udc->vbus_prev = 0; @@ -1842,23 +1827,14 @@ static int atmel_usba_start(struct usb_gadget_driver *driver, spin_unlock_irqrestore(&udc->lock, flags); return 0; - -err_driver_bind: - udc->driver = NULL; - udc->gadget.dev.driver = NULL; - return ret; } -static int atmel_usba_stop(struct usb_gadget_driver *driver) +static int atmel_usba_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct usba_udc *udc = &the_udc; + struct usba_udc *udc = container_of(gadget, struct usba_udc, gadget); unsigned long flags; - if (!udc->pdev) - return -ENODEV; - if (driver != udc->driver || !driver->unbind) - return -EINVAL; - if (gpio_is_valid(udc->vbus_pin)) disable_irq(gpio_to_irq(udc->vbus_pin)); @@ -1871,10 +1847,6 @@ static int atmel_usba_stop(struct usb_gadget_driver *driver) toggle_bias(0); usba_writel(udc, CTRL, USBA_DISABLE_MASK); - if (udc->driver->disconnect) - udc->driver->disconnect(&udc->gadget); - - driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; udc->driver = NULL; diff --git a/drivers/usb/gadget/atmel_usba_udc.h b/drivers/usb/gadget/atmel_usba_udc.h index 88a2e07a11a8..9791259cbda7 100644 --- a/drivers/usb/gadget/atmel_usba_udc.h +++ b/drivers/usb/gadget/atmel_usba_udc.h @@ -280,7 +280,6 @@ struct usba_ep { struct usba_udc *udc; struct list_head queue; - const struct usb_endpoint_descriptor *desc; u16 fifo_size; u8 nr_banks; diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c deleted file mode 100644 index 243ef1adf969..000000000000 --- a/drivers/usb/gadget/ci13xxx_udc.c +++ /dev/null @@ -1,2996 +0,0 @@ -/* - * ci13xxx_udc.c - MIPS USB IP core family device controller - * - * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. - * - * Author: David Lopo - * - * 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. - */ - -/* - * Description: MIPS USB IP core family device controller - * Currently it only supports IP part number CI13412 - * - * This driver is composed of several blocks: - * - HW: hardware interface - * - DBG: debug facilities (optional) - * - UTIL: utilities - * - ISR: interrupts handling - * - ENDPT: endpoint operations (Gadget API) - * - GADGET: gadget operations (Gadget API) - * - BUS: bus glue code, bus abstraction layer - * - * Compile Options - * - CONFIG_USB_GADGET_DEBUG_FILES: enable debug facilities - * - STALL_IN: non-empty bulk-in pipes cannot be halted - * if defined mass storage compliance succeeds but with warnings - * => case 4: Hi > Dn - * => case 5: Hi > Di - * => case 8: Hi <> Do - * if undefined usbtest 13 fails - * - TRACE: enable function tracing (depends on DEBUG) - * - * Main Features - * - Chapter 9 & Mass Storage Compliance with Gadget File Storage - * - Chapter 9 Compliance with Gadget Zero (STALL_IN undefined) - * - Normal & LPM support - * - * USBTEST Report - * - OK: 0-12, 13 (STALL_IN defined) & 14 - * - Not Supported: 15 & 16 (ISO) - * - * TODO List - * - OTG - * - Isochronous & Interrupt Traffic - * - Handle requests which spawns into several TDs - * - GET_STATUS(device) - always reports 0 - * - Gadget API (majority of optional features) - * - Suspend & Remote Wakeup - */ -#include <linux/delay.h> -#include <linux/device.h> -#include <linux/dmapool.h> -#include <linux/dma-mapping.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/pm_runtime.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb/otg.h> - -#include "ci13xxx_udc.h" - - -/****************************************************************************** - * DEFINE - *****************************************************************************/ - -#define DMA_ADDR_INVALID (~(dma_addr_t)0) - -/* ctrl register bank access */ -static DEFINE_SPINLOCK(udc_lock); - -/* control endpoint description */ -static const struct usb_endpoint_descriptor -ctrl_endpt_out_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_OUT, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), -}; - -static const struct usb_endpoint_descriptor -ctrl_endpt_in_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - - .bEndpointAddress = USB_DIR_IN, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = cpu_to_le16(CTRL_PAYLOAD_MAX), -}; - -/* UDC descriptor */ -static struct ci13xxx *_udc; - -/* Interrupt statistics */ -#define ISR_MASK 0x1F -static struct { - u32 test; - u32 ui; - u32 uei; - u32 pci; - u32 uri; - u32 sli; - u32 none; - struct { - u32 cnt; - u32 buf[ISR_MASK+1]; - u32 idx; - } hndl; -} isr_statistics; - -/** - * ffs_nr: find first (least significant) bit set - * @x: the word to search - * - * This function returns bit number (instead of position) - */ -static int ffs_nr(u32 x) -{ - int n = ffs(x); - - return n ? n-1 : 32; -} - -/****************************************************************************** - * HW block - *****************************************************************************/ -/* register bank descriptor */ -static struct { - unsigned lpm; /* is LPM? */ - void __iomem *abs; /* bus map offset */ - void __iomem *cap; /* bus map offset + CAP offset + CAP data */ - size_t size; /* bank size */ -} hw_bank; - -/* MSM specific */ -#define ABS_AHBBURST (0x0090UL) -#define ABS_AHBMODE (0x0098UL) -/* UDC register map */ -#define ABS_CAPLENGTH (0x100UL) -#define ABS_HCCPARAMS (0x108UL) -#define ABS_DCCPARAMS (0x124UL) -#define ABS_TESTMODE (hw_bank.lpm ? 0x0FCUL : 0x138UL) -/* offset to CAPLENTGH (addr + data) */ -#define CAP_USBCMD (0x000UL) -#define CAP_USBSTS (0x004UL) -#define CAP_USBINTR (0x008UL) -#define CAP_DEVICEADDR (0x014UL) -#define CAP_ENDPTLISTADDR (0x018UL) -#define CAP_PORTSC (0x044UL) -#define CAP_DEVLC (0x084UL) -#define CAP_USBMODE (hw_bank.lpm ? 0x0C8UL : 0x068UL) -#define CAP_ENDPTSETUPSTAT (hw_bank.lpm ? 0x0D8UL : 0x06CUL) -#define CAP_ENDPTPRIME (hw_bank.lpm ? 0x0DCUL : 0x070UL) -#define CAP_ENDPTFLUSH (hw_bank.lpm ? 0x0E0UL : 0x074UL) -#define CAP_ENDPTSTAT (hw_bank.lpm ? 0x0E4UL : 0x078UL) -#define CAP_ENDPTCOMPLETE (hw_bank.lpm ? 0x0E8UL : 0x07CUL) -#define CAP_ENDPTCTRL (hw_bank.lpm ? 0x0ECUL : 0x080UL) -#define CAP_LAST (hw_bank.lpm ? 0x12CUL : 0x0C0UL) - -/* maximum number of enpoints: valid only after hw_device_reset() */ -static unsigned hw_ep_max; - -/** - * hw_ep_bit: calculates the bit number - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns bit number - */ -static inline int hw_ep_bit(int num, int dir) -{ - return num + (dir ? 16 : 0); -} - -static int ep_to_bit(int n) -{ - int fill = 16 - hw_ep_max / 2; - - if (n >= hw_ep_max / 2) - n += fill; - - return n; -} - -/** - * hw_aread: reads from register bitfield - * @addr: address relative to bus map - * @mask: bitfield mask - * - * This function returns register bitfield data - */ -static u32 hw_aread(u32 addr, u32 mask) -{ - return ioread32(addr + hw_bank.abs) & mask; -} - -/** - * hw_awrite: writes to register bitfield - * @addr: address relative to bus map - * @mask: bitfield mask - * @data: new data - */ -static void hw_awrite(u32 addr, u32 mask, u32 data) -{ - iowrite32(hw_aread(addr, ~mask) | (data & mask), - addr + hw_bank.abs); -} - -/** - * hw_cread: reads from register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * - * This function returns register bitfield data - */ -static u32 hw_cread(u32 addr, u32 mask) -{ - return ioread32(addr + hw_bank.cap) & mask; -} - -/** - * hw_cwrite: writes to register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * @data: new data - */ -static void hw_cwrite(u32 addr, u32 mask, u32 data) -{ - iowrite32(hw_cread(addr, ~mask) | (data & mask), - addr + hw_bank.cap); -} - -/** - * hw_ctest_and_clear: tests & clears register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * - * This function returns register bitfield data - */ -static u32 hw_ctest_and_clear(u32 addr, u32 mask) -{ - u32 reg = hw_cread(addr, mask); - - iowrite32(reg, addr + hw_bank.cap); - return reg; -} - -/** - * hw_ctest_and_write: tests & writes register bitfield - * @addr: address relative to CAP offset plus content - * @mask: bitfield mask - * @data: new data - * - * This function returns register bitfield data - */ -static u32 hw_ctest_and_write(u32 addr, u32 mask, u32 data) -{ - u32 reg = hw_cread(addr, ~0); - - iowrite32((reg & ~mask) | (data & mask), addr + hw_bank.cap); - return (reg & mask) >> ffs_nr(mask); -} - -static int hw_device_init(void __iomem *base) -{ - u32 reg; - - /* bank is a module variable */ - hw_bank.abs = base; - - hw_bank.cap = hw_bank.abs; - hw_bank.cap += ABS_CAPLENGTH; - hw_bank.cap += ioread8(hw_bank.cap); - - reg = hw_aread(ABS_HCCPARAMS, HCCPARAMS_LEN) >> ffs_nr(HCCPARAMS_LEN); - hw_bank.lpm = reg; - hw_bank.size = hw_bank.cap - hw_bank.abs; - hw_bank.size += CAP_LAST; - hw_bank.size /= sizeof(u32); - - reg = hw_aread(ABS_DCCPARAMS, DCCPARAMS_DEN) >> ffs_nr(DCCPARAMS_DEN); - hw_ep_max = reg * 2; /* cache hw ENDPT_MAX */ - - if (hw_ep_max == 0 || hw_ep_max > ENDPT_MAX) - return -ENODEV; - - /* setup lock mode ? */ - - /* ENDPTSETUPSTAT is '0' by default */ - - /* HCSPARAMS.bf.ppc SHOULD BE zero for device */ - - return 0; -} -/** - * hw_device_reset: resets chip (execute without interruption) - * @base: register base address - * - * This function returns an error code - */ -static int hw_device_reset(struct ci13xxx *udc) -{ - /* should flush & stop before reset */ - hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); - hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); - - hw_cwrite(CAP_USBCMD, USBCMD_RST, USBCMD_RST); - while (hw_cread(CAP_USBCMD, USBCMD_RST)) - udelay(10); /* not RTOS friendly */ - - - if (udc->udc_driver->notify_event) - udc->udc_driver->notify_event(udc, - CI13XXX_CONTROLLER_RESET_EVENT); - - if (udc->udc_driver->flags & CI13XXX_DISABLE_STREAMING) - hw_cwrite(CAP_USBMODE, USBMODE_SDIS, USBMODE_SDIS); - - /* USBMODE should be configured step by step */ - hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_IDLE); - hw_cwrite(CAP_USBMODE, USBMODE_CM, USBMODE_CM_DEVICE); - hw_cwrite(CAP_USBMODE, USBMODE_SLOM, USBMODE_SLOM); /* HW >= 2.3 */ - - if (hw_cread(CAP_USBMODE, USBMODE_CM) != USBMODE_CM_DEVICE) { - pr_err("cannot enter in device mode"); - pr_err("lpm = %i", hw_bank.lpm); - return -ENODEV; - } - - return 0; -} - -/** - * hw_device_state: enables/disables interrupts & starts/stops device (execute - * without interruption) - * @dma: 0 => disable, !0 => enable and set dma engine - * - * This function returns an error code - */ -static int hw_device_state(u32 dma) -{ - if (dma) { - hw_cwrite(CAP_ENDPTLISTADDR, ~0, dma); - /* interrupt, error, port change, reset, sleep/suspend */ - hw_cwrite(CAP_USBINTR, ~0, - USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI); - hw_cwrite(CAP_USBCMD, USBCMD_RS, USBCMD_RS); - } else { - hw_cwrite(CAP_USBCMD, USBCMD_RS, 0); - hw_cwrite(CAP_USBINTR, ~0, 0); - } - return 0; -} - -/** - * hw_ep_flush: flush endpoint fifo (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns an error code - */ -static int hw_ep_flush(int num, int dir) -{ - int n = hw_ep_bit(num, dir); - - do { - /* flush any pending transfer */ - hw_cwrite(CAP_ENDPTFLUSH, BIT(n), BIT(n)); - while (hw_cread(CAP_ENDPTFLUSH, BIT(n))) - cpu_relax(); - } while (hw_cread(CAP_ENDPTSTAT, BIT(n))); - - return 0; -} - -/** - * hw_ep_disable: disables endpoint (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns an error code - */ -static int hw_ep_disable(int num, int dir) -{ - hw_ep_flush(num, dir); - hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), - dir ? ENDPTCTRL_TXE : ENDPTCTRL_RXE, 0); - return 0; -} - -/** - * hw_ep_enable: enables endpoint (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * @type: endpoint type - * - * This function returns an error code - */ -static int hw_ep_enable(int num, int dir, int type) -{ - u32 mask, data; - - if (dir) { - mask = ENDPTCTRL_TXT; /* type */ - data = type << ffs_nr(mask); - - mask |= ENDPTCTRL_TXS; /* unstall */ - mask |= ENDPTCTRL_TXR; /* reset data toggle */ - data |= ENDPTCTRL_TXR; - mask |= ENDPTCTRL_TXE; /* enable */ - data |= ENDPTCTRL_TXE; - } else { - mask = ENDPTCTRL_RXT; /* type */ - data = type << ffs_nr(mask); - - mask |= ENDPTCTRL_RXS; /* unstall */ - mask |= ENDPTCTRL_RXR; /* reset data toggle */ - data |= ENDPTCTRL_RXR; - mask |= ENDPTCTRL_RXE; /* enable */ - data |= ENDPTCTRL_RXE; - } - hw_cwrite(CAP_ENDPTCTRL + num * sizeof(u32), mask, data); - return 0; -} - -/** - * hw_ep_get_halt: return endpoint halt status - * @num: endpoint number - * @dir: endpoint direction - * - * This function returns 1 if endpoint halted - */ -static int hw_ep_get_halt(int num, int dir) -{ - u32 mask = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; - - return hw_cread(CAP_ENDPTCTRL + num * sizeof(u32), mask) ? 1 : 0; -} - -/** - * hw_test_and_clear_setup_status: test & clear setup status (execute without - * interruption) - * @n: endpoint number - * - * This function returns setup status - */ -static int hw_test_and_clear_setup_status(int n) -{ - n = ep_to_bit(n); - return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n)); -} - -/** - * hw_ep_prime: primes endpoint (execute without interruption) - * @num: endpoint number - * @dir: endpoint direction - * @is_ctrl: true if control endpoint - * - * This function returns an error code - */ -static int hw_ep_prime(int num, int dir, int is_ctrl) -{ - int n = hw_ep_bit(num, dir); - - if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) - return -EAGAIN; - - hw_cwrite(CAP_ENDPTPRIME, BIT(n), BIT(n)); - - while (hw_cread(CAP_ENDPTPRIME, BIT(n))) - cpu_relax(); - if (is_ctrl && dir == RX && hw_cread(CAP_ENDPTSETUPSTAT, BIT(num))) - return -EAGAIN; - - /* status shoult be tested according with manual but it doesn't work */ - return 0; -} - -/** - * hw_ep_set_halt: configures ep halt & resets data toggle after clear (execute - * without interruption) - * @num: endpoint number - * @dir: endpoint direction - * @value: true => stall, false => unstall - * - * This function returns an error code - */ -static int hw_ep_set_halt(int num, int dir, int value) -{ - if (value != 0 && value != 1) - return -EINVAL; - - do { - u32 addr = CAP_ENDPTCTRL + num * sizeof(u32); - u32 mask_xs = dir ? ENDPTCTRL_TXS : ENDPTCTRL_RXS; - u32 mask_xr = dir ? ENDPTCTRL_TXR : ENDPTCTRL_RXR; - - /* data toggle - reserved for EP0 but it's in ESS */ - hw_cwrite(addr, mask_xs|mask_xr, value ? mask_xs : mask_xr); - - } while (value != hw_ep_get_halt(num, dir)); - - return 0; -} - -/** - * hw_intr_clear: disables interrupt & clears interrupt status (execute without - * interruption) - * @n: interrupt bit - * - * This function returns an error code - */ -static int hw_intr_clear(int n) -{ - if (n >= REG_BITS) - return -EINVAL; - - hw_cwrite(CAP_USBINTR, BIT(n), 0); - hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); - return 0; -} - -/** - * hw_intr_force: enables interrupt & forces interrupt status (execute without - * interruption) - * @n: interrupt bit - * - * This function returns an error code - */ -static int hw_intr_force(int n) -{ - if (n >= REG_BITS) - return -EINVAL; - - hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, TESTMODE_FORCE); - hw_cwrite(CAP_USBINTR, BIT(n), BIT(n)); - hw_cwrite(CAP_USBSTS, BIT(n), BIT(n)); - hw_awrite(ABS_TESTMODE, TESTMODE_FORCE, 0); - return 0; -} - -/** - * hw_is_port_high_speed: test if port is high speed - * - * This function returns true if high speed port - */ -static int hw_port_is_high_speed(void) -{ - return hw_bank.lpm ? hw_cread(CAP_DEVLC, DEVLC_PSPD) : - hw_cread(CAP_PORTSC, PORTSC_HSP); -} - -/** - * hw_port_test_get: reads port test mode value - * - * This function returns port test mode value - */ -static u8 hw_port_test_get(void) -{ - return hw_cread(CAP_PORTSC, PORTSC_PTC) >> ffs_nr(PORTSC_PTC); -} - -/** - * hw_port_test_set: writes port test mode (execute without interruption) - * @mode: new value - * - * This function returns an error code - */ -static int hw_port_test_set(u8 mode) -{ - const u8 TEST_MODE_MAX = 7; - - if (mode > TEST_MODE_MAX) - return -EINVAL; - - hw_cwrite(CAP_PORTSC, PORTSC_PTC, mode << ffs_nr(PORTSC_PTC)); - return 0; -} - -/** - * hw_read_intr_enable: returns interrupt enable register - * - * This function returns register data - */ -static u32 hw_read_intr_enable(void) -{ - return hw_cread(CAP_USBINTR, ~0); -} - -/** - * hw_read_intr_status: returns interrupt status register - * - * This function returns register data - */ -static u32 hw_read_intr_status(void) -{ - return hw_cread(CAP_USBSTS, ~0); -} - -/** - * hw_register_read: reads all device registers (execute without interruption) - * @buf: destination buffer - * @size: buffer size - * - * This function returns number of registers read - */ -static size_t hw_register_read(u32 *buf, size_t size) -{ - unsigned i; - - if (size > hw_bank.size) - size = hw_bank.size; - - for (i = 0; i < size; i++) - buf[i] = hw_aread(i * sizeof(u32), ~0); - - return size; -} - -/** - * hw_register_write: writes to register - * @addr: register address - * @data: register value - * - * This function returns an error code - */ -static int hw_register_write(u16 addr, u32 data) -{ - /* align */ - addr /= sizeof(u32); - - if (addr >= hw_bank.size) - return -EINVAL; - - /* align */ - addr *= sizeof(u32); - - hw_awrite(addr, ~0, data); - return 0; -} - -/** - * hw_test_and_clear_complete: test & clear complete status (execute without - * interruption) - * @n: endpoint number - * - * This function returns complete status - */ -static int hw_test_and_clear_complete(int n) -{ - n = ep_to_bit(n); - return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n)); -} - -/** - * hw_test_and_clear_intr_active: test & clear active interrupts (execute - * without interruption) - * - * This function returns active interrutps - */ -static u32 hw_test_and_clear_intr_active(void) -{ - u32 reg = hw_read_intr_status() & hw_read_intr_enable(); - - hw_cwrite(CAP_USBSTS, ~0, reg); - return reg; -} - -/** - * hw_test_and_clear_setup_guard: test & clear setup guard (execute without - * interruption) - * - * This function returns guard value - */ -static int hw_test_and_clear_setup_guard(void) -{ - return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, 0); -} - -/** - * hw_test_and_set_setup_guard: test & set setup guard (execute without - * interruption) - * - * This function returns guard value - */ -static int hw_test_and_set_setup_guard(void) -{ - return hw_ctest_and_write(CAP_USBCMD, USBCMD_SUTW, USBCMD_SUTW); -} - -/** - * hw_usb_set_address: configures USB address (execute without interruption) - * @value: new USB address - * - * This function returns an error code - */ -static int hw_usb_set_address(u8 value) -{ - /* advance */ - hw_cwrite(CAP_DEVICEADDR, DEVICEADDR_USBADR | DEVICEADDR_USBADRA, - value << ffs_nr(DEVICEADDR_USBADR) | DEVICEADDR_USBADRA); - return 0; -} - -/** - * hw_usb_reset: restart device after a bus reset (execute without - * interruption) - * - * This function returns an error code - */ -static int hw_usb_reset(void) -{ - hw_usb_set_address(0); - - /* ESS flushes only at end?!? */ - hw_cwrite(CAP_ENDPTFLUSH, ~0, ~0); /* flush all EPs */ - - /* clear setup token semaphores */ - hw_cwrite(CAP_ENDPTSETUPSTAT, 0, 0); /* writes its content */ - - /* clear complete status */ - hw_cwrite(CAP_ENDPTCOMPLETE, 0, 0); /* writes its content */ - - /* wait until all bits cleared */ - while (hw_cread(CAP_ENDPTPRIME, ~0)) - udelay(10); /* not RTOS friendly */ - - /* reset all endpoints ? */ - - /* reset internal status and wait for further instructions - no need to verify the port reset status (ESS does it) */ - - return 0; -} - -/****************************************************************************** - * DBG block - *****************************************************************************/ -/** - * show_device: prints information about device capabilities and status - * - * Check "device.h" for details - */ -static ssize_t show_device(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - struct usb_gadget *gadget = &udc->gadget; - int n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - n += scnprintf(buf + n, PAGE_SIZE - n, "speed = %d\n", - gadget->speed); - n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed = %d\n", - gadget->max_speed); - /* TODO: Scheduled for removal in 3.8. */ - n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed = %d\n", - gadget_is_dualspeed(gadget)); - n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg = %d\n", - gadget->is_otg); - n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral = %d\n", - gadget->is_a_peripheral); - n += scnprintf(buf + n, PAGE_SIZE - n, "b_hnp_enable = %d\n", - gadget->b_hnp_enable); - n += scnprintf(buf + n, PAGE_SIZE - n, "a_hnp_support = %d\n", - gadget->a_hnp_support); - n += scnprintf(buf + n, PAGE_SIZE - n, "a_alt_hnp_support = %d\n", - gadget->a_alt_hnp_support); - n += scnprintf(buf + n, PAGE_SIZE - n, "name = %s\n", - (gadget->name ? gadget->name : "")); - - return n; -} -static DEVICE_ATTR(device, S_IRUSR, show_device, NULL); - -/** - * show_driver: prints information about attached gadget (if any) - * - * Check "device.h" for details - */ -static ssize_t show_driver(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - struct usb_gadget_driver *driver = udc->driver; - int n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - if (driver == NULL) - return scnprintf(buf, PAGE_SIZE, - "There is no gadget attached!\n"); - - n += scnprintf(buf + n, PAGE_SIZE - n, "function = %s\n", - (driver->function ? driver->function : "")); - n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n", - driver->max_speed); - - return n; -} -static DEVICE_ATTR(driver, S_IRUSR, show_driver, NULL); - -/* Maximum event message length */ -#define DBG_DATA_MSG 64UL - -/* Maximum event messages */ -#define DBG_DATA_MAX 128UL - -/* Event buffer descriptor */ -static struct { - char (buf[DBG_DATA_MAX])[DBG_DATA_MSG]; /* buffer */ - unsigned idx; /* index */ - unsigned tty; /* print to console? */ - rwlock_t lck; /* lock */ -} dbg_data = { - .idx = 0, - .tty = 0, - .lck = __RW_LOCK_UNLOCKED(lck) -}; - -/** - * dbg_dec: decrements debug event index - * @idx: buffer index - */ -static void dbg_dec(unsigned *idx) -{ - *idx = (*idx - 1) & (DBG_DATA_MAX-1); -} - -/** - * dbg_inc: increments debug event index - * @idx: buffer index - */ -static void dbg_inc(unsigned *idx) -{ - *idx = (*idx + 1) & (DBG_DATA_MAX-1); -} - -/** - * dbg_print: prints the common part of the event - * @addr: endpoint address - * @name: event name - * @status: status - * @extra: extra information - */ -static void dbg_print(u8 addr, const char *name, int status, const char *extra) -{ - struct timeval tval; - unsigned int stamp; - unsigned long flags; - - write_lock_irqsave(&dbg_data.lck, flags); - - do_gettimeofday(&tval); - stamp = tval.tv_sec & 0xFFFF; /* 2^32 = 4294967296. Limit to 4096s */ - stamp = stamp * 1000000 + tval.tv_usec; - - scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG, - "%04X\t? %02X %-7.7s %4i ?\t%s\n", - stamp, addr, name, status, extra); - - dbg_inc(&dbg_data.idx); - - write_unlock_irqrestore(&dbg_data.lck, flags); - - if (dbg_data.tty != 0) - pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n", - stamp, addr, name, status, extra); -} - -/** - * dbg_done: prints a DONE event - * @addr: endpoint address - * @td: transfer descriptor - * @status: status - */ -static void dbg_done(u8 addr, const u32 token, int status) -{ - char msg[DBG_DATA_MSG]; - - scnprintf(msg, sizeof(msg), "%d %02X", - (int)(token & TD_TOTAL_BYTES) >> ffs_nr(TD_TOTAL_BYTES), - (int)(token & TD_STATUS) >> ffs_nr(TD_STATUS)); - dbg_print(addr, "DONE", status, msg); -} - -/** - * dbg_event: prints a generic event - * @addr: endpoint address - * @name: event name - * @status: status - */ -static void dbg_event(u8 addr, const char *name, int status) -{ - if (name != NULL) - dbg_print(addr, name, status, ""); -} - -/* - * dbg_queue: prints a QUEUE event - * @addr: endpoint address - * @req: USB request - * @status: status - */ -static void dbg_queue(u8 addr, const struct usb_request *req, int status) -{ - char msg[DBG_DATA_MSG]; - - if (req != NULL) { - scnprintf(msg, sizeof(msg), - "%d %d", !req->no_interrupt, req->length); - dbg_print(addr, "QUEUE", status, msg); - } -} - -/** - * dbg_setup: prints a SETUP event - * @addr: endpoint address - * @req: setup request - */ -static void dbg_setup(u8 addr, const struct usb_ctrlrequest *req) -{ - char msg[DBG_DATA_MSG]; - - if (req != NULL) { - scnprintf(msg, sizeof(msg), - "%02X %02X %04X %04X %d", req->bRequestType, - req->bRequest, le16_to_cpu(req->wValue), - le16_to_cpu(req->wIndex), le16_to_cpu(req->wLength)); - dbg_print(addr, "SETUP", 0, msg); - } -} - -/** - * show_events: displays the event buffer - * - * Check "device.h" for details - */ -static ssize_t show_events(struct device *dev, struct device_attribute *attr, - char *buf) -{ - unsigned long flags; - unsigned i, j, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - read_lock_irqsave(&dbg_data.lck, flags); - - i = dbg_data.idx; - for (dbg_dec(&i); i != dbg_data.idx; dbg_dec(&i)) { - n += strlen(dbg_data.buf[i]); - if (n >= PAGE_SIZE) { - n -= strlen(dbg_data.buf[i]); - break; - } - } - for (j = 0, dbg_inc(&i); j < n; dbg_inc(&i)) - j += scnprintf(buf + j, PAGE_SIZE - j, - "%s", dbg_data.buf[i]); - - read_unlock_irqrestore(&dbg_data.lck, flags); - - return n; -} - -/** - * store_events: configure if events are going to be also printed to console - * - * Check "device.h" for details - */ -static ssize_t store_events(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned tty; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u", &tty) != 1 || tty > 1) { - dev_err(dev, "<1|0>: enable|disable console log\n"); - goto done; - } - - dbg_data.tty = tty; - dev_info(dev, "tty = %u", dbg_data.tty); - - done: - return count; -} -static DEVICE_ATTR(events, S_IRUSR | S_IWUSR, show_events, store_events); - -/** - * show_inters: interrupt status, enable status and historic - * - * Check "device.h" for details - */ -static ssize_t show_inters(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - u32 intr; - unsigned i, j, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - - n += scnprintf(buf + n, PAGE_SIZE - n, - "status = %08x\n", hw_read_intr_status()); - n += scnprintf(buf + n, PAGE_SIZE - n, - "enable = %08x\n", hw_read_intr_enable()); - - n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n", - isr_statistics.test); - n += scnprintf(buf + n, PAGE_SIZE - n, "? ui = %d\n", - isr_statistics.ui); - n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n", - isr_statistics.uei); - n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n", - isr_statistics.pci); - n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n", - isr_statistics.uri); - n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n", - isr_statistics.sli); - n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n", - isr_statistics.none); - n += scnprintf(buf + n, PAGE_SIZE - n, "*hndl = %d\n", - isr_statistics.hndl.cnt); - - for (i = isr_statistics.hndl.idx, j = 0; j <= ISR_MASK; j++, i++) { - i &= ISR_MASK; - intr = isr_statistics.hndl.buf[i]; - - if (USBi_UI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "ui "); - intr &= ~USBi_UI; - if (USBi_UEI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "uei "); - intr &= ~USBi_UEI; - if (USBi_PCI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "pci "); - intr &= ~USBi_PCI; - if (USBi_URI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "uri "); - intr &= ~USBi_URI; - if (USBi_SLI & intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "sli "); - intr &= ~USBi_SLI; - if (intr) - n += scnprintf(buf + n, PAGE_SIZE - n, "??? "); - if (isr_statistics.hndl.buf[i]) - n += scnprintf(buf + n, PAGE_SIZE - n, "\n"); - } - - spin_unlock_irqrestore(udc->lock, flags); - - return n; -} - -/** - * store_inters: enable & force or disable an individual interrutps - * (to be used for test purposes only) - * - * Check "device.h" for details - */ -static ssize_t store_inters(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned en, bit; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u %u", &en, &bit) != 2 || en > 1) { - dev_err(dev, "<1|0> <bit>: enable|disable interrupt"); - goto done; - } - - spin_lock_irqsave(udc->lock, flags); - if (en) { - if (hw_intr_force(bit)) - dev_err(dev, "invalid bit number\n"); - else - isr_statistics.test++; - } else { - if (hw_intr_clear(bit)) - dev_err(dev, "invalid bit number\n"); - } - spin_unlock_irqrestore(udc->lock, flags); - - done: - return count; -} -static DEVICE_ATTR(inters, S_IRUSR | S_IWUSR, show_inters, store_inters); - -/** - * show_port_test: reads port test mode - * - * Check "device.h" for details - */ -static ssize_t show_port_test(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned mode; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - mode = hw_port_test_get(); - spin_unlock_irqrestore(udc->lock, flags); - - return scnprintf(buf, PAGE_SIZE, "mode = %u\n", mode); -} - -/** - * store_port_test: writes port test mode - * - * Check "device.h" for details - */ -static ssize_t store_port_test(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned mode; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%u", &mode) != 1) { - dev_err(dev, "<mode>: set port test mode"); - goto done; - } - - spin_lock_irqsave(udc->lock, flags); - if (hw_port_test_set(mode)) - dev_err(dev, "invalid mode\n"); - spin_unlock_irqrestore(udc->lock, flags); - - done: - return count; -} -static DEVICE_ATTR(port_test, S_IRUSR | S_IWUSR, - show_port_test, store_port_test); - -/** - * show_qheads: DMA contents of all queue heads - * - * Check "device.h" for details - */ -static ssize_t show_qheads(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - unsigned i, j, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - for (i = 0; i < hw_ep_max/2; i++) { - struct ci13xxx_ep *mEpRx = &udc->ci13xxx_ep[i]; - struct ci13xxx_ep *mEpTx = &udc->ci13xxx_ep[i + hw_ep_max/2]; - n += scnprintf(buf + n, PAGE_SIZE - n, - "EP=%02i: RX=%08X TX=%08X\n", - i, (u32)mEpRx->qh.dma, (u32)mEpTx->qh.dma); - for (j = 0; j < (sizeof(struct ci13xxx_qh)/sizeof(u32)); j++) { - n += scnprintf(buf + n, PAGE_SIZE - n, - " %04X: %08X %08X\n", j, - *((u32 *)mEpRx->qh.ptr + j), - *((u32 *)mEpTx->qh.ptr + j)); - } - } - spin_unlock_irqrestore(udc->lock, flags); - - return n; -} -static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL); - -/** - * show_registers: dumps all registers - * - * Check "device.h" for details - */ -#define DUMP_ENTRIES 512 -static ssize_t show_registers(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - u32 *dump; - unsigned i, k, n = 0; - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL); - if (!dump) { - dev_err(dev, "%s: out of memory\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - k = hw_register_read(dump, DUMP_ENTRIES); - spin_unlock_irqrestore(udc->lock, flags); - - for (i = 0; i < k; i++) { - n += scnprintf(buf + n, PAGE_SIZE - n, - "reg[0x%04X] = 0x%08X\n", - i * (unsigned)sizeof(u32), dump[i]); - } - kfree(dump); - - return n; -} - -/** - * store_registers: writes value to register address - * - * Check "device.h" for details - */ -static ssize_t store_registers(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long addr, data, flags; - - dbg_trace("[%s] %p, %d\n", __func__, buf, count); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - goto done; - } - - if (sscanf(buf, "%li %li", &addr, &data) != 2) { - dev_err(dev, "<addr> <data>: write data to register address"); - goto done; - } - - spin_lock_irqsave(udc->lock, flags); - if (hw_register_write(addr, data)) - dev_err(dev, "invalid address range\n"); - spin_unlock_irqrestore(udc->lock, flags); - - done: - return count; -} -static DEVICE_ATTR(registers, S_IRUSR | S_IWUSR, - show_registers, store_registers); - -/** - * show_requests: DMA contents of all requests currently queued (all endpts) - * - * Check "device.h" for details - */ -static ssize_t show_requests(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev); - unsigned long flags; - struct list_head *ptr = NULL; - struct ci13xxx_req *req = NULL; - unsigned i, j, n = 0, qSize = sizeof(struct ci13xxx_td)/sizeof(u32); - - dbg_trace("[%s] %p\n", __func__, buf); - if (attr == NULL || buf == NULL) { - dev_err(dev, "[%s] EINVAL\n", __func__); - return 0; - } - - spin_lock_irqsave(udc->lock, flags); - for (i = 0; i < hw_ep_max; i++) - list_for_each(ptr, &udc->ci13xxx_ep[i].qh.queue) - { - req = list_entry(ptr, struct ci13xxx_req, queue); - - n += scnprintf(buf + n, PAGE_SIZE - n, - "EP=%02i: TD=%08X %s\n", - i % hw_ep_max/2, (u32)req->dma, - ((i < hw_ep_max/2) ? "RX" : "TX")); - - for (j = 0; j < qSize; j++) - n += scnprintf(buf + n, PAGE_SIZE - n, - " %04X: %08X\n", j, - *((u32 *)req->ptr + j)); - } - spin_unlock_irqrestore(udc->lock, flags); - - return n; -} -static DEVICE_ATTR(requests, S_IRUSR, show_requests, NULL); - -/** - * dbg_create_files: initializes the attribute interface - * @dev: device - * - * This function returns an error code - */ -__maybe_unused static int dbg_create_files(struct device *dev) -{ - int retval = 0; - - if (dev == NULL) - return -EINVAL; - retval = device_create_file(dev, &dev_attr_device); - if (retval) - goto done; - retval = device_create_file(dev, &dev_attr_driver); - if (retval) - goto rm_device; - retval = device_create_file(dev, &dev_attr_events); - if (retval) - goto rm_driver; - retval = device_create_file(dev, &dev_attr_inters); - if (retval) - goto rm_events; - retval = device_create_file(dev, &dev_attr_port_test); - if (retval) - goto rm_inters; - retval = device_create_file(dev, &dev_attr_qheads); - if (retval) - goto rm_port_test; - retval = device_create_file(dev, &dev_attr_registers); - if (retval) - goto rm_qheads; - retval = device_create_file(dev, &dev_attr_requests); - if (retval) - goto rm_registers; - return 0; - - rm_registers: - device_remove_file(dev, &dev_attr_registers); - rm_qheads: - device_remove_file(dev, &dev_attr_qheads); - rm_port_test: - device_remove_file(dev, &dev_attr_port_test); - rm_inters: - device_remove_file(dev, &dev_attr_inters); - rm_events: - device_remove_file(dev, &dev_attr_events); - rm_driver: - device_remove_file(dev, &dev_attr_driver); - rm_device: - device_remove_file(dev, &dev_attr_device); - done: - return retval; -} - -/** - * dbg_remove_files: destroys the attribute interface - * @dev: device - * - * This function returns an error code - */ -__maybe_unused static int dbg_remove_files(struct device *dev) -{ - if (dev == NULL) - return -EINVAL; - device_remove_file(dev, &dev_attr_requests); - device_remove_file(dev, &dev_attr_registers); - device_remove_file(dev, &dev_attr_qheads); - device_remove_file(dev, &dev_attr_port_test); - device_remove_file(dev, &dev_attr_inters); - device_remove_file(dev, &dev_attr_events); - device_remove_file(dev, &dev_attr_driver); - device_remove_file(dev, &dev_attr_device); - return 0; -} - -/****************************************************************************** - * UTIL block - *****************************************************************************/ -/** - * _usb_addr: calculates endpoint address from direction & number - * @ep: endpoint - */ -static inline u8 _usb_addr(struct ci13xxx_ep *ep) -{ - return ((ep->dir == TX) ? USB_ENDPOINT_DIR_MASK : 0) | ep->num; -} - -/** - * _hardware_queue: configures a request at hardware level - * @gadget: gadget - * @mEp: endpoint - * - * This function returns an error code - */ -static int _hardware_enqueue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) -{ - unsigned i; - int ret = 0; - unsigned length = mReq->req.length; - - trace("%p, %p", mEp, mReq); - - /* don't queue twice */ - if (mReq->req.status == -EALREADY) - return -EALREADY; - - mReq->req.status = -EALREADY; - if (length && mReq->req.dma == DMA_ADDR_INVALID) { - mReq->req.dma = \ - dma_map_single(mEp->device, mReq->req.buf, - length, mEp->dir ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - if (mReq->req.dma == 0) - return -ENOMEM; - - mReq->map = 1; - } - - if (mReq->req.zero && length && (length % mEp->ep.maxpacket == 0)) { - mReq->zptr = dma_pool_alloc(mEp->td_pool, GFP_ATOMIC, - &mReq->zdma); - if (mReq->zptr == NULL) { - if (mReq->map) { - dma_unmap_single(mEp->device, mReq->req.dma, - length, mEp->dir ? DMA_TO_DEVICE : - DMA_FROM_DEVICE); - mReq->req.dma = DMA_ADDR_INVALID; - mReq->map = 0; - } - return -ENOMEM; - } - memset(mReq->zptr, 0, sizeof(*mReq->zptr)); - mReq->zptr->next = TD_TERMINATE; - mReq->zptr->token = TD_STATUS_ACTIVE; - if (!mReq->req.no_interrupt) - mReq->zptr->token |= TD_IOC; - } - /* - * TD configuration - * TODO - handle requests which spawns into several TDs - */ - memset(mReq->ptr, 0, sizeof(*mReq->ptr)); - mReq->ptr->token = length << ffs_nr(TD_TOTAL_BYTES); - mReq->ptr->token &= TD_TOTAL_BYTES; - mReq->ptr->token |= TD_STATUS_ACTIVE; - if (mReq->zptr) { - mReq->ptr->next = mReq->zdma; - } else { - mReq->ptr->next = TD_TERMINATE; - if (!mReq->req.no_interrupt) - mReq->ptr->token |= TD_IOC; - } - mReq->ptr->page[0] = mReq->req.dma; - for (i = 1; i < 5; i++) - mReq->ptr->page[i] = - (mReq->req.dma + i * CI13XXX_PAGE_SIZE) & ~TD_RESERVED_MASK; - - if (!list_empty(&mEp->qh.queue)) { - struct ci13xxx_req *mReqPrev; - int n = hw_ep_bit(mEp->num, mEp->dir); - int tmp_stat; - - mReqPrev = list_entry(mEp->qh.queue.prev, - struct ci13xxx_req, queue); - if (mReqPrev->zptr) - mReqPrev->zptr->next = mReq->dma & TD_ADDR_MASK; - else - mReqPrev->ptr->next = mReq->dma & TD_ADDR_MASK; - wmb(); - if (hw_cread(CAP_ENDPTPRIME, BIT(n))) - goto done; - do { - hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, USBCMD_ATDTW); - tmp_stat = hw_cread(CAP_ENDPTSTAT, BIT(n)); - } while (!hw_cread(CAP_USBCMD, USBCMD_ATDTW)); - hw_cwrite(CAP_USBCMD, USBCMD_ATDTW, 0); - if (tmp_stat) - goto done; - } - - /* QH configuration */ - mEp->qh.ptr->td.next = mReq->dma; /* TERMINATE = 0 */ - mEp->qh.ptr->td.token &= ~TD_STATUS; /* clear status */ - mEp->qh.ptr->cap |= QH_ZLT; - - wmb(); /* synchronize before ep prime */ - - ret = hw_ep_prime(mEp->num, mEp->dir, - mEp->type == USB_ENDPOINT_XFER_CONTROL); -done: - return ret; -} - -/** - * _hardware_dequeue: handles a request at hardware level - * @gadget: gadget - * @mEp: endpoint - * - * This function returns an error code - */ -static int _hardware_dequeue(struct ci13xxx_ep *mEp, struct ci13xxx_req *mReq) -{ - trace("%p, %p", mEp, mReq); - - if (mReq->req.status != -EALREADY) - return -EINVAL; - - if ((TD_STATUS_ACTIVE & mReq->ptr->token) != 0) - return -EBUSY; - - if (mReq->zptr) { - if ((TD_STATUS_ACTIVE & mReq->zptr->token) != 0) - return -EBUSY; - dma_pool_free(mEp->td_pool, mReq->zptr, mReq->zdma); - mReq->zptr = NULL; - } - - mReq->req.status = 0; - - if (mReq->map) { - dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, - mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mReq->req.dma = DMA_ADDR_INVALID; - mReq->map = 0; - } - - mReq->req.status = mReq->ptr->token & TD_STATUS; - if ((TD_STATUS_HALTED & mReq->req.status) != 0) - mReq->req.status = -1; - else if ((TD_STATUS_DT_ERR & mReq->req.status) != 0) - mReq->req.status = -1; - else if ((TD_STATUS_TR_ERR & mReq->req.status) != 0) - mReq->req.status = -1; - - mReq->req.actual = mReq->ptr->token & TD_TOTAL_BYTES; - mReq->req.actual >>= ffs_nr(TD_TOTAL_BYTES); - mReq->req.actual = mReq->req.length - mReq->req.actual; - mReq->req.actual = mReq->req.status ? 0 : mReq->req.actual; - - return mReq->req.actual; -} - -/** - * _ep_nuke: dequeues all endpoint requests - * @mEp: endpoint - * - * This function returns an error code - * Caller must hold lock - */ -static int _ep_nuke(struct ci13xxx_ep *mEp) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - trace("%p", mEp); - - if (mEp == NULL) - return -EINVAL; - - hw_ep_flush(mEp->num, mEp->dir); - - while (!list_empty(&mEp->qh.queue)) { - - /* pop oldest request */ - struct ci13xxx_req *mReq = \ - list_entry(mEp->qh.queue.next, - struct ci13xxx_req, queue); - list_del_init(&mReq->queue); - mReq->req.status = -ESHUTDOWN; - - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - mReq->req.complete(&mEp->ep, &mReq->req); - spin_lock(mEp->lock); - } - } - return 0; -} - -/** - * _gadget_stop_activity: stops all USB activity, flushes & disables all endpts - * @gadget: gadget - * - * This function returns an error code - */ -static int _gadget_stop_activity(struct usb_gadget *gadget) -{ - struct usb_ep *ep; - struct ci13xxx *udc = container_of(gadget, struct ci13xxx, gadget); - unsigned long flags; - - trace("%p", gadget); - - if (gadget == NULL) - return -EINVAL; - - spin_lock_irqsave(udc->lock, flags); - udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->remote_wakeup = 0; - udc->suspended = 0; - spin_unlock_irqrestore(udc->lock, flags); - - /* flush all endpoints */ - gadget_for_each_ep(ep, gadget) { - usb_ep_fifo_flush(ep); - } - usb_ep_fifo_flush(&udc->ep0out.ep); - usb_ep_fifo_flush(&udc->ep0in.ep); - - udc->driver->disconnect(gadget); - - /* make sure to disable all endpoints */ - gadget_for_each_ep(ep, gadget) { - usb_ep_disable(ep); - } - - if (udc->status != NULL) { - usb_ep_free_request(&udc->ep0in.ep, udc->status); - udc->status = NULL; - } - - return 0; -} - -/****************************************************************************** - * ISR block - *****************************************************************************/ -/** - * isr_reset_handler: USB reset interrupt handler - * @udc: UDC device - * - * This function resets USB engine after a bus reset occurred - */ -static void isr_reset_handler(struct ci13xxx *udc) -__releases(udc->lock) -__acquires(udc->lock) -{ - int retval; - - trace("%p", udc); - - if (udc == NULL) { - err("EINVAL"); - return; - } - - dbg_event(0xFF, "BUS RST", 0); - - spin_unlock(udc->lock); - retval = _gadget_stop_activity(&udc->gadget); - if (retval) - goto done; - - retval = hw_usb_reset(); - if (retval) - goto done; - - udc->status = usb_ep_alloc_request(&udc->ep0in.ep, GFP_ATOMIC); - if (udc->status == NULL) - retval = -ENOMEM; - - spin_lock(udc->lock); - - done: - if (retval) - err("error: %i", retval); -} - -/** - * isr_get_status_complete: get_status request complete function - * @ep: endpoint - * @req: request handled - * - * Caller must release lock - */ -static void isr_get_status_complete(struct usb_ep *ep, struct usb_request *req) -{ - trace("%p, %p", ep, req); - - if (ep == NULL || req == NULL) { - err("EINVAL"); - return; - } - - kfree(req->buf); - usb_ep_free_request(ep, req); -} - -/** - * isr_get_status_response: get_status request response - * @udc: udc struct - * @setup: setup request packet - * - * This function returns an error code - */ -static int isr_get_status_response(struct ci13xxx *udc, - struct usb_ctrlrequest *setup) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - struct ci13xxx_ep *mEp = &udc->ep0in; - struct usb_request *req = NULL; - gfp_t gfp_flags = GFP_ATOMIC; - int dir, num, retval; - - trace("%p, %p", mEp, setup); - - if (mEp == NULL || setup == NULL) - return -EINVAL; - - spin_unlock(mEp->lock); - req = usb_ep_alloc_request(&mEp->ep, gfp_flags); - spin_lock(mEp->lock); - if (req == NULL) - return -ENOMEM; - - req->complete = isr_get_status_complete; - req->length = 2; - req->buf = kzalloc(req->length, gfp_flags); - if (req->buf == NULL) { - retval = -ENOMEM; - goto err_free_req; - } - - if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* Assume that device is bus powered for now. */ - *((u16 *)req->buf) = _udc->remote_wakeup << 1; - retval = 0; - } else if ((setup->bRequestType & USB_RECIP_MASK) \ - == USB_RECIP_ENDPOINT) { - dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ? - TX : RX; - num = le16_to_cpu(setup->wIndex) & USB_ENDPOINT_NUMBER_MASK; - *((u16 *)req->buf) = hw_ep_get_halt(num, dir); - } - /* else do nothing; reserved for future use */ - - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, req, gfp_flags); - spin_lock(mEp->lock); - if (retval) - goto err_free_buf; - - return 0; - - err_free_buf: - kfree(req->buf); - err_free_req: - spin_unlock(mEp->lock); - usb_ep_free_request(&mEp->ep, req); - spin_lock(mEp->lock); - return retval; -} - -/** - * isr_setup_status_complete: setup_status request complete function - * @ep: endpoint - * @req: request handled - * - * Caller must release lock. Put the port in test mode if test mode - * feature is selected. - */ -static void -isr_setup_status_complete(struct usb_ep *ep, struct usb_request *req) -{ - struct ci13xxx *udc = req->context; - unsigned long flags; - - trace("%p, %p", ep, req); - - spin_lock_irqsave(udc->lock, flags); - if (udc->test_mode) - hw_port_test_set(udc->test_mode); - spin_unlock_irqrestore(udc->lock, flags); -} - -/** - * isr_setup_status_phase: queues the status phase of a setup transation - * @udc: udc struct - * - * This function returns an error code - */ -static int isr_setup_status_phase(struct ci13xxx *udc) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - int retval; - struct ci13xxx_ep *mEp; - - trace("%p", udc); - - mEp = (udc->ep0_dir == TX) ? &udc->ep0out : &udc->ep0in; - udc->status->context = udc; - udc->status->complete = isr_setup_status_complete; - - spin_unlock(mEp->lock); - retval = usb_ep_queue(&mEp->ep, udc->status, GFP_ATOMIC); - spin_lock(mEp->lock); - - return retval; -} - -/** - * isr_tr_complete_low: transaction complete low level handler - * @mEp: endpoint - * - * This function returns an error code - * Caller must hold lock - */ -static int isr_tr_complete_low(struct ci13xxx_ep *mEp) -__releases(mEp->lock) -__acquires(mEp->lock) -{ - struct ci13xxx_req *mReq, *mReqTemp; - struct ci13xxx_ep *mEpTemp = mEp; - int uninitialized_var(retval); - - trace("%p", mEp); - - if (list_empty(&mEp->qh.queue)) - return -EINVAL; - - list_for_each_entry_safe(mReq, mReqTemp, &mEp->qh.queue, - queue) { - retval = _hardware_dequeue(mEp, mReq); - if (retval < 0) - break; - list_del_init(&mReq->queue); - dbg_done(_usb_addr(mEp), mReq->ptr->token, retval); - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - if ((mEp->type == USB_ENDPOINT_XFER_CONTROL) && - mReq->req.length) - mEpTemp = &_udc->ep0in; - mReq->req.complete(&mEpTemp->ep, &mReq->req); - spin_lock(mEp->lock); - } - } - - if (retval == -EBUSY) - retval = 0; - if (retval < 0) - dbg_event(_usb_addr(mEp), "DONE", retval); - - return retval; -} - -/** - * isr_tr_complete_handler: transaction complete interrupt handler - * @udc: UDC descriptor - * - * This function handles traffic events - */ -static void isr_tr_complete_handler(struct ci13xxx *udc) -__releases(udc->lock) -__acquires(udc->lock) -{ - unsigned i; - u8 tmode = 0; - - trace("%p", udc); - - if (udc == NULL) { - err("EINVAL"); - return; - } - - for (i = 0; i < hw_ep_max; i++) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; - int type, num, dir, err = -EINVAL; - struct usb_ctrlrequest req; - - if (mEp->desc == NULL) - continue; /* not configured */ - - if (hw_test_and_clear_complete(i)) { - err = isr_tr_complete_low(mEp); - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { - if (err > 0) /* needs status phase */ - err = isr_setup_status_phase(udc); - if (err < 0) { - dbg_event(_usb_addr(mEp), - "ERROR", err); - spin_unlock(udc->lock); - if (usb_ep_set_halt(&mEp->ep)) - err("error: ep_set_halt"); - spin_lock(udc->lock); - } - } - } - - if (mEp->type != USB_ENDPOINT_XFER_CONTROL || - !hw_test_and_clear_setup_status(i)) - continue; - - if (i != 0) { - warn("ctrl traffic received at endpoint"); - continue; - } - - /* - * Flush data and handshake transactions of previous - * setup packet. - */ - _ep_nuke(&udc->ep0out); - _ep_nuke(&udc->ep0in); - - /* read_setup_packet */ - do { - hw_test_and_set_setup_guard(); - memcpy(&req, &mEp->qh.ptr->setup, sizeof(req)); - } while (!hw_test_and_clear_setup_guard()); - - type = req.bRequestType; - - udc->ep0_dir = (type & USB_DIR_IN) ? TX : RX; - - dbg_setup(_usb_addr(mEp), &req); - - switch (req.bRequest) { - case USB_REQ_CLEAR_FEATURE: - if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && - le16_to_cpu(req.wValue) == - USB_ENDPOINT_HALT) { - if (req.wLength != 0) - break; - num = le16_to_cpu(req.wIndex); - dir = num & USB_ENDPOINT_DIR_MASK; - num &= USB_ENDPOINT_NUMBER_MASK; - if (dir) /* TX */ - num += hw_ep_max/2; - if (!udc->ci13xxx_ep[num].wedge) { - spin_unlock(udc->lock); - err = usb_ep_clear_halt( - &udc->ci13xxx_ep[num].ep); - spin_lock(udc->lock); - if (err) - break; - } - err = isr_setup_status_phase(udc); - } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE) && - le16_to_cpu(req.wValue) == - USB_DEVICE_REMOTE_WAKEUP) { - if (req.wLength != 0) - break; - udc->remote_wakeup = 0; - err = isr_setup_status_phase(udc); - } else { - goto delegate; - } - break; - case USB_REQ_GET_STATUS: - if (type != (USB_DIR_IN|USB_RECIP_DEVICE) && - type != (USB_DIR_IN|USB_RECIP_ENDPOINT) && - type != (USB_DIR_IN|USB_RECIP_INTERFACE)) - goto delegate; - if (le16_to_cpu(req.wLength) != 2 || - le16_to_cpu(req.wValue) != 0) - break; - err = isr_get_status_response(udc, &req); - break; - case USB_REQ_SET_ADDRESS: - if (type != (USB_DIR_OUT|USB_RECIP_DEVICE)) - goto delegate; - if (le16_to_cpu(req.wLength) != 0 || - le16_to_cpu(req.wIndex) != 0) - break; - err = hw_usb_set_address((u8)le16_to_cpu(req.wValue)); - if (err) - break; - err = isr_setup_status_phase(udc); - break; - case USB_REQ_SET_FEATURE: - if (type == (USB_DIR_OUT|USB_RECIP_ENDPOINT) && - le16_to_cpu(req.wValue) == - USB_ENDPOINT_HALT) { - if (req.wLength != 0) - break; - num = le16_to_cpu(req.wIndex); - dir = num & USB_ENDPOINT_DIR_MASK; - num &= USB_ENDPOINT_NUMBER_MASK; - if (dir) /* TX */ - num += hw_ep_max/2; - - spin_unlock(udc->lock); - err = usb_ep_set_halt(&udc->ci13xxx_ep[num].ep); - spin_lock(udc->lock); - if (!err) - isr_setup_status_phase(udc); - } else if (type == (USB_DIR_OUT|USB_RECIP_DEVICE)) { - if (req.wLength != 0) - break; - switch (le16_to_cpu(req.wValue)) { - case USB_DEVICE_REMOTE_WAKEUP: - udc->remote_wakeup = 1; - err = isr_setup_status_phase(udc); - break; - case USB_DEVICE_TEST_MODE: - tmode = le16_to_cpu(req.wIndex) >> 8; - switch (tmode) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: - udc->test_mode = tmode; - err = isr_setup_status_phase( - udc); - break; - default: - break; - } - default: - goto delegate; - } - } else { - goto delegate; - } - break; - default: -delegate: - if (req.wLength == 0) /* no data phase */ - udc->ep0_dir = TX; - - spin_unlock(udc->lock); - err = udc->driver->setup(&udc->gadget, &req); - spin_lock(udc->lock); - break; - } - - if (err < 0) { - dbg_event(_usb_addr(mEp), "ERROR", err); - - spin_unlock(udc->lock); - if (usb_ep_set_halt(&mEp->ep)) - err("error: ep_set_halt"); - spin_lock(udc->lock); - } - } -} - -/****************************************************************************** - * ENDPT block - *****************************************************************************/ -/** - * ep_enable: configure endpoint, making it usable - * - * Check usb_ep_enable() at "usb_gadget.h" for details - */ -static int ep_enable(struct usb_ep *ep, - const struct usb_endpoint_descriptor *desc) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int retval = 0; - unsigned long flags; - - trace("%p, %p", ep, desc); - - if (ep == NULL || desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - /* only internal SW should enable ctrl endpts */ - - mEp->desc = desc; - - if (!list_empty(&mEp->qh.queue)) - warn("enabling a non-empty endpoint!"); - - mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX; - mEp->num = usb_endpoint_num(desc); - mEp->type = usb_endpoint_type(desc); - - mEp->ep.maxpacket = usb_endpoint_maxp(desc); - - dbg_event(_usb_addr(mEp), "ENABLE", 0); - - mEp->qh.ptr->cap = 0; - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->qh.ptr->cap |= QH_IOS; - else if (mEp->type == USB_ENDPOINT_XFER_ISOC) - mEp->qh.ptr->cap &= ~QH_MULT; - else - mEp->qh.ptr->cap &= ~QH_ZLT; - - mEp->qh.ptr->cap |= - (mEp->ep.maxpacket << ffs_nr(QH_MAX_PKT)) & QH_MAX_PKT; - mEp->qh.ptr->td.next |= TD_TERMINATE; /* needed? */ - - /* - * Enable endpoints in the HW other than ep0 as ep0 - * is always enabled - */ - if (mEp->num) - retval |= hw_ep_enable(mEp->num, mEp->dir, mEp->type); - - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_disable: endpoint is no longer usable - * - * Check usb_ep_disable() at "usb_gadget.h" for details - */ -static int ep_disable(struct usb_ep *ep) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int direction, retval = 0; - unsigned long flags; - - trace("%p", ep); - - if (ep == NULL) - return -EINVAL; - else if (mEp->desc == NULL) - return -EBUSY; - - spin_lock_irqsave(mEp->lock, flags); - - /* only internal SW should disable ctrl endpts */ - - direction = mEp->dir; - do { - dbg_event(_usb_addr(mEp), "DISABLE", 0); - - retval |= _ep_nuke(mEp); - retval |= hw_ep_disable(mEp->num, mEp->dir); - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->dir = (mEp->dir == TX) ? RX : TX; - - } while (mEp->dir != direction); - - mEp->desc = NULL; - mEp->ep.desc = NULL; - - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_alloc_request: allocate a request object to use with this endpoint - * - * Check usb_ep_alloc_request() at "usb_gadget.h" for details - */ -static struct usb_request *ep_alloc_request(struct usb_ep *ep, gfp_t gfp_flags) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = NULL; - - trace("%p, %i", ep, gfp_flags); - - if (ep == NULL) { - err("EINVAL"); - return NULL; - } - - mReq = kzalloc(sizeof(struct ci13xxx_req), gfp_flags); - if (mReq != NULL) { - INIT_LIST_HEAD(&mReq->queue); - mReq->req.dma = DMA_ADDR_INVALID; - - mReq->ptr = dma_pool_alloc(mEp->td_pool, gfp_flags, - &mReq->dma); - if (mReq->ptr == NULL) { - kfree(mReq); - mReq = NULL; - } - } - - dbg_event(_usb_addr(mEp), "ALLOC", mReq == NULL); - - return (mReq == NULL) ? NULL : &mReq->req; -} - -/** - * ep_free_request: frees a request object - * - * Check usb_ep_free_request() at "usb_gadget.h" for details - */ -static void ep_free_request(struct usb_ep *ep, struct usb_request *req) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - unsigned long flags; - - trace("%p, %p", ep, req); - - if (ep == NULL || req == NULL) { - err("EINVAL"); - return; - } else if (!list_empty(&mReq->queue)) { - err("EBUSY"); - return; - } - - spin_lock_irqsave(mEp->lock, flags); - - if (mReq->ptr) - dma_pool_free(mEp->td_pool, mReq->ptr, mReq->dma); - kfree(mReq); - - dbg_event(_usb_addr(mEp), "FREE", 0); - - spin_unlock_irqrestore(mEp->lock, flags); -} - -/** - * ep_queue: queues (submits) an I/O request to an endpoint - * - * Check usb_ep_queue()* at usb_gadget.h" for details - */ -static int ep_queue(struct usb_ep *ep, struct usb_request *req, - gfp_t __maybe_unused gfp_flags) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - int retval = 0; - unsigned long flags; - - trace("%p, %p, %X", ep, req, gfp_flags); - - if (ep == NULL || req == NULL || mEp->desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) { - if (req->length) - mEp = (_udc->ep0_dir == RX) ? - &_udc->ep0out : &_udc->ep0in; - if (!list_empty(&mEp->qh.queue)) { - _ep_nuke(mEp); - retval = -EOVERFLOW; - warn("endpoint ctrl %X nuked", _usb_addr(mEp)); - } - } - - /* first nuke then test link, e.g. previous status has not sent */ - if (!list_empty(&mReq->queue)) { - retval = -EBUSY; - err("request already in queue"); - goto done; - } - - if (req->length > (4 * CI13XXX_PAGE_SIZE)) { - req->length = (4 * CI13XXX_PAGE_SIZE); - retval = -EMSGSIZE; - warn("request length truncated"); - } - - dbg_queue(_usb_addr(mEp), req, retval); - - /* push request */ - mReq->req.status = -EINPROGRESS; - mReq->req.actual = 0; - - retval = _hardware_enqueue(mEp, mReq); - - if (retval == -EALREADY) { - dbg_event(_usb_addr(mEp), "QUEUE", retval); - retval = 0; - } - if (!retval) - list_add_tail(&mReq->queue, &mEp->qh.queue); - - done: - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_dequeue: dequeues (cancels, unlinks) an I/O request from an endpoint - * - * Check usb_ep_dequeue() at "usb_gadget.h" for details - */ -static int ep_dequeue(struct usb_ep *ep, struct usb_request *req) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - struct ci13xxx_req *mReq = container_of(req, struct ci13xxx_req, req); - unsigned long flags; - - trace("%p, %p", ep, req); - - if (ep == NULL || req == NULL || mReq->req.status != -EALREADY || - mEp->desc == NULL || list_empty(&mReq->queue) || - list_empty(&mEp->qh.queue)) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "DEQUEUE", 0); - - hw_ep_flush(mEp->num, mEp->dir); - - /* pop request */ - list_del_init(&mReq->queue); - if (mReq->map) { - dma_unmap_single(mEp->device, mReq->req.dma, mReq->req.length, - mEp->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mReq->req.dma = DMA_ADDR_INVALID; - mReq->map = 0; - } - req->status = -ECONNRESET; - - if (mReq->req.complete != NULL) { - spin_unlock(mEp->lock); - mReq->req.complete(&mEp->ep, &mReq->req); - spin_lock(mEp->lock); - } - - spin_unlock_irqrestore(mEp->lock, flags); - return 0; -} - -/** - * ep_set_halt: sets the endpoint halt feature - * - * Check usb_ep_set_halt() at "usb_gadget.h" for details - */ -static int ep_set_halt(struct usb_ep *ep, int value) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - int direction, retval = 0; - unsigned long flags; - - trace("%p, %i", ep, value); - - if (ep == NULL || mEp->desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - -#ifndef STALL_IN - /* g_file_storage MS compliant but g_zero fails chapter 9 compliance */ - if (value && mEp->type == USB_ENDPOINT_XFER_BULK && mEp->dir == TX && - !list_empty(&mEp->qh.queue)) { - spin_unlock_irqrestore(mEp->lock, flags); - return -EAGAIN; - } -#endif - - direction = mEp->dir; - do { - dbg_event(_usb_addr(mEp), "HALT", value); - retval |= hw_ep_set_halt(mEp->num, mEp->dir, value); - - if (!value) - mEp->wedge = 0; - - if (mEp->type == USB_ENDPOINT_XFER_CONTROL) - mEp->dir = (mEp->dir == TX) ? RX : TX; - - } while (mEp->dir != direction); - - spin_unlock_irqrestore(mEp->lock, flags); - return retval; -} - -/** - * ep_set_wedge: sets the halt feature and ignores clear requests - * - * Check usb_ep_set_wedge() at "usb_gadget.h" for details - */ -static int ep_set_wedge(struct usb_ep *ep) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - unsigned long flags; - - trace("%p", ep); - - if (ep == NULL || mEp->desc == NULL) - return -EINVAL; - - spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "WEDGE", 0); - mEp->wedge = 1; - - spin_unlock_irqrestore(mEp->lock, flags); - - return usb_ep_set_halt(ep); -} - -/** - * ep_fifo_flush: flushes contents of a fifo - * - * Check usb_ep_fifo_flush() at "usb_gadget.h" for details - */ -static void ep_fifo_flush(struct usb_ep *ep) -{ - struct ci13xxx_ep *mEp = container_of(ep, struct ci13xxx_ep, ep); - unsigned long flags; - - trace("%p", ep); - - if (ep == NULL) { - err("%02X: -EINVAL", _usb_addr(mEp)); - return; - } - - spin_lock_irqsave(mEp->lock, flags); - - dbg_event(_usb_addr(mEp), "FFLUSH", 0); - hw_ep_flush(mEp->num, mEp->dir); - - spin_unlock_irqrestore(mEp->lock, flags); -} - -/** - * Endpoint-specific part of the API to the USB controller hardware - * Check "usb_gadget.h" for details - */ -static const struct usb_ep_ops usb_ep_ops = { - .enable = ep_enable, - .disable = ep_disable, - .alloc_request = ep_alloc_request, - .free_request = ep_free_request, - .queue = ep_queue, - .dequeue = ep_dequeue, - .set_halt = ep_set_halt, - .set_wedge = ep_set_wedge, - .fifo_flush = ep_fifo_flush, -}; - -/****************************************************************************** - * GADGET block - *****************************************************************************/ -static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active) -{ - struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); - unsigned long flags; - int gadget_ready = 0; - - if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS)) - return -EOPNOTSUPP; - - spin_lock_irqsave(udc->lock, flags); - udc->vbus_active = is_active; - if (udc->driver) - gadget_ready = 1; - spin_unlock_irqrestore(udc->lock, flags); - - if (gadget_ready) { - if (is_active) { - pm_runtime_get_sync(&_gadget->dev); - hw_device_reset(udc); - hw_device_state(udc->ep0out.qh.dma); - } else { - hw_device_state(0); - if (udc->udc_driver->notify_event) - udc->udc_driver->notify_event(udc, - CI13XXX_CONTROLLER_STOPPED_EVENT); - _gadget_stop_activity(&udc->gadget); - pm_runtime_put_sync(&_gadget->dev); - } - } - - return 0; -} - -static int ci13xxx_wakeup(struct usb_gadget *_gadget) -{ - struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); - unsigned long flags; - int ret = 0; - - trace(); - - spin_lock_irqsave(udc->lock, flags); - if (!udc->remote_wakeup) { - ret = -EOPNOTSUPP; - trace("remote wakeup feature is not enabled\n"); - goto out; - } - if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) { - ret = -EINVAL; - trace("port is not suspended\n"); - goto out; - } - hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR); -out: - spin_unlock_irqrestore(udc->lock, flags); - return ret; -} - -static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA) -{ - struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget); - - if (udc->transceiver) - return usb_phy_set_power(udc->transceiver, mA); - return -ENOTSUPP; -} - -static int ci13xxx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int ci13xxx_stop(struct usb_gadget_driver *driver); -/** - * Device operations part of the API to the USB controller hardware, - * which don't involve endpoints (or i/o) - * Check "usb_gadget.h" for details - */ -static const struct usb_gadget_ops usb_gadget_ops = { - .vbus_session = ci13xxx_vbus_session, - .wakeup = ci13xxx_wakeup, - .vbus_draw = ci13xxx_vbus_draw, - .start = ci13xxx_start, - .stop = ci13xxx_stop, -}; - -/** - * ci13xxx_start: register a gadget driver - * @driver: the driver being registered - * @bind: the driver's bind callback - * - * Check ci13xxx_start() at <linux/usb/gadget.h> for details. - * Interrupts are enabled here. - */ -static int ci13xxx_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) -{ - struct ci13xxx *udc = _udc; - unsigned long flags; - int i, j; - int retval = -ENOMEM; - - trace("%p", driver); - - if (driver == NULL || - bind == NULL || - driver->setup == NULL || - driver->disconnect == NULL) - return -EINVAL; - else if (udc == NULL) - return -ENODEV; - else if (udc->driver != NULL) - return -EBUSY; - - /* alloc resources */ - udc->qh_pool = dma_pool_create("ci13xxx_qh", &udc->gadget.dev, - sizeof(struct ci13xxx_qh), - 64, CI13XXX_PAGE_SIZE); - if (udc->qh_pool == NULL) - return -ENOMEM; - - udc->td_pool = dma_pool_create("ci13xxx_td", &udc->gadget.dev, - sizeof(struct ci13xxx_td), - 64, CI13XXX_PAGE_SIZE); - if (udc->td_pool == NULL) { - dma_pool_destroy(udc->qh_pool); - udc->qh_pool = NULL; - return -ENOMEM; - } - - spin_lock_irqsave(udc->lock, flags); - - info("hw_ep_max = %d", hw_ep_max); - - udc->gadget.dev.driver = NULL; - - retval = 0; - for (i = 0; i < hw_ep_max/2; i++) { - for (j = RX; j <= TX; j++) { - int k = i + j * hw_ep_max/2; - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[k]; - - scnprintf(mEp->name, sizeof(mEp->name), "ep%i%s", i, - (j == TX) ? "in" : "out"); - - mEp->lock = udc->lock; - mEp->device = &udc->gadget.dev; - mEp->td_pool = udc->td_pool; - - mEp->ep.name = mEp->name; - mEp->ep.ops = &usb_ep_ops; - mEp->ep.maxpacket = CTRL_PAYLOAD_MAX; - - INIT_LIST_HEAD(&mEp->qh.queue); - spin_unlock_irqrestore(udc->lock, flags); - mEp->qh.ptr = dma_pool_alloc(udc->qh_pool, GFP_KERNEL, - &mEp->qh.dma); - spin_lock_irqsave(udc->lock, flags); - if (mEp->qh.ptr == NULL) - retval = -ENOMEM; - else - memset(mEp->qh.ptr, 0, sizeof(*mEp->qh.ptr)); - - /* skip ep0 out and in endpoints */ - if (i == 0) - continue; - - list_add_tail(&mEp->ep.ep_list, &udc->gadget.ep_list); - } - } - if (retval) - goto done; - spin_unlock_irqrestore(udc->lock, flags); - udc->ep0out.ep.desc = &ctrl_endpt_out_desc; - retval = usb_ep_enable(&udc->ep0out.ep); - if (retval) - return retval; - - udc->ep0in.ep.desc = &ctrl_endpt_in_desc; - retval = usb_ep_enable(&udc->ep0in.ep); - if (retval) - return retval; - spin_lock_irqsave(udc->lock, flags); - - udc->gadget.ep0 = &udc->ep0in.ep; - /* bind gadget */ - driver->driver.bus = NULL; - udc->gadget.dev.driver = &driver->driver; - - spin_unlock_irqrestore(udc->lock, flags); - retval = bind(&udc->gadget); /* MAY SLEEP */ - spin_lock_irqsave(udc->lock, flags); - - if (retval) { - udc->gadget.dev.driver = NULL; - goto done; - } - - udc->driver = driver; - pm_runtime_get_sync(&udc->gadget.dev); - if (udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) { - if (udc->vbus_active) { - if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) - hw_device_reset(udc); - } else { - pm_runtime_put_sync(&udc->gadget.dev); - goto done; - } - } - - retval = hw_device_state(udc->ep0out.qh.dma); - if (retval) - pm_runtime_put_sync(&udc->gadget.dev); - - done: - spin_unlock_irqrestore(udc->lock, flags); - return retval; -} - -/** - * ci13xxx_stop: unregister a gadget driver - * - * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details - */ -static int ci13xxx_stop(struct usb_gadget_driver *driver) -{ - struct ci13xxx *udc = _udc; - unsigned long i, flags; - - trace("%p", driver); - - if (driver == NULL || - driver->unbind == NULL || - driver->setup == NULL || - driver->disconnect == NULL || - driver != udc->driver) - return -EINVAL; - - spin_lock_irqsave(udc->lock, flags); - - if (!(udc->udc_driver->flags & CI13XXX_PULLUP_ON_VBUS) || - udc->vbus_active) { - hw_device_state(0); - if (udc->udc_driver->notify_event) - udc->udc_driver->notify_event(udc, - CI13XXX_CONTROLLER_STOPPED_EVENT); - spin_unlock_irqrestore(udc->lock, flags); - _gadget_stop_activity(&udc->gadget); - spin_lock_irqsave(udc->lock, flags); - pm_runtime_put(&udc->gadget.dev); - } - - /* unbind gadget */ - spin_unlock_irqrestore(udc->lock, flags); - driver->unbind(&udc->gadget); /* MAY SLEEP */ - spin_lock_irqsave(udc->lock, flags); - - udc->gadget.dev.driver = NULL; - - /* free resources */ - for (i = 0; i < hw_ep_max; i++) { - struct ci13xxx_ep *mEp = &udc->ci13xxx_ep[i]; - - if (!list_empty(&mEp->ep.ep_list)) - list_del_init(&mEp->ep.ep_list); - - if (mEp->qh.ptr != NULL) - dma_pool_free(udc->qh_pool, mEp->qh.ptr, mEp->qh.dma); - } - - udc->gadget.ep0 = NULL; - udc->driver = NULL; - - spin_unlock_irqrestore(udc->lock, flags); - - if (udc->td_pool != NULL) { - dma_pool_destroy(udc->td_pool); - udc->td_pool = NULL; - } - if (udc->qh_pool != NULL) { - dma_pool_destroy(udc->qh_pool); - udc->qh_pool = NULL; - } - - return 0; -} - -/****************************************************************************** - * BUS block - *****************************************************************************/ -/** - * udc_irq: global interrupt handler - * - * This function returns IRQ_HANDLED if the IRQ has been handled - * It locks access to registers - */ -static irqreturn_t udc_irq(void) -{ - struct ci13xxx *udc = _udc; - irqreturn_t retval; - u32 intr; - - trace(); - - if (udc == NULL) { - err("ENODEV"); - return IRQ_HANDLED; - } - - spin_lock(udc->lock); - - if (udc->udc_driver->flags & CI13XXX_REGS_SHARED) { - if (hw_cread(CAP_USBMODE, USBMODE_CM) != - USBMODE_CM_DEVICE) { - spin_unlock(udc->lock); - return IRQ_NONE; - } - } - intr = hw_test_and_clear_intr_active(); - if (intr) { - isr_statistics.hndl.buf[isr_statistics.hndl.idx++] = intr; - isr_statistics.hndl.idx &= ISR_MASK; - isr_statistics.hndl.cnt++; - - /* order defines priority - do NOT change it */ - if (USBi_URI & intr) { - isr_statistics.uri++; - isr_reset_handler(udc); - } - if (USBi_PCI & intr) { - isr_statistics.pci++; - udc->gadget.speed = hw_port_is_high_speed() ? - USB_SPEED_HIGH : USB_SPEED_FULL; - if (udc->suspended && udc->driver->resume) { - spin_unlock(udc->lock); - udc->driver->resume(&udc->gadget); - spin_lock(udc->lock); - udc->suspended = 0; - } - } - if (USBi_UEI & intr) - isr_statistics.uei++; - if (USBi_UI & intr) { - isr_statistics.ui++; - isr_tr_complete_handler(udc); - } - if (USBi_SLI & intr) { - if (udc->gadget.speed != USB_SPEED_UNKNOWN && - udc->driver->suspend) { - udc->suspended = 1; - spin_unlock(udc->lock); - udc->driver->suspend(&udc->gadget); - spin_lock(udc->lock); - } - isr_statistics.sli++; - } - retval = IRQ_HANDLED; - } else { - isr_statistics.none++; - retval = IRQ_NONE; - } - spin_unlock(udc->lock); - - return retval; -} - -/** - * udc_release: driver release function - * @dev: device - * - * Currently does nothing - */ -static void udc_release(struct device *dev) -{ - trace("%p", dev); - - if (dev == NULL) - err("EINVAL"); -} - -/** - * udc_probe: parent probe must call this to initialize UDC - * @dev: parent device - * @regs: registers base address - * @name: driver name - * - * This function returns an error code - * No interrupts active, the IRQ has not been requested yet - * Kernel assumes 32-bit DMA operations by default, no need to dma_set_mask - */ -static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev, - void __iomem *regs) -{ - struct ci13xxx *udc; - int retval = 0; - - trace("%p, %p, %p", dev, regs, driver->name); - - if (dev == NULL || regs == NULL || driver == NULL || - driver->name == NULL) - return -EINVAL; - - udc = kzalloc(sizeof(struct ci13xxx), GFP_KERNEL); - if (udc == NULL) - return -ENOMEM; - - udc->lock = &udc_lock; - udc->regs = regs; - udc->udc_driver = driver; - - udc->gadget.ops = &usb_gadget_ops; - udc->gadget.speed = USB_SPEED_UNKNOWN; - udc->gadget.max_speed = USB_SPEED_HIGH; - udc->gadget.is_otg = 0; - udc->gadget.name = driver->name; - - INIT_LIST_HEAD(&udc->gadget.ep_list); - udc->gadget.ep0 = NULL; - - dev_set_name(&udc->gadget.dev, "gadget"); - udc->gadget.dev.dma_mask = dev->dma_mask; - udc->gadget.dev.coherent_dma_mask = dev->coherent_dma_mask; - udc->gadget.dev.parent = dev; - udc->gadget.dev.release = udc_release; - - retval = hw_device_init(regs); - if (retval < 0) - goto free_udc; - - udc->transceiver = usb_get_transceiver(); - - if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) { - if (udc->transceiver == NULL) { - retval = -ENODEV; - goto free_udc; - } - } - - if (!(udc->udc_driver->flags & CI13XXX_REGS_SHARED)) { - retval = hw_device_reset(udc); - if (retval) - goto put_transceiver; - } - - retval = device_register(&udc->gadget.dev); - if (retval) { - put_device(&udc->gadget.dev); - goto put_transceiver; - } - -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - retval = dbg_create_files(&udc->gadget.dev); -#endif - if (retval) - goto unreg_device; - - if (udc->transceiver) { - retval = otg_set_peripheral(udc->transceiver->otg, - &udc->gadget); - if (retval) - goto remove_dbg; - } - - retval = usb_add_gadget_udc(dev, &udc->gadget); - if (retval) - goto remove_trans; - - pm_runtime_no_callbacks(&udc->gadget.dev); - pm_runtime_enable(&udc->gadget.dev); - - _udc = udc; - return retval; - -remove_trans: - if (udc->transceiver) { - otg_set_peripheral(udc->transceiver->otg, &udc->gadget); - usb_put_transceiver(udc->transceiver); - } - - err("error = %i", retval); -remove_dbg: -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - dbg_remove_files(&udc->gadget.dev); -#endif -unreg_device: - device_unregister(&udc->gadget.dev); -put_transceiver: - if (udc->transceiver) - usb_put_transceiver(udc->transceiver); -free_udc: - kfree(udc); - _udc = NULL; - return retval; -} - -/** - * udc_remove: parent remove must call this to remove UDC - * - * No interrupts active, the IRQ has been released - */ -static void udc_remove(void) -{ - struct ci13xxx *udc = _udc; - - if (udc == NULL) { - err("EINVAL"); - return; - } - usb_del_gadget_udc(&udc->gadget); - - if (udc->transceiver) { - otg_set_peripheral(udc->transceiver->otg, &udc->gadget); - usb_put_transceiver(udc->transceiver); - } -#ifdef CONFIG_USB_GADGET_DEBUG_FILES - dbg_remove_files(&udc->gadget.dev); -#endif - device_unregister(&udc->gadget.dev); - - kfree(udc); - _udc = NULL; -} diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h deleted file mode 100644 index 0d31af56c989..000000000000 --- a/drivers/usb/gadget/ci13xxx_udc.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * ci13xxx_udc.h - structures, registers, and macros MIPS USB IP core - * - * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. - * - * Author: David Lopo - * - * 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. - * - * Description: MIPS USB IP core family device controller - * Structures, registers and logging macros - */ - -#ifndef _CI13XXX_h_ -#define _CI13XXX_h_ - -/****************************************************************************** - * DEFINE - *****************************************************************************/ -#define CI13XXX_PAGE_SIZE 4096ul /* page size for TD's */ -#define ENDPT_MAX (32) -#define CTRL_PAYLOAD_MAX (64) -#define RX (0) /* similar to USB_DIR_OUT but can be used as an index */ -#define TX (1) /* similar to USB_DIR_IN but can be used as an index */ - -/****************************************************************************** - * STRUCTURES - *****************************************************************************/ -/* DMA layout of transfer descriptors */ -struct ci13xxx_td { - /* 0 */ - u32 next; -#define TD_TERMINATE BIT(0) -#define TD_ADDR_MASK (0xFFFFFFEUL << 5) - /* 1 */ - u32 token; -#define TD_STATUS (0x00FFUL << 0) -#define TD_STATUS_TR_ERR BIT(3) -#define TD_STATUS_DT_ERR BIT(5) -#define TD_STATUS_HALTED BIT(6) -#define TD_STATUS_ACTIVE BIT(7) -#define TD_MULTO (0x0003UL << 10) -#define TD_IOC BIT(15) -#define TD_TOTAL_BYTES (0x7FFFUL << 16) - /* 2 */ - u32 page[5]; -#define TD_CURR_OFFSET (0x0FFFUL << 0) -#define TD_FRAME_NUM (0x07FFUL << 0) -#define TD_RESERVED_MASK (0x0FFFUL << 0) -} __attribute__ ((packed)); - -/* DMA layout of queue heads */ -struct ci13xxx_qh { - /* 0 */ - u32 cap; -#define QH_IOS BIT(15) -#define QH_MAX_PKT (0x07FFUL << 16) -#define QH_ZLT BIT(29) -#define QH_MULT (0x0003UL << 30) - /* 1 */ - u32 curr; - /* 2 - 8 */ - struct ci13xxx_td td; - /* 9 */ - u32 RESERVED; - struct usb_ctrlrequest setup; -} __attribute__ ((packed)); - -/* Extension of usb_request */ -struct ci13xxx_req { - struct usb_request req; - unsigned map; - struct list_head queue; - struct ci13xxx_td *ptr; - dma_addr_t dma; - struct ci13xxx_td *zptr; - dma_addr_t zdma; -}; - -/* Extension of usb_ep */ -struct ci13xxx_ep { - struct usb_ep ep; - const struct usb_endpoint_descriptor *desc; - u8 dir; - u8 num; - u8 type; - char name[16]; - struct { - struct list_head queue; - struct ci13xxx_qh *ptr; - dma_addr_t dma; - } qh; - int wedge; - - /* global resources */ - spinlock_t *lock; - struct device *device; - struct dma_pool *td_pool; -}; - -struct ci13xxx; -struct ci13xxx_udc_driver { - const char *name; - unsigned long flags; -#define CI13XXX_REGS_SHARED BIT(0) -#define CI13XXX_REQUIRE_TRANSCEIVER BIT(1) -#define CI13XXX_PULLUP_ON_VBUS BIT(2) -#define CI13XXX_DISABLE_STREAMING BIT(3) - -#define CI13XXX_CONTROLLER_RESET_EVENT 0 -#define CI13XXX_CONTROLLER_STOPPED_EVENT 1 - void (*notify_event) (struct ci13xxx *udc, unsigned event); -}; - -/* CI13XXX UDC descriptor & global resources */ -struct ci13xxx { - spinlock_t *lock; /* ctrl register bank access */ - void __iomem *regs; /* registers address space */ - - struct dma_pool *qh_pool; /* DMA pool for queue heads */ - struct dma_pool *td_pool; /* DMA pool for transfer descs */ - struct usb_request *status; /* ep0 status request */ - - struct usb_gadget gadget; /* USB slave device */ - struct ci13xxx_ep ci13xxx_ep[ENDPT_MAX]; /* extended endpts */ - u32 ep0_dir; /* ep0 direction */ -#define ep0out ci13xxx_ep[0] -#define ep0in ci13xxx_ep[hw_ep_max / 2] - u8 remote_wakeup; /* Is remote wakeup feature - enabled by the host? */ - u8 suspended; /* suspended by the host */ - u8 test_mode; /* the selected test mode */ - - struct usb_gadget_driver *driver; /* 3rd party gadget driver */ - struct ci13xxx_udc_driver *udc_driver; /* device controller driver */ - int vbus_active; /* is VBUS active */ - struct usb_phy *transceiver; /* Transceiver struct */ -}; - -/****************************************************************************** - * REGISTERS - *****************************************************************************/ -/* register size */ -#define REG_BITS (32) - -/* HCCPARAMS */ -#define HCCPARAMS_LEN BIT(17) - -/* DCCPARAMS */ -#define DCCPARAMS_DEN (0x1F << 0) -#define DCCPARAMS_DC BIT(7) - -/* TESTMODE */ -#define TESTMODE_FORCE BIT(0) - -/* USBCMD */ -#define USBCMD_RS BIT(0) -#define USBCMD_RST BIT(1) -#define USBCMD_SUTW BIT(13) -#define USBCMD_ATDTW BIT(14) - -/* USBSTS & USBINTR */ -#define USBi_UI BIT(0) -#define USBi_UEI BIT(1) -#define USBi_PCI BIT(2) -#define USBi_URI BIT(6) -#define USBi_SLI BIT(8) - -/* DEVICEADDR */ -#define DEVICEADDR_USBADRA BIT(24) -#define DEVICEADDR_USBADR (0x7FUL << 25) - -/* PORTSC */ -#define PORTSC_FPR BIT(6) -#define PORTSC_SUSP BIT(7) -#define PORTSC_HSP BIT(9) -#define PORTSC_PTC (0x0FUL << 16) - -/* DEVLC */ -#define DEVLC_PSPD (0x03UL << 25) -#define DEVLC_PSPD_HS (0x02UL << 25) - -/* USBMODE */ -#define USBMODE_CM (0x03UL << 0) -#define USBMODE_CM_IDLE (0x00UL << 0) -#define USBMODE_CM_DEVICE (0x02UL << 0) -#define USBMODE_CM_HOST (0x03UL << 0) -#define USBMODE_SLOM BIT(3) -#define USBMODE_SDIS BIT(4) - -/* ENDPTCTRL */ -#define ENDPTCTRL_RXS BIT(0) -#define ENDPTCTRL_RXT (0x03UL << 2) -#define ENDPTCTRL_RXR BIT(6) /* reserved for port 0 */ -#define ENDPTCTRL_RXE BIT(7) -#define ENDPTCTRL_TXS BIT(16) -#define ENDPTCTRL_TXT (0x03UL << 18) -#define ENDPTCTRL_TXR BIT(22) /* reserved for port 0 */ -#define ENDPTCTRL_TXE BIT(23) - -/****************************************************************************** - * LOGGING - *****************************************************************************/ -#define ci13xxx_printk(level, format, args...) \ -do { \ - if (_udc == NULL) \ - printk(level "[%s] " format "\n", __func__, ## args); \ - else \ - dev_printk(level, _udc->gadget.dev.parent, \ - "[%s] " format "\n", __func__, ## args); \ -} while (0) - -#define err(format, args...) ci13xxx_printk(KERN_ERR, format, ## args) -#define warn(format, args...) ci13xxx_printk(KERN_WARNING, format, ## args) -#define info(format, args...) ci13xxx_printk(KERN_INFO, format, ## args) - -#ifdef TRACE -#define trace(format, args...) ci13xxx_printk(KERN_DEBUG, format, ## args) -#define dbg_trace(format, args...) dev_dbg(dev, format, ##args) -#else -#define trace(format, args...) do {} while (0) -#define dbg_trace(format, args...) do {} while (0) -#endif - -#endif /* _CI13XXX_h_ */ diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index baaebf2830fc..390749bbb0c3 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -40,27 +40,27 @@ static int (*composite_gadget_bind)(struct usb_composite_dev *cdev); */ static ushort idVendor; -module_param(idVendor, ushort, 0); +module_param(idVendor, ushort, 0644); MODULE_PARM_DESC(idVendor, "USB Vendor ID"); static ushort idProduct; -module_param(idProduct, ushort, 0); +module_param(idProduct, ushort, 0644); MODULE_PARM_DESC(idProduct, "USB Product ID"); static ushort bcdDevice; -module_param(bcdDevice, ushort, 0); +module_param(bcdDevice, ushort, 0644); MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); static char *iManufacturer; -module_param(iManufacturer, charp, 0); +module_param(iManufacturer, charp, 0644); MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); static char *iProduct; -module_param(iProduct, charp, 0); +module_param(iProduct, charp, 0644); MODULE_PARM_DESC(iProduct, "USB Product string"); static char *iSerialNumber; -module_param(iSerialNumber, charp, 0); +module_param(iSerialNumber, charp, 0644); MODULE_PARM_DESC(iSerialNumber, "SerialNumber string"); static char composite_manufacturer[50]; @@ -734,9 +734,23 @@ int usb_add_config(struct usb_composite_dev *cdev, INIT_LIST_HEAD(&config->functions); config->next_interface_id = 0; + memset(config->interface, 0, sizeof(config->interface)); status = bind(config); if (status < 0) { + while (!list_empty(&config->functions)) { + struct usb_function *f; + + f = list_first_entry(&config->functions, + struct usb_function, list); + list_del(&f->list); + if (f->unbind) { + DBG(cdev, "unbind function '%s'/%p\n", + f->name, f); + f->unbind(config, f); + /* may free memory for "f" */ + } + } list_del(&config->list); config->cdev = NULL; } else { @@ -774,6 +788,53 @@ done: return status; } +static void remove_config(struct usb_composite_dev *cdev, + struct usb_configuration *config) +{ + while (!list_empty(&config->functions)) { + struct usb_function *f; + + f = list_first_entry(&config->functions, + struct usb_function, list); + list_del(&f->list); + if (f->unbind) { + DBG(cdev, "unbind function '%s'/%p\n", f->name, f); + f->unbind(config, f); + /* may free memory for "f" */ + } + } + list_del(&config->list); + if (config->unbind) { + DBG(cdev, "unbind config '%s'/%p\n", config->label, config); + config->unbind(config); + /* may free memory for "c" */ + } +} + +/** + * usb_remove_config() - remove a configuration from a device. + * @cdev: wraps the USB gadget + * @config: the configuration + * + * Drivers must call usb_gadget_disconnect before calling this function + * to disconnect the device from the host and make sure the host will not + * try to enumerate the device while we are changing the config list. + */ +void usb_remove_config(struct usb_composite_dev *cdev, + struct usb_configuration *config) +{ + unsigned long flags; + + spin_lock_irqsave(&cdev->lock, flags); + + if (cdev->config == config) + reset_config(cdev); + + spin_unlock_irqrestore(&cdev->lock, flags); + + remove_config(cdev, config); +} + /*-------------------------------------------------------------------------*/ /* We support strings in multiple languages ... string descriptor zero @@ -785,7 +846,7 @@ done: static void collect_langs(struct usb_gadget_strings **sp, __le16 *buf) { const struct usb_gadget_strings *s; - u16 language; + __le16 language; __le16 *tmp; while (*sp) { @@ -877,7 +938,7 @@ static int get_string(struct usb_composite_dev *cdev, else if (cdev->product_override == id) str = iProduct ?: composite->iProduct; else if (cdev->serial_override == id) - str = iSerialNumber; + str = iSerialNumber ?: composite->iSerialNumber; else str = NULL; if (str) { @@ -1328,28 +1389,9 @@ composite_unbind(struct usb_gadget *gadget) while (!list_empty(&cdev->configs)) { struct usb_configuration *c; - c = list_first_entry(&cdev->configs, struct usb_configuration, list); - while (!list_empty(&c->functions)) { - struct usb_function *f; - - f = list_first_entry(&c->functions, - struct usb_function, list); - list_del(&f->list); - if (f->unbind) { - DBG(cdev, "unbind function '%s'/%p\n", - f->name, f); - f->unbind(c, f); - /* may free memory for "f" */ - } - } - list_del(&c->list); - if (c->unbind) { - DBG(cdev, "unbind config '%s'/%p\n", c->label, c); - c->unbind(c); - /* may free memory for "c" */ - } + remove_config(cdev, c); } if (composite->unbind) composite->unbind(cdev); @@ -1431,10 +1473,16 @@ static int composite_bind(struct usb_gadget *gadget) /* standardized runtime overrides for device ID data */ if (idVendor) cdev->desc.idVendor = cpu_to_le16(idVendor); + else + idVendor = le16_to_cpu(cdev->desc.idVendor); if (idProduct) cdev->desc.idProduct = cpu_to_le16(idProduct); + else + idProduct = le16_to_cpu(cdev->desc.idProduct); if (bcdDevice) cdev->desc.bcdDevice = cpu_to_le16(bcdDevice); + else + bcdDevice = le16_to_cpu(cdev->desc.bcdDevice); /* string overrides */ if (iManufacturer || !cdev->desc.iManufacturer) { @@ -1455,7 +1503,8 @@ static int composite_bind(struct usb_gadget *gadget) cdev->product_override = override_id(cdev, &cdev->desc.iProduct); - if (iSerialNumber) + if (iSerialNumber || + (!cdev->desc.iSerialNumber && composite->iSerialNumber)) cdev->serial_override = override_id(cdev, &cdev->desc.iSerialNumber); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index 170cbe89d9f8..b799106027ad 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -595,14 +595,12 @@ static struct usb_request *dummy_alloc_request(struct usb_ep *_ep, static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req) { - struct dummy_ep *ep; struct dummy_request *req; - if (!_ep || !_req) - return; - ep = usb_ep_to_dummy_ep(_ep); - if (!ep->desc && _ep->name != ep0name) + if (!_ep || !_req) { + WARN_ON(1); return; + } req = usb_request_to_dummy_request(_req); WARN_ON(!list_empty(&req->queue)); diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c index f52cb1ae45d9..dcd1c7fbb016 100644 --- a/drivers/usb/gadget/f_fs.c +++ b/drivers/usb/gadget/f_fs.c @@ -1031,6 +1031,12 @@ struct ffs_sb_fill_data { struct ffs_file_perms perms; umode_t root_mode; const char *dev_name; + union { + /* set by ffs_fs_mount(), read by ffs_sb_fill() */ + void *private_data; + /* set by ffs_sb_fill(), read by ffs_fs_mount */ + struct ffs_data *ffs_data; + }; }; static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) @@ -1047,8 +1053,14 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent) goto Enomem; ffs->sb = sb; - ffs->dev_name = data->dev_name; + ffs->dev_name = kstrdup(data->dev_name, GFP_KERNEL); + if (unlikely(!ffs->dev_name)) + goto Enomem; ffs->file_perms = data->perms; + ffs->private_data = data->private_data; + + /* used by the caller of this function */ + data->ffs_data = ffs; sb->s_fs_info = ffs; sb->s_blocksize = PAGE_CACHE_SIZE; @@ -1167,20 +1179,29 @@ ffs_fs_mount(struct file_system_type *t, int flags, }, .root_mode = S_IFDIR | 0500, }; + struct dentry *rv; int ret; + void *ffs_dev; ENTER(); - ret = functionfs_check_dev_callback(dev_name); - if (unlikely(ret < 0)) - return ERR_PTR(ret); - ret = ffs_fs_parse_opts(&data, opts); if (unlikely(ret < 0)) return ERR_PTR(ret); + ffs_dev = functionfs_acquire_dev_callback(dev_name); + if (IS_ERR(ffs_dev)) + return ffs_dev; + data.dev_name = dev_name; - return mount_single(t, flags, &data, ffs_sb_fill); + data.private_data = ffs_dev; + rv = mount_nodev(t, flags, &data, ffs_sb_fill); + + /* data.ffs_data is set by ffs_sb_fill */ + if (IS_ERR(rv)) + functionfs_release_dev_callback(data.ffs_data); + + return rv; } static void @@ -1189,8 +1210,10 @@ ffs_fs_kill_sb(struct super_block *sb) ENTER(); kill_litter_super(sb); - if (sb->s_fs_info) + if (sb->s_fs_info) { + functionfs_release_dev_callback(sb->s_fs_info); ffs_data_put(sb->s_fs_info); + } } static struct file_system_type ffs_fs_type = { @@ -1256,6 +1279,7 @@ static void ffs_data_put(struct ffs_data *ffs) ffs_data_clear(ffs); BUG_ON(waitqueue_active(&ffs->ev.waitq) || waitqueue_active(&ffs->ep0req_completion.wait)); + kfree(ffs->dev_name); kfree(ffs); } } @@ -1473,8 +1497,22 @@ static int functionfs_bind_config(struct usb_composite_dev *cdev, static void ffs_func_free(struct ffs_function *func) { + struct ffs_ep *ep = func->eps; + unsigned count = func->ffs->eps_count; + unsigned long flags; + ENTER(); + /* cleanup after autoconfig */ + spin_lock_irqsave(&func->ffs->eps_lock, flags); + do { + if (ep->ep && ep->req) + usb_ep_free_request(ep->ep, ep->req); + ep->req = NULL; + ++ep; + } while (--count); + spin_unlock_irqrestore(&func->ffs->eps_lock, flags); + ffs_data_put(func->ffs); kfree(func->eps); diff --git a/drivers/usb/gadget/f_hid.c b/drivers/usb/gadget/f_hid.c index b2113420b806..3b3932c55361 100644 --- a/drivers/usb/gadget/f_hid.c +++ b/drivers/usb/gadget/f_hid.c @@ -374,7 +374,7 @@ static int hidg_setup(struct usb_function *f, break; default: - VDBG(cdev, "Unknown decriptor request 0x%x\n", + VDBG(cdev, "Unknown descriptor request 0x%x\n", value >> 8); goto stall; break; diff --git a/drivers/usb/gadget/f_loopback.c b/drivers/usb/gadget/f_loopback.c index 2c0cd824c667..7275706caeb0 100644 --- a/drivers/usb/gadget/f_loopback.c +++ b/drivers/usb/gadget/f_loopback.c @@ -286,7 +286,7 @@ static void disable_loopback(struct f_loopback *loop) struct usb_composite_dev *cdev; cdev = loop->function.config->cdev; - disable_endpoints(cdev, loop->in_ep, loop->out_ep); + disable_endpoints(cdev, loop->in_ep, loop->out_ep, NULL, NULL); VDBG(cdev, "%s disabled\n", loop->function.name); } @@ -329,7 +329,7 @@ fail0: * than 'buflen' bytes each. */ for (i = 0; i < qlen && result == 0; i++) { - req = alloc_ep_req(ep); + req = alloc_ep_req(ep, 0); if (req) { req->complete = loopback_complete; result = usb_ep_queue(ep, req, GFP_ATOMIC); diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c index cb8c162cae5a..f67b453740bd 100644 --- a/drivers/usb/gadget/f_mass_storage.c +++ b/drivers/usb/gadget/f_mass_storage.c @@ -3110,13 +3110,6 @@ static int fsg_bind_config(struct usb_composite_dev *cdev, return rc; } -static inline int __deprecated __maybe_unused -fsg_add(struct usb_composite_dev *cdev, struct usb_configuration *c, - struct fsg_common *common) -{ - return fsg_bind_config(cdev, c, common); -} - /************************* Module parameters *************************/ diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c index 52343654f5df..b1681e45aca7 100644 --- a/drivers/usb/gadget/f_rndis.c +++ b/drivers/usb/gadget/f_rndis.c @@ -71,6 +71,8 @@ struct f_rndis { struct gether port; u8 ctrl_id, data_id; u8 ethaddr[ETH_ALEN]; + u32 vendorID; + const char *manufacturer; int config; struct usb_ep *notify; @@ -637,7 +639,7 @@ static void rndis_open(struct gether *geth) DBG(cdev, "%s\n", __func__); - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, + rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, bitrate(cdev->gadget) / 100); rndis_signal_connect(rndis->config); } @@ -648,7 +650,7 @@ static void rndis_close(struct gether *geth) DBG(geth->func.config->cdev, "%s\n", __func__); - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); rndis_signal_disconnect(rndis->config); } @@ -765,15 +767,13 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f) goto fail; rndis->config = status; - rndis_set_param_medium(rndis->config, NDIS_MEDIUM_802_3, 0); + rndis_set_param_medium(rndis->config, RNDIS_MEDIUM_802_3, 0); rndis_set_host_mac(rndis->config, rndis->ethaddr); -#if 0 -// FIXME - if (rndis_set_param_vendor(rndis->config, vendorID, - manufacturer)) - goto fail0; -#endif + if (rndis->manufacturer && rndis->vendorID && + rndis_set_param_vendor(rndis->config, rndis->vendorID, + rndis->manufacturer)) + goto fail; /* NOTE: all that is done without knowing or caring about * the network link ... which is unavailable to this code @@ -820,6 +820,7 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f) rndis_deregister(rndis->config); rndis_exit(); + rndis_string_defs[0].id = 0; if (gadget_is_superspeed(c->cdev->gadget)) usb_free_descriptors(f->ss_descriptors); @@ -840,20 +841,9 @@ static inline bool can_support_rndis(struct usb_configuration *c) return true; } -/** - * rndis_bind_config - add RNDIS network link to a configuration - * @c: the configuration to support the network link - * @ethaddr: a buffer in which the ethernet address of the host side - * side of the link was recorded - * Context: single threaded during gadget setup - * - * Returns zero on success, else negative errno. - * - * Caller must have called @gether_setup(). Caller is also responsible - * for calling @gether_cleanup() before module unload. - */ int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer) { struct f_rndis *rndis; int status; @@ -898,6 +888,8 @@ rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) goto fail; memcpy(rndis->ethaddr, ethaddr, ETH_ALEN); + rndis->vendorID = vendorID; + rndis->manufacturer = manufacturer; /* RNDIS activates when the host changes this filter */ rndis->port.cdc_filter = 0; diff --git a/drivers/usb/gadget/f_sourcesink.c b/drivers/usb/gadget/f_sourcesink.c index 7aa7ac82c02c..5c1b68b63c98 100644 --- a/drivers/usb/gadget/f_sourcesink.c +++ b/drivers/usb/gadget/f_sourcesink.c @@ -51,6 +51,9 @@ struct f_sourcesink { struct usb_ep *in_ep; struct usb_ep *out_ep; + struct usb_ep *iso_in_ep; + struct usb_ep *iso_out_ep; + int cur_alt; }; static inline struct f_sourcesink *func_to_ss(struct usb_function *f) @@ -59,18 +62,45 @@ static inline struct f_sourcesink *func_to_ss(struct usb_function *f) } static unsigned pattern; -module_param(pattern, uint, 0); -MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63 "); +module_param(pattern, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(pattern, "0 = all zeroes, 1 = mod63, 2 = none"); + +static unsigned isoc_interval = 4; +module_param(isoc_interval, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_interval, "1 - 16"); + +static unsigned isoc_maxpacket = 1024; +module_param(isoc_maxpacket, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_maxpacket, "0 - 1023 (fs), 0 - 1024 (hs/ss)"); + +static unsigned isoc_mult; +module_param(isoc_mult, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_mult, "0 - 2 (hs/ss only)"); + +static unsigned isoc_maxburst; +module_param(isoc_maxburst, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(isoc_maxburst, "0 - 15 (ss only)"); /*-------------------------------------------------------------------------*/ -static struct usb_interface_descriptor source_sink_intf = { - .bLength = sizeof source_sink_intf, +static struct usb_interface_descriptor source_sink_intf_alt0 = { + .bLength = USB_DT_INTERFACE_SIZE, .bDescriptorType = USB_DT_INTERFACE, + .bAlternateSetting = 0, .bNumEndpoints = 2, .bInterfaceClass = USB_CLASS_VENDOR_SPEC, - /* .iInterface = DYNAMIC */ + /* .iInterface = DYNAMIC */ +}; + +static struct usb_interface_descriptor source_sink_intf_alt1 = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + + .bAlternateSetting = 1, + .bNumEndpoints = 4, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + /* .iInterface = DYNAMIC */ }; /* full speed support: */ @@ -91,10 +121,36 @@ static struct usb_endpoint_descriptor fs_sink_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK, }; +static struct usb_endpoint_descriptor fs_iso_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1023), + .bInterval = 4, +}; + +static struct usb_endpoint_descriptor fs_iso_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1023), + .bInterval = 4, +}; + static struct usb_descriptor_header *fs_source_sink_descs[] = { - (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &source_sink_intf_alt0, (struct usb_descriptor_header *) &fs_sink_desc, (struct usb_descriptor_header *) &fs_source_desc, + (struct usb_descriptor_header *) &source_sink_intf_alt1, +#define FS_ALT_IFC_1_OFFSET 3 + (struct usb_descriptor_header *) &fs_sink_desc, + (struct usb_descriptor_header *) &fs_source_desc, + (struct usb_descriptor_header *) &fs_iso_sink_desc, + (struct usb_descriptor_header *) &fs_iso_source_desc, NULL, }; @@ -116,10 +172,34 @@ static struct usb_endpoint_descriptor hs_sink_desc = { .wMaxPacketSize = cpu_to_le16(512), }; +static struct usb_endpoint_descriptor hs_iso_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 4, +}; + +static struct usb_endpoint_descriptor hs_iso_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 4, +}; + static struct usb_descriptor_header *hs_source_sink_descs[] = { - (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &source_sink_intf_alt0, (struct usb_descriptor_header *) &hs_source_desc, (struct usb_descriptor_header *) &hs_sink_desc, + (struct usb_descriptor_header *) &source_sink_intf_alt1, +#define HS_ALT_IFC_1_OFFSET 3 + (struct usb_descriptor_header *) &hs_source_desc, + (struct usb_descriptor_header *) &hs_sink_desc, + (struct usb_descriptor_header *) &hs_iso_source_desc, + (struct usb_descriptor_header *) &hs_iso_sink_desc, NULL, }; @@ -136,6 +216,7 @@ static struct usb_endpoint_descriptor ss_source_desc = { struct usb_ss_ep_comp_descriptor ss_source_comp_desc = { .bLength = USB_DT_SS_EP_COMP_SIZE, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, .bmAttributes = 0, .wBytesPerInterval = 0, @@ -152,17 +233,64 @@ static struct usb_endpoint_descriptor ss_sink_desc = { struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = { .bLength = USB_DT_SS_EP_COMP_SIZE, .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, .bmAttributes = 0, .wBytesPerInterval = 0, }; +static struct usb_endpoint_descriptor ss_iso_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 4, +}; + +struct usb_ss_ep_comp_descriptor ss_iso_source_comp_desc = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = cpu_to_le16(1024), +}; + +static struct usb_endpoint_descriptor ss_iso_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bmAttributes = USB_ENDPOINT_XFER_ISOC, + .wMaxPacketSize = cpu_to_le16(1024), + .bInterval = 4, +}; + +struct usb_ss_ep_comp_descriptor ss_iso_sink_comp_desc = { + .bLength = USB_DT_SS_EP_COMP_SIZE, + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + + .bMaxBurst = 0, + .bmAttributes = 0, + .wBytesPerInterval = cpu_to_le16(1024), +}; + static struct usb_descriptor_header *ss_source_sink_descs[] = { - (struct usb_descriptor_header *) &source_sink_intf, + (struct usb_descriptor_header *) &source_sink_intf_alt0, (struct usb_descriptor_header *) &ss_source_desc, (struct usb_descriptor_header *) &ss_source_comp_desc, (struct usb_descriptor_header *) &ss_sink_desc, (struct usb_descriptor_header *) &ss_sink_comp_desc, + (struct usb_descriptor_header *) &source_sink_intf_alt1, +#define SS_ALT_IFC_1_OFFSET 5 + (struct usb_descriptor_header *) &ss_source_desc, + (struct usb_descriptor_header *) &ss_source_comp_desc, + (struct usb_descriptor_header *) &ss_sink_desc, + (struct usb_descriptor_header *) &ss_sink_comp_desc, + (struct usb_descriptor_header *) &ss_iso_source_desc, + (struct usb_descriptor_header *) &ss_iso_source_comp_desc, + (struct usb_descriptor_header *) &ss_iso_sink_desc, + (struct usb_descriptor_header *) &ss_iso_sink_comp_desc, NULL, }; @@ -196,9 +324,10 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f) id = usb_interface_id(c, f); if (id < 0) return id; - source_sink_intf.bInterfaceNumber = id; + source_sink_intf_alt0.bInterfaceNumber = id; + source_sink_intf_alt1.bInterfaceNumber = id; - /* allocate endpoints */ + /* allocate bulk endpoints */ ss->in_ep = usb_ep_autoconfig(cdev->gadget, &fs_source_desc); if (!ss->in_ep) { autoconf_fail: @@ -213,12 +342,74 @@ autoconf_fail: goto autoconf_fail; ss->out_ep->driver_data = cdev; /* claim */ + /* sanity check the isoc module parameters */ + if (isoc_interval < 1) + isoc_interval = 1; + if (isoc_interval > 16) + isoc_interval = 16; + if (isoc_mult > 2) + isoc_mult = 2; + if (isoc_maxburst > 15) + isoc_maxburst = 15; + + /* fill in the FS isoc descriptors from the module parameters */ + fs_iso_source_desc.wMaxPacketSize = isoc_maxpacket > 1023 ? + 1023 : isoc_maxpacket; + fs_iso_source_desc.bInterval = isoc_interval; + fs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket > 1023 ? + 1023 : isoc_maxpacket; + fs_iso_sink_desc.bInterval = isoc_interval; + + /* allocate iso endpoints */ + ss->iso_in_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_source_desc); + if (!ss->iso_in_ep) + goto no_iso; + ss->iso_in_ep->driver_data = cdev; /* claim */ + + ss->iso_out_ep = usb_ep_autoconfig(cdev->gadget, &fs_iso_sink_desc); + if (ss->iso_out_ep) { + ss->iso_out_ep->driver_data = cdev; /* claim */ + } else { + ss->iso_in_ep->driver_data = NULL; + ss->iso_in_ep = NULL; +no_iso: + /* + * We still want to work even if the UDC doesn't have isoc + * endpoints, so null out the alt interface that contains + * them and continue. + */ + fs_source_sink_descs[FS_ALT_IFC_1_OFFSET] = NULL; + hs_source_sink_descs[HS_ALT_IFC_1_OFFSET] = NULL; + ss_source_sink_descs[SS_ALT_IFC_1_OFFSET] = NULL; + } + + if (isoc_maxpacket > 1024) + isoc_maxpacket = 1024; + /* support high speed hardware */ if (gadget_is_dualspeed(c->cdev->gadget)) { hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress; hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; + + /* + * Fill in the HS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket; + hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11; + hs_iso_source_desc.bInterval = isoc_interval; + hs_iso_source_desc.bEndpointAddress = + fs_iso_source_desc.bEndpointAddress; + + hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; + hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11; + hs_iso_sink_desc.bInterval = isoc_interval; + hs_iso_sink_desc.bEndpointAddress = + fs_iso_sink_desc.bEndpointAddress; + f->hs_descriptors = hs_source_sink_descs; } @@ -228,13 +419,39 @@ autoconf_fail: fs_source_desc.bEndpointAddress; ss_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress; + + /* + * Fill in the SS isoc descriptors from the module parameters. + * We assume that the user knows what they are doing and won't + * give parameters that their UDC doesn't support. + */ + ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket; + ss_iso_source_desc.bInterval = isoc_interval; + ss_iso_source_comp_desc.bmAttributes = isoc_mult; + ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst; + ss_iso_source_comp_desc.wBytesPerInterval = + isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); + ss_iso_source_desc.bEndpointAddress = + fs_iso_source_desc.bEndpointAddress; + + ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket; + ss_iso_sink_desc.bInterval = isoc_interval; + ss_iso_sink_comp_desc.bmAttributes = isoc_mult; + ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst; + ss_iso_sink_comp_desc.wBytesPerInterval = + isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1); + ss_iso_sink_desc.bEndpointAddress = + fs_iso_sink_desc.bEndpointAddress; + f->ss_descriptors = ss_source_sink_descs; } - DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n", + DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n", (gadget_is_superspeed(c->cdev->gadget) ? "super" : (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")), - f->name, ss->in_ep->name, ss->out_ep->name); + f->name, ss->in_ep->name, ss->out_ep->name, + ss->iso_in_ep ? ss->iso_in_ep->name : "<none>", + ss->iso_out_ep ? ss->iso_out_ep->name : "<none>"); return 0; } @@ -251,6 +468,9 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req) u8 *buf = req->buf; struct usb_composite_dev *cdev = ss->function.config->cdev; + if (pattern == 2) + return 0; + for (i = 0; i < req->actual; i++, buf++) { switch (pattern) { @@ -265,7 +485,7 @@ static int check_read_data(struct f_sourcesink *ss, struct usb_request *req) * each usb transfer request should be. Resync is done * with set_interface or set_config. (We *WANT* it to * get quickly out of sync if controllers or their drivers - * stutter for any reason, including buffer duplcation...) + * stutter for any reason, including buffer duplication...) */ case 1: if (*buf == (u8)(i % 63)) @@ -292,21 +512,30 @@ static void reinit_write_data(struct usb_ep *ep, struct usb_request *req) for (i = 0; i < req->length; i++) *buf++ = (u8) (i % 63); break; + case 2: + break; } } static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) { - struct f_sourcesink *ss = ep->driver_data; - struct usb_composite_dev *cdev = ss->function.config->cdev; - int status = req->status; + struct usb_composite_dev *cdev; + struct f_sourcesink *ss = ep->driver_data; + int status = req->status; + + /* driver_data will be null if ep has been disabled */ + if (!ss) + return; + + cdev = ss->function.config->cdev; switch (status) { case 0: /* normal completion? */ if (ep == ss->out_ep) { check_read_data(ss, req); - memset(req->buf, 0x55, req->length); + if (pattern != 2) + memset(req->buf, 0x55, req->length); } else reinit_write_data(ep, req); break; @@ -344,32 +573,57 @@ static void source_sink_complete(struct usb_ep *ep, struct usb_request *req) } } -static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in) +static int source_sink_start_ep(struct f_sourcesink *ss, bool is_in, + bool is_iso, int speed) { struct usb_ep *ep; struct usb_request *req; - int status; + int i, size, status; + + for (i = 0; i < 8; i++) { + if (is_iso) { + switch (speed) { + case USB_SPEED_SUPER: + size = isoc_maxpacket * (isoc_mult + 1) * + (isoc_maxburst + 1); + break; + case USB_SPEED_HIGH: + size = isoc_maxpacket * (isoc_mult + 1); + break; + default: + size = isoc_maxpacket > 1023 ? + 1023 : isoc_maxpacket; + break; + } + ep = is_in ? ss->iso_in_ep : ss->iso_out_ep; + req = alloc_ep_req(ep, size); + } else { + ep = is_in ? ss->in_ep : ss->out_ep; + req = alloc_ep_req(ep, 0); + } - ep = is_in ? ss->in_ep : ss->out_ep; - req = alloc_ep_req(ep); - if (!req) - return -ENOMEM; + if (!req) + return -ENOMEM; - req->complete = source_sink_complete; - if (is_in) - reinit_write_data(ep, req); - else - memset(req->buf, 0x55, req->length); + req->complete = source_sink_complete; + if (is_in) + reinit_write_data(ep, req); + else if (pattern != 2) + memset(req->buf, 0x55, req->length); - status = usb_ep_queue(ep, req, GFP_ATOMIC); - if (status) { - struct usb_composite_dev *cdev; + status = usb_ep_queue(ep, req, GFP_ATOMIC); + if (status) { + struct usb_composite_dev *cdev; - cdev = ss->function.config->cdev; - ERROR(cdev, "start %s %s --> %d\n", - is_in ? "IN" : "OUT", - ep->name, status); - free_ep_req(ep, req); + cdev = ss->function.config->cdev; + ERROR(cdev, "start %s%s %s --> %d\n", + is_iso ? "ISO-" : "", is_in ? "IN" : "OUT", + ep->name, status); + free_ep_req(ep, req); + } + + if (!is_iso) + break; } return status; @@ -380,17 +634,20 @@ static void disable_source_sink(struct f_sourcesink *ss) struct usb_composite_dev *cdev; cdev = ss->function.config->cdev; - disable_endpoints(cdev, ss->in_ep, ss->out_ep); + disable_endpoints(cdev, ss->in_ep, ss->out_ep, ss->iso_in_ep, + ss->iso_out_ep); VDBG(cdev, "%s disabled\n", ss->function.name); } static int -enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) +enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss, + int alt) { int result = 0; + int speed = cdev->gadget->speed; struct usb_ep *ep; - /* one endpoint writes (sources) zeroes IN (to the host) */ + /* one bulk endpoint writes (sources) zeroes IN (to the host) */ ep = ss->in_ep; result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); if (result) @@ -400,7 +657,7 @@ enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss) return result; ep->driver_data = ss; - result = source_sink_start_ep(ss, true); + result = source_sink_start_ep(ss, true, false, speed); if (result < 0) { fail: ep = ss->in_ep; @@ -409,7 +666,7 @@ fail: return result; } - /* one endpoint reads (sinks) anything OUT (from the host) */ + /* one bulk endpoint reads (sinks) anything OUT (from the host) */ ep = ss->out_ep; result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); if (result) @@ -419,27 +676,82 @@ fail: goto fail; ep->driver_data = ss; - result = source_sink_start_ep(ss, false); + result = source_sink_start_ep(ss, false, false, speed); if (result < 0) { +fail2: + ep = ss->out_ep; usb_ep_disable(ep); ep->driver_data = NULL; goto fail; } - DBG(cdev, "%s enabled\n", ss->function.name); + if (alt == 0) + goto out; + + /* one iso endpoint writes (sources) zeroes IN (to the host) */ + ep = ss->iso_in_ep; + if (ep) { + result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); + if (result) + goto fail2; + result = usb_ep_enable(ep); + if (result < 0) + goto fail2; + ep->driver_data = ss; + + result = source_sink_start_ep(ss, true, true, speed); + if (result < 0) { +fail3: + ep = ss->iso_in_ep; + if (ep) { + usb_ep_disable(ep); + ep->driver_data = NULL; + } + goto fail2; + } + } + + /* one iso endpoint reads (sinks) anything OUT (from the host) */ + ep = ss->iso_out_ep; + if (ep) { + result = config_ep_by_speed(cdev->gadget, &(ss->function), ep); + if (result) + goto fail3; + result = usb_ep_enable(ep); + if (result < 0) + goto fail3; + ep->driver_data = ss; + + result = source_sink_start_ep(ss, false, true, speed); + if (result < 0) { + usb_ep_disable(ep); + ep->driver_data = NULL; + goto fail3; + } + } +out: + ss->cur_alt = alt; + + DBG(cdev, "%s enabled, alt intf %d\n", ss->function.name, alt); return result; } static int sourcesink_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { - struct f_sourcesink *ss = func_to_ss(f); - struct usb_composite_dev *cdev = f->config->cdev; + struct f_sourcesink *ss = func_to_ss(f); + struct usb_composite_dev *cdev = f->config->cdev; - /* we know alt is zero */ if (ss->in_ep->driver_data) disable_source_sink(ss); - return enable_source_sink(cdev, ss); + return enable_source_sink(cdev, ss, alt); +} + +static int sourcesink_get_alt(struct usb_function *f, unsigned intf) +{ + struct f_sourcesink *ss = func_to_ss(f); + + return ss->cur_alt; } static void sourcesink_disable(struct usb_function *f) @@ -465,6 +777,7 @@ static int __init sourcesink_bind_config(struct usb_configuration *c) ss->function.bind = sourcesink_bind; ss->function.unbind = sourcesink_unbind; ss->function.set_alt = sourcesink_set_alt; + ss->function.get_alt = sourcesink_get_alt; ss->function.disable = sourcesink_disable; status = usb_add_function(c, &ss->function); @@ -536,7 +849,7 @@ unknown: req->length = value; value = usb_ep_queue(c->cdev->gadget->ep0, req, GFP_ATOMIC); if (value < 0) - ERROR(c->cdev, "source/sinkc response, err %d\n", + ERROR(c->cdev, "source/sink response, err %d\n", value); } @@ -545,12 +858,12 @@ unknown: } static struct usb_configuration sourcesink_driver = { - .label = "source/sink", - .strings = sourcesink_strings, - .setup = sourcesink_setup, - .bConfigurationValue = 3, - .bmAttributes = USB_CONFIG_ATT_SELFPOWER, - /* .iConfiguration = DYNAMIC */ + .label = "source/sink", + .strings = sourcesink_strings, + .setup = sourcesink_setup, + .bConfigurationValue = 3, + .bmAttributes = USB_CONFIG_ATT_SELFPOWER, + /* .iConfiguration = DYNAMIC */ }; /** @@ -567,7 +880,8 @@ int __init sourcesink_add(struct usb_composite_dev *cdev, bool autoresume) return id; strings_sourcesink[0].id = id; - source_sink_intf.iInterface = id; + source_sink_intf_alt0.iInterface = id; + source_sink_intf_alt1.iInterface = id; sourcesink_driver.iConfiguration = id; /* support autoresume for remote wakeup testing */ diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c index 877a2c46672b..51881f3bd07a 100644 --- a/drivers/usb/gadget/fsl_qe_udc.c +++ b/drivers/usb/gadget/fsl_qe_udc.c @@ -71,9 +71,6 @@ static struct usb_endpoint_descriptor qe_ep0_desc = { .wMaxPacketSize = USB_MAX_CTRL_PAYLOAD, }; -/* it is initialized in probe() */ -static struct qe_udc *udc_controller; - /******************************************************************** * Internal Used Function Start ********************************************************************/ @@ -188,8 +185,8 @@ static int qe_ep0_stall(struct qe_udc *udc) { qe_eptx_stall_change(&udc->eps[0], 1); qe_eprx_stall_change(&udc->eps[0], 1); - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; return 0; } @@ -450,13 +447,13 @@ static int qe_ep_rxbd_update(struct qe_ep *ep) ep->rxbuf_d = virt_to_phys((void *)ep->rxbuffer); if (ep->rxbuf_d == DMA_ADDR_INVALID) { - ep->rxbuf_d = dma_map_single(udc_controller->gadget.dev.parent, + ep->rxbuf_d = dma_map_single(ep->udc->gadget.dev.parent, ep->rxbuffer, size, DMA_FROM_DEVICE); ep->rxbufmap = 1; } else { - dma_sync_single_for_device(udc_controller->gadget.dev.parent, + dma_sync_single_for_device(ep->udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); ep->rxbufmap = 0; @@ -489,10 +486,10 @@ static int qe_ep_register_init(struct qe_udc *udc, unsigned char pipe_num) epparam = udc->ep_param[pipe_num]; usep = 0; - logepnum = (ep->desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); + logepnum = (ep->ep.desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); usep |= (logepnum << USB_EPNUM_SHIFT); - switch (ep->desc->bmAttributes & 0x03) { + switch (ep->ep.desc->bmAttributes & 0x03) { case USB_ENDPOINT_XFER_BULK: usep |= USB_TRANS_BULK; break; @@ -644,7 +641,7 @@ static int qe_ep_init(struct qe_udc *udc, /* initialize ep structure */ ep->ep.maxpacket = max; ep->tm = (u8)(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK); - ep->desc = desc; + ep->ep.desc = desc; ep->stopped = 0; ep->init = 1; @@ -698,14 +695,14 @@ en_done: return -ENODEV; } -static inline void qe_usb_enable(void) +static inline void qe_usb_enable(struct qe_udc *udc) { - setbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN); + setbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN); } -static inline void qe_usb_disable(void) +static inline void qe_usb_disable(struct qe_udc *udc) { - clrbits8(&udc_controller->usb_regs->usb_usmod, USB_MODE_EN); + clrbits8(&udc->usb_regs->usb_usmod, USB_MODE_EN); } /*----------------------------------------------------------------------------* @@ -1599,7 +1596,7 @@ static int qe_ep_enable(struct usb_ep *_ep, ep = container_of(_ep, struct qe_ep, ep); /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc || _ep->name == ep_name[0] || + if (!_ep || !desc || ep->ep.desc || _ep->name == ep_name[0] || (desc->bDescriptorType != USB_DT_ENDPOINT)) return -EINVAL; @@ -1629,7 +1626,7 @@ static int qe_ep_disable(struct usb_ep *_ep) ep = container_of(_ep, struct qe_ep, ep); udc = ep->udc; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { dev_dbg(udc->dev, "%s not enabled\n", _ep ? ep->ep.name : NULL); return -EINVAL; } @@ -1637,7 +1634,6 @@ static int qe_ep_disable(struct usb_ep *_ep) spin_lock_irqsave(&udc->lock, flags); /* Nuke all pending requests (does flush) */ nuke(ep, -ESHUTDOWN); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; ep->tx_req = NULL; @@ -1656,13 +1652,13 @@ static int qe_ep_disable(struct usb_ep *_ep) if (ep->dir != USB_DIR_IN) { kfree(ep->rxframe); if (ep->rxbufmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, + dma_unmap_single(udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); ep->rxbuf_d = DMA_ADDR_INVALID; } else { dma_sync_single_for_cpu( - udc_controller->gadget.dev.parent, + udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); } @@ -1715,7 +1711,7 @@ static int __qe_ep_queue(struct usb_ep *_ep, struct usb_request *_req) dev_dbg(udc->dev, "bad params\n"); return -EINVAL; } - if (!_ep || (!ep->desc && ep_index(ep))) { + if (!_ep || (!ep->ep.desc && ep_index(ep))) { dev_dbg(udc->dev, "bad ep\n"); return -EINVAL; } @@ -1826,7 +1822,7 @@ static int qe_ep_set_halt(struct usb_ep *_ep, int value) struct qe_udc *udc; ep = container_of(_ep, struct qe_ep, ep); - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { status = -EINVAL; goto out; } @@ -1880,9 +1876,10 @@ static struct usb_ep_ops qe_ep_ops = { /* Get the current frame number */ static int qe_get_frame(struct usb_gadget *gadget) { + struct qe_udc *udc = container_of(gadget, struct qe_udc, gadget); u16 tmp; - tmp = in_be16(&udc_controller->usb_param->frame_n); + tmp = in_be16(&udc->usb_param->frame_n); if (tmp & 0x8000) tmp = tmp & 0x07ff; else @@ -1891,57 +1888,16 @@ static int qe_get_frame(struct usb_gadget *gadget) return (int)tmp; } -/* Tries to wake up the host connected to this gadget - * - * Return : 0-success - * Negative-this feature not enabled by host or not supported by device hw - */ -static int qe_wakeup(struct usb_gadget *gadget) -{ - return -ENOTSUPP; -} - -/* Notify controller that VBUS is powered, Called by whatever - detects VBUS sessions */ -static int qe_vbus_session(struct usb_gadget *gadget, int is_active) -{ - return -ENOTSUPP; -} - -/* constrain controller's VBUS power usage - * This call is used by gadget drivers during SET_CONFIGURATION calls, - * reporting how much power the device may consume. For example, this - * could affect how quickly batteries are recharged. - * - * Returns zero on success, else negative errno. - */ -static int qe_vbus_draw(struct usb_gadget *gadget, unsigned mA) -{ - return -ENOTSUPP; -} - -/* Change Data+ pullup status - * this func is used by usb_gadget_connect/disconnect - */ -static int qe_pullup(struct usb_gadget *gadget, int is_on) -{ - return -ENOTSUPP; -} - -static int fsl_qe_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int fsl_qe_stop(struct usb_gadget_driver *driver); +static int fsl_qe_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int fsl_qe_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); /* defined in usb_gadget.h */ static struct usb_gadget_ops qe_gadget_ops = { .get_frame = qe_get_frame, - .wakeup = qe_wakeup, -/* .set_selfpowered = qe_set_selfpowered,*/ /* always selfpowered */ - .vbus_session = qe_vbus_session, - .vbus_draw = qe_vbus_draw, - .pullup = qe_pullup, - .start = fsl_qe_start, - .stop = fsl_qe_stop, + .udc_start = fsl_qe_start, + .udc_stop = fsl_qe_stop, }; /*------------------------------------------------------------------------- @@ -2015,7 +1971,7 @@ static void ch9getstatus(struct qe_udc *udc, u8 request_type, u16 value, u16 usep; /* stall if endpoint doesn't exist */ - if (!target_ep->desc) + if (!target_ep->ep.desc) goto stall; usep = in_be16(&udc->usb_regs->usb_usep[pipe]); @@ -2190,7 +2146,7 @@ static int reset_irq(struct qe_udc *udc) if (udc->usb_state == USB_STATE_DEFAULT) return 0; - qe_usb_disable(); + qe_usb_disable(udc); out_8(&udc->usb_regs->usb_usadr, 0); for (i = 0; i < USB_MAX_ENDPOINTS; i++) { @@ -2202,7 +2158,7 @@ static int reset_irq(struct qe_udc *udc) udc->usb_state = USB_STATE_DEFAULT; udc->ep0_state = WAIT_FOR_SETUP; udc->ep0_dir = USB_DIR_OUT; - qe_usb_enable(); + qe_usb_enable(udc); return 0; } @@ -2327,92 +2283,65 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc) /*------------------------------------------------------------------------- Gadget driver probe and unregister. --------------------------------------------------------------------------*/ -static int fsl_qe_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int fsl_qe_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - int retval; - unsigned long flags = 0; - - /* standard operations */ - if (!udc_controller) - return -ENODEV; - - if (!driver || driver->max_speed < USB_SPEED_FULL - || !bind || !driver->disconnect || !driver->setup) - return -EINVAL; - - if (udc_controller->driver) - return -EBUSY; + struct qe_udc *udc; + unsigned long flags; + udc = container_of(gadget, struct qe_udc, gadget); /* lock is needed but whether should use this lock or another */ - spin_lock_irqsave(&udc_controller->lock, flags); + spin_lock_irqsave(&udc->lock, flags); driver->driver.bus = NULL; /* hook up the driver */ - udc_controller->driver = driver; - udc_controller->gadget.dev.driver = &driver->driver; - udc_controller->gadget.speed = driver->max_speed; - spin_unlock_irqrestore(&udc_controller->lock, flags); - - retval = bind(&udc_controller->gadget); - if (retval) { - dev_err(udc_controller->dev, "bind to %s --> %d", - driver->driver.name, retval); - udc_controller->gadget.dev.driver = NULL; - udc_controller->driver = NULL; - return retval; - } + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + udc->gadget.speed = driver->max_speed; /* Enable IRQ reg and Set usbcmd reg EN bit */ - qe_usb_enable(); - - out_be16(&udc_controller->usb_regs->usb_usber, 0xffff); - out_be16(&udc_controller->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE); - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = USB_DIR_OUT; - dev_info(udc_controller->dev, "%s bind to driver %s \n", - udc_controller->gadget.name, driver->driver.name); + qe_usb_enable(udc); + + out_be16(&udc->usb_regs->usb_usber, 0xffff); + out_be16(&udc->usb_regs->usb_usbmr, USB_E_DEFAULT_DEVICE); + udc->usb_state = USB_STATE_ATTACHED; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = USB_DIR_OUT; + spin_unlock_irqrestore(&udc->lock, flags); + + dev_info(udc->dev, "%s bind to driver %s\n", udc->gadget.name, + driver->driver.name); return 0; } -static int fsl_qe_stop(struct usb_gadget_driver *driver) +static int fsl_qe_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { + struct qe_udc *udc; struct qe_ep *loop_ep; unsigned long flags; - if (!udc_controller) - return -ENODEV; - - if (!driver || driver != udc_controller->driver) - return -EINVAL; - + udc = container_of(gadget, struct qe_udc, gadget); /* stop usb controller, disable intr */ - qe_usb_disable(); + qe_usb_disable(udc); /* in fact, no needed */ - udc_controller->usb_state = USB_STATE_ATTACHED; - udc_controller->ep0_state = WAIT_FOR_SETUP; - udc_controller->ep0_dir = 0; + udc->usb_state = USB_STATE_ATTACHED; + udc->ep0_state = WAIT_FOR_SETUP; + udc->ep0_dir = 0; /* stand operation */ - spin_lock_irqsave(&udc_controller->lock, flags); - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; - nuke(&udc_controller->eps[0], -ESHUTDOWN); - list_for_each_entry(loop_ep, &udc_controller->gadget.ep_list, - ep.ep_list) + spin_lock_irqsave(&udc->lock, flags); + udc->gadget.speed = USB_SPEED_UNKNOWN; + nuke(&udc->eps[0], -ESHUTDOWN); + list_for_each_entry(loop_ep, &udc->gadget.ep_list, ep.ep_list) nuke(loop_ep, -ESHUTDOWN); - spin_unlock_irqrestore(&udc_controller->lock, flags); - - /* report disconnect; the controller is already quiesced */ - driver->disconnect(&udc_controller->gadget); + spin_unlock_irqrestore(&udc->lock, flags); - /* unbind gadget and unhook driver. */ - driver->unbind(&udc_controller->gadget); - udc_controller->gadget.dev.driver = NULL; - udc_controller->driver = NULL; + udc->gadget.dev.driver = NULL; + udc->driver = NULL; - dev_info(udc_controller->dev, "unregistered gadget driver '%s'\r\n", + dev_info(udc->dev, "unregistered gadget driver '%s'\r\n", driver->driver.name); return 0; } @@ -2502,7 +2431,7 @@ static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) ep->ep.ops = &qe_ep_ops; ep->stopped = 1; ep->ep.maxpacket = (unsigned short) ~0; - ep->desc = NULL; + ep->ep.desc = NULL; ep->dir = 0xff; ep->epnum = (u8)pipe_num; ep->sent = 0; @@ -2531,21 +2460,22 @@ static int __devinit qe_ep_config(struct qe_udc *udc, unsigned char pipe_num) *----------------------------------------------------------------------*/ static void qe_udc_release(struct device *dev) { - int i = 0; + struct qe_udc *udc = container_of(dev, struct qe_udc, gadget.dev); + int i; - complete(udc_controller->done); - cpm_muram_free(cpm_muram_offset(udc_controller->ep_param[0])); + complete(udc->done); + cpm_muram_free(cpm_muram_offset(udc->ep_param[0])); for (i = 0; i < USB_MAX_ENDPOINTS; i++) - udc_controller->ep_param[i] = NULL; + udc->ep_param[i] = NULL; - kfree(udc_controller); - udc_controller = NULL; + kfree(udc); } /* Driver probe functions */ static const struct of_device_id qe_udc_match[]; static int __devinit qe_udc_probe(struct platform_device *ofdev) { + struct qe_udc *udc; const struct of_device_id *match; struct device_node *np = ofdev->dev.of_node; struct qe_ep *ep; @@ -2562,44 +2492,44 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev) return -ENODEV; /* Initialize the udc structure including QH member and other member */ - udc_controller = qe_udc_config(ofdev); - if (!udc_controller) { + udc = qe_udc_config(ofdev); + if (!udc) { dev_err(&ofdev->dev, "failed to initialize\n"); return -ENOMEM; } - udc_controller->soc_type = (unsigned long)match->data; - udc_controller->usb_regs = of_iomap(np, 0); - if (!udc_controller->usb_regs) { + udc->soc_type = (unsigned long)match->data; + udc->usb_regs = of_iomap(np, 0); + if (!udc->usb_regs) { ret = -ENOMEM; goto err1; } /* initialize usb hw reg except for regs for EP, * leave usbintr reg untouched*/ - qe_udc_reg_init(udc_controller); + qe_udc_reg_init(udc); /* here comes the stand operations for probe * set the qe_udc->gadget.xxx */ - udc_controller->gadget.ops = &qe_gadget_ops; + udc->gadget.ops = &qe_gadget_ops; /* gadget.ep0 is a pointer */ - udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; + udc->gadget.ep0 = &udc->eps[0].ep; - INIT_LIST_HEAD(&udc_controller->gadget.ep_list); + INIT_LIST_HEAD(&udc->gadget.ep_list); /* modify in register gadget process */ - udc_controller->gadget.speed = USB_SPEED_UNKNOWN; + udc->gadget.speed = USB_SPEED_UNKNOWN; /* name: Identifies the controller hardware type. */ - udc_controller->gadget.name = driver_name; + udc->gadget.name = driver_name; - device_initialize(&udc_controller->gadget.dev); + device_initialize(&udc->gadget.dev); - dev_set_name(&udc_controller->gadget.dev, "gadget"); + dev_set_name(&udc->gadget.dev, "gadget"); - udc_controller->gadget.dev.release = qe_udc_release; - udc_controller->gadget.dev.parent = &ofdev->dev; + udc->gadget.dev.release = qe_udc_release; + udc->gadget.dev.parent = &ofdev->dev; /* initialize qe_ep struct */ for (i = 0; i < USB_MAX_ENDPOINTS ; i++) { @@ -2608,104 +2538,104 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev) /* setup the qe_ep struct and link ep.ep.list * into gadget.ep_list */ - qe_ep_config(udc_controller, (unsigned char)i); + qe_ep_config(udc, (unsigned char)i); } /* ep0 initialization in here */ - ret = qe_ep_init(udc_controller, 0, &qe_ep0_desc); + ret = qe_ep_init(udc, 0, &qe_ep0_desc); if (ret) goto err2; /* create a buf for ZLP send, need to remain zeroed */ - udc_controller->nullbuf = kzalloc(256, GFP_KERNEL); - if (udc_controller->nullbuf == NULL) { - dev_err(udc_controller->dev, "cannot alloc nullbuf\n"); + udc->nullbuf = kzalloc(256, GFP_KERNEL); + if (udc->nullbuf == NULL) { + dev_err(udc->dev, "cannot alloc nullbuf\n"); ret = -ENOMEM; goto err3; } /* buffer for data of get_status request */ - udc_controller->statusbuf = kzalloc(2, GFP_KERNEL); - if (udc_controller->statusbuf == NULL) { + udc->statusbuf = kzalloc(2, GFP_KERNEL); + if (udc->statusbuf == NULL) { ret = -ENOMEM; goto err4; } - udc_controller->nullp = virt_to_phys((void *)udc_controller->nullbuf); - if (udc_controller->nullp == DMA_ADDR_INVALID) { - udc_controller->nullp = dma_map_single( - udc_controller->gadget.dev.parent, - udc_controller->nullbuf, + udc->nullp = virt_to_phys((void *)udc->nullbuf); + if (udc->nullp == DMA_ADDR_INVALID) { + udc->nullp = dma_map_single( + udc->gadget.dev.parent, + udc->nullbuf, 256, DMA_TO_DEVICE); - udc_controller->nullmap = 1; + udc->nullmap = 1; } else { - dma_sync_single_for_device(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + dma_sync_single_for_device(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); } - tasklet_init(&udc_controller->rx_tasklet, ep_rx_tasklet, - (unsigned long)udc_controller); + tasklet_init(&udc->rx_tasklet, ep_rx_tasklet, + (unsigned long)udc); /* request irq and disable DR */ - udc_controller->usb_irq = irq_of_parse_and_map(np, 0); - if (!udc_controller->usb_irq) { + udc->usb_irq = irq_of_parse_and_map(np, 0); + if (!udc->usb_irq) { ret = -EINVAL; goto err_noirq; } - ret = request_irq(udc_controller->usb_irq, qe_udc_irq, 0, - driver_name, udc_controller); + ret = request_irq(udc->usb_irq, qe_udc_irq, 0, + driver_name, udc); if (ret) { - dev_err(udc_controller->dev, "cannot request irq %d err %d \n", - udc_controller->usb_irq, ret); + dev_err(udc->dev, "cannot request irq %d err %d\n", + udc->usb_irq, ret); goto err5; } - ret = device_add(&udc_controller->gadget.dev); + ret = device_add(&udc->gadget.dev); if (ret) goto err6; - ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget); + ret = usb_add_gadget_udc(&ofdev->dev, &udc->gadget); if (ret) goto err7; - dev_info(udc_controller->dev, + dev_set_drvdata(&ofdev->dev, udc); + dev_info(udc->dev, "%s USB controller initialized as device\n", - (udc_controller->soc_type == PORT_QE) ? "QE" : "CPM"); + (udc->soc_type == PORT_QE) ? "QE" : "CPM"); return 0; err7: - device_unregister(&udc_controller->gadget.dev); + device_unregister(&udc->gadget.dev); err6: - free_irq(udc_controller->usb_irq, udc_controller); + free_irq(udc->usb_irq, udc); err5: - irq_dispose_mapping(udc_controller->usb_irq); + irq_dispose_mapping(udc->usb_irq); err_noirq: - if (udc_controller->nullmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + if (udc->nullmap) { + dma_unmap_single(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); - udc_controller->nullp = DMA_ADDR_INVALID; + udc->nullp = DMA_ADDR_INVALID; } else { - dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + dma_sync_single_for_cpu(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); } - kfree(udc_controller->statusbuf); + kfree(udc->statusbuf); err4: - kfree(udc_controller->nullbuf); + kfree(udc->nullbuf); err3: - ep = &udc_controller->eps[0]; + ep = &udc->eps[0]; cpm_muram_free(cpm_muram_offset(ep->rxbase)); kfree(ep->rxframe); kfree(ep->rxbuffer); kfree(ep->txframe); err2: - iounmap(udc_controller->usb_regs); + iounmap(udc->usb_regs); err1: - kfree(udc_controller); - udc_controller = NULL; + kfree(udc); return ret; } @@ -2723,44 +2653,41 @@ static int qe_udc_resume(struct platform_device *dev) static int __devexit qe_udc_remove(struct platform_device *ofdev) { + struct qe_udc *udc = dev_get_drvdata(&ofdev->dev); struct qe_ep *ep; unsigned int size; - DECLARE_COMPLETION(done); - if (!udc_controller) - return -ENODEV; - - usb_del_gadget_udc(&udc_controller->gadget); + usb_del_gadget_udc(&udc->gadget); - udc_controller->done = &done; - tasklet_disable(&udc_controller->rx_tasklet); + udc->done = &done; + tasklet_disable(&udc->rx_tasklet); - if (udc_controller->nullmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + if (udc->nullmap) { + dma_unmap_single(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); - udc_controller->nullp = DMA_ADDR_INVALID; + udc->nullp = DMA_ADDR_INVALID; } else { - dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, - udc_controller->nullp, 256, + dma_sync_single_for_cpu(udc->gadget.dev.parent, + udc->nullp, 256, DMA_TO_DEVICE); } - kfree(udc_controller->statusbuf); - kfree(udc_controller->nullbuf); + kfree(udc->statusbuf); + kfree(udc->nullbuf); - ep = &udc_controller->eps[0]; + ep = &udc->eps[0]; cpm_muram_free(cpm_muram_offset(ep->rxbase)); size = (ep->ep.maxpacket + USB_CRC_SIZE + 2) * (USB_BDRING_LEN + 1); kfree(ep->rxframe); if (ep->rxbufmap) { - dma_unmap_single(udc_controller->gadget.dev.parent, + dma_unmap_single(udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); ep->rxbuf_d = DMA_ADDR_INVALID; } else { - dma_sync_single_for_cpu(udc_controller->gadget.dev.parent, + dma_sync_single_for_cpu(udc->gadget.dev.parent, ep->rxbuf_d, size, DMA_FROM_DEVICE); } @@ -2768,14 +2695,14 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev) kfree(ep->rxbuffer); kfree(ep->txframe); - free_irq(udc_controller->usb_irq, udc_controller); - irq_dispose_mapping(udc_controller->usb_irq); + free_irq(udc->usb_irq, udc); + irq_dispose_mapping(udc->usb_irq); - tasklet_kill(&udc_controller->rx_tasklet); + tasklet_kill(&udc->rx_tasklet); - iounmap(udc_controller->usb_regs); + iounmap(udc->usb_regs); - device_unregister(&udc_controller->gadget.dev); + device_unregister(&udc->gadget.dev); /* wait for release() of gadget.dev to free udc */ wait_for_completion(&done); diff --git a/drivers/usb/gadget/fsl_qe_udc.h b/drivers/usb/gadget/fsl_qe_udc.h index 1da5fb03d218..4c07ca9cebf3 100644 --- a/drivers/usb/gadget/fsl_qe_udc.h +++ b/drivers/usb/gadget/fsl_qe_udc.h @@ -266,7 +266,6 @@ struct qe_ep { struct usb_ep ep; struct list_head queue; struct qe_udc *udc; - const struct usb_endpoint_descriptor *desc; struct usb_gadget *gadget; u8 state; diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c index 55abfb6bd612..28316858208b 100644 --- a/drivers/usb/gadget/fsl_udc_core.c +++ b/drivers/usb/gadget/fsl_udc_core.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004-2007,2011 Freescale Semiconductor, Inc. + * Copyright (C) 2004-2007,2011-2012 Freescale Semiconductor, Inc. * All rights reserved. * * Author: Li Yang <leoli@freescale.com> @@ -58,9 +58,8 @@ static const char driver_name[] = "fsl-usb2-udc"; static const char driver_desc[] = DRIVER_DESC; static struct usb_dr_device *dr_regs; -#ifndef CONFIG_ARCH_MXC + static struct usb_sys_interface *usb_sys_regs; -#endif /* it is initialized in probe() */ static struct fsl_udc *udc_controller = NULL; @@ -244,10 +243,9 @@ static int dr_controller_setup(struct fsl_udc *udc) { unsigned int tmp, portctrl, ep_num; unsigned int max_no_of_ep; -#ifndef CONFIG_ARCH_MXC unsigned int ctrl; -#endif unsigned long timeout; + #define FSL_UDC_RESET_TIMEOUT 1000 /* Config PHY interface */ @@ -255,12 +253,32 @@ static int dr_controller_setup(struct fsl_udc *udc) portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH); switch (udc->phy_mode) { case FSL_USB2_PHY_ULPI: + if (udc->pdata->have_sysif_regs) { + if (udc->pdata->controller_ver) { + /* controller version 1.6 or above */ + ctrl = __raw_readl(&usb_sys_regs->control); + ctrl &= ~USB_CTRL_UTMI_PHY_EN; + ctrl |= USB_CTRL_USB_EN; + __raw_writel(ctrl, &usb_sys_regs->control); + } + } portctrl |= PORTSCX_PTS_ULPI; break; case FSL_USB2_PHY_UTMI_WIDE: portctrl |= PORTSCX_PTW_16BIT; /* fall through */ case FSL_USB2_PHY_UTMI: + if (udc->pdata->have_sysif_regs) { + if (udc->pdata->controller_ver) { + /* controller version 1.6 or above */ + ctrl = __raw_readl(&usb_sys_regs->control); + ctrl |= (USB_CTRL_UTMI_PHY_EN | + USB_CTRL_USB_EN); + __raw_writel(ctrl, &usb_sys_regs->control); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI + PHY CLK to become stable - 10ms*/ + } + } portctrl |= PORTSCX_PTS_UTMI; break; case FSL_USB2_PHY_SERIAL: @@ -549,7 +567,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, ep = container_of(_ep, struct fsl_ep, ep); /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || (desc->bDescriptorType != USB_DT_ENDPOINT)) return -EINVAL; @@ -590,7 +608,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, spin_lock_irqsave(&udc->lock, flags); ep->ep.maxpacket = max; - ep->desc = desc; + ep->ep.desc = desc; ep->stopped = 0; /* Controller related setup */ @@ -614,7 +632,7 @@ static int fsl_ep_enable(struct usb_ep *_ep, retval = 0; VDBG("enabled %s (ep%d%s) maxpacket %d",ep->ep.name, - ep->desc->bEndpointAddress & 0x0f, + ep->ep.desc->bEndpointAddress & 0x0f, (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", max); en_done: @@ -634,7 +652,7 @@ static int fsl_ep_disable(struct usb_ep *_ep) int ep_num; ep = container_of(_ep, struct fsl_ep, ep); - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { VDBG("%s not enabled", _ep ? ep->ep.name : NULL); return -EINVAL; } @@ -657,7 +675,6 @@ static int fsl_ep_disable(struct usb_ep *_ep) /* nuke all pending requests (does flush) */ nuke(ep, -ESHUTDOWN); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; spin_unlock_irqrestore(&udc->lock, flags); @@ -736,6 +753,8 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req) lastreq = list_entry(ep->queue.prev, struct fsl_req, queue); lastreq->tail->next_td_ptr = cpu_to_hc32(req->head->td_dma & DTD_ADDR_MASK); + /* Ensure dTD's next dtd pointer to be updated */ + wmb(); /* Read prime bit, if 1 goto done */ if (fsl_readl(&dr_regs->endpointprime) & bitmask) return; @@ -874,11 +893,11 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) VDBG("%s, bad params", __func__); return -EINVAL; } - if (unlikely(!_ep || !ep->desc)) { + if (unlikely(!_ep || !ep->ep.desc)) { VDBG("%s, bad ep", __func__); return -EINVAL; } - if (usb_endpoint_xfer_isoc(ep->desc)) { + if (usb_endpoint_xfer_isoc(ep->ep.desc)) { if (req->req.length > ep->ep.maxpacket) return -EMSGSIZE; } @@ -1017,12 +1036,12 @@ static int fsl_ep_set_halt(struct usb_ep *_ep, int value) ep = container_of(_ep, struct fsl_ep, ep); udc = ep->udc; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { status = -EINVAL; goto out; } - if (usb_endpoint_xfer_isoc(ep->desc)) { + if (usb_endpoint_xfer_isoc(ep->ep.desc)) { status = -EOPNOTSUPP; goto out; } @@ -1061,7 +1080,7 @@ static int fsl_ep_fifo_status(struct usb_ep *_ep) struct ep_queue_head *qh; ep = container_of(_ep, struct fsl_ep, ep); - if (!_ep || (!ep->desc && ep_index(ep) != 0)) + if (!_ep || (!ep->ep.desc && ep_index(ep) != 0)) return -ENODEV; udc = (struct fsl_udc *)ep->udc; @@ -1094,7 +1113,7 @@ static void fsl_ep_fifo_flush(struct usb_ep *_ep) return; } else { ep = container_of(_ep, struct fsl_ep, ep); - if (!ep->desc) + if (!ep->ep.desc) return; } ep_num = ep_index(ep); @@ -1349,7 +1368,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value, target_ep = get_ep_by_pipe(udc, get_pipe_by_windex(index)); /* stall if endpoint doesn't exist */ - if (!target_ep->desc) + if (!target_ep->ep.desc) goto stall; tmp = dr_ep_get_stall(ep_index(target_ep), ep_is_in(target_ep)) << USB_ENDPOINT_HALT; @@ -2259,7 +2278,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count, } /* other gadget->eplist ep */ list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) { + if (ep->ep.desc) { t = scnprintf(next, size, "\nFor %s Maxpkt is 0x%x " "index is 0x%x\n", diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h index e651469fd39b..5cd7b7e7ddb4 100644 --- a/drivers/usb/gadget/fsl_usb2_udc.h +++ b/drivers/usb/gadget/fsl_usb2_udc.h @@ -1,4 +1,12 @@ /* + * Copyright (C) 2004,2012 Freescale Semiconductor, Inc + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * * Freescale USB device/endpoint management registers */ #ifndef __FSL_USB2_UDC_H @@ -348,6 +356,9 @@ struct usb_sys_interface { /* control Register Bit Masks */ #define USB_CTRL_IOENB 0x00000004 #define USB_CTRL_ULPI_INT0EN 0x00000001 +#define USB_CTRL_UTMI_PHY_EN 0x00000200 +#define USB_CTRL_USB_EN 0x00000004 +#define USB_CTRL_ULPI_PHY_CLK_SEL 0x00000400 /* Endpoint Queue Head data struct * Rem: all the variables of qh are LittleEndian Mode @@ -450,7 +461,6 @@ struct fsl_ep { struct list_head queue; struct fsl_udc *udc; struct ep_queue_head *qh; - const struct usb_endpoint_descriptor *desc; struct usb_gadget *gadget; char name[14]; diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c index 5831cb4a0b35..cdd94540e1cd 100644 --- a/drivers/usb/gadget/fusb300_udc.c +++ b/drivers/usb/gadget/fusb300_udc.c @@ -203,7 +203,7 @@ static int config_ep(struct fusb300_ep *ep, struct fusb300 *fusb300 = ep->fusb300; struct fusb300_ep_info info; - ep->desc = desc; + ep->ep.desc = desc; info.interval = 0; info.addrofs = 0; @@ -443,7 +443,7 @@ static int fusb300_queue(struct usb_ep *_ep, struct usb_request *_req, req->req.actual = 0; req->req.status = -EINPROGRESS; - if (ep->desc == NULL) /* ep0 */ + if (ep->ep.desc == NULL) /* ep0 */ ep0_queue(ep, req); else if (request && !ep->stall) enable_fifo_int(ep); diff --git a/drivers/usb/gadget/fusb300_udc.h b/drivers/usb/gadget/fusb300_udc.h index 92745bd03064..542cd83cc806 100644 --- a/drivers/usb/gadget/fusb300_udc.h +++ b/drivers/usb/gadget/fusb300_udc.h @@ -650,7 +650,6 @@ struct fusb300_ep { unsigned char epnum; unsigned char type; - const struct usb_endpoint_descriptor *desc; }; struct fusb300 { diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c index a85eaf40b948..d3ace9002a6a 100644 --- a/drivers/usb/gadget/g_ffs.c +++ b/drivers/usb/gadget/g_ffs.c @@ -67,6 +67,15 @@ MODULE_LICENSE("GPL"); #define GFS_VENDOR_ID 0x1d6b /* Linux Foundation */ #define GFS_PRODUCT_ID 0x0105 /* FunctionFS Gadget */ +#define GFS_MAX_DEVS 10 + +struct gfs_ffs_obj { + const char *name; + bool mounted; + bool desc_ready; + struct ffs_data *ffs_data; +}; + static struct usb_device_descriptor gfs_dev_desc = { .bLength = sizeof gfs_dev_desc, .bDescriptorType = USB_DT_DEVICE, @@ -78,12 +87,17 @@ static struct usb_device_descriptor gfs_dev_desc = { .idProduct = cpu_to_le16(GFS_PRODUCT_ID), }; +static char *func_names[GFS_MAX_DEVS]; +static unsigned int func_num; + module_param_named(bDeviceClass, gfs_dev_desc.bDeviceClass, byte, 0644); MODULE_PARM_DESC(bDeviceClass, "USB Device class"); module_param_named(bDeviceSubClass, gfs_dev_desc.bDeviceSubClass, byte, 0644); MODULE_PARM_DESC(bDeviceSubClass, "USB Device subclass"); module_param_named(bDeviceProtocol, gfs_dev_desc.bDeviceProtocol, byte, 0644); MODULE_PARM_DESC(bDeviceProtocol, "USB Device protocol"); +module_param_array_named(functions, func_names, charp, &func_num, 0); +MODULE_PARM_DESC(functions, "USB Functions list"); static const struct usb_descriptor_header *gfs_otg_desc[] = { (const struct usb_descriptor_header *) @@ -158,13 +172,34 @@ static struct usb_composite_driver gfs_driver = { .iProduct = DRIVER_DESC, }; -static struct ffs_data *gfs_ffs_data; -static unsigned long gfs_registered; +static DEFINE_MUTEX(gfs_lock); +static unsigned int missing_funcs; +static bool gfs_ether_setup; +static bool gfs_registered; +static bool gfs_single_func; +static struct gfs_ffs_obj *ffs_tab; static int __init gfs_init(void) { + int i; + ENTER(); + if (!func_num) { + gfs_single_func = true; + func_num = 1; + } + + ffs_tab = kcalloc(func_num, sizeof *ffs_tab, GFP_KERNEL); + if (!ffs_tab) + return -ENOMEM; + + if (!gfs_single_func) + for (i = 0; i < func_num; i++) + ffs_tab[i].name = func_names[i]; + + missing_funcs = func_num; + return functionfs_init(); } module_init(gfs_init); @@ -172,63 +207,165 @@ module_init(gfs_init); static void __exit gfs_exit(void) { ENTER(); + mutex_lock(&gfs_lock); - if (test_and_clear_bit(0, &gfs_registered)) + if (gfs_registered) usb_composite_unregister(&gfs_driver); + gfs_registered = false; functionfs_cleanup(); + + mutex_unlock(&gfs_lock); + kfree(ffs_tab); } module_exit(gfs_exit); +static struct gfs_ffs_obj *gfs_find_dev(const char *dev_name) +{ + int i; + + ENTER(); + + if (gfs_single_func) + return &ffs_tab[0]; + + for (i = 0; i < func_num; i++) + if (strcmp(ffs_tab[i].name, dev_name) == 0) + return &ffs_tab[i]; + + return NULL; +} + static int functionfs_ready_callback(struct ffs_data *ffs) { + struct gfs_ffs_obj *ffs_obj; int ret; ENTER(); + mutex_lock(&gfs_lock); + + ffs_obj = ffs->private_data; + if (!ffs_obj) { + ret = -EINVAL; + goto done; + } + + if (WARN_ON(ffs_obj->desc_ready)) { + ret = -EBUSY; + goto done; + } + ffs_obj->desc_ready = true; + ffs_obj->ffs_data = ffs; - if (WARN_ON(test_and_set_bit(0, &gfs_registered))) - return -EBUSY; + if (--missing_funcs) { + ret = 0; + goto done; + } + + if (gfs_registered) { + ret = -EBUSY; + goto done; + } + gfs_registered = true; - gfs_ffs_data = ffs; ret = usb_composite_probe(&gfs_driver, gfs_bind); if (unlikely(ret < 0)) - clear_bit(0, &gfs_registered); + gfs_registered = false; + +done: + mutex_unlock(&gfs_lock); return ret; } static void functionfs_closed_callback(struct ffs_data *ffs) { + struct gfs_ffs_obj *ffs_obj; + ENTER(); + mutex_lock(&gfs_lock); - if (test_and_clear_bit(0, &gfs_registered)) + ffs_obj = ffs->private_data; + if (!ffs_obj) + goto done; + + ffs_obj->desc_ready = false; + missing_funcs++; + + if (gfs_registered) usb_composite_unregister(&gfs_driver); + gfs_registered = false; + +done: + mutex_unlock(&gfs_lock); } -static int functionfs_check_dev_callback(const char *dev_name) +static void *functionfs_acquire_dev_callback(const char *dev_name) { - return 0; + struct gfs_ffs_obj *ffs_dev; + + ENTER(); + mutex_lock(&gfs_lock); + + ffs_dev = gfs_find_dev(dev_name); + if (!ffs_dev) { + ffs_dev = ERR_PTR(-ENODEV); + goto done; + } + + if (ffs_dev->mounted) { + ffs_dev = ERR_PTR(-EBUSY); + goto done; + } + ffs_dev->mounted = true; + +done: + mutex_unlock(&gfs_lock); + return ffs_dev; } +static void functionfs_release_dev_callback(struct ffs_data *ffs_data) +{ + struct gfs_ffs_obj *ffs_dev; + + ENTER(); + mutex_lock(&gfs_lock); + + ffs_dev = ffs_data->private_data; + if (ffs_dev) + ffs_dev->mounted = false; + + mutex_unlock(&gfs_lock); +} + +/* + * It is assumed that gfs_bind is called from a context where gfs_lock is held + */ static int gfs_bind(struct usb_composite_dev *cdev) { int ret, i; ENTER(); - if (WARN_ON(!gfs_ffs_data)) + if (missing_funcs) return -ENODEV; ret = gether_setup(cdev->gadget, gfs_hostaddr); if (unlikely(ret < 0)) goto error_quick; + gfs_ether_setup = true; ret = usb_string_ids_tab(cdev, gfs_strings); if (unlikely(ret < 0)) goto error; - ret = functionfs_bind(gfs_ffs_data, cdev); - if (unlikely(ret < 0)) - goto error; + for (i = func_num; --i; ) { + ret = functionfs_bind(ffs_tab[i].ffs_data, cdev); + if (unlikely(ret < 0)) { + while (++i < func_num) + functionfs_unbind(ffs_tab[i].ffs_data); + goto error; + } + } for (i = 0; i < ARRAY_SIZE(gfs_configurations); ++i) { struct gfs_configuration *c = gfs_configurations + i; @@ -246,16 +383,22 @@ static int gfs_bind(struct usb_composite_dev *cdev) return 0; error_unbind: - functionfs_unbind(gfs_ffs_data); + for (i = 0; i < func_num; i++) + functionfs_unbind(ffs_tab[i].ffs_data); error: gether_cleanup(); error_quick: - gfs_ffs_data = NULL; + gfs_ether_setup = false; return ret; } +/* + * It is assumed that gfs_unbind is called from a context where gfs_lock is held + */ static int gfs_unbind(struct usb_composite_dev *cdev) { + int i; + ENTER(); /* @@ -266,22 +409,29 @@ static int gfs_unbind(struct usb_composite_dev *cdev) * from composite on orror recovery, but what you're gonna * do...? */ - if (gfs_ffs_data) { + if (gfs_ether_setup) gether_cleanup(); - functionfs_unbind(gfs_ffs_data); - gfs_ffs_data = NULL; - } + gfs_ether_setup = false; + + for (i = func_num; --i; ) + if (ffs_tab[i].ffs_data) + functionfs_unbind(ffs_tab[i].ffs_data); return 0; } +/* + * It is assumed that gfs_do_config is called from a context where + * gfs_lock is held + */ static int gfs_do_config(struct usb_configuration *c) { struct gfs_configuration *gc = container_of(c, struct gfs_configuration, c); + int i; int ret; - if (WARN_ON(!gfs_ffs_data)) + if (missing_funcs) return -ENODEV; if (gadget_is_otg(c->cdev->gadget)) { @@ -295,9 +445,11 @@ static int gfs_do_config(struct usb_configuration *c) return ret; } - ret = functionfs_bind_config(c->cdev, c, gfs_ffs_data); - if (unlikely(ret < 0)) - return ret; + for (i = 0; i < func_num; i++) { + ret = functionfs_bind_config(c->cdev, c, ffs_tab[i].ffs_data); + if (unlikely(ret < 0)) + return ret; + } /* * After previous do_configs there may be some invalid diff --git a/drivers/usb/gadget/g_zero.h b/drivers/usb/gadget/g_zero.h index e84b3c47ed3c..71ca193358b8 100644 --- a/drivers/usb/gadget/g_zero.h +++ b/drivers/usb/gadget/g_zero.h @@ -13,10 +13,11 @@ extern unsigned buflen; extern const struct usb_descriptor_header *otg_desc[]; /* common utilities */ -struct usb_request *alloc_ep_req(struct usb_ep *ep); +struct usb_request *alloc_ep_req(struct usb_ep *ep, int len); void free_ep_req(struct usb_ep *ep, struct usb_request *req); void disable_endpoints(struct usb_composite_dev *cdev, - struct usb_ep *in, struct usb_ep *out); + struct usb_ep *in, struct usb_ep *out, + struct usb_ep *iso_in, struct usb_ep *iso_out); /* configuration-specific linkup */ int sourcesink_add(struct usb_composite_dev *cdev, bool autoresume); diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h index a8855d0b7f3b..b8b3a3411218 100644 --- a/drivers/usb/gadget/gadget_chips.h +++ b/drivers/usb/gadget/gadget_chips.h @@ -37,6 +37,7 @@ #define gadget_is_goku(g) (!strcmp("goku_udc", (g)->name)) #define gadget_is_imx(g) (!strcmp("imx_udc", (g)->name)) #define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name)) +#define gadget_is_lpc32xx(g) (!strcmp("lpc32xx_udc", (g)->name)) #define gadget_is_m66592(g) (!strcmp("m66592_udc", (g)->name)) #define gadget_is_musbhdrc(g) (!strcmp("musb-hdrc", (g)->name)) #define gadget_is_net2272(g) (!strcmp("net2272", (g)->name)) @@ -118,6 +119,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget) return 0x31; else if (gadget_is_dwc3(gadget)) return 0x32; + else if (gadget_is_lpc32xx(gadget)) + return 0x33; return -ENOENT; } diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c index e151d6b87dee..b241e6c6a7f2 100644 --- a/drivers/usb/gadget/goku_udc.c +++ b/drivers/usb/gadget/goku_udc.c @@ -102,7 +102,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) unsigned long flags; ep = container_of(_ep, struct goku_ep, ep); - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; dev = ep->dev; @@ -176,7 +176,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) command(ep->dev->regs, COMMAND_RESET, ep->num); ep->ep.maxpacket = max; ep->stopped = 0; - ep->desc = desc; + ep->ep.desc = desc; spin_unlock_irqrestore(&ep->dev->lock, flags); DBG(dev, "enable %s %s %s maxpacket %u\n", ep->ep.name, @@ -233,7 +233,6 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep) } ep->ep.maxpacket = MAX_FIFO_SIZE; - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; ep->irqs = 0; @@ -247,7 +246,7 @@ static int goku_ep_disable(struct usb_ep *_ep) unsigned long flags; ep = container_of(_ep, struct goku_ep, ep); - if (!_ep || !ep->desc) + if (!_ep || !ep->ep.desc) return -ENODEV; dev = ep->dev; if (dev->ep0state == EP0_SUSPEND) @@ -722,7 +721,7 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) || !_req->buf || !list_empty(&req->queue))) return -EINVAL; ep = container_of(_ep, struct goku_ep, ep); - if (unlikely(!_ep || (!ep->desc && ep->num != 0))) + if (unlikely(!_ep || (!ep->ep.desc && ep->num != 0))) return -EINVAL; dev = ep->dev; if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) @@ -815,7 +814,7 @@ static int goku_dequeue(struct usb_ep *_ep, struct usb_request *_req) unsigned long flags; ep = container_of(_ep, struct goku_ep, ep); - if (!_ep || !_req || (!ep->desc && ep->num != 0)) + if (!_ep || !_req || (!ep->ep.desc && ep->num != 0)) return -EINVAL; dev = ep->dev; if (!dev->driver) @@ -896,7 +895,7 @@ static int goku_set_halt(struct usb_ep *_ep, int value) return -EINVAL; /* don't change EPxSTATUS_EP_INVALID to READY */ - } else if (!ep->desc) { + } else if (!ep->ep.desc) { DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name); return -EINVAL; } @@ -955,7 +954,7 @@ static void goku_fifo_flush(struct usb_ep *_ep) VDBG(ep->dev, "%s %s\n", __func__, ep->ep.name); /* don't change EPxSTATUS_EP_INVALID to READY */ - if (!ep->desc && ep->num != 0) { + if (!ep->ep.desc && ep->num != 0) { DBG(ep->dev, "%s %s inactive?\n", __func__, ep->ep.name); return; } @@ -1152,7 +1151,7 @@ udc_proc_read(char *buffer, char **start, off_t off, int count, struct goku_ep *ep = &dev->ep [i]; struct goku_request *req; - if (i && !ep->desc) + if (i && !ep->ep.desc) continue; tmp = readl(ep->reg_status); @@ -1473,7 +1472,8 @@ static void ep0_setup(struct goku_udc *dev) case USB_RECIP_ENDPOINT: tmp = le16_to_cpu(ctrl.wIndex) & 0x0f; /* active endpoint */ - if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0)) + if (tmp > 3 || + (!dev->ep[tmp].ep.desc && tmp != 0)) goto stall; if (ctrl.wIndex & cpu_to_le16( USB_DIR_IN)) { @@ -1895,14 +1895,4 @@ static struct pci_driver goku_pci_driver = { /* FIXME add power management support */ }; -static int __init init (void) -{ - return pci_register_driver (&goku_pci_driver); -} -module_init (init); - -static void __exit cleanup (void) -{ - pci_unregister_driver (&goku_pci_driver); -} -module_exit (cleanup); +module_pci_driver(goku_pci_driver); diff --git a/drivers/usb/gadget/goku_udc.h b/drivers/usb/gadget/goku_udc.h index e7e0c69d3b1f..85cdce0d1901 100644 --- a/drivers/usb/gadget/goku_udc.h +++ b/drivers/usb/gadget/goku_udc.h @@ -216,7 +216,6 @@ struct goku_ep { /* analogous to a host-side qh */ struct list_head queue; - const struct usb_endpoint_descriptor *desc; u32 __iomem *reg_fifo; u32 __iomem *reg_mode; diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c index 8d1c75abd73d..54034f84f992 100644 --- a/drivers/usb/gadget/imx_udc.c +++ b/drivers/usb/gadget/imx_udc.c @@ -1237,14 +1237,15 @@ irq_handler_t intr_handler(int i) ******************************************************************************* */ -static int imx_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)); -static int imx_udc_stop(struct usb_gadget_driver *driver); +static int imx_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); +static int imx_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver); static const struct usb_gadget_ops imx_udc_ops = { - .get_frame = imx_udc_get_frame, - .wakeup = imx_udc_wakeup, - .start = imx_udc_start, - .stop = imx_udc_stop, + .get_frame = imx_udc_get_frame, + .wakeup = imx_udc_wakeup, + .udc_start = imx_udc_start, + .udc_stop = imx_udc_stop, }; static struct imx_udc_struct controller = { @@ -1329,23 +1330,13 @@ static struct imx_udc_struct controller = { * USB gadget driver functions ******************************************************************************* */ -static int imx_udc_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +static int imx_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct imx_udc_struct *imx_usb = &controller; + struct imx_udc_struct *imx_usb; int retval; - if (!driver - || driver->max_speed < USB_SPEED_FULL - || !bind - || !driver->disconnect - || !driver->setup) - return -EINVAL; - if (!imx_usb) - return -ENODEV; - if (imx_usb->driver) - return -EBUSY; - + imx_usb = container_of(gadget, struct imx_udc_struct, gadget); /* first hook up the driver ... */ imx_usb->driver = driver; imx_usb->gadget.dev.driver = &driver->driver; @@ -1353,14 +1344,6 @@ static int imx_udc_start(struct usb_gadget_driver *driver, retval = device_add(&imx_usb->gadget.dev); if (retval) goto fail; - retval = bind(&imx_usb->gadget); - if (retval) { - D_ERR(imx_usb->dev, "<%s> bind to driver %s --> error %d\n", - __func__, driver->driver.name, retval); - device_del(&imx_usb->gadget.dev); - - goto fail; - } D_INI(imx_usb->dev, "<%s> registered gadget driver '%s'\n", __func__, driver->driver.name); @@ -1374,20 +1357,16 @@ fail: return retval; } -static int imx_udc_stop(struct usb_gadget_driver *driver) +static int imx_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct imx_udc_struct *imx_usb = &controller; - - if (!imx_usb) - return -ENODEV; - if (!driver || driver != imx_usb->driver || !driver->unbind) - return -EINVAL; + struct imx_udc_struct *imx_usb = container_of(gadget, + struct imx_udc_struct, gadget); udc_stop_activity(imx_usb, driver); imx_udc_disable(imx_usb); del_timer(&imx_usb->timer); - driver->unbind(&imx_usb->gadget); imx_usb->gadget.dev.driver = NULL; imx_usb->driver = NULL; diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c deleted file mode 100644 index f9cedd52cf20..000000000000 --- a/drivers/usb/gadget/langwell_udc.c +++ /dev/null @@ -1,3434 +0,0 @@ -/* - * Intel Langwell USB Device Controller driver - * Copyright (C) 2008-2009, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - */ - - -/* #undef DEBUG */ -/* #undef VERBOSE_DEBUG */ - -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/dma-mapping.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/list.h> -#include <linux/interrupt.h> -#include <linux/moduleparam.h> -#include <linux/device.h> -#include <linux/usb/ch9.h> -#include <linux/usb/gadget.h> -#include <linux/usb/otg.h> -#include <linux/pm.h> -#include <linux/io.h> -#include <linux/irq.h> -#include <asm/unaligned.h> - -#include "langwell_udc.h" - - -#define DRIVER_DESC "Intel Langwell USB Device Controller driver" -#define DRIVER_VERSION "16 May 2009" - -static const char driver_name[] = "langwell_udc"; -static const char driver_desc[] = DRIVER_DESC; - - -/* for endpoint 0 operations */ -static const struct usb_endpoint_descriptor -langwell_ep0_desc = { - .bLength = USB_DT_ENDPOINT_SIZE, - .bDescriptorType = USB_DT_ENDPOINT, - .bEndpointAddress = 0, - .bmAttributes = USB_ENDPOINT_XFER_CONTROL, - .wMaxPacketSize = EP0_MAX_PKT_SIZE, -}; - - -/*-------------------------------------------------------------------------*/ -/* debugging */ - -#ifdef VERBOSE_DEBUG -static inline void print_all_registers(struct langwell_udc *dev) -{ - int i; - - /* Capability Registers */ - dev_dbg(&dev->pdev->dev, - "Capability Registers (offset: 0x%04x, length: 0x%08x)\n", - CAP_REG_OFFSET, (u32)sizeof(struct langwell_cap_regs)); - dev_dbg(&dev->pdev->dev, "caplength=0x%02x\n", - readb(&dev->cap_regs->caplength)); - dev_dbg(&dev->pdev->dev, "hciversion=0x%04x\n", - readw(&dev->cap_regs->hciversion)); - dev_dbg(&dev->pdev->dev, "hcsparams=0x%08x\n", - readl(&dev->cap_regs->hcsparams)); - dev_dbg(&dev->pdev->dev, "hccparams=0x%08x\n", - readl(&dev->cap_regs->hccparams)); - dev_dbg(&dev->pdev->dev, "dciversion=0x%04x\n", - readw(&dev->cap_regs->dciversion)); - dev_dbg(&dev->pdev->dev, "dccparams=0x%08x\n", - readl(&dev->cap_regs->dccparams)); - - /* Operational Registers */ - dev_dbg(&dev->pdev->dev, - "Operational Registers (offset: 0x%04x, length: 0x%08x)\n", - OP_REG_OFFSET, (u32)sizeof(struct langwell_op_regs)); - dev_dbg(&dev->pdev->dev, "extsts=0x%08x\n", - readl(&dev->op_regs->extsts)); - dev_dbg(&dev->pdev->dev, "extintr=0x%08x\n", - readl(&dev->op_regs->extintr)); - dev_dbg(&dev->pdev->dev, "usbcmd=0x%08x\n", - readl(&dev->op_regs->usbcmd)); - dev_dbg(&dev->pdev->dev, "usbsts=0x%08x\n", - readl(&dev->op_regs->usbsts)); - dev_dbg(&dev->pdev->dev, "usbintr=0x%08x\n", - readl(&dev->op_regs->usbintr)); - dev_dbg(&dev->pdev->dev, "frindex=0x%08x\n", - readl(&dev->op_regs->frindex)); - dev_dbg(&dev->pdev->dev, "ctrldssegment=0x%08x\n", - readl(&dev->op_regs->ctrldssegment)); - dev_dbg(&dev->pdev->dev, "deviceaddr=0x%08x\n", - readl(&dev->op_regs->deviceaddr)); - dev_dbg(&dev->pdev->dev, "endpointlistaddr=0x%08x\n", - readl(&dev->op_regs->endpointlistaddr)); - dev_dbg(&dev->pdev->dev, "ttctrl=0x%08x\n", - readl(&dev->op_regs->ttctrl)); - dev_dbg(&dev->pdev->dev, "burstsize=0x%08x\n", - readl(&dev->op_regs->burstsize)); - dev_dbg(&dev->pdev->dev, "txfilltuning=0x%08x\n", - readl(&dev->op_regs->txfilltuning)); - dev_dbg(&dev->pdev->dev, "txttfilltuning=0x%08x\n", - readl(&dev->op_regs->txttfilltuning)); - dev_dbg(&dev->pdev->dev, "ic_usb=0x%08x\n", - readl(&dev->op_regs->ic_usb)); - dev_dbg(&dev->pdev->dev, "ulpi_viewport=0x%08x\n", - readl(&dev->op_regs->ulpi_viewport)); - dev_dbg(&dev->pdev->dev, "configflag=0x%08x\n", - readl(&dev->op_regs->configflag)); - dev_dbg(&dev->pdev->dev, "portsc1=0x%08x\n", - readl(&dev->op_regs->portsc1)); - dev_dbg(&dev->pdev->dev, "devlc=0x%08x\n", - readl(&dev->op_regs->devlc)); - dev_dbg(&dev->pdev->dev, "otgsc=0x%08x\n", - readl(&dev->op_regs->otgsc)); - dev_dbg(&dev->pdev->dev, "usbmode=0x%08x\n", - readl(&dev->op_regs->usbmode)); - dev_dbg(&dev->pdev->dev, "endptnak=0x%08x\n", - readl(&dev->op_regs->endptnak)); - dev_dbg(&dev->pdev->dev, "endptnaken=0x%08x\n", - readl(&dev->op_regs->endptnaken)); - dev_dbg(&dev->pdev->dev, "endptsetupstat=0x%08x\n", - readl(&dev->op_regs->endptsetupstat)); - dev_dbg(&dev->pdev->dev, "endptprime=0x%08x\n", - readl(&dev->op_regs->endptprime)); - dev_dbg(&dev->pdev->dev, "endptflush=0x%08x\n", - readl(&dev->op_regs->endptflush)); - dev_dbg(&dev->pdev->dev, "endptstat=0x%08x\n", - readl(&dev->op_regs->endptstat)); - dev_dbg(&dev->pdev->dev, "endptcomplete=0x%08x\n", - readl(&dev->op_regs->endptcomplete)); - - for (i = 0; i < dev->ep_max / 2; i++) { - dev_dbg(&dev->pdev->dev, "endptctrl[%d]=0x%08x\n", - i, readl(&dev->op_regs->endptctrl[i])); - } -} -#else - -#define print_all_registers(dev) do { } while (0) - -#endif /* VERBOSE_DEBUG */ - - -/*-------------------------------------------------------------------------*/ - -#define is_in(ep) (((ep)->ep_num == 0) ? ((ep)->dev->ep0_dir == \ - USB_DIR_IN) : (usb_endpoint_dir_in((ep)->desc))) - -#define DIR_STRING(ep) (is_in(ep) ? "in" : "out") - - -static char *type_string(const struct usb_endpoint_descriptor *desc) -{ - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_BULK: - return "bulk"; - case USB_ENDPOINT_XFER_ISOC: - return "iso"; - case USB_ENDPOINT_XFER_INT: - return "int"; - }; - - return "control"; -} - - -/* configure endpoint control registers */ -static void ep_reset(struct langwell_ep *ep, unsigned char ep_num, - unsigned char is_in, unsigned char ep_type) -{ - struct langwell_udc *dev; - u32 endptctrl; - - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in) { /* TX */ - if (ep_num) - endptctrl |= EPCTRL_TXR; - endptctrl |= EPCTRL_TXE; - endptctrl |= ep_type << EPCTRL_TXT_SHIFT; - } else { /* RX */ - if (ep_num) - endptctrl |= EPCTRL_RXR; - endptctrl |= EPCTRL_RXE; - endptctrl |= ep_type << EPCTRL_RXT_SHIFT; - } - - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* reset ep0 dQH and endptctrl */ -static void ep0_reset(struct langwell_udc *dev) -{ - struct langwell_ep *ep; - int i; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* ep0 in and out */ - for (i = 0; i < 2; i++) { - ep = &dev->ep[i]; - ep->dev = dev; - - /* ep0 dQH */ - ep->dqh = &dev->ep_dqh[i]; - - /* configure ep0 endpoint capabilities in dQH */ - ep->dqh->dqh_ios = 1; - ep->dqh->dqh_mpl = EP0_MAX_PKT_SIZE; - - /* enable ep0-in HW zero length termination select */ - if (is_in(ep)) - ep->dqh->dqh_zlt = 0; - ep->dqh->dqh_mult = 0; - - ep->dqh->dtd_next = DTD_TERM; - - /* configure ep0 control registers */ - ep_reset(&dev->ep[0], 0, i, USB_ENDPOINT_XFER_CONTROL); - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/*-------------------------------------------------------------------------*/ - -/* endpoints operations */ - -/* configure endpoint, making it usable */ -static int langwell_ep_enable(struct usb_ep *_ep, - const struct usb_endpoint_descriptor *desc) -{ - struct langwell_udc *dev; - struct langwell_ep *ep; - u16 max = 0; - unsigned long flags; - int i, retval = 0; - unsigned char zlt, ios = 0, mult = 0; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !desc || ep->desc - || desc->bDescriptorType != USB_DT_ENDPOINT) - return -EINVAL; - - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - max = usb_endpoint_maxp(desc); - - /* - * disable HW zero length termination select - * driver handles zero length packet through req->req.zero - */ - zlt = 1; - - /* - * sanity check type, direction, address, and then - * initialize the endpoint capabilities fields in dQH - */ - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_CONTROL: - ios = 1; - break; - case USB_ENDPOINT_XFER_BULK: - if ((dev->gadget.speed == USB_SPEED_HIGH - && max != 512) - || (dev->gadget.speed == USB_SPEED_FULL - && max > 64)) { - goto done; - } - break; - case USB_ENDPOINT_XFER_INT: - if (strstr(ep->ep.name, "-iso")) /* bulk is ok */ - goto done; - - switch (dev->gadget.speed) { - case USB_SPEED_HIGH: - if (max <= 1024) - break; - case USB_SPEED_FULL: - if (max <= 64) - break; - default: - if (max <= 8) - break; - goto done; - } - break; - case USB_ENDPOINT_XFER_ISOC: - if (strstr(ep->ep.name, "-bulk") - || strstr(ep->ep.name, "-int")) - goto done; - - switch (dev->gadget.speed) { - case USB_SPEED_HIGH: - if (max <= 1024) - break; - case USB_SPEED_FULL: - if (max <= 1023) - break; - default: - goto done; - } - /* - * FIXME: - * calculate transactions needed for high bandwidth iso - */ - mult = (unsigned char)(1 + ((max >> 11) & 0x03)); - max = max & 0x8ff; /* bit 0~10 */ - /* 3 transactions at most */ - if (mult > 3) - goto done; - break; - default: - goto done; - } - - spin_lock_irqsave(&dev->lock, flags); - - ep->ep.maxpacket = max; - ep->desc = desc; - ep->stopped = 0; - ep->ep_num = usb_endpoint_num(desc); - - /* ep_type */ - ep->ep_type = usb_endpoint_type(desc); - - /* configure endpoint control registers */ - ep_reset(ep, ep->ep_num, is_in(ep), ep->ep_type); - - /* configure endpoint capabilities in dQH */ - i = ep->ep_num * 2 + is_in(ep); - ep->dqh = &dev->ep_dqh[i]; - ep->dqh->dqh_ios = ios; - ep->dqh->dqh_mpl = cpu_to_le16(max); - ep->dqh->dqh_zlt = zlt; - ep->dqh->dqh_mult = mult; - ep->dqh->dtd_next = DTD_TERM; - - dev_dbg(&dev->pdev->dev, "enabled %s (ep%d%s-%s), max %04x\n", - _ep->name, - ep->ep_num, - DIR_STRING(ep), - type_string(desc), - max); - - spin_unlock_irqrestore(&dev->lock, flags); -done: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/* retire a request */ -static void done(struct langwell_ep *ep, struct langwell_request *req, - int status) -{ - struct langwell_udc *dev = ep->dev; - unsigned stopped = ep->stopped; - struct langwell_dtd *curr_dtd, *next_dtd; - int i; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* remove the req from ep->queue */ - list_del_init(&req->queue); - - if (req->req.status == -EINPROGRESS) - req->req.status = status; - else - status = req->req.status; - - /* free dTD for the request */ - next_dtd = req->head; - for (i = 0; i < req->dtd_count; i++) { - curr_dtd = next_dtd; - if (i != req->dtd_count - 1) - next_dtd = curr_dtd->next_dtd_virt; - dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma); - } - - usb_gadget_unmap_request(&dev->gadget, &req->req, is_in(ep)); - - if (status != -ESHUTDOWN) - dev_dbg(&dev->pdev->dev, - "complete %s, req %p, stat %d, len %u/%u\n", - ep->ep.name, &req->req, status, - req->req.actual, req->req.length); - - /* don't modify queue heads during completion callback */ - ep->stopped = 1; - - spin_unlock(&dev->lock); - /* complete routine from gadget driver */ - if (req->req.complete) - req->req.complete(&ep->ep, &req->req); - - spin_lock(&dev->lock); - ep->stopped = stopped; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -static void langwell_ep_fifo_flush(struct usb_ep *_ep); - -/* delete all endpoint requests, called with spinlock held */ -static void nuke(struct langwell_ep *ep, int status) -{ - /* called with spinlock held */ - ep->stopped = 1; - - /* endpoint fifo flush */ - if (&ep->ep && ep->desc) - langwell_ep_fifo_flush(&ep->ep); - - while (!list_empty(&ep->queue)) { - struct langwell_request *req = NULL; - req = list_entry(ep->queue.next, struct langwell_request, - queue); - done(ep, req, status); - } -} - - -/*-------------------------------------------------------------------------*/ - -/* endpoint is no longer usable */ -static int langwell_ep_disable(struct usb_ep *_ep) -{ - struct langwell_ep *ep; - unsigned long flags; - struct langwell_udc *dev; - int ep_num; - u32 endptctrl; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) - return -EINVAL; - - spin_lock_irqsave(&dev->lock, flags); - - /* disable endpoint control register */ - ep_num = ep->ep_num; - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in(ep)) - endptctrl &= ~EPCTRL_TXE; - else - endptctrl &= ~EPCTRL_RXE; - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - /* nuke all pending requests (does flush) */ - nuke(ep, -ESHUTDOWN); - - ep->desc = NULL; - ep->ep.desc = NULL; - ep->stopped = 1; - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_dbg(&dev->pdev->dev, "disabled %s\n", _ep->name); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return 0; -} - - -/* allocate a request object to use with this endpoint */ -static struct usb_request *langwell_alloc_request(struct usb_ep *_ep, - gfp_t gfp_flags) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - struct langwell_request *req = NULL; - - if (!_ep) - return NULL; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - req = kzalloc(sizeof(*req), gfp_flags); - if (!req) - return NULL; - - req->req.dma = DMA_ADDR_INVALID; - INIT_LIST_HEAD(&req->queue); - - dev_vdbg(&dev->pdev->dev, "alloc request for %s\n", _ep->name); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return &req->req; -} - - -/* free a request object */ -static void langwell_free_request(struct usb_ep *_ep, - struct usb_request *_req) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - struct langwell_request *req = NULL; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !_req) - return; - - req = container_of(_req, struct langwell_request, req); - WARN_ON(!list_empty(&req->queue)); - - if (_req) - kfree(req); - - dev_vdbg(&dev->pdev->dev, "free request for %s\n", _ep->name); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/*-------------------------------------------------------------------------*/ - -/* queue dTD and PRIME endpoint */ -static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req) -{ - u32 bit_mask, usbcmd, endptstat, dtd_dma; - u8 dtd_status; - int i; - struct langwell_dqh *dqh; - struct langwell_udc *dev; - - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - i = ep->ep_num * 2 + is_in(ep); - dqh = &dev->ep_dqh[i]; - - if (ep->ep_num) - dev_vdbg(&dev->pdev->dev, "%s\n", ep->name); - else - /* ep0 */ - dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep)); - - dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n", - i, &(dev->ep_dqh[i])); - - bit_mask = is_in(ep) ? - (1 << (ep->ep_num + 16)) : (1 << (ep->ep_num)); - - dev_vdbg(&dev->pdev->dev, "bit_mask = 0x%08x\n", bit_mask); - - /* check if the pipe is empty */ - if (!(list_empty(&ep->queue))) { - /* add dTD to the end of linked list */ - struct langwell_request *lastreq; - lastreq = list_entry(ep->queue.prev, - struct langwell_request, queue); - - lastreq->tail->dtd_next = - cpu_to_le32(req->head->dtd_dma & DTD_NEXT_MASK); - - /* read prime bit, if 1 goto out */ - if (readl(&dev->op_regs->endptprime) & bit_mask) - goto out; - - do { - /* set ATDTW bit in USBCMD */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd | CMD_ATDTW, &dev->op_regs->usbcmd); - - /* read correct status bit */ - endptstat = readl(&dev->op_regs->endptstat) & bit_mask; - - } while (!(readl(&dev->op_regs->usbcmd) & CMD_ATDTW)); - - /* write ATDTW bit to 0 */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd & ~CMD_ATDTW, &dev->op_regs->usbcmd); - - if (endptstat) - goto out; - } - - /* write dQH next pointer and terminate bit to 0 */ - dtd_dma = req->head->dtd_dma & DTD_NEXT_MASK; - dqh->dtd_next = cpu_to_le32(dtd_dma); - - /* clear active and halt bit */ - dtd_status = (u8) ~(DTD_STS_ACTIVE | DTD_STS_HALTED); - dqh->dtd_status &= dtd_status; - dev_vdbg(&dev->pdev->dev, "dqh->dtd_status = 0x%x\n", dqh->dtd_status); - - /* ensure that updates to the dQH will occur before priming */ - wmb(); - - /* write 1 to endptprime register to PRIME endpoint */ - bit_mask = is_in(ep) ? (1 << (ep->ep_num + 16)) : (1 << ep->ep_num); - dev_vdbg(&dev->pdev->dev, "endprime bit_mask = 0x%08x\n", bit_mask); - writel(bit_mask, &dev->op_regs->endptprime); -out: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* fill in the dTD structure to build a transfer descriptor */ -static struct langwell_dtd *build_dtd(struct langwell_request *req, - unsigned *length, dma_addr_t *dma, int *is_last) -{ - u32 buf_ptr; - struct langwell_dtd *dtd; - struct langwell_udc *dev; - int i; - - dev = req->ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* the maximum transfer length, up to 16k bytes */ - *length = min(req->req.length - req->req.actual, - (unsigned)DTD_MAX_TRANSFER_LENGTH); - - /* create dTD dma_pool resource */ - dtd = dma_pool_alloc(dev->dtd_pool, GFP_KERNEL, dma); - if (dtd == NULL) - return dtd; - dtd->dtd_dma = *dma; - - /* initialize buffer page pointers */ - buf_ptr = (u32)(req->req.dma + req->req.actual); - for (i = 0; i < 5; i++) - dtd->dtd_buf[i] = cpu_to_le32(buf_ptr + i * PAGE_SIZE); - - req->req.actual += *length; - - /* fill in total bytes with transfer size */ - dtd->dtd_total = cpu_to_le16(*length); - dev_vdbg(&dev->pdev->dev, "dtd->dtd_total = %d\n", dtd->dtd_total); - - /* set is_last flag if req->req.zero is set or not */ - if (req->req.zero) { - if (*length == 0 || (*length % req->ep->ep.maxpacket) != 0) - *is_last = 1; - else - *is_last = 0; - } else if (req->req.length == req->req.actual) { - *is_last = 1; - } else - *is_last = 0; - - if (*is_last == 0) - dev_vdbg(&dev->pdev->dev, "multi-dtd request!\n"); - - /* set interrupt on complete bit for the last dTD */ - if (*is_last && !req->req.no_interrupt) - dtd->dtd_ioc = 1; - - /* set multiplier override 0 for non-ISO and non-TX endpoint */ - dtd->dtd_multo = 0; - - /* set the active bit of status field to 1 */ - dtd->dtd_status = DTD_STS_ACTIVE; - dev_vdbg(&dev->pdev->dev, "dtd->dtd_status = 0x%02x\n", - dtd->dtd_status); - - dev_vdbg(&dev->pdev->dev, "length = %d, dma addr= 0x%08x\n", - *length, (int)*dma); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return dtd; -} - - -/* generate dTD linked list for a request */ -static int req_to_dtd(struct langwell_request *req) -{ - unsigned count; - int is_last, is_first = 1; - struct langwell_dtd *dtd, *last_dtd = NULL; - struct langwell_udc *dev; - dma_addr_t dma; - - dev = req->ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - do { - dtd = build_dtd(req, &count, &dma, &is_last); - if (dtd == NULL) - return -ENOMEM; - - if (is_first) { - is_first = 0; - req->head = dtd; - } else { - last_dtd->dtd_next = cpu_to_le32(dma); - last_dtd->next_dtd_virt = dtd; - } - last_dtd = dtd; - req->dtd_count++; - } while (!is_last); - - /* set terminate bit to 1 for the last dTD */ - dtd->dtd_next = DTD_TERM; - - req->tail = dtd; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* queue (submits) an I/O requests to an endpoint */ -static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req, - gfp_t gfp_flags) -{ - struct langwell_request *req; - struct langwell_ep *ep; - struct langwell_udc *dev; - unsigned long flags; - int is_iso = 0; - int ret; - - /* always require a cpu-view buffer */ - req = container_of(_req, struct langwell_request, req); - ep = container_of(_ep, struct langwell_ep, ep); - - if (!_req || !_req->complete || !_req->buf - || !list_empty(&req->queue)) { - return -EINVAL; - } - - if (unlikely(!_ep || !ep->desc)) - return -EINVAL; - - dev = ep->dev; - req->ep = ep; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (usb_endpoint_xfer_isoc(ep->desc)) { - if (req->req.length > ep->ep.maxpacket) - return -EMSGSIZE; - is_iso = 1; - } - - if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)) - return -ESHUTDOWN; - - /* set up dma mapping */ - ret = usb_gadget_map_request(&dev->gadget, &req->req, is_in(ep)); - if (ret) - return ret; - - dev_dbg(&dev->pdev->dev, - "%s queue req %p, len %u, buf %p, dma 0x%08x\n", - _ep->name, - _req, _req->length, _req->buf, (int)_req->dma); - - _req->status = -EINPROGRESS; - _req->actual = 0; - req->dtd_count = 0; - - spin_lock_irqsave(&dev->lock, flags); - - /* build and put dTDs to endpoint queue */ - if (!req_to_dtd(req)) { - queue_dtd(ep, req); - } else { - spin_unlock_irqrestore(&dev->lock, flags); - return -ENOMEM; - } - - /* update ep0 state */ - if (ep->ep_num == 0) - dev->ep0_state = DATA_STATE_XMIT; - - if (likely(req != NULL)) { - list_add_tail(&req->queue, &ep->queue); - dev_vdbg(&dev->pdev->dev, "list_add_tail()\n"); - } - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* dequeue (cancels, unlinks) an I/O request from an endpoint */ -static int langwell_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - struct langwell_request *req; - unsigned long flags; - int stopped, ep_num, retval = 0; - u32 endptctrl; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc || !_req) - return -EINVAL; - - if (!dev->driver) - return -ESHUTDOWN; - - spin_lock_irqsave(&dev->lock, flags); - stopped = ep->stopped; - - /* quiesce dma while we patch the queue */ - ep->stopped = 1; - ep_num = ep->ep_num; - - /* disable endpoint control register */ - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in(ep)) - endptctrl &= ~EPCTRL_TXE; - else - endptctrl &= ~EPCTRL_RXE; - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - /* make sure it's still queued on this endpoint */ - list_for_each_entry(req, &ep->queue, queue) { - if (&req->req == _req) - break; - } - - if (&req->req != _req) { - retval = -EINVAL; - goto done; - } - - /* queue head may be partially complete. */ - if (ep->queue.next == &req->queue) { - dev_dbg(&dev->pdev->dev, "unlink (%s) dma\n", _ep->name); - _req->status = -ECONNRESET; - langwell_ep_fifo_flush(&ep->ep); - - /* not the last request in endpoint queue */ - if (likely(ep->queue.next == &req->queue)) { - struct langwell_dqh *dqh; - struct langwell_request *next_req; - - dqh = ep->dqh; - next_req = list_entry(req->queue.next, - struct langwell_request, queue); - - /* point the dQH to the first dTD of next request */ - writel((u32) next_req->head, &dqh->dqh_current); - } - } else { - struct langwell_request *prev_req; - - prev_req = list_entry(req->queue.prev, - struct langwell_request, queue); - writel(readl(&req->tail->dtd_next), - &prev_req->tail->dtd_next); - } - - done(ep, req, -ECONNRESET); - -done: - /* enable endpoint again */ - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - if (is_in(ep)) - endptctrl |= EPCTRL_TXE; - else - endptctrl |= EPCTRL_RXE; - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - ep->stopped = stopped; - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/*-------------------------------------------------------------------------*/ - -/* endpoint set/clear halt */ -static void ep_set_halt(struct langwell_ep *ep, int value) -{ - u32 endptctrl = 0; - int ep_num; - struct langwell_udc *dev = ep->dev; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - ep_num = ep->ep_num; - endptctrl = readl(&dev->op_regs->endptctrl[ep_num]); - - /* value: 1 - set halt, 0 - clear halt */ - if (value) { - /* set the stall bit */ - if (is_in(ep)) - endptctrl |= EPCTRL_TXS; - else - endptctrl |= EPCTRL_RXS; - } else { - /* clear the stall bit and reset data toggle */ - if (is_in(ep)) { - endptctrl &= ~EPCTRL_TXS; - endptctrl |= EPCTRL_TXR; - } else { - endptctrl &= ~EPCTRL_RXS; - endptctrl |= EPCTRL_RXR; - } - } - - writel(endptctrl, &dev->op_regs->endptctrl[ep_num]); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* set the endpoint halt feature */ -static int langwell_ep_set_halt(struct usb_ep *_ep, int value) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - unsigned long flags; - int retval = 0; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) - return -EINVAL; - - if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN) - return -ESHUTDOWN; - - if (usb_endpoint_xfer_isoc(ep->desc)) - return -EOPNOTSUPP; - - spin_lock_irqsave(&dev->lock, flags); - - /* - * attempt to halt IN ep will fail if any transfer requests - * are still queue - */ - if (!list_empty(&ep->queue) && is_in(ep) && value) { - /* IN endpoint FIFO holds bytes */ - dev_dbg(&dev->pdev->dev, "%s FIFO holds bytes\n", _ep->name); - retval = -EAGAIN; - goto done; - } - - /* endpoint set/clear halt */ - if (ep->ep_num) { - ep_set_halt(ep, value); - } else { /* endpoint 0 */ - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - } -done: - spin_unlock_irqrestore(&dev->lock, flags); - dev_dbg(&dev->pdev->dev, "%s %s halt\n", - _ep->name, value ? "set" : "clear"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/* set the halt feature and ignores clear requests */ -static int langwell_ep_set_wedge(struct usb_ep *_ep) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) - return -EINVAL; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return usb_ep_set_halt(_ep); -} - - -/* flush contents of a fifo */ -static void langwell_ep_fifo_flush(struct usb_ep *_ep) -{ - struct langwell_ep *ep; - struct langwell_udc *dev; - u32 flush_bit; - unsigned long timeout; - - ep = container_of(_ep, struct langwell_ep, ep); - dev = ep->dev; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (!_ep || !ep->desc) { - dev_vdbg(&dev->pdev->dev, "ep or ep->desc is NULL\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return; - } - - dev_vdbg(&dev->pdev->dev, "%s-%s fifo flush\n", - _ep->name, DIR_STRING(ep)); - - /* flush endpoint buffer */ - if (ep->ep_num == 0) - flush_bit = (1 << 16) | 1; - else if (is_in(ep)) - flush_bit = 1 << (ep->ep_num + 16); /* TX */ - else - flush_bit = 1 << ep->ep_num; /* RX */ - - /* wait until flush complete */ - timeout = jiffies + FLUSH_TIMEOUT; - do { - writel(flush_bit, &dev->op_regs->endptflush); - while (readl(&dev->op_regs->endptflush)) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "ep flush timeout\n"); - goto done; - } - cpu_relax(); - } - } while (readl(&dev->op_regs->endptstat) & flush_bit); -done: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* endpoints operations structure */ -static const struct usb_ep_ops langwell_ep_ops = { - - /* configure endpoint, making it usable */ - .enable = langwell_ep_enable, - - /* endpoint is no longer usable */ - .disable = langwell_ep_disable, - - /* allocate a request object to use with this endpoint */ - .alloc_request = langwell_alloc_request, - - /* free a request object */ - .free_request = langwell_free_request, - - /* queue (submits) an I/O requests to an endpoint */ - .queue = langwell_ep_queue, - - /* dequeue (cancels, unlinks) an I/O request from an endpoint */ - .dequeue = langwell_ep_dequeue, - - /* set the endpoint halt feature */ - .set_halt = langwell_ep_set_halt, - - /* set the halt feature and ignores clear requests */ - .set_wedge = langwell_ep_set_wedge, - - /* flush contents of a fifo */ - .fifo_flush = langwell_ep_fifo_flush, -}; - - -/*-------------------------------------------------------------------------*/ - -/* device controller usb_gadget_ops structure */ - -/* returns the current frame number */ -static int langwell_get_frame(struct usb_gadget *_gadget) -{ - struct langwell_udc *dev; - u16 retval; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - retval = readl(&dev->op_regs->frindex) & FRINDEX_MASK; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/* enter or exit PHY low power state */ -static void langwell_phy_low_power(struct langwell_udc *dev, bool flag) -{ - u32 devlc; - u8 devlc_byte2; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc); - - if (flag) - devlc |= LPM_PHCD; - else - devlc &= ~LPM_PHCD; - - /* FIXME: workaround for Langwell A1/A2/A3 sighting */ - devlc_byte2 = (devlc >> 16) & 0xff; - writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2); - - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, - "%s PHY low power suspend, devlc = 0x%08x\n", - flag ? "enter" : "exit", devlc); -} - - -/* tries to wake up the host connected to this gadget */ -static int langwell_wakeup(struct usb_gadget *_gadget) -{ - struct langwell_udc *dev; - u32 portsc1; - unsigned long flags; - - if (!_gadget) - return 0; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* remote wakeup feature not enabled by host */ - if (!dev->remote_wakeup) { - dev_info(&dev->pdev->dev, "remote wakeup is disabled\n"); - return -ENOTSUPP; - } - - spin_lock_irqsave(&dev->lock, flags); - - portsc1 = readl(&dev->op_regs->portsc1); - if (!(portsc1 & PORTS_SUSP)) { - spin_unlock_irqrestore(&dev->lock, flags); - return 0; - } - - /* LPM L1 to L0 or legacy remote wakeup */ - if (dev->lpm && dev->lpm_state == LPM_L1) - dev_info(&dev->pdev->dev, "LPM L1 to L0 remote wakeup\n"); - else - dev_info(&dev->pdev->dev, "device remote wakeup\n"); - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* force port resume */ - portsc1 |= PORTS_FPR; - writel(portsc1, &dev->op_regs->portsc1); - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* notify controller that VBUS is powered or not */ -static int langwell_vbus_session(struct usb_gadget *_gadget, int is_active) -{ - struct langwell_udc *dev; - unsigned long flags; - u32 usbcmd; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - dev_vdbg(&dev->pdev->dev, "VBUS status: %s\n", - is_active ? "on" : "off"); - - dev->vbus_active = (is_active != 0); - if (dev->driver && dev->softconnected && dev->vbus_active) { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } else { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } - - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* constrain controller's VBUS power usage */ -static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA) -{ - struct langwell_udc *dev; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->transceiver) { - dev_vdbg(&dev->pdev->dev, "usb_phy_set_power\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return usb_phy_set_power(dev->transceiver, mA); - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return -ENOTSUPP; -} - - -/* D+ pullup, software-controlled connect/disconnect to USB host */ -static int langwell_pullup(struct usb_gadget *_gadget, int is_on) -{ - struct langwell_udc *dev; - u32 usbcmd; - unsigned long flags; - - if (!_gadget) - return -ENODEV; - - dev = container_of(_gadget, struct langwell_udc, gadget); - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - dev->softconnected = (is_on != 0); - - if (dev->driver && dev->softconnected && dev->vbus_active) { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } else { - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - } - spin_unlock_irqrestore(&dev->lock, flags); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - -static int langwell_start(struct usb_gadget *g, - struct usb_gadget_driver *driver); - -static int langwell_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver); - -/* device controller usb_gadget_ops structure */ -static const struct usb_gadget_ops langwell_ops = { - - /* returns the current frame number */ - .get_frame = langwell_get_frame, - - /* tries to wake up the host connected to this gadget */ - .wakeup = langwell_wakeup, - - /* set the device selfpowered feature, always selfpowered */ - /* .set_selfpowered = langwell_set_selfpowered, */ - - /* notify controller that VBUS is powered or not */ - .vbus_session = langwell_vbus_session, - - /* constrain controller's VBUS power usage */ - .vbus_draw = langwell_vbus_draw, - - /* D+ pullup, software-controlled connect/disconnect to USB host */ - .pullup = langwell_pullup, - - .udc_start = langwell_start, - .udc_stop = langwell_stop, -}; - - -/*-------------------------------------------------------------------------*/ - -/* device controller operations */ - -/* reset device controller */ -static int langwell_udc_reset(struct langwell_udc *dev) -{ - u32 usbcmd, usbmode, devlc, endpointlistaddr; - u8 devlc_byte0, devlc_byte2; - unsigned long timeout; - - if (!dev) - return -EINVAL; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* set controller to stop state */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - - /* reset device controller */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RST; - writel(usbcmd, &dev->op_regs->usbcmd); - - /* wait for reset to complete */ - timeout = jiffies + RESET_TIMEOUT; - while (readl(&dev->op_regs->usbcmd) & CMD_RST) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "device reset timeout\n"); - return -ETIMEDOUT; - } - cpu_relax(); - } - - /* set controller to device mode */ - usbmode = readl(&dev->op_regs->usbmode); - usbmode |= MODE_DEVICE; - - /* turn setup lockout off, require setup tripwire in usbcmd */ - usbmode |= MODE_SLOM; - - writel(usbmode, &dev->op_regs->usbmode); - usbmode = readl(&dev->op_regs->usbmode); - dev_vdbg(&dev->pdev->dev, "usbmode=0x%08x\n", usbmode); - - /* Write-Clear setup status */ - writel(0, &dev->op_regs->usbsts); - - /* if support USB LPM, ACK all LPM token */ - if (dev->lpm) { - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, "devlc = 0x%08x\n", devlc); - /* FIXME: workaround for Langwell A1/A2/A3 sighting */ - devlc &= ~LPM_STL; /* don't STALL LPM token */ - devlc &= ~LPM_NYT_ACK; /* ACK LPM token */ - devlc_byte0 = devlc & 0xff; - devlc_byte2 = (devlc >> 16) & 0xff; - writeb(devlc_byte0, (u8 *)&dev->op_regs->devlc); - writeb(devlc_byte2, (u8 *)&dev->op_regs->devlc + 2); - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, - "ACK LPM token, devlc = 0x%08x\n", devlc); - } - - /* fill endpointlistaddr register */ - endpointlistaddr = dev->ep_dqh_dma; - endpointlistaddr &= ENDPOINTLISTADDR_MASK; - writel(endpointlistaddr, &dev->op_regs->endpointlistaddr); - - dev_vdbg(&dev->pdev->dev, - "dQH base (vir: %p, phy: 0x%08x), endpointlistaddr=0x%08x\n", - dev->ep_dqh, endpointlistaddr, - readl(&dev->op_regs->endpointlistaddr)); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* reinitialize device controller endpoints */ -static int eps_reinit(struct langwell_udc *dev) -{ - struct langwell_ep *ep; - char name[14]; - int i; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* initialize ep0 */ - ep = &dev->ep[0]; - ep->dev = dev; - strncpy(ep->name, "ep0", sizeof(ep->name)); - ep->ep.name = ep->name; - ep->ep.ops = &langwell_ep_ops; - ep->stopped = 0; - ep->ep.maxpacket = EP0_MAX_PKT_SIZE; - ep->ep_num = 0; - ep->desc = &langwell_ep0_desc; - INIT_LIST_HEAD(&ep->queue); - - ep->ep_type = USB_ENDPOINT_XFER_CONTROL; - - /* initialize other endpoints */ - for (i = 2; i < dev->ep_max; i++) { - ep = &dev->ep[i]; - if (i % 2) - snprintf(name, sizeof(name), "ep%din", i / 2); - else - snprintf(name, sizeof(name), "ep%dout", i / 2); - ep->dev = dev; - strncpy(ep->name, name, sizeof(ep->name)); - ep->ep.name = ep->name; - - ep->ep.ops = &langwell_ep_ops; - ep->stopped = 0; - ep->ep.maxpacket = (unsigned short) ~0; - ep->ep_num = i / 2; - - INIT_LIST_HEAD(&ep->queue); - list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list); - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* enable interrupt and set controller to run state */ -static void langwell_udc_start(struct langwell_udc *dev) -{ - u32 usbintr, usbcmd; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* enable interrupts */ - usbintr = INTR_ULPIE /* ULPI */ - | INTR_SLE /* suspend */ - /* | INTR_SRE SOF received */ - | INTR_URE /* USB reset */ - | INTR_AAE /* async advance */ - | INTR_SEE /* system error */ - | INTR_FRE /* frame list rollover */ - | INTR_PCE /* port change detect */ - | INTR_UEE /* USB error interrupt */ - | INTR_UE; /* USB interrupt */ - writel(usbintr, &dev->op_regs->usbintr); - - /* clear stopped bit */ - dev->stopped = 0; - - /* set controller to run */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd |= CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* disable interrupt and set controller to stop state */ -static void langwell_udc_stop(struct langwell_udc *dev) -{ - u32 usbcmd; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* disable all interrupts */ - writel(0, &dev->op_regs->usbintr); - - /* set stopped bit */ - dev->stopped = 1; - - /* set controller to stop state */ - usbcmd = readl(&dev->op_regs->usbcmd); - usbcmd &= ~CMD_RUNSTOP; - writel(usbcmd, &dev->op_regs->usbcmd); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* stop all USB activities */ -static void stop_activity(struct langwell_udc *dev) -{ - struct langwell_ep *ep; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - nuke(&dev->ep[0], -ESHUTDOWN); - - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - nuke(ep, -ESHUTDOWN); - } - - /* report disconnect; the driver is already quiesced */ - if (dev->driver) { - spin_unlock(&dev->lock); - dev->driver->disconnect(&dev->gadget); - spin_lock(&dev->lock); - } - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/*-------------------------------------------------------------------------*/ - -/* device "function" sysfs attribute file */ -static ssize_t show_function(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - - if (!dev->driver || !dev->driver->function - || strlen(dev->driver->function) > PAGE_SIZE) - return 0; - - return scnprintf(buf, PAGE_SIZE, "%s\n", dev->driver->function); -} -static DEVICE_ATTR(function, S_IRUGO, show_function, NULL); - - -static inline enum usb_device_speed lpm_device_speed(u32 reg) -{ - switch (LPM_PSPD(reg)) { - case LPM_SPEED_HIGH: - return USB_SPEED_HIGH; - case LPM_SPEED_FULL: - return USB_SPEED_FULL; - case LPM_SPEED_LOW: - return USB_SPEED_LOW; - default: - return USB_SPEED_UNKNOWN; - } -} - -/* device "langwell_udc" sysfs attribute file */ -static ssize_t show_langwell_udc(struct device *_dev, - struct device_attribute *attr, char *buf) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - struct langwell_request *req; - struct langwell_ep *ep = NULL; - char *next; - unsigned size; - unsigned t; - unsigned i; - unsigned long flags; - u32 tmp_reg; - - next = buf; - size = PAGE_SIZE; - spin_lock_irqsave(&dev->lock, flags); - - /* driver basic information */ - t = scnprintf(next, size, - DRIVER_DESC "\n" - "%s version: %s\n" - "Gadget driver: %s\n\n", - driver_name, DRIVER_VERSION, - dev->driver ? dev->driver->driver.name : "(none)"); - size -= t; - next += t; - - /* device registers */ - tmp_reg = readl(&dev->op_regs->usbcmd); - t = scnprintf(next, size, - "USBCMD reg:\n" - "SetupTW: %d\n" - "Run/Stop: %s\n\n", - (tmp_reg & CMD_SUTW) ? 1 : 0, - (tmp_reg & CMD_RUNSTOP) ? "Run" : "Stop"); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->usbsts); - t = scnprintf(next, size, - "USB Status Reg:\n" - "Device Suspend: %d\n" - "Reset Received: %d\n" - "System Error: %s\n" - "USB Error Interrupt: %s\n\n", - (tmp_reg & STS_SLI) ? 1 : 0, - (tmp_reg & STS_URI) ? 1 : 0, - (tmp_reg & STS_SEI) ? "Error" : "No error", - (tmp_reg & STS_UEI) ? "Error detected" : "No error"); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->usbintr); - t = scnprintf(next, size, - "USB Intrrupt Enable Reg:\n" - "Sleep Enable: %d\n" - "SOF Received Enable: %d\n" - "Reset Enable: %d\n" - "System Error Enable: %d\n" - "Port Change Dectected Enable: %d\n" - "USB Error Intr Enable: %d\n" - "USB Intr Enable: %d\n\n", - (tmp_reg & INTR_SLE) ? 1 : 0, - (tmp_reg & INTR_SRE) ? 1 : 0, - (tmp_reg & INTR_URE) ? 1 : 0, - (tmp_reg & INTR_SEE) ? 1 : 0, - (tmp_reg & INTR_PCE) ? 1 : 0, - (tmp_reg & INTR_UEE) ? 1 : 0, - (tmp_reg & INTR_UE) ? 1 : 0); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->frindex); - t = scnprintf(next, size, - "USB Frame Index Reg:\n" - "Frame Number is 0x%08x\n\n", - (tmp_reg & FRINDEX_MASK)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->deviceaddr); - t = scnprintf(next, size, - "USB Device Address Reg:\n" - "Device Addr is 0x%x\n\n", - USBADR(tmp_reg)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->endpointlistaddr); - t = scnprintf(next, size, - "USB Endpoint List Address Reg:\n" - "Endpoint List Pointer is 0x%x\n\n", - EPBASE(tmp_reg)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->portsc1); - t = scnprintf(next, size, - "USB Port Status & Control Reg:\n" - "Port Reset: %s\n" - "Port Suspend Mode: %s\n" - "Over-current Change: %s\n" - "Port Enable/Disable Change: %s\n" - "Port Enabled/Disabled: %s\n" - "Current Connect Status: %s\n" - "LPM Suspend Status: %s\n\n", - (tmp_reg & PORTS_PR) ? "Reset" : "Not Reset", - (tmp_reg & PORTS_SUSP) ? "Suspend " : "Not Suspend", - (tmp_reg & PORTS_OCC) ? "Detected" : "No", - (tmp_reg & PORTS_PEC) ? "Changed" : "Not Changed", - (tmp_reg & PORTS_PE) ? "Enable" : "Not Correct", - (tmp_reg & PORTS_CCS) ? "Attached" : "Not Attached", - (tmp_reg & PORTS_SLP) ? "LPM L1" : "LPM L0"); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->devlc); - t = scnprintf(next, size, - "Device LPM Control Reg:\n" - "Parallel Transceiver : %d\n" - "Serial Transceiver : %d\n" - "Port Speed: %s\n" - "Port Force Full Speed Connenct: %s\n" - "PHY Low Power Suspend Clock: %s\n" - "BmAttributes: %d\n\n", - LPM_PTS(tmp_reg), - (tmp_reg & LPM_STS) ? 1 : 0, - usb_speed_string(lpm_device_speed(tmp_reg)), - (tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force", - (tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled", - LPM_BA(tmp_reg)); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->usbmode); - t = scnprintf(next, size, - "USB Mode Reg:\n" - "Controller Mode is : %s\n\n", ({ - char *s; - switch (MODE_CM(tmp_reg)) { - case MODE_IDLE: - s = "Idle"; break; - case MODE_DEVICE: - s = "Device Controller"; break; - case MODE_HOST: - s = "Host Controller"; break; - default: - s = "None"; break; - } - s; - })); - size -= t; - next += t; - - tmp_reg = readl(&dev->op_regs->endptsetupstat); - t = scnprintf(next, size, - "Endpoint Setup Status Reg:\n" - "SETUP on ep 0x%04x\n\n", - tmp_reg & SETUPSTAT_MASK); - size -= t; - next += t; - - for (i = 0; i < dev->ep_max / 2; i++) { - tmp_reg = readl(&dev->op_regs->endptctrl[i]); - t = scnprintf(next, size, "EP Ctrl Reg [%d]: 0x%08x\n", - i, tmp_reg); - size -= t; - next += t; - } - tmp_reg = readl(&dev->op_regs->endptprime); - t = scnprintf(next, size, "EP Prime Reg: 0x%08x\n\n", tmp_reg); - size -= t; - next += t; - - /* langwell_udc, langwell_ep, langwell_request structure information */ - ep = &dev->ep[0]; - t = scnprintf(next, size, "%s MaxPacketSize: 0x%x, ep_num: %d\n", - ep->ep.name, ep->ep.maxpacket, ep->ep_num); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length 0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } - } - /* other gadget->eplist ep */ - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - if (ep->desc) { - t = scnprintf(next, size, - "\n%s MaxPacketSize: 0x%x, " - "ep_num: %d\n", - ep->ep.name, ep->ep.maxpacket, - ep->ep_num); - size -= t; - next += t; - - if (list_empty(&ep->queue)) { - t = scnprintf(next, size, - "its req queue is empty\n\n"); - size -= t; - next += t; - } else { - list_for_each_entry(req, &ep->queue, queue) { - t = scnprintf(next, size, - "req %p actual 0x%x length " - "0x%x buf %p\n", - &req->req, req->req.actual, - req->req.length, req->req.buf); - size -= t; - next += t; - } - } - } - } - - spin_unlock_irqrestore(&dev->lock, flags); - return PAGE_SIZE - size; -} -static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL); - - -/* device "remote_wakeup" sysfs attribute file */ -static ssize_t store_remote_wakeup(struct device *_dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - unsigned long flags; - ssize_t rc = count; - - if (count > 2) - return -EINVAL; - - if (count > 0 && buf[count-1] == '\n') - ((char *) buf)[count-1] = 0; - - if (buf[0] != '1') - return -EINVAL; - - /* force remote wakeup enabled in case gadget driver doesn't support */ - spin_lock_irqsave(&dev->lock, flags); - dev->remote_wakeup = 1; - dev->dev_status |= (1 << USB_DEVICE_REMOTE_WAKEUP); - spin_unlock_irqrestore(&dev->lock, flags); - - langwell_wakeup(&dev->gadget); - - return rc; -} -static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup); - - -/*-------------------------------------------------------------------------*/ - -/* - * 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. - */ - -static int langwell_start(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct langwell_udc *dev = gadget_to_langwell(g); - unsigned long flags; - int retval; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - spin_lock_irqsave(&dev->lock, flags); - - /* hook up the driver ... */ - driver->driver.bus = NULL; - dev->driver = driver; - dev->gadget.dev.driver = &driver->driver; - - spin_unlock_irqrestore(&dev->lock, flags); - - retval = device_create_file(&dev->pdev->dev, &dev_attr_function); - if (retval) - goto err; - - dev->usb_state = USB_STATE_ATTACHED; - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - /* enable interrupt and set controller to run state */ - if (dev->got_irq) - langwell_udc_start(dev); - - dev_vdbg(&dev->pdev->dev, - "After langwell_udc_start(), print all registers:\n"); - print_all_registers(dev); - - dev_info(&dev->pdev->dev, "register driver: %s\n", - driver->driver.name); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return 0; - -err: - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return retval; -} - -/* unregister gadget driver */ -static int langwell_stop(struct usb_gadget *g, - struct usb_gadget_driver *driver) -{ - struct langwell_udc *dev = gadget_to_langwell(g); - unsigned long flags; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* unbind OTG transceiver */ - if (dev->transceiver) - (void)otg_set_peripheral(dev->transceiver->otg, 0); - - /* disable interrupt and set controller to stop state */ - langwell_udc_stop(dev); - - dev->usb_state = USB_STATE_ATTACHED; - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - spin_lock_irqsave(&dev->lock, flags); - - /* stop all usb activities */ - dev->gadget.speed = USB_SPEED_UNKNOWN; - dev->gadget.dev.driver = NULL; - dev->driver = NULL; - stop_activity(dev); - spin_unlock_irqrestore(&dev->lock, flags); - - device_remove_file(&dev->pdev->dev, &dev_attr_function); - - dev_info(&dev->pdev->dev, "unregistered driver '%s'\n", - driver->driver.name); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - return 0; -} - -/*-------------------------------------------------------------------------*/ - -/* - * setup tripwire is used as a semaphore to ensure that the setup data - * payload is extracted from a dQH without being corrupted - */ -static void setup_tripwire(struct langwell_udc *dev) -{ - u32 usbcmd, - endptsetupstat; - unsigned long timeout; - struct langwell_dqh *dqh; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* ep0 OUT dQH */ - dqh = &dev->ep_dqh[EP_DIR_OUT]; - - /* Write-Clear endptsetupstat */ - endptsetupstat = readl(&dev->op_regs->endptsetupstat); - writel(endptsetupstat, &dev->op_regs->endptsetupstat); - - /* wait until endptsetupstat is cleared */ - timeout = jiffies + SETUPSTAT_TIMEOUT; - while (readl(&dev->op_regs->endptsetupstat)) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "setup_tripwire timeout\n"); - break; - } - cpu_relax(); - } - - /* while a hazard exists when setup packet arrives */ - do { - /* set setup tripwire bit */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd | CMD_SUTW, &dev->op_regs->usbcmd); - - /* copy the setup packet to local buffer */ - memcpy(&dev->local_setup_buff, &dqh->dqh_setup, 8); - } while (!(readl(&dev->op_regs->usbcmd) & CMD_SUTW)); - - /* Write-Clear setup tripwire bit */ - usbcmd = readl(&dev->op_regs->usbcmd); - writel(usbcmd & ~CMD_SUTW, &dev->op_regs->usbcmd); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* protocol ep0 stall, will automatically be cleared on new transaction */ -static void ep0_stall(struct langwell_udc *dev) -{ - u32 endptctrl; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* set TX and RX to stall */ - endptctrl = readl(&dev->op_regs->endptctrl[0]); - endptctrl |= EPCTRL_TXS | EPCTRL_RXS; - writel(endptctrl, &dev->op_regs->endptctrl[0]); - - /* update ep0 state */ - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* PRIME a status phase for ep0 */ -static int prime_status_phase(struct langwell_udc *dev, int dir) -{ - struct langwell_request *req; - struct langwell_ep *ep; - int status = 0; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dir == EP_DIR_IN) - dev->ep0_dir = USB_DIR_IN; - else - dev->ep0_dir = USB_DIR_OUT; - - ep = &dev->ep[0]; - dev->ep0_state = WAIT_FOR_OUT_STATUS; - - req = dev->status_req; - - req->ep = ep; - req->req.length = 0; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - if (!req_to_dtd(req)) - status = queue_dtd(ep, req); - else - return -ENOMEM; - - if (status) - dev_err(&dev->pdev->dev, "can't queue ep0 status request\n"); - - list_add_tail(&req->queue, &ep->queue); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return status; -} - - -/* SET_ADDRESS request routine */ -static void set_address(struct langwell_udc *dev, u16 value, - u16 index, u16 length) -{ - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* save the new address to device struct */ - dev->dev_addr = (u8) value; - dev_vdbg(&dev->pdev->dev, "dev->dev_addr = %d\n", dev->dev_addr); - - /* update usb state */ - dev->usb_state = USB_STATE_ADDRESS; - - /* STATUS phase */ - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* return endpoint by windex */ -static struct langwell_ep *get_ep_by_windex(struct langwell_udc *dev, - u16 wIndex) -{ - struct langwell_ep *ep; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0) - return &dev->ep[0]; - - list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) { - u8 bEndpointAddress; - if (!ep->desc) - continue; - - bEndpointAddress = ep->desc->bEndpointAddress; - if ((wIndex ^ bEndpointAddress) & USB_DIR_IN) - continue; - - if ((wIndex & USB_ENDPOINT_NUMBER_MASK) - == (bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) - return ep; - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return NULL; -} - - -/* return whether endpoint is stalled, 0: not stalled; 1: stalled */ -static int ep_is_stall(struct langwell_ep *ep) -{ - struct langwell_udc *dev = ep->dev; - u32 endptctrl; - int retval; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - endptctrl = readl(&dev->op_regs->endptctrl[ep->ep_num]); - if (is_in(ep)) - retval = endptctrl & EPCTRL_TXS ? 1 : 0; - else - retval = endptctrl & EPCTRL_RXS ? 1 : 0; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return retval; -} - - -/* GET_STATUS request routine */ -static void get_status(struct langwell_udc *dev, u8 request_type, u16 value, - u16 index, u16 length) -{ - struct langwell_request *req; - struct langwell_ep *ep; - u16 status_data = 0; /* 16 bits cpu view status data */ - int status = 0; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - ep = &dev->ep[0]; - - if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) { - /* get device status */ - status_data = dev->dev_status; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) { - /* get interface status */ - status_data = 0; - } else if ((request_type & USB_RECIP_MASK) == USB_RECIP_ENDPOINT) { - /* get endpoint status */ - struct langwell_ep *epn; - epn = get_ep_by_windex(dev, index); - /* stall if endpoint doesn't exist */ - if (!epn) - goto stall; - - status_data = ep_is_stall(epn) << USB_ENDPOINT_HALT; - } - - dev_dbg(&dev->pdev->dev, "get status data: 0x%04x\n", status_data); - - dev->ep0_dir = USB_DIR_IN; - - /* borrow the per device status_req */ - req = dev->status_req; - - /* fill in the reqest structure */ - *((u16 *) req->req.buf) = cpu_to_le16(status_data); - req->ep = ep; - req->req.length = 2; - req->req.status = -EINPROGRESS; - req->req.actual = 0; - req->req.complete = NULL; - req->dtd_count = 0; - - /* prime the data phase */ - if (!req_to_dtd(req)) - status = queue_dtd(ep, req); - else /* no mem */ - goto stall; - - if (status) { - dev_err(&dev->pdev->dev, - "response error on GET_STATUS request\n"); - goto stall; - } - - list_add_tail(&req->queue, &ep->queue); - dev->ep0_state = DATA_STATE_XMIT; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return; -stall: - ep0_stall(dev); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* setup packet interrupt handler */ -static void handle_setup_packet(struct langwell_udc *dev, - struct usb_ctrlrequest *setup) -{ - u16 wValue = le16_to_cpu(setup->wValue); - u16 wIndex = le16_to_cpu(setup->wIndex); - u16 wLength = le16_to_cpu(setup->wLength); - u32 portsc1; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* ep0 fifo flush */ - nuke(&dev->ep[0], -ESHUTDOWN); - - dev_dbg(&dev->pdev->dev, "SETUP %02x.%02x v%04x i%04x l%04x\n", - setup->bRequestType, setup->bRequest, - wValue, wIndex, wLength); - - /* RNDIS gadget delegate */ - if ((setup->bRequestType == 0x21) && (setup->bRequest == 0x00)) { - /* USB_CDC_SEND_ENCAPSULATED_COMMAND */ - goto delegate; - } - - /* USB_CDC_GET_ENCAPSULATED_RESPONSE */ - if ((setup->bRequestType == 0xa1) && (setup->bRequest == 0x01)) { - /* USB_CDC_GET_ENCAPSULATED_RESPONSE */ - goto delegate; - } - - /* We process some stardard setup requests here */ - switch (setup->bRequest) { - case USB_REQ_GET_STATUS: - dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_GET_STATUS\n"); - /* get status, DATA and STATUS phase */ - if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK)) - != (USB_DIR_IN | USB_TYPE_STANDARD)) - break; - get_status(dev, setup->bRequestType, wValue, wIndex, wLength); - goto end; - - case USB_REQ_SET_ADDRESS: - dev_dbg(&dev->pdev->dev, "SETUP: USB_REQ_SET_ADDRESS\n"); - /* STATUS phase */ - if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD - | USB_RECIP_DEVICE)) - break; - set_address(dev, wValue, wIndex, wLength); - goto end; - - case USB_REQ_CLEAR_FEATURE: - case USB_REQ_SET_FEATURE: - /* STATUS phase */ - { - int rc = -EOPNOTSUPP; - if (setup->bRequest == USB_REQ_SET_FEATURE) - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_FEATURE\n"); - else if (setup->bRequest == USB_REQ_CLEAR_FEATURE) - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_CLEAR_FEATURE\n"); - - if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK)) - == (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) { - struct langwell_ep *epn; - epn = get_ep_by_windex(dev, wIndex); - /* stall if endpoint doesn't exist */ - if (!epn) { - ep0_stall(dev); - goto end; - } - - if (wValue != 0 || wLength != 0 - || epn->ep_num > dev->ep_max) - break; - - spin_unlock(&dev->lock); - rc = langwell_ep_set_halt(&epn->ep, - (setup->bRequest == USB_REQ_SET_FEATURE) - ? 1 : 0); - spin_lock(&dev->lock); - - } else if ((setup->bRequestType & (USB_RECIP_MASK - | USB_TYPE_MASK)) == (USB_RECIP_DEVICE - | USB_TYPE_STANDARD)) { - rc = 0; - switch (wValue) { - case USB_DEVICE_REMOTE_WAKEUP: - if (setup->bRequest == USB_REQ_SET_FEATURE) { - dev->remote_wakeup = 1; - dev->dev_status |= (1 << wValue); - } else { - dev->remote_wakeup = 0; - dev->dev_status &= ~(1 << wValue); - } - break; - case USB_DEVICE_TEST_MODE: - dev_dbg(&dev->pdev->dev, "SETUP: TEST MODE\n"); - if ((wIndex & 0xff) || - (dev->gadget.speed != USB_SPEED_HIGH)) - ep0_stall(dev); - - switch (wIndex >> 8) { - case TEST_J: - case TEST_K: - case TEST_SE0_NAK: - case TEST_PACKET: - case TEST_FORCE_EN: - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - portsc1 = readl(&dev->op_regs->portsc1); - portsc1 |= (wIndex & 0xf00) << 8; - writel(portsc1, &dev->op_regs->portsc1); - goto end; - default: - rc = -EOPNOTSUPP; - } - break; - default: - rc = -EOPNOTSUPP; - break; - } - - if (!gadget_is_otg(&dev->gadget)) - break; - else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE) - dev->gadget.b_hnp_enable = 1; - else if (setup->bRequest == USB_DEVICE_A_HNP_SUPPORT) - dev->gadget.a_hnp_support = 1; - else if (setup->bRequest == - USB_DEVICE_A_ALT_HNP_SUPPORT) - dev->gadget.a_alt_hnp_support = 1; - else - break; - } else - break; - - if (rc == 0) { - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - } - goto end; - } - - case USB_REQ_GET_DESCRIPTOR: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_GET_DESCRIPTOR\n"); - goto delegate; - - case USB_REQ_SET_DESCRIPTOR: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_DESCRIPTOR unsupported\n"); - goto delegate; - - case USB_REQ_GET_CONFIGURATION: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_GET_CONFIGURATION\n"); - goto delegate; - - case USB_REQ_SET_CONFIGURATION: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_CONFIGURATION\n"); - goto delegate; - - case USB_REQ_GET_INTERFACE: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_GET_INTERFACE\n"); - goto delegate; - - case USB_REQ_SET_INTERFACE: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SET_INTERFACE\n"); - goto delegate; - - case USB_REQ_SYNCH_FRAME: - dev_dbg(&dev->pdev->dev, - "SETUP: USB_REQ_SYNCH_FRAME unsupported\n"); - goto delegate; - - default: - /* delegate USB standard requests to the gadget driver */ - goto delegate; -delegate: - /* USB requests handled by gadget */ - if (wLength) { - /* DATA phase from gadget, STATUS phase from udc */ - dev->ep0_dir = (setup->bRequestType & USB_DIR_IN) - ? USB_DIR_IN : USB_DIR_OUT; - dev_vdbg(&dev->pdev->dev, - "dev->ep0_dir = 0x%x, wLength = %d\n", - dev->ep0_dir, wLength); - spin_unlock(&dev->lock); - if (dev->driver->setup(&dev->gadget, - &dev->local_setup_buff) < 0) - ep0_stall(dev); - spin_lock(&dev->lock); - dev->ep0_state = (setup->bRequestType & USB_DIR_IN) - ? DATA_STATE_XMIT : DATA_STATE_RECV; - } else { - /* no DATA phase, IN STATUS phase from gadget */ - dev->ep0_dir = USB_DIR_IN; - dev_vdbg(&dev->pdev->dev, - "dev->ep0_dir = 0x%x, wLength = %d\n", - dev->ep0_dir, wLength); - spin_unlock(&dev->lock); - if (dev->driver->setup(&dev->gadget, - &dev->local_setup_buff) < 0) - ep0_stall(dev); - spin_lock(&dev->lock); - dev->ep0_state = WAIT_FOR_OUT_STATUS; - } - break; - } -end: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* transfer completion, process endpoint request and free the completed dTDs - * for this request - */ -static int process_ep_req(struct langwell_udc *dev, int index, - struct langwell_request *curr_req) -{ - struct langwell_dtd *curr_dtd; - struct langwell_dqh *curr_dqh; - int td_complete, actual, remaining_length; - int i, dir; - u8 dtd_status = 0; - int retval = 0; - - curr_dqh = &dev->ep_dqh[index]; - dir = index % 2; - - curr_dtd = curr_req->head; - td_complete = 0; - actual = curr_req->req.length; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - for (i = 0; i < curr_req->dtd_count; i++) { - - /* command execution states by dTD */ - dtd_status = curr_dtd->dtd_status; - - barrier(); - remaining_length = le16_to_cpu(curr_dtd->dtd_total); - actual -= remaining_length; - - if (!dtd_status) { - /* transfers completed successfully */ - if (!remaining_length) { - td_complete++; - dev_vdbg(&dev->pdev->dev, - "dTD transmitted successfully\n"); - } else { - if (dir) { - dev_vdbg(&dev->pdev->dev, - "TX dTD remains data\n"); - retval = -EPROTO; - break; - - } else { - td_complete++; - break; - } - } - } else { - /* transfers completed with errors */ - if (dtd_status & DTD_STS_ACTIVE) { - dev_dbg(&dev->pdev->dev, - "dTD status ACTIVE dQH[%d]\n", index); - retval = 1; - return retval; - } else if (dtd_status & DTD_STS_HALTED) { - dev_err(&dev->pdev->dev, - "dTD error %08x dQH[%d]\n", - dtd_status, index); - /* clear the errors and halt condition */ - curr_dqh->dtd_status = 0; - retval = -EPIPE; - break; - } else if (dtd_status & DTD_STS_DBE) { - dev_dbg(&dev->pdev->dev, - "data buffer (overflow) error\n"); - retval = -EPROTO; - break; - } else if (dtd_status & DTD_STS_TRE) { - dev_dbg(&dev->pdev->dev, - "transaction(ISO) error\n"); - retval = -EILSEQ; - break; - } else - dev_err(&dev->pdev->dev, - "unknown error (0x%x)!\n", - dtd_status); - } - - if (i != curr_req->dtd_count - 1) - curr_dtd = (struct langwell_dtd *) - curr_dtd->next_dtd_virt; - } - - if (retval) - return retval; - - curr_req->req.actual = actual; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* complete DATA or STATUS phase of ep0 prime status phase if needed */ -static void ep0_req_complete(struct langwell_udc *dev, - struct langwell_ep *ep0, struct langwell_request *req) -{ - u32 new_addr; - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->usb_state == USB_STATE_ADDRESS) { - /* set the new address */ - new_addr = (u32)dev->dev_addr; - writel(new_addr << USBADR_SHIFT, &dev->op_regs->deviceaddr); - - new_addr = USBADR(readl(&dev->op_regs->deviceaddr)); - dev_vdbg(&dev->pdev->dev, "new_addr = %d\n", new_addr); - } - - done(ep0, req, 0); - - switch (dev->ep0_state) { - case DATA_STATE_XMIT: - /* receive status phase */ - if (prime_status_phase(dev, EP_DIR_OUT)) - ep0_stall(dev); - break; - case DATA_STATE_RECV: - /* send status phase */ - if (prime_status_phase(dev, EP_DIR_IN)) - ep0_stall(dev); - break; - case WAIT_FOR_OUT_STATUS: - dev->ep0_state = WAIT_FOR_SETUP; - break; - case WAIT_FOR_SETUP: - dev_err(&dev->pdev->dev, "unexpect ep0 packets\n"); - break; - default: - ep0_stall(dev); - break; - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB transfer completion interrupt */ -static void handle_trans_complete(struct langwell_udc *dev) -{ - u32 complete_bits; - int i, ep_num, dir, bit_mask, status; - struct langwell_ep *epn; - struct langwell_request *curr_req, *temp_req; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - complete_bits = readl(&dev->op_regs->endptcomplete); - dev_vdbg(&dev->pdev->dev, "endptcomplete register: 0x%08x\n", - complete_bits); - - /* Write-Clear the bits in endptcomplete register */ - writel(complete_bits, &dev->op_regs->endptcomplete); - - if (!complete_bits) { - dev_dbg(&dev->pdev->dev, "complete_bits = 0\n"); - goto done; - } - - for (i = 0; i < dev->ep_max; i++) { - ep_num = i / 2; - dir = i % 2; - - bit_mask = 1 << (ep_num + 16 * dir); - - if (!(complete_bits & bit_mask)) - continue; - - /* ep0 */ - if (i == 1) - epn = &dev->ep[0]; - else - epn = &dev->ep[i]; - - if (epn->name == NULL) { - dev_warn(&dev->pdev->dev, "invalid endpoint\n"); - continue; - } - - if (i < 2) - /* ep0 in and out */ - dev_dbg(&dev->pdev->dev, "%s-%s transfer completed\n", - epn->name, - is_in(epn) ? "in" : "out"); - else - dev_dbg(&dev->pdev->dev, "%s transfer completed\n", - epn->name); - - /* process the req queue until an uncomplete request */ - list_for_each_entry_safe(curr_req, temp_req, - &epn->queue, queue) { - status = process_ep_req(dev, i, curr_req); - dev_vdbg(&dev->pdev->dev, "%s req status: %d\n", - epn->name, status); - - if (status) - break; - - /* write back status to req */ - curr_req->req.status = status; - - /* ep0 request completion */ - if (ep_num == 0) { - ep0_req_complete(dev, epn, curr_req); - break; - } else { - done(epn, curr_req, status); - } - } - } -done: - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - -/* port change detect interrupt handler */ -static void handle_port_change(struct langwell_udc *dev) -{ - u32 portsc1, devlc; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->bus_reset) - dev->bus_reset = 0; - - portsc1 = readl(&dev->op_regs->portsc1); - devlc = readl(&dev->op_regs->devlc); - dev_vdbg(&dev->pdev->dev, "portsc1 = 0x%08x, devlc = 0x%08x\n", - portsc1, devlc); - - /* bus reset is finished */ - if (!(portsc1 & PORTS_PR)) { - /* get the speed */ - dev->gadget.speed = lpm_device_speed(devlc); - dev_vdbg(&dev->pdev->dev, "dev->gadget.speed = %d\n", - dev->gadget.speed); - } - - /* LPM L0 to L1 */ - if (dev->lpm && dev->lpm_state == LPM_L0) - if (portsc1 & PORTS_SUSP && portsc1 & PORTS_SLP) { - dev_info(&dev->pdev->dev, "LPM L0 to L1\n"); - dev->lpm_state = LPM_L1; - } - - /* LPM L1 to L0, force resume or remote wakeup finished */ - if (dev->lpm && dev->lpm_state == LPM_L1) - if (!(portsc1 & PORTS_SUSP)) { - dev_info(&dev->pdev->dev, "LPM L1 to L0\n"); - dev->lpm_state = LPM_L0; - } - - /* update USB state */ - if (!dev->resume_state) - dev->usb_state = USB_STATE_DEFAULT; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB reset interrupt handler */ -static void handle_usb_reset(struct langwell_udc *dev) -{ - u32 deviceaddr, - endptsetupstat, - endptcomplete; - unsigned long timeout; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* Write-Clear the device address */ - deviceaddr = readl(&dev->op_regs->deviceaddr); - writel(deviceaddr & ~USBADR_MASK, &dev->op_regs->deviceaddr); - - dev->dev_addr = 0; - - /* clear usb state */ - dev->resume_state = 0; - - /* LPM L1 to L0, reset */ - if (dev->lpm) - dev->lpm_state = LPM_L0; - - dev->ep0_dir = USB_DIR_OUT; - dev->ep0_state = WAIT_FOR_SETUP; - - /* remote wakeup reset to 0 when the device is reset */ - dev->remote_wakeup = 0; - dev->dev_status = 1 << USB_DEVICE_SELF_POWERED; - dev->gadget.b_hnp_enable = 0; - dev->gadget.a_hnp_support = 0; - dev->gadget.a_alt_hnp_support = 0; - - /* Write-Clear all the setup token semaphores */ - endptsetupstat = readl(&dev->op_regs->endptsetupstat); - writel(endptsetupstat, &dev->op_regs->endptsetupstat); - - /* Write-Clear all the endpoint complete status bits */ - endptcomplete = readl(&dev->op_regs->endptcomplete); - writel(endptcomplete, &dev->op_regs->endptcomplete); - - /* wait until all endptprime bits cleared */ - timeout = jiffies + PRIME_TIMEOUT; - while (readl(&dev->op_regs->endptprime)) { - if (time_after(jiffies, timeout)) { - dev_err(&dev->pdev->dev, "USB reset timeout\n"); - break; - } - cpu_relax(); - } - - /* write 1s to endptflush register to clear any primed buffers */ - writel((u32) ~0, &dev->op_regs->endptflush); - - if (readl(&dev->op_regs->portsc1) & PORTS_PR) { - dev_vdbg(&dev->pdev->dev, "USB bus reset\n"); - /* bus is reseting */ - dev->bus_reset = 1; - - /* reset all the queues, stop all USB activities */ - stop_activity(dev); - dev->usb_state = USB_STATE_DEFAULT; - } else { - dev_vdbg(&dev->pdev->dev, "device controller reset\n"); - /* controller reset */ - langwell_udc_reset(dev); - - /* reset all the queues, stop all USB activities */ - stop_activity(dev); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(dev); - - /* enable interrupt and set controller to run state */ - langwell_udc_start(dev); - - dev->usb_state = USB_STATE_ATTACHED; - } - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB bus suspend/resume interrupt */ -static void handle_bus_suspend(struct langwell_udc *dev) -{ - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->resume_state = dev->usb_state; - dev->usb_state = USB_STATE_SUSPENDED; - - /* report suspend to the driver */ - if (dev->driver) { - if (dev->driver->suspend) { - spin_unlock(&dev->lock); - dev->driver->suspend(&dev->gadget); - spin_lock(&dev->lock); - dev_dbg(&dev->pdev->dev, "suspend %s\n", - dev->driver->driver.name); - } - } - - /* enter PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -static void handle_bus_resume(struct langwell_udc *dev) -{ - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->usb_state = dev->resume_state; - dev->resume_state = 0; - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* report resume to the driver */ - if (dev->driver) { - if (dev->driver->resume) { - spin_unlock(&dev->lock); - dev->driver->resume(&dev->gadget); - spin_lock(&dev->lock); - dev_dbg(&dev->pdev->dev, "resume %s\n", - dev->driver->driver.name); - } - } - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* USB device controller interrupt handler */ -static irqreturn_t langwell_irq(int irq, void *_dev) -{ - struct langwell_udc *dev = _dev; - u32 usbsts, - usbintr, - irq_sts, - portsc1; - - dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__); - - if (dev->stopped) { - dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return IRQ_NONE; - } - - spin_lock(&dev->lock); - - /* USB status */ - usbsts = readl(&dev->op_regs->usbsts); - - /* USB interrupt enable */ - usbintr = readl(&dev->op_regs->usbintr); - - irq_sts = usbsts & usbintr; - dev_vdbg(&dev->pdev->dev, - "usbsts = 0x%08x, usbintr = 0x%08x, irq_sts = 0x%08x\n", - usbsts, usbintr, irq_sts); - - if (!irq_sts) { - dev_vdbg(&dev->pdev->dev, "handle IRQ_NONE\n"); - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - spin_unlock(&dev->lock); - return IRQ_NONE; - } - - /* Write-Clear interrupt status bits */ - writel(irq_sts, &dev->op_regs->usbsts); - - /* resume from suspend */ - portsc1 = readl(&dev->op_regs->portsc1); - if (dev->usb_state == USB_STATE_SUSPENDED) - if (!(portsc1 & PORTS_SUSP)) - handle_bus_resume(dev); - - /* USB interrupt */ - if (irq_sts & STS_UI) { - dev_vdbg(&dev->pdev->dev, "USB interrupt\n"); - - /* setup packet received from ep0 */ - if (readl(&dev->op_regs->endptsetupstat) - & EP0SETUPSTAT_MASK) { - dev_vdbg(&dev->pdev->dev, - "USB SETUP packet received interrupt\n"); - /* setup tripwire semaphone */ - setup_tripwire(dev); - handle_setup_packet(dev, &dev->local_setup_buff); - } - - /* USB transfer completion */ - if (readl(&dev->op_regs->endptcomplete)) { - dev_vdbg(&dev->pdev->dev, - "USB transfer completion interrupt\n"); - handle_trans_complete(dev); - } - } - - /* SOF received interrupt (for ISO transfer) */ - if (irq_sts & STS_SRI) { - /* FIXME */ - /* dev_vdbg(&dev->pdev->dev, "SOF received interrupt\n"); */ - } - - /* port change detect interrupt */ - if (irq_sts & STS_PCI) { - dev_vdbg(&dev->pdev->dev, "port change detect interrupt\n"); - handle_port_change(dev); - } - - /* suspend interrupt */ - if (irq_sts & STS_SLI) { - dev_vdbg(&dev->pdev->dev, "suspend interrupt\n"); - handle_bus_suspend(dev); - } - - /* USB reset interrupt */ - if (irq_sts & STS_URI) { - dev_vdbg(&dev->pdev->dev, "USB reset interrupt\n"); - handle_usb_reset(dev); - } - - /* USB error or system error interrupt */ - if (irq_sts & (STS_UEI | STS_SEI)) { - /* FIXME */ - dev_warn(&dev->pdev->dev, "error IRQ, irq_sts: %x\n", irq_sts); - } - - spin_unlock(&dev->lock); - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return IRQ_HANDLED; -} - - -/*-------------------------------------------------------------------------*/ - -/* release device structure */ -static void gadget_release(struct device *_dev) -{ - struct langwell_udc *dev = dev_get_drvdata(_dev); - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - complete(dev->done); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - kfree(dev); -} - - -/* enable SRAM caching if SRAM detected */ -static void sram_init(struct langwell_udc *dev) -{ - struct pci_dev *pdev = dev->pdev; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->sram_addr = pci_resource_start(pdev, 1); - dev->sram_size = pci_resource_len(pdev, 1); - dev_info(&dev->pdev->dev, "Found private SRAM at %x size:%x\n", - dev->sram_addr, dev->sram_size); - dev->got_sram = 1; - - if (pci_request_region(pdev, 1, kobject_name(&pdev->dev.kobj))) { - dev_warn(&dev->pdev->dev, "SRAM request failed\n"); - dev->got_sram = 0; - } else if (!dma_declare_coherent_memory(&pdev->dev, dev->sram_addr, - dev->sram_addr, dev->sram_size, DMA_MEMORY_MAP)) { - dev_warn(&dev->pdev->dev, "SRAM DMA declare failed\n"); - pci_release_region(pdev, 1); - dev->got_sram = 0; - } - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* release SRAM caching */ -static void sram_deinit(struct langwell_udc *dev) -{ - struct pci_dev *pdev = dev->pdev; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dma_release_declared_memory(&pdev->dev); - pci_release_region(pdev, 1); - - dev->got_sram = 0; - - dev_info(&dev->pdev->dev, "release SRAM caching\n"); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - - -/* tear down the binding between this driver and the pci device */ -static void langwell_udc_remove(struct pci_dev *pdev) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - - DECLARE_COMPLETION(done); - - BUG_ON(dev->driver); - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - dev->done = &done; - - /* free dTD dma_pool and dQH */ - if (dev->dtd_pool) - dma_pool_destroy(dev->dtd_pool); - - if (dev->ep_dqh) - dma_free_coherent(&pdev->dev, dev->ep_dqh_size, - dev->ep_dqh, dev->ep_dqh_dma); - - /* release SRAM caching */ - if (dev->has_sram && dev->got_sram) - sram_deinit(dev); - - if (dev->status_req) { - kfree(dev->status_req->req.buf); - kfree(dev->status_req); - } - - kfree(dev->ep); - - /* disable IRQ handler */ - if (dev->got_irq) - free_irq(pdev->irq, dev); - - if (dev->cap_regs) - iounmap(dev->cap_regs); - - if (dev->region) - release_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - - if (dev->enabled) - pci_disable_device(pdev); - - dev->cap_regs = NULL; - - dev_info(&dev->pdev->dev, "unbind\n"); - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - - device_unregister(&dev->gadget.dev); - device_remove_file(&pdev->dev, &dev_attr_langwell_udc); - device_remove_file(&pdev->dev, &dev_attr_remote_wakeup); - - pci_set_drvdata(pdev, NULL); - - /* free dev, wait for the release() finished */ - wait_for_completion(&done); -} - - -/* - * wrap this driver around the specified device, but - * don't respond over USB until a gadget driver binds to us. - */ -static int langwell_udc_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - struct langwell_udc *dev; - unsigned long resource, len; - void __iomem *base = NULL; - size_t size; - int retval; - - /* alloc, and start init */ - dev = kzalloc(sizeof *dev, GFP_KERNEL); - if (dev == NULL) { - retval = -ENOMEM; - goto error; - } - - /* initialize device spinlock */ - spin_lock_init(&dev->lock); - - dev->pdev = pdev; - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - pci_set_drvdata(pdev, dev); - - /* now all the pci goodies ... */ - if (pci_enable_device(pdev) < 0) { - retval = -ENODEV; - goto error; - } - dev->enabled = 1; - - /* control register: BAR 0 */ - resource = pci_resource_start(pdev, 0); - len = pci_resource_len(pdev, 0); - if (!request_mem_region(resource, len, driver_name)) { - dev_err(&dev->pdev->dev, "controller already in use\n"); - retval = -EBUSY; - goto error; - } - dev->region = 1; - - base = ioremap_nocache(resource, len); - if (base == NULL) { - dev_err(&dev->pdev->dev, "can't map memory\n"); - retval = -EFAULT; - goto error; - } - - dev->cap_regs = (struct langwell_cap_regs __iomem *) base; - dev_vdbg(&dev->pdev->dev, "dev->cap_regs: %p\n", dev->cap_regs); - dev->op_regs = (struct langwell_op_regs __iomem *) - (base + OP_REG_OFFSET); - dev_vdbg(&dev->pdev->dev, "dev->op_regs: %p\n", dev->op_regs); - - /* irq setup after old hardware is cleaned up */ - if (!pdev->irq) { - dev_err(&dev->pdev->dev, "No IRQ. Check PCI setup!\n"); - retval = -ENODEV; - goto error; - } - - dev->has_sram = 1; - dev->got_sram = 0; - dev_vdbg(&dev->pdev->dev, "dev->has_sram: %d\n", dev->has_sram); - - /* enable SRAM caching if detected */ - if (dev->has_sram && !dev->got_sram) - sram_init(dev); - - dev_info(&dev->pdev->dev, - "irq %d, io mem: 0x%08lx, len: 0x%08lx, pci mem 0x%p\n", - pdev->irq, resource, len, base); - /* enables bus-mastering for device dev */ - pci_set_master(pdev); - - if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, - driver_name, dev) != 0) { - dev_err(&dev->pdev->dev, - "request interrupt %d failed\n", pdev->irq); - retval = -EBUSY; - goto error; - } - dev->got_irq = 1; - - /* set stopped bit */ - dev->stopped = 1; - - /* capabilities and endpoint number */ - dev->lpm = (readl(&dev->cap_regs->hccparams) & HCC_LEN) ? 1 : 0; - dev->dciversion = readw(&dev->cap_regs->dciversion); - dev->devcap = (readl(&dev->cap_regs->dccparams) & DEVCAP) ? 1 : 0; - dev_vdbg(&dev->pdev->dev, "dev->lpm: %d\n", dev->lpm); - dev_vdbg(&dev->pdev->dev, "dev->dciversion: 0x%04x\n", - dev->dciversion); - dev_vdbg(&dev->pdev->dev, "dccparams: 0x%08x\n", - readl(&dev->cap_regs->dccparams)); - dev_vdbg(&dev->pdev->dev, "dev->devcap: %d\n", dev->devcap); - if (!dev->devcap) { - dev_err(&dev->pdev->dev, "can't support device mode\n"); - retval = -ENODEV; - goto error; - } - - /* a pair of endpoints (out/in) for each address */ - dev->ep_max = DEN(readl(&dev->cap_regs->dccparams)) * 2; - dev_vdbg(&dev->pdev->dev, "dev->ep_max: %d\n", dev->ep_max); - - /* allocate endpoints memory */ - dev->ep = kzalloc(sizeof(struct langwell_ep) * dev->ep_max, - GFP_KERNEL); - if (!dev->ep) { - dev_err(&dev->pdev->dev, "allocate endpoints memory failed\n"); - retval = -ENOMEM; - goto error; - } - - /* allocate device dQH memory */ - size = dev->ep_max * sizeof(struct langwell_dqh); - dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size); - if (size < DQH_ALIGNMENT) - size = DQH_ALIGNMENT; - else if ((size % DQH_ALIGNMENT) != 0) { - size += DQH_ALIGNMENT + 1; - size &= ~(DQH_ALIGNMENT - 1); - } - dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size, - &dev->ep_dqh_dma, GFP_KERNEL); - if (!dev->ep_dqh) { - dev_err(&dev->pdev->dev, "allocate dQH memory failed\n"); - retval = -ENOMEM; - goto error; - } - dev->ep_dqh_size = size; - dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size); - - /* initialize ep0 status request structure */ - dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL); - if (!dev->status_req) { - dev_err(&dev->pdev->dev, - "allocate status_req memory failed\n"); - retval = -ENOMEM; - goto error; - } - INIT_LIST_HEAD(&dev->status_req->queue); - - /* allocate a small amount of memory to get valid address */ - dev->status_req->req.buf = kmalloc(8, GFP_KERNEL); - dev->status_req->req.dma = virt_to_phys(dev->status_req->req.buf); - - dev->resume_state = USB_STATE_NOTATTACHED; - dev->usb_state = USB_STATE_POWERED; - dev->ep0_dir = USB_DIR_OUT; - - /* remote wakeup reset to 0 when the device is reset */ - dev->remote_wakeup = 0; - dev->dev_status = 1 << USB_DEVICE_SELF_POWERED; - - /* reset device controller */ - langwell_udc_reset(dev); - - /* initialize gadget structure */ - dev->gadget.ops = &langwell_ops; /* usb_gadget_ops */ - dev->gadget.ep0 = &dev->ep[0].ep; /* gadget ep0 */ - INIT_LIST_HEAD(&dev->gadget.ep_list); /* ep_list */ - dev->gadget.speed = USB_SPEED_UNKNOWN; /* speed */ - dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */ - - /* the "gadget" abstracts/virtualizes the controller */ - dev_set_name(&dev->gadget.dev, "gadget"); - dev->gadget.dev.parent = &pdev->dev; - dev->gadget.dev.dma_mask = pdev->dev.dma_mask; - dev->gadget.dev.release = gadget_release; - dev->gadget.name = driver_name; /* gadget name */ - - /* controller endpoints reinit */ - eps_reinit(dev); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(dev); - - /* create dTD dma_pool resource */ - dev->dtd_pool = dma_pool_create("langwell_dtd", - &dev->pdev->dev, - sizeof(struct langwell_dtd), - DTD_ALIGNMENT, - DMA_BOUNDARY); - - if (!dev->dtd_pool) { - retval = -ENOMEM; - goto error; - } - - /* done */ - dev_info(&dev->pdev->dev, "%s\n", driver_desc); - dev_info(&dev->pdev->dev, "irq %d, pci mem %p\n", pdev->irq, base); - dev_info(&dev->pdev->dev, "Driver version: " DRIVER_VERSION "\n"); - dev_info(&dev->pdev->dev, "Support (max) %d endpoints\n", dev->ep_max); - dev_info(&dev->pdev->dev, "Device interface version: 0x%04x\n", - dev->dciversion); - dev_info(&dev->pdev->dev, "Controller mode: %s\n", - dev->devcap ? "Device" : "Host"); - dev_info(&dev->pdev->dev, "Support USB LPM: %s\n", - dev->lpm ? "Yes" : "No"); - - dev_vdbg(&dev->pdev->dev, - "After langwell_udc_probe(), print all registers:\n"); - print_all_registers(dev); - - retval = device_register(&dev->gadget.dev); - if (retval) - goto error; - - retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget); - if (retval) - goto error; - - retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc); - if (retval) - goto error; - - retval = device_create_file(&pdev->dev, &dev_attr_remote_wakeup); - if (retval) - goto error_attr1; - - dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; - -error_attr1: - device_remove_file(&pdev->dev, &dev_attr_langwell_udc); -error: - if (dev) { - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - langwell_udc_remove(pdev); - } - - return retval; -} - - -/* device controller suspend */ -static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - usb_del_gadget_udc(&dev->gadget); - /* disable interrupt and set controller to stop state */ - langwell_udc_stop(dev); - - /* disable IRQ handler */ - if (dev->got_irq) - free_irq(pdev->irq, dev); - dev->got_irq = 0; - - /* save PCI state */ - pci_save_state(pdev); - - spin_lock_irq(&dev->lock); - /* stop all usb activities */ - stop_activity(dev); - spin_unlock_irq(&dev->lock); - - /* free dTD dma_pool and dQH */ - if (dev->dtd_pool) - dma_pool_destroy(dev->dtd_pool); - - if (dev->ep_dqh) - dma_free_coherent(&pdev->dev, dev->ep_dqh_size, - dev->ep_dqh, dev->ep_dqh_dma); - - /* release SRAM caching */ - if (dev->has_sram && dev->got_sram) - sram_deinit(dev); - - /* set device power state */ - pci_set_power_state(pdev, PCI_D3hot); - - /* enter PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 1); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* device controller resume */ -static int langwell_udc_resume(struct pci_dev *pdev) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - size_t size; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* exit PHY low power suspend */ - if (dev->pdev->device != 0x0829) - langwell_phy_low_power(dev, 0); - - /* set device D0 power state */ - pci_set_power_state(pdev, PCI_D0); - - /* enable SRAM caching if detected */ - if (dev->has_sram && !dev->got_sram) - sram_init(dev); - - /* allocate device dQH memory */ - size = dev->ep_max * sizeof(struct langwell_dqh); - dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size); - if (size < DQH_ALIGNMENT) - size = DQH_ALIGNMENT; - else if ((size % DQH_ALIGNMENT) != 0) { - size += DQH_ALIGNMENT + 1; - size &= ~(DQH_ALIGNMENT - 1); - } - dev->ep_dqh = dma_alloc_coherent(&pdev->dev, size, - &dev->ep_dqh_dma, GFP_KERNEL); - if (!dev->ep_dqh) { - dev_err(&dev->pdev->dev, "allocate dQH memory failed\n"); - return -ENOMEM; - } - dev->ep_dqh_size = size; - dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size); - - /* create dTD dma_pool resource */ - dev->dtd_pool = dma_pool_create("langwell_dtd", - &dev->pdev->dev, - sizeof(struct langwell_dtd), - DTD_ALIGNMENT, - DMA_BOUNDARY); - - if (!dev->dtd_pool) - return -ENOMEM; - - /* restore PCI state */ - pci_restore_state(pdev); - - /* enable IRQ handler */ - if (request_irq(pdev->irq, langwell_irq, IRQF_SHARED, - driver_name, dev) != 0) { - dev_err(&dev->pdev->dev, "request interrupt %d failed\n", - pdev->irq); - return -EBUSY; - } - dev->got_irq = 1; - - /* reset and start controller to run state */ - if (dev->stopped) { - /* reset device controller */ - langwell_udc_reset(dev); - - /* reset ep0 dQH and endptctrl */ - ep0_reset(dev); - - /* start device if gadget is loaded */ - if (dev->driver) - langwell_udc_start(dev); - } - - /* reset USB status */ - dev->usb_state = USB_STATE_ATTACHED; - dev->ep0_state = WAIT_FOR_SETUP; - dev->ep0_dir = USB_DIR_OUT; - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); - return 0; -} - - -/* pci driver shutdown */ -static void langwell_udc_shutdown(struct pci_dev *pdev) -{ - struct langwell_udc *dev = pci_get_drvdata(pdev); - u32 usbmode; - - dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__); - - /* reset controller mode to IDLE */ - usbmode = readl(&dev->op_regs->usbmode); - dev_dbg(&dev->pdev->dev, "usbmode = 0x%08x\n", usbmode); - usbmode &= (~3 | MODE_IDLE); - writel(usbmode, &dev->op_regs->usbmode); - - dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__); -} - -/*-------------------------------------------------------------------------*/ - -static const struct pci_device_id pci_ids[] = { { - .class = ((PCI_CLASS_SERIAL_USB << 8) | 0xfe), - .class_mask = ~0, - .vendor = 0x8086, - .device = 0x0811, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, -}, { /* end: all zeroes */ } -}; - -MODULE_DEVICE_TABLE(pci, pci_ids); - - -static struct pci_driver langwell_pci_driver = { - .name = (char *) driver_name, - .id_table = pci_ids, - - .probe = langwell_udc_probe, - .remove = langwell_udc_remove, - - /* device controller suspend/resume */ - .suspend = langwell_udc_suspend, - .resume = langwell_udc_resume, - - .shutdown = langwell_udc_shutdown, -}; - - -static int __init init(void) -{ - return pci_register_driver(&langwell_pci_driver); -} -module_init(init); - - -static void __exit cleanup(void) -{ - pci_unregister_driver(&langwell_pci_driver); -} -module_exit(cleanup); - - -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Xiaochen Shen <xiaochen.shen@intel.com>"); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); - diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h deleted file mode 100644 index 8c8087abb481..000000000000 --- a/drivers/usb/gadget/langwell_udc.h +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Intel Langwell USB Device Controller driver - * Copyright (C) 2008-2009, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - */ - -#include <linux/usb/langwell_udc.h> - -/*-------------------------------------------------------------------------*/ - -/* driver data structures and utilities */ - -/* - * dTD: Device Endpoint Transfer Descriptor - * describe to the device controller the location and quantity of - * data to be send/received for given transfer - */ -struct langwell_dtd { - u32 dtd_next; -/* bits 31:5, next transfer element pointer */ -#define DTD_NEXT(d) (((d)>>5)&0x7ffffff) -#define DTD_NEXT_MASK (0x7ffffff << 5) -/* terminate */ -#define DTD_TERM BIT(0) - /* bits 7:0, execution back states */ - u32 dtd_status:8; -#define DTD_STATUS(d) (((d)>>0)&0xff) -#define DTD_STS_ACTIVE BIT(7) /* active */ -#define DTD_STS_HALTED BIT(6) /* halted */ -#define DTD_STS_DBE BIT(5) /* data buffer error */ -#define DTD_STS_TRE BIT(3) /* transaction error */ - /* bits 9:8 */ - u32 dtd_res0:2; - /* bits 11:10, multipier override */ - u32 dtd_multo:2; -#define DTD_MULTO (BIT(11) | BIT(10)) - /* bits 14:12 */ - u32 dtd_res1:3; - /* bit 15, interrupt on complete */ - u32 dtd_ioc:1; -#define DTD_IOC BIT(15) - /* bits 30:16, total bytes */ - u32 dtd_total:15; -#define DTD_TOTAL(d) (((d)>>16)&0x7fff) -#define DTD_MAX_TRANSFER_LENGTH 0x4000 - /* bit 31 */ - u32 dtd_res2:1; - /* dTD buffer pointer page 0 to 4 */ - u32 dtd_buf[5]; -#define DTD_OFFSET_MASK 0xfff -/* bits 31:12, buffer pointer */ -#define DTD_BUFFER(d) (((d)>>12)&0x3ff) -/* bits 11:0, current offset */ -#define DTD_C_OFFSET(d) (((d)>>0)&0xfff) -/* bits 10:0, frame number */ -#define DTD_FRAME(d) (((d)>>0)&0x7ff) - - /* driver-private parts */ - - /* dtd dma address */ - dma_addr_t dtd_dma; - /* next dtd virtual address */ - struct langwell_dtd *next_dtd_virt; -}; - - -/* - * dQH: Device Endpoint Queue Head - * describe where all transfers are managed - * 48-byte data structure, aligned on 64-byte boundary - * - * These are associated with dTD structure - */ -struct langwell_dqh { - /* endpoint capabilities and characteristics */ - u32 dqh_res0:15; /* bits 14:0 */ - u32 dqh_ios:1; /* bit 15, interrupt on setup */ -#define DQH_IOS BIT(15) - u32 dqh_mpl:11; /* bits 26:16, maximum packet length */ -#define DQH_MPL (0x7ff << 16) - u32 dqh_res1:2; /* bits 28:27 */ - u32 dqh_zlt:1; /* bit 29, zero length termination */ -#define DQH_ZLT BIT(29) - u32 dqh_mult:2; /* bits 31:30 */ -#define DQH_MULT (BIT(30) | BIT(31)) - - /* current dTD pointer */ - u32 dqh_current; /* locate the transfer in progress */ -#define DQH_C_DTD(e) \ - (((e)>>5)&0x7ffffff) /* bits 31:5, current dTD pointer */ - - /* transfer overlay, hardware parts of a struct langwell_dtd */ - u32 dtd_next; - u32 dtd_status:8; /* bits 7:0, execution back states */ - u32 dtd_res0:2; /* bits 9:8 */ - u32 dtd_multo:2; /* bits 11:10, multipier override */ - u32 dtd_res1:3; /* bits 14:12 */ - u32 dtd_ioc:1; /* bit 15, interrupt on complete */ - u32 dtd_total:15; /* bits 30:16, total bytes */ - u32 dtd_res2:1; /* bit 31 */ - u32 dtd_buf[5]; /* dTD buffer pointer page 0 to 4 */ - - u32 dqh_res2; - struct usb_ctrlrequest dqh_setup; /* setup packet buffer */ -} __attribute__ ((aligned(64))); - - -/* endpoint data structure */ -struct langwell_ep { - struct usb_ep ep; - dma_addr_t dma; - struct langwell_udc *dev; - unsigned long irqs; - struct list_head queue; - struct langwell_dqh *dqh; - const struct usb_endpoint_descriptor *desc; - char name[14]; - unsigned stopped:1, - ep_type:2, - ep_num:8; -}; - - -/* request data structure */ -struct langwell_request { - struct usb_request req; - struct langwell_dtd *dtd, *head, *tail; - struct langwell_ep *ep; - dma_addr_t dtd_dma; - struct list_head queue; - unsigned dtd_count; - unsigned mapped:1; -}; - - -/* ep0 transfer state */ -enum ep0_state { - WAIT_FOR_SETUP, - DATA_STATE_XMIT, - DATA_STATE_NEED_ZLP, - WAIT_FOR_OUT_STATUS, - DATA_STATE_RECV, -}; - - -/* device suspend state */ -enum lpm_state { - LPM_L0, /* on */ - LPM_L1, /* LPM L1 sleep */ - LPM_L2, /* suspend */ - LPM_L3, /* off */ -}; - - -/* device data structure */ -struct langwell_udc { - /* each pci device provides one gadget, several endpoints */ - struct usb_gadget gadget; - spinlock_t lock; /* device lock */ - struct langwell_ep *ep; - struct usb_gadget_driver *driver; - struct usb_phy *transceiver; - u8 dev_addr; - u32 usb_state; - u32 resume_state; - u32 bus_reset; - enum lpm_state lpm_state; - enum ep0_state ep0_state; - u32 ep0_dir; - u16 dciversion; - unsigned ep_max; - unsigned devcap:1, - enabled:1, - region:1, - got_irq:1, - powered:1, - remote_wakeup:1, - rate:1, - is_reset:1, - softconnected:1, - vbus_active:1, - suspended:1, - stopped:1, - lpm:1, /* LPM capability */ - has_sram:1, /* SRAM caching */ - got_sram:1; - - /* pci state used to access those endpoints */ - struct pci_dev *pdev; - - /* Langwell otg transceiver */ - struct langwell_otg *lotg; - - /* control registers */ - struct langwell_cap_regs __iomem *cap_regs; - struct langwell_op_regs __iomem *op_regs; - - struct usb_ctrlrequest local_setup_buff; - struct langwell_dqh *ep_dqh; - size_t ep_dqh_size; - dma_addr_t ep_dqh_dma; - - /* ep0 status request */ - struct langwell_request *status_req; - - /* dma pool */ - struct dma_pool *dtd_pool; - - /* make sure release() is done */ - struct completion *done; - - /* for private SRAM caching */ - unsigned int sram_addr; - unsigned int sram_size; - - /* device status data for get_status request */ - u16 dev_status; -}; - -#define gadget_to_langwell(g) container_of((g), struct langwell_udc, gadget) - diff --git a/drivers/usb/gadget/lpc32xx_udc.c b/drivers/usb/gadget/lpc32xx_udc.c new file mode 100644 index 000000000000..262acfd53e32 --- /dev/null +++ b/drivers/usb/gadget/lpc32xx_udc.c @@ -0,0 +1,3538 @@ +/* + * USB Gadget driver for LPC32xx + * + * Authors: + * Kevin Wells <kevin.wells@nxp.com> + * Mike James + * Roland Stigge <stigge@antcom.de> + * + * Copyright (C) 2006 Philips Semiconductors + * Copyright (C) 2009 NXP Semiconductors + * Copyright (C) 2012 Roland Stigge + * + * Note: This driver is based on original work done by Mike James for + * the LPC3180. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/interrupt.h> +#include <linux/proc_fs.h> +#include <linux/clk.h> +#include <linux/usb/ch9.h> +#include <linux/usb/gadget.h> +#include <linux/i2c.h> +#include <linux/kthread.h> +#include <linux/freezer.h> +#include <linux/dma-mapping.h> +#include <linux/dmapool.h> +#include <linux/workqueue.h> +#include <linux/of.h> +#include <linux/usb/isp1301.h> + +#include <asm/byteorder.h> +#include <mach/hardware.h> +#include <linux/io.h> +#include <asm/irq.h> +#include <asm/system.h> + +#include <mach/platform.h> +#include <mach/irqs.h> +#include <mach/board.h> +#ifdef CONFIG_USB_GADGET_DEBUG_FILES +#include <linux/seq_file.h> +#endif + +/* + * USB device configuration structure + */ +typedef void (*usc_chg_event)(int); +struct lpc32xx_usbd_cfg { + int vbus_drv_pol; /* 0=active low drive for VBUS via ISP1301 */ + usc_chg_event conn_chgb; /* Connection change event (optional) */ + usc_chg_event susp_chgb; /* Suspend/resume event (optional) */ + usc_chg_event rmwk_chgb; /* Enable/disable remote wakeup */ +}; + +/* + * controller driver data structures + */ + +/* 16 endpoints (not to be confused with 32 hardware endpoints) */ +#define NUM_ENDPOINTS 16 + +/* + * IRQ indices make reading the code a little easier + */ +#define IRQ_USB_LP 0 +#define IRQ_USB_HP 1 +#define IRQ_USB_DEVDMA 2 +#define IRQ_USB_ATX 3 + +#define EP_OUT 0 /* RX (from host) */ +#define EP_IN 1 /* TX (to host) */ + +/* Returns the interrupt mask for the selected hardware endpoint */ +#define EP_MASK_SEL(ep, dir) (1 << (((ep) * 2) + dir)) + +#define EP_INT_TYPE 0 +#define EP_ISO_TYPE 1 +#define EP_BLK_TYPE 2 +#define EP_CTL_TYPE 3 + +/* EP0 states */ +#define WAIT_FOR_SETUP 0 /* Wait for setup packet */ +#define DATA_IN 1 /* Expect dev->host transfer */ +#define DATA_OUT 2 /* Expect host->dev transfer */ + +/* DD (DMA Descriptor) structure, requires word alignment, this is already + * defined in the LPC32XX USB device header file, but this version is slightly + * modified to tag some work data with each DMA descriptor. */ +struct lpc32xx_usbd_dd_gad { + u32 dd_next_phy; + u32 dd_setup; + u32 dd_buffer_addr; + u32 dd_status; + u32 dd_iso_ps_mem_addr; + u32 this_dma; + u32 iso_status[6]; /* 5 spare */ + u32 dd_next_v; +}; + +/* + * Logical endpoint structure + */ +struct lpc32xx_ep { + struct usb_ep ep; + struct list_head queue; + struct lpc32xx_udc *udc; + + u32 hwep_num_base; /* Physical hardware EP */ + u32 hwep_num; /* Maps to hardware endpoint */ + u32 maxpacket; + u32 lep; + + bool is_in; + bool req_pending; + u32 eptype; + + u32 totalints; + + bool wedge; + + const struct usb_endpoint_descriptor *desc; +}; + +/* + * Common UDC structure + */ +struct lpc32xx_udc { + struct usb_gadget gadget; + struct usb_gadget_driver *driver; + struct platform_device *pdev; + struct device *dev; + struct dentry *pde; + spinlock_t lock; + struct i2c_client *isp1301_i2c_client; + + /* Board and device specific */ + struct lpc32xx_usbd_cfg *board; + u32 io_p_start; + u32 io_p_size; + void __iomem *udp_baseaddr; + int udp_irq[4]; + struct clk *usb_pll_clk; + struct clk *usb_slv_clk; + + /* DMA support */ + u32 *udca_v_base; + u32 udca_p_base; + struct dma_pool *dd_cache; + + /* Common EP and control data */ + u32 enabled_devints; + u32 enabled_hwepints; + u32 dev_status; + u32 realized_eps; + + /* VBUS detection, pullup, and power flags */ + u8 vbus; + u8 last_vbus; + int pullup; + int poweron; + + /* Work queues related to I2C support */ + struct work_struct pullup_job; + struct work_struct vbus_job; + struct work_struct power_job; + + /* USB device peripheral - various */ + struct lpc32xx_ep ep[NUM_ENDPOINTS]; + bool enabled; + bool clocked; + bool suspended; + bool selfpowered; + int ep0state; + atomic_t enabled_ep_cnt; + wait_queue_head_t ep_disable_wait_queue; +}; + +/* + * Endpoint request + */ +struct lpc32xx_request { + struct usb_request req; + struct list_head queue; + struct lpc32xx_usbd_dd_gad *dd_desc_ptr; + bool mapped; + bool send_zlp; +}; + +static inline struct lpc32xx_udc *to_udc(struct usb_gadget *g) +{ + return container_of(g, struct lpc32xx_udc, gadget); +} + +#define ep_dbg(epp, fmt, arg...) \ + dev_dbg(epp->udc->dev, "%s: " fmt, __func__, ## arg) +#define ep_err(epp, fmt, arg...) \ + dev_err(epp->udc->dev, "%s: " fmt, __func__, ## arg) +#define ep_info(epp, fmt, arg...) \ + dev_info(epp->udc->dev, "%s: " fmt, __func__, ## arg) +#define ep_warn(epp, fmt, arg...) \ + dev_warn(epp->udc->dev, "%s:" fmt, __func__, ## arg) + +#define UDCA_BUFF_SIZE (128) + +/* TODO: When the clock framework is introduced in LPC32xx, IO_ADDRESS will + * be replaced with an inremap()ed pointer, see USB_OTG_CLK_CTRL() + * */ +#define USB_CTRL IO_ADDRESS(LPC32XX_CLK_PM_BASE + 0x64) +#define USB_CLOCK_MASK (AHB_M_CLOCK_ON | OTG_CLOCK_ON | \ + DEV_CLOCK_ON | I2C_CLOCK_ON) + +/* USB_CTRL bit defines */ +#define USB_SLAVE_HCLK_EN (1 << 24) +#define USB_HOST_NEED_CLK_EN (1 << 21) +#define USB_DEV_NEED_CLK_EN (1 << 22) + +#define USB_OTG_CLK_CTRL(udc) ((udc)->udp_baseaddr + 0xFF4) +#define USB_OTG_CLK_STAT(udc) ((udc)->udp_baseaddr + 0xFF8) + +/* USB_OTG_CLK_CTRL bit defines */ +#define AHB_M_CLOCK_ON (1 << 4) +#define OTG_CLOCK_ON (1 << 3) +#define I2C_CLOCK_ON (1 << 2) +#define DEV_CLOCK_ON (1 << 1) +#define HOST_CLOCK_ON (1 << 0) + +#define USB_OTG_STAT_CONTROL(udc) (udc->udp_baseaddr + 0x110) + +/* USB_OTG_STAT_CONTROL bit defines */ +#define TRANSPARENT_I2C_EN (1 << 7) +#define HOST_EN (1 << 0) + +/********************************************************************** + * USB device controller register offsets + **********************************************************************/ + +#define USBD_DEVINTST(x) ((x) + 0x200) +#define USBD_DEVINTEN(x) ((x) + 0x204) +#define USBD_DEVINTCLR(x) ((x) + 0x208) +#define USBD_DEVINTSET(x) ((x) + 0x20C) +#define USBD_CMDCODE(x) ((x) + 0x210) +#define USBD_CMDDATA(x) ((x) + 0x214) +#define USBD_RXDATA(x) ((x) + 0x218) +#define USBD_TXDATA(x) ((x) + 0x21C) +#define USBD_RXPLEN(x) ((x) + 0x220) +#define USBD_TXPLEN(x) ((x) + 0x224) +#define USBD_CTRL(x) ((x) + 0x228) +#define USBD_DEVINTPRI(x) ((x) + 0x22C) +#define USBD_EPINTST(x) ((x) + 0x230) +#define USBD_EPINTEN(x) ((x) + 0x234) +#define USBD_EPINTCLR(x) ((x) + 0x238) +#define USBD_EPINTSET(x) ((x) + 0x23C) +#define USBD_EPINTPRI(x) ((x) + 0x240) +#define USBD_REEP(x) ((x) + 0x244) +#define USBD_EPIND(x) ((x) + 0x248) +#define USBD_EPMAXPSIZE(x) ((x) + 0x24C) +/* DMA support registers only below */ +/* Set, clear, or get enabled state of the DMA request status. If + * enabled, an IN or OUT token will start a DMA transfer for the EP */ +#define USBD_DMARST(x) ((x) + 0x250) +#define USBD_DMARCLR(x) ((x) + 0x254) +#define USBD_DMARSET(x) ((x) + 0x258) +/* DMA UDCA head pointer */ +#define USBD_UDCAH(x) ((x) + 0x280) +/* EP DMA status, enable, and disable. This is used to specifically + * enabled or disable DMA for a specific EP */ +#define USBD_EPDMAST(x) ((x) + 0x284) +#define USBD_EPDMAEN(x) ((x) + 0x288) +#define USBD_EPDMADIS(x) ((x) + 0x28C) +/* DMA master interrupts enable and pending interrupts */ +#define USBD_DMAINTST(x) ((x) + 0x290) +#define USBD_DMAINTEN(x) ((x) + 0x294) +/* DMA end of transfer interrupt enable, disable, status */ +#define USBD_EOTINTST(x) ((x) + 0x2A0) +#define USBD_EOTINTCLR(x) ((x) + 0x2A4) +#define USBD_EOTINTSET(x) ((x) + 0x2A8) +/* New DD request interrupt enable, disable, status */ +#define USBD_NDDRTINTST(x) ((x) + 0x2AC) +#define USBD_NDDRTINTCLR(x) ((x) + 0x2B0) +#define USBD_NDDRTINTSET(x) ((x) + 0x2B4) +/* DMA error interrupt enable, disable, status */ +#define USBD_SYSERRTINTST(x) ((x) + 0x2B8) +#define USBD_SYSERRTINTCLR(x) ((x) + 0x2BC) +#define USBD_SYSERRTINTSET(x) ((x) + 0x2C0) + +/********************************************************************** + * USBD_DEVINTST/USBD_DEVINTEN/USBD_DEVINTCLR/USBD_DEVINTSET/ + * USBD_DEVINTPRI register definitions + **********************************************************************/ +#define USBD_ERR_INT (1 << 9) +#define USBD_EP_RLZED (1 << 8) +#define USBD_TXENDPKT (1 << 7) +#define USBD_RXENDPKT (1 << 6) +#define USBD_CDFULL (1 << 5) +#define USBD_CCEMPTY (1 << 4) +#define USBD_DEV_STAT (1 << 3) +#define USBD_EP_SLOW (1 << 2) +#define USBD_EP_FAST (1 << 1) +#define USBD_FRAME (1 << 0) + +/********************************************************************** + * USBD_EPINTST/USBD_EPINTEN/USBD_EPINTCLR/USBD_EPINTSET/ + * USBD_EPINTPRI register definitions + **********************************************************************/ +/* End point selection macro (RX) */ +#define USBD_RX_EP_SEL(e) (1 << ((e) << 1)) + +/* End point selection macro (TX) */ +#define USBD_TX_EP_SEL(e) (1 << (((e) << 1) + 1)) + +/********************************************************************** + * USBD_REEP/USBD_DMARST/USBD_DMARCLR/USBD_DMARSET/USBD_EPDMAST/ + * USBD_EPDMAEN/USBD_EPDMADIS/ + * USBD_NDDRTINTST/USBD_NDDRTINTCLR/USBD_NDDRTINTSET/ + * USBD_EOTINTST/USBD_EOTINTCLR/USBD_EOTINTSET/ + * USBD_SYSERRTINTST/USBD_SYSERRTINTCLR/USBD_SYSERRTINTSET + * register definitions + **********************************************************************/ +/* Endpoint selection macro */ +#define USBD_EP_SEL(e) (1 << (e)) + +/********************************************************************** + * SBD_DMAINTST/USBD_DMAINTEN + **********************************************************************/ +#define USBD_SYS_ERR_INT (1 << 2) +#define USBD_NEW_DD_INT (1 << 1) +#define USBD_EOT_INT (1 << 0) + +/********************************************************************** + * USBD_RXPLEN register definitions + **********************************************************************/ +#define USBD_PKT_RDY (1 << 11) +#define USBD_DV (1 << 10) +#define USBD_PK_LEN_MASK 0x3FF + +/********************************************************************** + * USBD_CTRL register definitions + **********************************************************************/ +#define USBD_LOG_ENDPOINT(e) ((e) << 2) +#define USBD_WR_EN (1 << 1) +#define USBD_RD_EN (1 << 0) + +/********************************************************************** + * USBD_CMDCODE register definitions + **********************************************************************/ +#define USBD_CMD_CODE(c) ((c) << 16) +#define USBD_CMD_PHASE(p) ((p) << 8) + +/********************************************************************** + * USBD_DMARST/USBD_DMARCLR/USBD_DMARSET register definitions + **********************************************************************/ +#define USBD_DMAEP(e) (1 << (e)) + +/* DD (DMA Descriptor) structure, requires word alignment */ +struct lpc32xx_usbd_dd { + u32 *dd_next; + u32 dd_setup; + u32 dd_buffer_addr; + u32 dd_status; + u32 dd_iso_ps_mem_addr; +}; + +/* dd_setup bit defines */ +#define DD_SETUP_ATLE_DMA_MODE 0x01 +#define DD_SETUP_NEXT_DD_VALID 0x04 +#define DD_SETUP_ISO_EP 0x10 +#define DD_SETUP_PACKETLEN(n) (((n) & 0x7FF) << 5) +#define DD_SETUP_DMALENBYTES(n) (((n) & 0xFFFF) << 16) + +/* dd_status bit defines */ +#define DD_STATUS_DD_RETIRED 0x01 +#define DD_STATUS_STS_MASK 0x1E +#define DD_STATUS_STS_NS 0x00 /* Not serviced */ +#define DD_STATUS_STS_BS 0x02 /* Being serviced */ +#define DD_STATUS_STS_NC 0x04 /* Normal completion */ +#define DD_STATUS_STS_DUR 0x06 /* Data underrun (short packet) */ +#define DD_STATUS_STS_DOR 0x08 /* Data overrun */ +#define DD_STATUS_STS_SE 0x12 /* System error */ +#define DD_STATUS_PKT_VAL 0x20 /* Packet valid */ +#define DD_STATUS_LSB_EX 0x40 /* LS byte extracted (ATLE) */ +#define DD_STATUS_MSB_EX 0x80 /* MS byte extracted (ATLE) */ +#define DD_STATUS_MLEN(n) (((n) >> 8) & 0x3F) +#define DD_STATUS_CURDMACNT(n) (((n) >> 16) & 0xFFFF) + +/* + * + * Protocol engine bits below + * + */ +/* Device Interrupt Bit Definitions */ +#define FRAME_INT 0x00000001 +#define EP_FAST_INT 0x00000002 +#define EP_SLOW_INT 0x00000004 +#define DEV_STAT_INT 0x00000008 +#define CCEMTY_INT 0x00000010 +#define CDFULL_INT 0x00000020 +#define RxENDPKT_INT 0x00000040 +#define TxENDPKT_INT 0x00000080 +#define EP_RLZED_INT 0x00000100 +#define ERR_INT 0x00000200 + +/* Rx & Tx Packet Length Definitions */ +#define PKT_LNGTH_MASK 0x000003FF +#define PKT_DV 0x00000400 +#define PKT_RDY 0x00000800 + +/* USB Control Definitions */ +#define CTRL_RD_EN 0x00000001 +#define CTRL_WR_EN 0x00000002 + +/* Command Codes */ +#define CMD_SET_ADDR 0x00D00500 +#define CMD_CFG_DEV 0x00D80500 +#define CMD_SET_MODE 0x00F30500 +#define CMD_RD_FRAME 0x00F50500 +#define DAT_RD_FRAME 0x00F50200 +#define CMD_RD_TEST 0x00FD0500 +#define DAT_RD_TEST 0x00FD0200 +#define CMD_SET_DEV_STAT 0x00FE0500 +#define CMD_GET_DEV_STAT 0x00FE0500 +#define DAT_GET_DEV_STAT 0x00FE0200 +#define CMD_GET_ERR_CODE 0x00FF0500 +#define DAT_GET_ERR_CODE 0x00FF0200 +#define CMD_RD_ERR_STAT 0x00FB0500 +#define DAT_RD_ERR_STAT 0x00FB0200 +#define DAT_WR_BYTE(x) (0x00000100 | ((x) << 16)) +#define CMD_SEL_EP(x) (0x00000500 | ((x) << 16)) +#define DAT_SEL_EP(x) (0x00000200 | ((x) << 16)) +#define CMD_SEL_EP_CLRI(x) (0x00400500 | ((x) << 16)) +#define DAT_SEL_EP_CLRI(x) (0x00400200 | ((x) << 16)) +#define CMD_SET_EP_STAT(x) (0x00400500 | ((x) << 16)) +#define CMD_CLR_BUF 0x00F20500 +#define DAT_CLR_BUF 0x00F20200 +#define CMD_VALID_BUF 0x00FA0500 + +/* Device Address Register Definitions */ +#define DEV_ADDR_MASK 0x7F +#define DEV_EN 0x80 + +/* Device Configure Register Definitions */ +#define CONF_DVICE 0x01 + +/* Device Mode Register Definitions */ +#define AP_CLK 0x01 +#define INAK_CI 0x02 +#define INAK_CO 0x04 +#define INAK_II 0x08 +#define INAK_IO 0x10 +#define INAK_BI 0x20 +#define INAK_BO 0x40 + +/* Device Status Register Definitions */ +#define DEV_CON 0x01 +#define DEV_CON_CH 0x02 +#define DEV_SUS 0x04 +#define DEV_SUS_CH 0x08 +#define DEV_RST 0x10 + +/* Error Code Register Definitions */ +#define ERR_EC_MASK 0x0F +#define ERR_EA 0x10 + +/* Error Status Register Definitions */ +#define ERR_PID 0x01 +#define ERR_UEPKT 0x02 +#define ERR_DCRC 0x04 +#define ERR_TIMOUT 0x08 +#define ERR_EOP 0x10 +#define ERR_B_OVRN 0x20 +#define ERR_BTSTF 0x40 +#define ERR_TGL 0x80 + +/* Endpoint Select Register Definitions */ +#define EP_SEL_F 0x01 +#define EP_SEL_ST 0x02 +#define EP_SEL_STP 0x04 +#define EP_SEL_PO 0x08 +#define EP_SEL_EPN 0x10 +#define EP_SEL_B_1_FULL 0x20 +#define EP_SEL_B_2_FULL 0x40 + +/* Endpoint Status Register Definitions */ +#define EP_STAT_ST 0x01 +#define EP_STAT_DA 0x20 +#define EP_STAT_RF_MO 0x40 +#define EP_STAT_CND_ST 0x80 + +/* Clear Buffer Register Definitions */ +#define CLR_BUF_PO 0x01 + +/* DMA Interrupt Bit Definitions */ +#define EOT_INT 0x01 +#define NDD_REQ_INT 0x02 +#define SYS_ERR_INT 0x04 + +#define DRIVER_VERSION "1.03" +static const char driver_name[] = "lpc32xx_udc"; + +/* + * + * proc interface support + * + */ +#ifdef CONFIG_USB_GADGET_DEBUG_FILES +static char *epnames[] = {"INT", "ISO", "BULK", "CTRL"}; +static const char debug_filename[] = "driver/udc"; + +static void proc_ep_show(struct seq_file *s, struct lpc32xx_ep *ep) +{ + struct lpc32xx_request *req; + + seq_printf(s, "\n"); + seq_printf(s, "%12s, maxpacket %4d %3s", + ep->ep.name, ep->ep.maxpacket, + ep->is_in ? "in" : "out"); + seq_printf(s, " type %4s", epnames[ep->eptype]); + seq_printf(s, " ints: %12d", ep->totalints); + + if (list_empty(&ep->queue)) + seq_printf(s, "\t(queue empty)\n"); + else { + list_for_each_entry(req, &ep->queue, queue) { + u32 length = req->req.actual; + + seq_printf(s, "\treq %p len %d/%d buf %p\n", + &req->req, length, + req->req.length, req->req.buf); + } + } +} + +static int proc_udc_show(struct seq_file *s, void *unused) +{ + struct lpc32xx_udc *udc = s->private; + struct lpc32xx_ep *ep; + unsigned long flags; + + seq_printf(s, "%s: version %s\n", driver_name, DRIVER_VERSION); + + spin_lock_irqsave(&udc->lock, flags); + + seq_printf(s, "vbus %s, pullup %s, %s powered%s, gadget %s\n\n", + udc->vbus ? "present" : "off", + udc->enabled ? (udc->vbus ? "active" : "enabled") : + "disabled", + udc->selfpowered ? "self" : "VBUS", + udc->suspended ? ", suspended" : "", + udc->driver ? udc->driver->driver.name : "(none)"); + + if (udc->enabled && udc->vbus) { + proc_ep_show(s, &udc->ep[0]); + list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) { + if (ep->desc) + proc_ep_show(s, ep); + } + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +static int proc_udc_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_udc_show, PDE(inode)->data); +} + +static const struct file_operations proc_ops = { + .owner = THIS_MODULE, + .open = proc_udc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static void create_debug_file(struct lpc32xx_udc *udc) +{ + udc->pde = debugfs_create_file(debug_filename, 0, NULL, udc, &proc_ops); +} + +static void remove_debug_file(struct lpc32xx_udc *udc) +{ + if (udc->pde) + debugfs_remove(udc->pde); +} + +#else +static inline void create_debug_file(struct lpc32xx_udc *udc) {} +static inline void remove_debug_file(struct lpc32xx_udc *udc) {} +#endif + +/* Primary initialization sequence for the ISP1301 transceiver */ +static void isp1301_udc_configure(struct lpc32xx_udc *udc) +{ + /* LPC32XX only supports DAT_SE0 USB mode */ + /* This sequence is important */ + + /* Disable transparent UART mode first */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), + MC1_UART_EN); + + /* Set full speed and SE0 mode */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_MODE_CONTROL_1, (MC1_SPEED_REG | MC1_DAT_SE0)); + + /* + * The PSW_OE enable bit state is reversed in the ISP1301 User's Guide + */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_MODE_CONTROL_2, (MC2_BI_DI | MC2_SPD_SUSP_CTRL)); + + /* Driver VBUS_DRV high or low depending on board setup */ + if (udc->board->vbus_drv_pol != 0) + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DRV); + else + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, + OTG1_VBUS_DRV); + + /* Bi-directional mode with suspend control + * Enable both pulldowns for now - the pullup will be enable when VBUS + * is detected */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, + (0 | OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN)); + + /* Discharge VBUS (just in case) */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG); + msleep(1); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), + OTG1_VBUS_DISCHRG); + + /* Clear and enable VBUS high edge interrupt */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_FALLING, INT_VBUS_VLD); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_RISING, INT_VBUS_VLD); + + /* Enable usb_need_clk clock after transceiver is initialized */ + writel((readl(USB_CTRL) | (1 << 22)), USB_CTRL); + + dev_info(udc->dev, "ISP1301 Vendor ID : 0x%04x\n", + i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x00)); + dev_info(udc->dev, "ISP1301 Product ID : 0x%04x\n", + i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x02)); + dev_info(udc->dev, "ISP1301 Version ID : 0x%04x\n", + i2c_smbus_read_word_data(udc->isp1301_i2c_client, 0x14)); +} + +/* Enables or disables the USB device pullup via the ISP1301 transceiver */ +static void isp1301_pullup_set(struct lpc32xx_udc *udc) +{ + if (udc->pullup) + /* Enable pullup for bus signalling */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, OTG1_DP_PULLUP); + else + /* Enable pullup for bus signalling */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, + OTG1_DP_PULLUP); +} + +static void pullup_work(struct work_struct *work) +{ + struct lpc32xx_udc *udc = + container_of(work, struct lpc32xx_udc, pullup_job); + + isp1301_pullup_set(udc); +} + +static void isp1301_pullup_enable(struct lpc32xx_udc *udc, int en_pullup, + int block) +{ + if (en_pullup == udc->pullup) + return; + + udc->pullup = en_pullup; + if (block) + isp1301_pullup_set(udc); + else + /* defer slow i2c pull up setting */ + schedule_work(&udc->pullup_job); +} + +#ifdef CONFIG_PM +/* Powers up or down the ISP1301 transceiver */ +static void isp1301_set_powerstate(struct lpc32xx_udc *udc, int enable) +{ + if (enable != 0) + /* Power up ISP1301 - this ISP1301 will automatically wakeup + when VBUS is detected */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR, + MC2_GLOBAL_PWR_DN); + else + /* Power down ISP1301 */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN); +} + +static void power_work(struct work_struct *work) +{ + struct lpc32xx_udc *udc = + container_of(work, struct lpc32xx_udc, power_job); + + isp1301_set_powerstate(udc, udc->poweron); +} +#endif + +/* + * + * USB protocol engine command/data read/write helper functions + * + */ +/* Issues a single command to the USB device state machine */ +static void udc_protocol_cmd_w(struct lpc32xx_udc *udc, u32 cmd) +{ + u32 pass = 0; + int to; + + /* EP may lock on CLRI if this read isn't done */ + u32 tmp = readl(USBD_DEVINTST(udc->udp_baseaddr)); + (void) tmp; + + while (pass == 0) { + writel(USBD_CCEMPTY, USBD_DEVINTCLR(udc->udp_baseaddr)); + + /* Write command code */ + writel(cmd, USBD_CMDCODE(udc->udp_baseaddr)); + to = 10000; + while (((readl(USBD_DEVINTST(udc->udp_baseaddr)) & + USBD_CCEMPTY) == 0) && (to > 0)) { + to--; + } + + if (to > 0) + pass = 1; + + cpu_relax(); + } +} + +/* Issues 2 commands (or command and data) to the USB device state machine */ +static inline void udc_protocol_cmd_data_w(struct lpc32xx_udc *udc, u32 cmd, + u32 data) +{ + udc_protocol_cmd_w(udc, cmd); + udc_protocol_cmd_w(udc, data); +} + +/* Issues a single command to the USB device state machine and reads + * response data */ +static u32 udc_protocol_cmd_r(struct lpc32xx_udc *udc, u32 cmd) +{ + u32 tmp; + int to = 1000; + + /* Write a command and read data from the protocol engine */ + writel((USBD_CDFULL | USBD_CCEMPTY), + USBD_DEVINTCLR(udc->udp_baseaddr)); + + /* Write command code */ + udc_protocol_cmd_w(udc, cmd); + + tmp = readl(USBD_DEVINTST(udc->udp_baseaddr)); + while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & USBD_CDFULL)) + && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, + "Protocol engine didn't receive response (CDFULL)\n"); + + return readl(USBD_CMDDATA(udc->udp_baseaddr)); +} + +/* + * + * USB device interrupt mask support functions + * + */ +/* Enable one or more USB device interrupts */ +static inline void uda_enable_devint(struct lpc32xx_udc *udc, u32 devmask) +{ + udc->enabled_devints |= devmask; + writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr)); +} + +/* Disable one or more USB device interrupts */ +static inline void uda_disable_devint(struct lpc32xx_udc *udc, u32 mask) +{ + udc->enabled_devints &= ~mask; + writel(udc->enabled_devints, USBD_DEVINTEN(udc->udp_baseaddr)); +} + +/* Clear one or more USB device interrupts */ +static inline void uda_clear_devint(struct lpc32xx_udc *udc, u32 mask) +{ + writel(mask, USBD_DEVINTCLR(udc->udp_baseaddr)); +} + +/* + * + * Endpoint interrupt disable/enable functions + * + */ +/* Enable one or more USB endpoint interrupts */ +static void uda_enable_hwepint(struct lpc32xx_udc *udc, u32 hwep) +{ + udc->enabled_hwepints |= (1 << hwep); + writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr)); +} + +/* Disable one or more USB endpoint interrupts */ +static void uda_disable_hwepint(struct lpc32xx_udc *udc, u32 hwep) +{ + udc->enabled_hwepints &= ~(1 << hwep); + writel(udc->enabled_hwepints, USBD_EPINTEN(udc->udp_baseaddr)); +} + +/* Clear one or more USB endpoint interrupts */ +static inline void uda_clear_hwepint(struct lpc32xx_udc *udc, u32 hwep) +{ + writel((1 << hwep), USBD_EPINTCLR(udc->udp_baseaddr)); +} + +/* Enable DMA for the HW channel */ +static inline void udc_ep_dma_enable(struct lpc32xx_udc *udc, u32 hwep) +{ + writel((1 << hwep), USBD_EPDMAEN(udc->udp_baseaddr)); +} + +/* Disable DMA for the HW channel */ +static inline void udc_ep_dma_disable(struct lpc32xx_udc *udc, u32 hwep) +{ + writel((1 << hwep), USBD_EPDMADIS(udc->udp_baseaddr)); +} + +/* + * + * Endpoint realize/unrealize functions + * + */ +/* Before an endpoint can be used, it needs to be realized + * in the USB protocol engine - this realizes the endpoint. + * The interrupt (FIFO or DMA) is not enabled with this function */ +static void udc_realize_hwep(struct lpc32xx_udc *udc, u32 hwep, + u32 maxpacket) +{ + int to = 1000; + + writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr)); + writel(hwep, USBD_EPIND(udc->udp_baseaddr)); + udc->realized_eps |= (1 << hwep); + writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr)); + writel(maxpacket, USBD_EPMAXPSIZE(udc->udp_baseaddr)); + + /* Wait until endpoint is realized in hardware */ + while ((!(readl(USBD_DEVINTST(udc->udp_baseaddr)) & + USBD_EP_RLZED)) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, "EP not correctly realized in hardware\n"); + + writel(USBD_EP_RLZED, USBD_DEVINTCLR(udc->udp_baseaddr)); +} + +/* Unrealize an EP */ +static void udc_unrealize_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc->realized_eps &= ~(1 << hwep); + writel(udc->realized_eps, USBD_REEP(udc->udp_baseaddr)); +} + +/* + * + * Endpoint support functions + * + */ +/* Select and clear endpoint interrupt */ +static u32 udc_selep_clrint(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_w(udc, CMD_SEL_EP_CLRI(hwep)); + return udc_protocol_cmd_r(udc, DAT_SEL_EP_CLRI(hwep)); +} + +/* Disables the endpoint in the USB protocol engine */ +static void udc_disable_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), + DAT_WR_BYTE(EP_STAT_DA)); +} + +/* Stalls the endpoint - endpoint will return STALL */ +static void udc_stall_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), + DAT_WR_BYTE(EP_STAT_ST)); +} + +/* Clear stall or reset endpoint */ +static void udc_clrstall_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(hwep), + DAT_WR_BYTE(0)); +} + +/* Select an endpoint for endpoint status, clear, validate */ +static void udc_select_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_protocol_cmd_w(udc, CMD_SEL_EP(hwep)); +} + +/* + * + * Endpoint buffer management functions + * + */ +/* Clear the current endpoint's buffer */ +static void udc_clr_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_select_hwep(udc, hwep); + udc_protocol_cmd_w(udc, CMD_CLR_BUF); +} + +/* Validate the current endpoint's buffer */ +static void udc_val_buffer_hwep(struct lpc32xx_udc *udc, u32 hwep) +{ + udc_select_hwep(udc, hwep); + udc_protocol_cmd_w(udc, CMD_VALID_BUF); +} + +static inline u32 udc_clearep_getsts(struct lpc32xx_udc *udc, u32 hwep) +{ + /* Clear EP interrupt */ + uda_clear_hwepint(udc, hwep); + return udc_selep_clrint(udc, hwep); +} + +/* + * + * USB EP DMA support + * + */ +/* Allocate a DMA Descriptor */ +static struct lpc32xx_usbd_dd_gad *udc_dd_alloc(struct lpc32xx_udc *udc) +{ + dma_addr_t dma; + struct lpc32xx_usbd_dd_gad *dd; + + dd = (struct lpc32xx_usbd_dd_gad *) dma_pool_alloc( + udc->dd_cache, (GFP_KERNEL | GFP_DMA), &dma); + if (dd) + dd->this_dma = dma; + + return dd; +} + +/* Free a DMA Descriptor */ +static void udc_dd_free(struct lpc32xx_udc *udc, struct lpc32xx_usbd_dd_gad *dd) +{ + dma_pool_free(udc->dd_cache, dd, dd->this_dma); +} + +/* + * + * USB setup and shutdown functions + * + */ +/* Enables or disables most of the USB system clocks when low power mode is + * needed. Clocks are typically started on a connection event, and disabled + * when a cable is disconnected */ +#define OTGOFF_CLK_MASK (AHB_M_CLOCK_ON | I2C_CLOCK_ON) +static void udc_clk_set(struct lpc32xx_udc *udc, int enable) +{ + int to = 1000; + + if (enable != 0) { + if (udc->clocked) + return; + + udc->clocked = 1; + + /* 48MHz PLL up */ + clk_enable(udc->usb_pll_clk); + + /* Enable the USB device clock */ + writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN, + USB_CTRL); + + /* Set to enable all needed USB OTG clocks */ + writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc)); + + while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) != + USB_CLOCK_MASK) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, "Cannot enable USB OTG clocking\n"); + } else { + if (!udc->clocked) + return; + + udc->clocked = 0; + + /* Never disable the USB_HCLK during normal operation */ + + /* 48MHz PLL dpwn */ + clk_disable(udc->usb_pll_clk); + + /* Enable the USB device clock */ + writel(readl(USB_CTRL) & ~USB_DEV_NEED_CLK_EN, + USB_CTRL); + + /* Set to enable all needed USB OTG clocks */ + writel(OTGOFF_CLK_MASK, USB_OTG_CLK_CTRL(udc)); + + while (((readl(USB_OTG_CLK_STAT(udc)) & + OTGOFF_CLK_MASK) != + OTGOFF_CLK_MASK) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, "Cannot disable USB OTG clocking\n"); + } +} + +/* Set/reset USB device address */ +static void udc_set_address(struct lpc32xx_udc *udc, u32 addr) +{ + /* Address will be latched at the end of the status phase, or + latched immediately if function is called twice */ + udc_protocol_cmd_data_w(udc, CMD_SET_ADDR, + DAT_WR_BYTE(DEV_EN | addr)); +} + +/* Setup up a IN request for DMA transfer - this consists of determining the + * list of DMA addresses for the transfer, allocating DMA Descriptors, + * installing the DD into the UDCA, and then enabling the DMA for that EP */ +static int udc_ep_in_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + struct lpc32xx_request *req; + u32 hwep = ep->hwep_num; + + ep->req_pending = 1; + + /* There will always be a request waiting here */ + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + + /* Place the DD Descriptor into the UDCA */ + udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma; + + /* Enable DMA and interrupt for the HW EP */ + udc_ep_dma_enable(udc, hwep); + + /* Clear ZLP if last packet is not of MAXP size */ + if (req->req.length % ep->ep.maxpacket) + req->send_zlp = 0; + + return 0; +} + +/* Setup up a OUT request for DMA transfer - this consists of determining the + * list of DMA addresses for the transfer, allocating DMA Descriptors, + * installing the DD into the UDCA, and then enabling the DMA for that EP */ +static int udc_ep_out_req_dma(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + struct lpc32xx_request *req; + u32 hwep = ep->hwep_num; + + ep->req_pending = 1; + + /* There will always be a request waiting here */ + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + + /* Place the DD Descriptor into the UDCA */ + udc->udca_v_base[hwep] = req->dd_desc_ptr->this_dma; + + /* Enable DMA and interrupt for the HW EP */ + udc_ep_dma_enable(udc, hwep); + return 0; +} + +static void udc_disable(struct lpc32xx_udc *udc) +{ + u32 i; + + /* Disable device */ + udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0)); + udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(0)); + + /* Disable all device interrupts (including EP0) */ + uda_disable_devint(udc, 0x3FF); + + /* Disable and reset all endpoint interrupts */ + for (i = 0; i < 32; i++) { + uda_disable_hwepint(udc, i); + uda_clear_hwepint(udc, i); + udc_disable_hwep(udc, i); + udc_unrealize_hwep(udc, i); + udc->udca_v_base[i] = 0; + + /* Disable and clear all interrupts and DMA */ + udc_ep_dma_disable(udc, i); + writel((1 << i), USBD_EOTINTCLR(udc->udp_baseaddr)); + writel((1 << i), USBD_NDDRTINTCLR(udc->udp_baseaddr)); + writel((1 << i), USBD_SYSERRTINTCLR(udc->udp_baseaddr)); + writel((1 << i), USBD_DMARCLR(udc->udp_baseaddr)); + } + + /* Disable DMA interrupts */ + writel(0, USBD_DMAINTEN(udc->udp_baseaddr)); + + writel(0, USBD_UDCAH(udc->udp_baseaddr)); +} + +static void udc_enable(struct lpc32xx_udc *udc) +{ + u32 i; + struct lpc32xx_ep *ep = &udc->ep[0]; + + /* Start with known state */ + udc_disable(udc); + + /* Enable device */ + udc_protocol_cmd_data_w(udc, CMD_SET_DEV_STAT, DAT_WR_BYTE(DEV_CON)); + + /* EP interrupts on high priority, FRAME interrupt on low priority */ + writel(USBD_EP_FAST, USBD_DEVINTPRI(udc->udp_baseaddr)); + writel(0xFFFF, USBD_EPINTPRI(udc->udp_baseaddr)); + + /* Clear any pending device interrupts */ + writel(0x3FF, USBD_DEVINTCLR(udc->udp_baseaddr)); + + /* Setup UDCA - not yet used (DMA) */ + writel(udc->udca_p_base, USBD_UDCAH(udc->udp_baseaddr)); + + /* Only enable EP0 in and out for now, EP0 only works in FIFO mode */ + for (i = 0; i <= 1; i++) { + udc_realize_hwep(udc, i, ep->ep.maxpacket); + uda_enable_hwepint(udc, i); + udc_select_hwep(udc, i); + udc_clrstall_hwep(udc, i); + udc_clr_buffer_hwep(udc, i); + } + + /* Device interrupt setup */ + uda_clear_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW | + USBD_EP_FAST)); + uda_enable_devint(udc, (USBD_ERR_INT | USBD_DEV_STAT | USBD_EP_SLOW | + USBD_EP_FAST)); + + /* Set device address to 0 - called twice to force a latch in the USB + engine without the need of a setup packet status closure */ + udc_set_address(udc, 0); + udc_set_address(udc, 0); + + /* Enable master DMA interrupts */ + writel((USBD_SYS_ERR_INT | USBD_EOT_INT), + USBD_DMAINTEN(udc->udp_baseaddr)); + + udc->dev_status = 0; +} + +/* + * + * USB device board specific events handled via callbacks + * + */ +/* Connection change event - notify board function of change */ +static void uda_power_event(struct lpc32xx_udc *udc, u32 conn) +{ + /* Just notify of a connection change event (optional) */ + if (udc->board->conn_chgb != NULL) + udc->board->conn_chgb(conn); +} + +/* Suspend/resume event - notify board function of change */ +static void uda_resm_susp_event(struct lpc32xx_udc *udc, u32 conn) +{ + /* Just notify of a Suspend/resume change event (optional) */ + if (udc->board->susp_chgb != NULL) + udc->board->susp_chgb(conn); + + if (conn) + udc->suspended = 0; + else + udc->suspended = 1; +} + +/* Remote wakeup enable/disable - notify board function of change */ +static void uda_remwkp_cgh(struct lpc32xx_udc *udc) +{ + if (udc->board->rmwk_chgb != NULL) + udc->board->rmwk_chgb(udc->dev_status & + (1 << USB_DEVICE_REMOTE_WAKEUP)); +} + +/* Reads data from FIFO, adjusts for alignment and data size */ +static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) +{ + int n, i, bl; + u16 *p16; + u32 *p32, tmp, cbytes; + + /* Use optimal data transfer method based on source address and size */ + switch (((u32) data) & 0x3) { + case 0: /* 32-bit aligned */ + p32 = (u32 *) data; + cbytes = (bytes & ~0x3); + + /* Copy 32-bit aligned data first */ + for (n = 0; n < cbytes; n += 4) + *p32++ = readl(USBD_RXDATA(udc->udp_baseaddr)); + + /* Handle any remaining bytes */ + bl = bytes - cbytes; + if (bl) { + tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); + for (n = 0; n < bl; n++) + data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF); + + } + break; + + case 1: /* 8-bit aligned */ + case 3: + /* Each byte has to be handled independently */ + for (n = 0; n < bytes; n += 4) { + tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); + + bl = bytes - n; + if (bl > 3) + bl = 3; + + for (i = 0; i < bl; i++) + data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF); + } + break; + + case 2: /* 16-bit aligned */ + p16 = (u16 *) data; + cbytes = (bytes & ~0x3); + + /* Copy 32-bit sized objects first with 16-bit alignment */ + for (n = 0; n < cbytes; n += 4) { + tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); + *p16++ = (u16)(tmp & 0xFFFF); + *p16++ = (u16)((tmp >> 16) & 0xFFFF); + } + + /* Handle any remaining bytes */ + bl = bytes - cbytes; + if (bl) { + tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); + for (n = 0; n < bl; n++) + data[cbytes + n] = ((tmp >> (n * 8)) & 0xFF); + } + break; + } +} + +/* Read data from the FIFO for an endpoint. This function is for endpoints (such + * as EP0) that don't use DMA. This function should only be called if a packet + * is known to be ready to read for the endpoint. Note that the endpoint must + * be selected in the protocol engine prior to this call. */ +static u32 udc_read_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data, + u32 bytes) +{ + u32 tmpv; + int to = 1000; + u32 tmp, hwrep = ((hwep & 0x1E) << 1) | CTRL_RD_EN; + + /* Setup read of endpoint */ + writel(hwrep, USBD_CTRL(udc->udp_baseaddr)); + + /* Wait until packet is ready */ + while ((((tmpv = readl(USBD_RXPLEN(udc->udp_baseaddr))) & + PKT_RDY) == 0) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, "No packet ready on FIFO EP read\n"); + + /* Mask out count */ + tmp = tmpv & PKT_LNGTH_MASK; + if (bytes < tmp) + tmp = bytes; + + if ((tmp > 0) && (data != NULL)) + udc_pop_fifo(udc, (u8 *) data, tmp); + + writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr)); + + /* Clear the buffer */ + udc_clr_buffer_hwep(udc, hwep); + + return tmp; +} + +/* Stuffs data into the FIFO, adjusts for alignment and data size */ +static void udc_stuff_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) +{ + int n, i, bl; + u16 *p16; + u32 *p32, tmp, cbytes; + + /* Use optimal data transfer method based on source address and size */ + switch (((u32) data) & 0x3) { + case 0: /* 32-bit aligned */ + p32 = (u32 *) data; + cbytes = (bytes & ~0x3); + + /* Copy 32-bit aligned data first */ + for (n = 0; n < cbytes; n += 4) + writel(*p32++, USBD_TXDATA(udc->udp_baseaddr)); + + /* Handle any remaining bytes */ + bl = bytes - cbytes; + if (bl) { + tmp = 0; + for (n = 0; n < bl; n++) + tmp |= data[cbytes + n] << (n * 8); + + writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); + } + break; + + case 1: /* 8-bit aligned */ + case 3: + /* Each byte has to be handled independently */ + for (n = 0; n < bytes; n += 4) { + bl = bytes - n; + if (bl > 4) + bl = 4; + + tmp = 0; + for (i = 0; i < bl; i++) + tmp |= data[n + i] << (i * 8); + + writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); + } + break; + + case 2: /* 16-bit aligned */ + p16 = (u16 *) data; + cbytes = (bytes & ~0x3); + + /* Copy 32-bit aligned data first */ + for (n = 0; n < cbytes; n += 4) { + tmp = *p16++ & 0xFFFF; + tmp |= (*p16++ & 0xFFFF) << 16; + writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); + } + + /* Handle any remaining bytes */ + bl = bytes - cbytes; + if (bl) { + tmp = 0; + for (n = 0; n < bl; n++) + tmp |= data[cbytes + n] << (n * 8); + + writel(tmp, USBD_TXDATA(udc->udp_baseaddr)); + } + break; + } +} + +/* Write data to the FIFO for an endpoint. This function is for endpoints (such + * as EP0) that don't use DMA. Note that the endpoint must be selected in the + * protocol engine prior to this call. */ +static void udc_write_hwep(struct lpc32xx_udc *udc, u32 hwep, u32 *data, + u32 bytes) +{ + u32 hwwep = ((hwep & 0x1E) << 1) | CTRL_WR_EN; + + if ((bytes > 0) && (data == NULL)) + return; + + /* Setup write of endpoint */ + writel(hwwep, USBD_CTRL(udc->udp_baseaddr)); + + writel(bytes, USBD_TXPLEN(udc->udp_baseaddr)); + + /* Need at least 1 byte to trigger TX */ + if (bytes == 0) + writel(0, USBD_TXDATA(udc->udp_baseaddr)); + else + udc_stuff_fifo(udc, (u8 *) data, bytes); + + writel(((hwep & 0x1E) << 1), USBD_CTRL(udc->udp_baseaddr)); + + udc_val_buffer_hwep(udc, hwep); +} + +/* USB device reset - resets USB to a default state with just EP0 + enabled */ +static void uda_usb_reset(struct lpc32xx_udc *udc) +{ + u32 i = 0; + /* Re-init device controller and EP0 */ + udc_enable(udc); + udc->gadget.speed = USB_SPEED_FULL; + + for (i = 1; i < NUM_ENDPOINTS; i++) { + struct lpc32xx_ep *ep = &udc->ep[i]; + ep->req_pending = 0; + } +} + +/* Send a ZLP on EP0 */ +static void udc_ep0_send_zlp(struct lpc32xx_udc *udc) +{ + udc_write_hwep(udc, EP_IN, NULL, 0); +} + +/* Get current frame number */ +static u16 udc_get_current_frame(struct lpc32xx_udc *udc) +{ + u16 flo, fhi; + + udc_protocol_cmd_w(udc, CMD_RD_FRAME); + flo = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME); + fhi = (u16) udc_protocol_cmd_r(udc, DAT_RD_FRAME); + + return (fhi << 8) | flo; +} + +/* Set the device as configured - enables all endpoints */ +static inline void udc_set_device_configured(struct lpc32xx_udc *udc) +{ + udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(CONF_DVICE)); +} + +/* Set the device as unconfigured - disables all endpoints */ +static inline void udc_set_device_unconfigured(struct lpc32xx_udc *udc) +{ + udc_protocol_cmd_data_w(udc, CMD_CFG_DEV, DAT_WR_BYTE(0)); +} + +/* reinit == restore initial software state */ +static void udc_reinit(struct lpc32xx_udc *udc) +{ + u32 i; + + INIT_LIST_HEAD(&udc->gadget.ep_list); + INIT_LIST_HEAD(&udc->gadget.ep0->ep_list); + + for (i = 0; i < NUM_ENDPOINTS; i++) { + struct lpc32xx_ep *ep = &udc->ep[i]; + + if (i != 0) + list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list); + ep->desc = NULL; + ep->ep.maxpacket = ep->maxpacket; + INIT_LIST_HEAD(&ep->queue); + ep->req_pending = 0; + } + + udc->ep0state = WAIT_FOR_SETUP; +} + +/* Must be called with lock */ +static void done(struct lpc32xx_ep *ep, struct lpc32xx_request *req, int status) +{ + struct lpc32xx_udc *udc = ep->udc; + + list_del_init(&req->queue); + if (req->req.status == -EINPROGRESS) + req->req.status = status; + else + status = req->req.status; + + if (ep->lep) { + enum dma_data_direction direction; + + if (ep->is_in) + direction = DMA_TO_DEVICE; + else + direction = DMA_FROM_DEVICE; + + if (req->mapped) { + dma_unmap_single(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + direction); + req->req.dma = 0; + req->mapped = 0; + } else + dma_sync_single_for_cpu(ep->udc->gadget.dev.parent, + req->req.dma, req->req.length, + direction); + + /* Free DDs */ + udc_dd_free(udc, req->dd_desc_ptr); + } + + if (status && status != -ESHUTDOWN) + ep_dbg(ep, "%s done %p, status %d\n", ep->ep.name, req, status); + + ep->req_pending = 0; + spin_unlock(&udc->lock); + req->req.complete(&ep->ep, &req->req); + spin_lock(&udc->lock); +} + +/* Must be called with lock */ +static void nuke(struct lpc32xx_ep *ep, int status) +{ + struct lpc32xx_request *req; + + while (!list_empty(&ep->queue)) { + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + done(ep, req, status); + } + + if (ep->desc && status == -ESHUTDOWN) { + uda_disable_hwepint(ep->udc, ep->hwep_num); + udc_disable_hwep(ep->udc, ep->hwep_num); + } +} + +/* IN endpoint 0 transfer */ +static int udc_ep0_in_req(struct lpc32xx_udc *udc) +{ + struct lpc32xx_request *req; + struct lpc32xx_ep *ep0 = &udc->ep[0]; + u32 tsend, ts = 0; + + if (list_empty(&ep0->queue)) + /* Nothing to send */ + return 0; + else + req = list_entry(ep0->queue.next, struct lpc32xx_request, + queue); + + tsend = ts = req->req.length - req->req.actual; + if (ts == 0) { + /* Send a ZLP */ + udc_ep0_send_zlp(udc); + done(ep0, req, 0); + return 1; + } else if (ts > ep0->ep.maxpacket) + ts = ep0->ep.maxpacket; /* Just send what we can */ + + /* Write data to the EP0 FIFO and start transfer */ + udc_write_hwep(udc, EP_IN, (req->req.buf + req->req.actual), ts); + + /* Increment data pointer */ + req->req.actual += ts; + + if (tsend >= ep0->ep.maxpacket) + return 0; /* Stay in data transfer state */ + + /* Transfer request is complete */ + udc->ep0state = WAIT_FOR_SETUP; + done(ep0, req, 0); + return 1; +} + +/* OUT endpoint 0 transfer */ +static int udc_ep0_out_req(struct lpc32xx_udc *udc) +{ + struct lpc32xx_request *req; + struct lpc32xx_ep *ep0 = &udc->ep[0]; + u32 tr, bufferspace; + + if (list_empty(&ep0->queue)) + return 0; + else + req = list_entry(ep0->queue.next, struct lpc32xx_request, + queue); + + if (req) { + if (req->req.length == 0) { + /* Just dequeue request */ + done(ep0, req, 0); + udc->ep0state = WAIT_FOR_SETUP; + return 1; + } + + /* Get data from FIFO */ + bufferspace = req->req.length - req->req.actual; + if (bufferspace > ep0->ep.maxpacket) + bufferspace = ep0->ep.maxpacket; + + /* Copy data to buffer */ + prefetchw(req->req.buf + req->req.actual); + tr = udc_read_hwep(udc, EP_OUT, req->req.buf + req->req.actual, + bufferspace); + req->req.actual += bufferspace; + + if (tr < ep0->ep.maxpacket) { + /* This is the last packet */ + done(ep0, req, 0); + udc->ep0state = WAIT_FOR_SETUP; + return 1; + } + } + + return 0; +} + +/* Must be called with lock */ +static void stop_activity(struct lpc32xx_udc *udc) +{ + struct usb_gadget_driver *driver = udc->driver; + int i; + + if (udc->gadget.speed == USB_SPEED_UNKNOWN) + driver = NULL; + + udc->gadget.speed = USB_SPEED_UNKNOWN; + udc->suspended = 0; + + for (i = 0; i < NUM_ENDPOINTS; i++) { + struct lpc32xx_ep *ep = &udc->ep[i]; + nuke(ep, -ESHUTDOWN); + } + if (driver) { + spin_unlock(&udc->lock); + driver->disconnect(&udc->gadget); + spin_lock(&udc->lock); + } + + isp1301_pullup_enable(udc, 0, 0); + udc_disable(udc); + udc_reinit(udc); +} + +/* + * Activate or kill host pullup + * Can be called with or without lock + */ +static void pullup(struct lpc32xx_udc *udc, int is_on) +{ + if (!udc->clocked) + return; + + if (!udc->enabled || !udc->vbus) + is_on = 0; + + if (is_on != udc->pullup) + isp1301_pullup_enable(udc, is_on, 0); +} + +/* Must be called without lock */ +static int lpc32xx_ep_disable(struct usb_ep *_ep) +{ + struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); + struct lpc32xx_udc *udc = ep->udc; + unsigned long flags; + + if ((ep->hwep_num_base == 0) || (ep->hwep_num == 0)) + return -EINVAL; + spin_lock_irqsave(&udc->lock, flags); + + nuke(ep, -ESHUTDOWN); + + /* restore the endpoint's pristine config */ + ep->desc = NULL; + + /* Clear all DMA statuses for this EP */ + udc_ep_dma_disable(udc, ep->hwep_num); + writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr)); + + /* Remove the DD pointer in the UDCA */ + udc->udca_v_base[ep->hwep_num] = 0; + + /* Disable and reset endpoint and interrupt */ + uda_clear_hwepint(udc, ep->hwep_num); + udc_unrealize_hwep(udc, ep->hwep_num); + + ep->hwep_num = 0; + + spin_unlock_irqrestore(&udc->lock, flags); + + atomic_dec(&udc->enabled_ep_cnt); + wake_up(&udc->ep_disable_wait_queue); + + return 0; +} + +/* Must be called without lock */ +static int lpc32xx_ep_enable(struct usb_ep *_ep, + const struct usb_endpoint_descriptor *desc) +{ + struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); + struct lpc32xx_udc *udc = ep->udc; + u16 maxpacket; + u32 tmp; + unsigned long flags; + + /* Verify EP data */ + if ((!_ep) || (!ep) || (!desc) || (ep->desc) || + (desc->bDescriptorType != USB_DT_ENDPOINT)) { + dev_dbg(udc->dev, "bad ep or descriptor\n"); + return -EINVAL; + } + maxpacket = usb_endpoint_maxp(desc); + if ((maxpacket == 0) || (maxpacket > ep->maxpacket)) { + dev_dbg(udc->dev, "bad ep descriptor's packet size\n"); + return -EINVAL; + } + + /* Don't touch EP0 */ + if (ep->hwep_num_base == 0) { + dev_dbg(udc->dev, "Can't re-enable EP0!!!\n"); + return -EINVAL; + } + + /* Is driver ready? */ + if ((!udc->driver) || (udc->gadget.speed == USB_SPEED_UNKNOWN)) { + dev_dbg(udc->dev, "bogus device state\n"); + return -ESHUTDOWN; + } + + tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; + switch (tmp) { + case USB_ENDPOINT_XFER_CONTROL: + return -EINVAL; + + case USB_ENDPOINT_XFER_INT: + if (maxpacket > ep->maxpacket) { + dev_dbg(udc->dev, + "Bad INT endpoint maxpacket %d\n", maxpacket); + return -EINVAL; + } + break; + + case USB_ENDPOINT_XFER_BULK: + switch (maxpacket) { + case 8: + case 16: + case 32: + case 64: + break; + + default: + dev_dbg(udc->dev, + "Bad BULK endpoint maxpacket %d\n", maxpacket); + return -EINVAL; + } + break; + + case USB_ENDPOINT_XFER_ISOC: + break; + } + spin_lock_irqsave(&udc->lock, flags); + + /* Initialize endpoint to match the selected descriptor */ + ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0; + ep->desc = desc; + ep->ep.maxpacket = maxpacket; + + /* Map hardware endpoint from base and direction */ + if (ep->is_in) + /* IN endpoints are offset 1 from the OUT endpoint */ + ep->hwep_num = ep->hwep_num_base + EP_IN; + else + ep->hwep_num = ep->hwep_num_base; + + ep_dbg(ep, "EP enabled: %s, HW:%d, MP:%d IN:%d\n", ep->ep.name, + ep->hwep_num, maxpacket, (ep->is_in == 1)); + + /* Realize the endpoint, interrupt is enabled later when + * buffers are queued, IN EPs will NAK until buffers are ready */ + udc_realize_hwep(udc, ep->hwep_num, ep->ep.maxpacket); + udc_clr_buffer_hwep(udc, ep->hwep_num); + uda_disable_hwepint(udc, ep->hwep_num); + udc_clrstall_hwep(udc, ep->hwep_num); + + /* Clear all DMA statuses for this EP */ + udc_ep_dma_disable(udc, ep->hwep_num); + writel(1 << ep->hwep_num, USBD_EOTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_NDDRTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_SYSERRTINTCLR(udc->udp_baseaddr)); + writel(1 << ep->hwep_num, USBD_DMARCLR(udc->udp_baseaddr)); + + spin_unlock_irqrestore(&udc->lock, flags); + + atomic_inc(&udc->enabled_ep_cnt); + return 0; +} + +/* + * Allocate a USB request list + * Can be called with or without lock + */ +static struct usb_request *lpc32xx_ep_alloc_request(struct usb_ep *_ep, + gfp_t gfp_flags) +{ + struct lpc32xx_request *req; + + req = kzalloc(sizeof(struct lpc32xx_request), gfp_flags); + if (!req) + return NULL; + + INIT_LIST_HEAD(&req->queue); + return &req->req; +} + +/* + * De-allocate a USB request list + * Can be called with or without lock + */ +static void lpc32xx_ep_free_request(struct usb_ep *_ep, + struct usb_request *_req) +{ + struct lpc32xx_request *req; + + req = container_of(_req, struct lpc32xx_request, req); + BUG_ON(!list_empty(&req->queue)); + kfree(req); +} + +/* Must be called without lock */ +static int lpc32xx_ep_queue(struct usb_ep *_ep, + struct usb_request *_req, gfp_t gfp_flags) +{ + struct lpc32xx_request *req; + struct lpc32xx_ep *ep; + struct lpc32xx_udc *udc; + unsigned long flags; + int status = 0; + + req = container_of(_req, struct lpc32xx_request, req); + ep = container_of(_ep, struct lpc32xx_ep, ep); + + if (!_req || !_req->complete || !_req->buf || + !list_empty(&req->queue)) + return -EINVAL; + + udc = ep->udc; + + if (!_ep || (!ep->desc && ep->hwep_num_base != 0)) { + dev_dbg(udc->dev, "invalid ep\n"); + return -EINVAL; + } + + + if ((!udc) || (!udc->driver) || + (udc->gadget.speed == USB_SPEED_UNKNOWN)) { + dev_dbg(udc->dev, "invalid device\n"); + return -EINVAL; + } + + if (ep->lep) { + enum dma_data_direction direction; + struct lpc32xx_usbd_dd_gad *dd; + + /* Map DMA pointer */ + if (ep->is_in) + direction = DMA_TO_DEVICE; + else + direction = DMA_FROM_DEVICE; + + if (req->req.dma == 0) { + req->req.dma = dma_map_single( + ep->udc->gadget.dev.parent, + req->req.buf, req->req.length, direction); + req->mapped = 1; + } else { + dma_sync_single_for_device( + ep->udc->gadget.dev.parent, req->req.dma, + req->req.length, direction); + req->mapped = 0; + } + + /* For the request, build a list of DDs */ + dd = udc_dd_alloc(udc); + if (!dd) { + /* Error allocating DD */ + return -ENOMEM; + } + req->dd_desc_ptr = dd; + + /* Setup the DMA descriptor */ + dd->dd_next_phy = dd->dd_next_v = 0; + dd->dd_buffer_addr = req->req.dma; + dd->dd_status = 0; + + /* Special handling for ISO EPs */ + if (ep->eptype == EP_ISO_TYPE) { + dd->dd_setup = DD_SETUP_ISO_EP | + DD_SETUP_PACKETLEN(0) | + DD_SETUP_DMALENBYTES(1); + dd->dd_iso_ps_mem_addr = dd->this_dma + 24; + if (ep->is_in) + dd->iso_status[0] = req->req.length; + else + dd->iso_status[0] = 0; + } else + dd->dd_setup = DD_SETUP_PACKETLEN(ep->ep.maxpacket) | + DD_SETUP_DMALENBYTES(req->req.length); + } + + ep_dbg(ep, "%s queue req %p len %d buf %p (in=%d) z=%d\n", _ep->name, + _req, _req->length, _req->buf, ep->is_in, _req->zero); + + spin_lock_irqsave(&udc->lock, flags); + + _req->status = -EINPROGRESS; + _req->actual = 0; + req->send_zlp = _req->zero; + + /* Kickstart empty queues */ + if (list_empty(&ep->queue)) { + list_add_tail(&req->queue, &ep->queue); + + if (ep->hwep_num_base == 0) { + /* Handle expected data direction */ + if (ep->is_in) { + /* IN packet to host */ + udc->ep0state = DATA_IN; + status = udc_ep0_in_req(udc); + } else { + /* OUT packet from host */ + udc->ep0state = DATA_OUT; + status = udc_ep0_out_req(udc); + } + } else if (ep->is_in) { + /* IN packet to host and kick off transfer */ + if (!ep->req_pending) + udc_ep_in_req_dma(udc, ep); + } else + /* OUT packet from host and kick off list */ + if (!ep->req_pending) + udc_ep_out_req_dma(udc, ep); + } else + list_add_tail(&req->queue, &ep->queue); + + spin_unlock_irqrestore(&udc->lock, flags); + + return (status < 0) ? status : 0; +} + +/* Must be called without lock */ +static int lpc32xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req) +{ + struct lpc32xx_ep *ep; + struct lpc32xx_request *req; + unsigned long flags; + + ep = container_of(_ep, struct lpc32xx_ep, ep); + if (!_ep || ep->hwep_num_base == 0) + return -EINVAL; + + spin_lock_irqsave(&ep->udc->lock, flags); + + /* make sure it's actually queued on this endpoint */ + list_for_each_entry(req, &ep->queue, queue) { + if (&req->req == _req) + break; + } + if (&req->req != _req) { + spin_unlock_irqrestore(&ep->udc->lock, flags); + return -EINVAL; + } + + done(ep, req, -ECONNRESET); + + spin_unlock_irqrestore(&ep->udc->lock, flags); + + return 0; +} + +/* Must be called without lock */ +static int lpc32xx_ep_set_halt(struct usb_ep *_ep, int value) +{ + struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); + struct lpc32xx_udc *udc = ep->udc; + unsigned long flags; + + if ((!ep) || (ep->desc == NULL) || (ep->hwep_num <= 1)) + return -EINVAL; + + /* Don't halt an IN EP */ + if (ep->is_in) + return -EAGAIN; + + spin_lock_irqsave(&udc->lock, flags); + + if (value == 1) { + /* stall */ + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num), + DAT_WR_BYTE(EP_STAT_ST)); + } else { + /* End stall */ + ep->wedge = 0; + udc_protocol_cmd_data_w(udc, CMD_SET_EP_STAT(ep->hwep_num), + DAT_WR_BYTE(0)); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/* set the halt feature and ignores clear requests */ +static int lpc32xx_ep_set_wedge(struct usb_ep *_ep) +{ + struct lpc32xx_ep *ep = container_of(_ep, struct lpc32xx_ep, ep); + + if (!_ep || !ep->udc) + return -EINVAL; + + ep->wedge = 1; + + return usb_ep_set_halt(_ep); +} + +static const struct usb_ep_ops lpc32xx_ep_ops = { + .enable = lpc32xx_ep_enable, + .disable = lpc32xx_ep_disable, + .alloc_request = lpc32xx_ep_alloc_request, + .free_request = lpc32xx_ep_free_request, + .queue = lpc32xx_ep_queue, + .dequeue = lpc32xx_ep_dequeue, + .set_halt = lpc32xx_ep_set_halt, + .set_wedge = lpc32xx_ep_set_wedge, +}; + +/* Send a ZLP on a non-0 IN EP */ +void udc_send_in_zlp(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + /* Clear EP status */ + udc_clearep_getsts(udc, ep->hwep_num); + + /* Send ZLP via FIFO mechanism */ + udc_write_hwep(udc, ep->hwep_num, NULL, 0); +} + +/* + * Handle EP completion for ZLP + * This function will only be called when a delayed ZLP needs to be sent out + * after a DMA transfer has filled both buffers. + */ +void udc_handle_eps(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + u32 epstatus; + struct lpc32xx_request *req; + + if (ep->hwep_num <= 0) + return; + + uda_clear_hwepint(udc, ep->hwep_num); + + /* If this interrupt isn't enabled, return now */ + if (!(udc->enabled_hwepints & (1 << ep->hwep_num))) + return; + + /* Get endpoint status */ + epstatus = udc_clearep_getsts(udc, ep->hwep_num); + + /* + * This should never happen, but protect against writing to the + * buffer when full. + */ + if (epstatus & EP_SEL_F) + return; + + if (ep->is_in) { + udc_send_in_zlp(udc, ep); + uda_disable_hwepint(udc, ep->hwep_num); + } else + return; + + /* If there isn't a request waiting, something went wrong */ + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + if (req) { + done(ep, req, 0); + + /* Start another request if ready */ + if (!list_empty(&ep->queue)) { + if (ep->is_in) + udc_ep_in_req_dma(udc, ep); + else + udc_ep_out_req_dma(udc, ep); + } else + ep->req_pending = 0; + } +} + + +/* DMA end of transfer completion */ +static void udc_handle_dma_ep(struct lpc32xx_udc *udc, struct lpc32xx_ep *ep) +{ + u32 status, epstatus; + struct lpc32xx_request *req; + struct lpc32xx_usbd_dd_gad *dd; + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + ep->totalints++; +#endif + + req = list_entry(ep->queue.next, struct lpc32xx_request, queue); + if (!req) { + ep_err(ep, "DMA interrupt on no req!\n"); + return; + } + dd = req->dd_desc_ptr; + + /* DMA descriptor should always be retired for this call */ + if (!(dd->dd_status & DD_STATUS_DD_RETIRED)) + ep_warn(ep, "DMA descriptor did not retire\n"); + + /* Disable DMA */ + udc_ep_dma_disable(udc, ep->hwep_num); + writel((1 << ep->hwep_num), USBD_EOTINTCLR(udc->udp_baseaddr)); + writel((1 << ep->hwep_num), USBD_NDDRTINTCLR(udc->udp_baseaddr)); + + /* System error? */ + if (readl(USBD_SYSERRTINTST(udc->udp_baseaddr)) & + (1 << ep->hwep_num)) { + writel((1 << ep->hwep_num), + USBD_SYSERRTINTCLR(udc->udp_baseaddr)); + ep_err(ep, "AHB critical error!\n"); + ep->req_pending = 0; + + /* The error could have occurred on a packet of a multipacket + * transfer, so recovering the transfer is not possible. Close + * the request with an error */ + done(ep, req, -ECONNABORTED); + return; + } + + /* Handle the current DD's status */ + status = dd->dd_status; + switch (status & DD_STATUS_STS_MASK) { + case DD_STATUS_STS_NS: + /* DD not serviced? This shouldn't happen! */ + ep->req_pending = 0; + ep_err(ep, "DMA critical EP error: DD not serviced (0x%x)!\n", + status); + + done(ep, req, -ECONNABORTED); + return; + + case DD_STATUS_STS_BS: + /* Interrupt only fires on EOT - This shouldn't happen! */ + ep->req_pending = 0; + ep_err(ep, "DMA critical EP error: EOT prior to service completion (0x%x)!\n", + status); + done(ep, req, -ECONNABORTED); + return; + + case DD_STATUS_STS_NC: + case DD_STATUS_STS_DUR: + /* Really just a short packet, not an underrun */ + /* This is a good status and what we expect */ + break; + + default: + /* Data overrun, system error, or unknown */ + ep->req_pending = 0; + ep_err(ep, "DMA critical EP error: System error (0x%x)!\n", + status); + done(ep, req, -ECONNABORTED); + return; + } + + /* ISO endpoints are handled differently */ + if (ep->eptype == EP_ISO_TYPE) { + if (ep->is_in) + req->req.actual = req->req.length; + else + req->req.actual = dd->iso_status[0] & 0xFFFF; + } else + req->req.actual += DD_STATUS_CURDMACNT(status); + + /* Send a ZLP if necessary. This will be done for non-int + * packets which have a size that is a divisor of MAXP */ + if (req->send_zlp) { + /* + * If at least 1 buffer is available, send the ZLP now. + * Otherwise, the ZLP send needs to be deferred until a + * buffer is available. + */ + if (udc_clearep_getsts(udc, ep->hwep_num) & EP_SEL_F) { + udc_clearep_getsts(udc, ep->hwep_num); + uda_enable_hwepint(udc, ep->hwep_num); + epstatus = udc_clearep_getsts(udc, ep->hwep_num); + + /* Let the EP interrupt handle the ZLP */ + return; + } else + udc_send_in_zlp(udc, ep); + } + + /* Transfer request is complete */ + done(ep, req, 0); + + /* Start another request if ready */ + udc_clearep_getsts(udc, ep->hwep_num); + if (!list_empty((&ep->queue))) { + if (ep->is_in) + udc_ep_in_req_dma(udc, ep); + else + udc_ep_out_req_dma(udc, ep); + } else + ep->req_pending = 0; + +} + +/* + * + * Endpoint 0 functions + * + */ +static void udc_handle_dev(struct lpc32xx_udc *udc) +{ + u32 tmp; + + udc_protocol_cmd_w(udc, CMD_GET_DEV_STAT); + tmp = udc_protocol_cmd_r(udc, DAT_GET_DEV_STAT); + + if (tmp & DEV_RST) + uda_usb_reset(udc); + else if (tmp & DEV_CON_CH) + uda_power_event(udc, (tmp & DEV_CON)); + else if (tmp & DEV_SUS_CH) { + if (tmp & DEV_SUS) { + if (udc->vbus == 0) + stop_activity(udc); + else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) && + udc->driver) { + /* Power down transceiver */ + udc->poweron = 0; + schedule_work(&udc->pullup_job); + uda_resm_susp_event(udc, 1); + } + } else if ((udc->gadget.speed != USB_SPEED_UNKNOWN) && + udc->driver && udc->vbus) { + uda_resm_susp_event(udc, 0); + /* Power up transceiver */ + udc->poweron = 1; + schedule_work(&udc->pullup_job); + } + } +} + +static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex) +{ + struct lpc32xx_ep *ep; + u32 ep0buff = 0, tmp; + + switch (reqtype & USB_RECIP_MASK) { + case USB_RECIP_INTERFACE: + break; /* Not supported */ + + case USB_RECIP_DEVICE: + ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED); + if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP)) + ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP); + break; + + case USB_RECIP_ENDPOINT: + tmp = wIndex & USB_ENDPOINT_NUMBER_MASK; + ep = &udc->ep[tmp]; + if ((tmp == 0) || (tmp >= NUM_ENDPOINTS) || (tmp && !ep->desc)) + return -EOPNOTSUPP; + + if (wIndex & USB_DIR_IN) { + if (!ep->is_in) + return -EOPNOTSUPP; /* Something's wrong */ + } else if (ep->is_in) + return -EOPNOTSUPP; /* Not an IN endpoint */ + + /* Get status of the endpoint */ + udc_protocol_cmd_w(udc, CMD_SEL_EP(ep->hwep_num)); + tmp = udc_protocol_cmd_r(udc, DAT_SEL_EP(ep->hwep_num)); + + if (tmp & EP_SEL_ST) + ep0buff = (1 << USB_ENDPOINT_HALT); + else + ep0buff = 0; + break; + + default: + break; + } + + /* Return data */ + udc_write_hwep(udc, EP_IN, &ep0buff, 2); + + return 0; +} + +static void udc_handle_ep0_setup(struct lpc32xx_udc *udc) +{ + struct lpc32xx_ep *ep, *ep0 = &udc->ep[0]; + struct usb_ctrlrequest ctrlpkt; + int i, bytes; + u16 wIndex, wValue, wLength, reqtype, req, tmp; + + /* Nuke previous transfers */ + nuke(ep0, -EPROTO); + + /* Get setup packet */ + bytes = udc_read_hwep(udc, EP_OUT, (u32 *) &ctrlpkt, 8); + if (bytes != 8) { + ep_warn(ep0, "Incorrectly sized setup packet (s/b 8, is %d)!\n", + bytes); + return; + } + + /* Native endianness */ + wIndex = le16_to_cpu(ctrlpkt.wIndex); + wValue = le16_to_cpu(ctrlpkt.wValue); + wLength = le16_to_cpu(ctrlpkt.wLength); + reqtype = le16_to_cpu(ctrlpkt.bRequestType); + + /* Set direction of EP0 */ + if (likely(reqtype & USB_DIR_IN)) + ep0->is_in = 1; + else + ep0->is_in = 0; + + /* Handle SETUP packet */ + req = le16_to_cpu(ctrlpkt.bRequest); + switch (req) { + case USB_REQ_CLEAR_FEATURE: + case USB_REQ_SET_FEATURE: + switch (reqtype) { + case (USB_TYPE_STANDARD | USB_RECIP_DEVICE): + if (wValue != USB_DEVICE_REMOTE_WAKEUP) + goto stall; /* Nothing else handled */ + + /* Tell board about event */ + if (req == USB_REQ_CLEAR_FEATURE) + udc->dev_status &= + ~(1 << USB_DEVICE_REMOTE_WAKEUP); + else + udc->dev_status |= + (1 << USB_DEVICE_REMOTE_WAKEUP); + uda_remwkp_cgh(udc); + goto zlp_send; + + case (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT): + tmp = wIndex & USB_ENDPOINT_NUMBER_MASK; + if ((wValue != USB_ENDPOINT_HALT) || + (tmp >= NUM_ENDPOINTS)) + break; + + /* Find hardware endpoint from logical endpoint */ + ep = &udc->ep[tmp]; + tmp = ep->hwep_num; + if (tmp == 0) + break; + + if (req == USB_REQ_SET_FEATURE) + udc_stall_hwep(udc, tmp); + else if (!ep->wedge) + udc_clrstall_hwep(udc, tmp); + + goto zlp_send; + + default: + break; + } + + + case USB_REQ_SET_ADDRESS: + if (reqtype == (USB_TYPE_STANDARD | USB_RECIP_DEVICE)) { + udc_set_address(udc, wValue); + goto zlp_send; + } + break; + + case USB_REQ_GET_STATUS: + udc_get_status(udc, reqtype, wIndex); + return; + + default: + break; /* Let GadgetFS handle the descriptor instead */ + } + + if (likely(udc->driver)) { + /* device-2-host (IN) or no data setup command, process + * immediately */ + spin_unlock(&udc->lock); + i = udc->driver->setup(&udc->gadget, &ctrlpkt); + + spin_lock(&udc->lock); + if (req == USB_REQ_SET_CONFIGURATION) { + /* Configuration is set after endpoints are realized */ + if (wValue) { + /* Set configuration */ + udc_set_device_configured(udc); + + udc_protocol_cmd_data_w(udc, CMD_SET_MODE, + DAT_WR_BYTE(AP_CLK | + INAK_BI | INAK_II)); + } else { + /* Clear configuration */ + udc_set_device_unconfigured(udc); + + /* Disable NAK interrupts */ + udc_protocol_cmd_data_w(udc, CMD_SET_MODE, + DAT_WR_BYTE(AP_CLK)); + } + } + + if (i < 0) { + /* setup processing failed, force stall */ + dev_err(udc->dev, + "req %02x.%02x protocol STALL; stat %d\n", + reqtype, req, i); + udc->ep0state = WAIT_FOR_SETUP; + goto stall; + } + } + + if (!ep0->is_in) + udc_ep0_send_zlp(udc); /* ZLP IN packet on data phase */ + + return; + +stall: + udc_stall_hwep(udc, EP_IN); + return; + +zlp_send: + udc_ep0_send_zlp(udc); + return; +} + +/* IN endpoint 0 transfer */ +static void udc_handle_ep0_in(struct lpc32xx_udc *udc) +{ + struct lpc32xx_ep *ep0 = &udc->ep[0]; + u32 epstatus; + + /* Clear EP interrupt */ + epstatus = udc_clearep_getsts(udc, EP_IN); + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + ep0->totalints++; +#endif + + /* Stalled? Clear stall and reset buffers */ + if (epstatus & EP_SEL_ST) { + udc_clrstall_hwep(udc, EP_IN); + nuke(ep0, -ECONNABORTED); + udc->ep0state = WAIT_FOR_SETUP; + return; + } + + /* Is a buffer available? */ + if (!(epstatus & EP_SEL_F)) { + /* Handle based on current state */ + if (udc->ep0state == DATA_IN) + udc_ep0_in_req(udc); + else { + /* Unknown state for EP0 oe end of DATA IN phase */ + nuke(ep0, -ECONNABORTED); + udc->ep0state = WAIT_FOR_SETUP; + } + } +} + +/* OUT endpoint 0 transfer */ +static void udc_handle_ep0_out(struct lpc32xx_udc *udc) +{ + struct lpc32xx_ep *ep0 = &udc->ep[0]; + u32 epstatus; + + /* Clear EP interrupt */ + epstatus = udc_clearep_getsts(udc, EP_OUT); + + +#ifdef CONFIG_USB_GADGET_DEBUG_FILES + ep0->totalints++; +#endif + + /* Stalled? */ + if (epstatus & EP_SEL_ST) { + udc_clrstall_hwep(udc, EP_OUT); + nuke(ep0, -ECONNABORTED); + udc->ep0state = WAIT_FOR_SETUP; + return; + } + + /* A NAK may occur if a packet couldn't be received yet */ + if (epstatus & EP_SEL_EPN) + return; + /* Setup packet incoming? */ + if (epstatus & EP_SEL_STP) { + nuke(ep0, 0); + udc->ep0state = WAIT_FOR_SETUP; + } + + /* Data available? */ + if (epstatus & EP_SEL_F) + /* Handle based on current state */ + switch (udc->ep0state) { + case WAIT_FOR_SETUP: + udc_handle_ep0_setup(udc); + break; + + case DATA_OUT: + udc_ep0_out_req(udc); + break; + + default: + /* Unknown state for EP0 */ + nuke(ep0, -ECONNABORTED); + udc->ep0state = WAIT_FOR_SETUP; + } +} + +/* Must be called without lock */ +static int lpc32xx_get_frame(struct usb_gadget *gadget) +{ + int frame; + unsigned long flags; + struct lpc32xx_udc *udc = to_udc(gadget); + + if (!udc->clocked) + return -EINVAL; + + spin_lock_irqsave(&udc->lock, flags); + + frame = (int) udc_get_current_frame(udc); + + spin_unlock_irqrestore(&udc->lock, flags); + + return frame; +} + +static int lpc32xx_wakeup(struct usb_gadget *gadget) +{ + return -ENOTSUPP; +} + +static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on) +{ + struct lpc32xx_udc *udc = to_udc(gadget); + + /* Always self-powered */ + udc->selfpowered = (is_on != 0); + + return 0; +} + +/* + * vbus is here! turn everything on that's ready + * Must be called without lock + */ +static int lpc32xx_vbus_session(struct usb_gadget *gadget, int is_active) +{ + unsigned long flags; + struct lpc32xx_udc *udc = to_udc(gadget); + + spin_lock_irqsave(&udc->lock, flags); + + /* Doesn't need lock */ + if (udc->driver) { + udc_clk_set(udc, 1); + udc_enable(udc); + pullup(udc, is_active); + } else { + stop_activity(udc); + pullup(udc, 0); + + spin_unlock_irqrestore(&udc->lock, flags); + /* + * Wait for all the endpoints to disable, + * before disabling clocks. Don't wait if + * endpoints are not enabled. + */ + if (atomic_read(&udc->enabled_ep_cnt)) + wait_event_interruptible(udc->ep_disable_wait_queue, + (atomic_read(&udc->enabled_ep_cnt) == 0)); + + spin_lock_irqsave(&udc->lock, flags); + + udc_clk_set(udc, 0); + } + + spin_unlock_irqrestore(&udc->lock, flags); + + return 0; +} + +/* Can be called with or without lock */ +static int lpc32xx_pullup(struct usb_gadget *gadget, int is_on) +{ + struct lpc32xx_udc *udc = to_udc(gadget); + + /* Doesn't need lock */ + pullup(udc, is_on); + + return 0; +} + +static int lpc32xx_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)); +static int lpc32xx_stop(struct usb_gadget_driver *driver); + +static const struct usb_gadget_ops lpc32xx_udc_ops = { + .get_frame = lpc32xx_get_frame, + .wakeup = lpc32xx_wakeup, + .set_selfpowered = lpc32xx_set_selfpowered, + .vbus_session = lpc32xx_vbus_session, + .pullup = lpc32xx_pullup, + .start = lpc32xx_start, + .stop = lpc32xx_stop, +}; + +static void nop_release(struct device *dev) +{ + /* nothing to free */ +} + +static struct lpc32xx_udc controller = { + .gadget = { + .ops = &lpc32xx_udc_ops, + .ep0 = &controller.ep[0].ep, + .name = driver_name, + .dev = { + .init_name = "gadget", + .release = nop_release, + } + }, + .ep[0] = { + .ep = { + .name = "ep0", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 0, + .hwep_num = 0, /* Can be 0 or 1, has special handling */ + .lep = 0, + .eptype = EP_CTL_TYPE, + }, + .ep[1] = { + .ep = { + .name = "ep1-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 2, + .hwep_num = 0, /* 2 or 3, will be set later */ + .lep = 1, + .eptype = EP_INT_TYPE, + }, + .ep[2] = { + .ep = { + .name = "ep2-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 4, + .hwep_num = 0, /* 4 or 5, will be set later */ + .lep = 2, + .eptype = EP_BLK_TYPE, + }, + .ep[3] = { + .ep = { + .name = "ep3-iso", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 6, + .hwep_num = 0, /* 6 or 7, will be set later */ + .lep = 3, + .eptype = EP_ISO_TYPE, + }, + .ep[4] = { + .ep = { + .name = "ep4-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 8, + .hwep_num = 0, /* 8 or 9, will be set later */ + .lep = 4, + .eptype = EP_INT_TYPE, + }, + .ep[5] = { + .ep = { + .name = "ep5-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 10, + .hwep_num = 0, /* 10 or 11, will be set later */ + .lep = 5, + .eptype = EP_BLK_TYPE, + }, + .ep[6] = { + .ep = { + .name = "ep6-iso", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 12, + .hwep_num = 0, /* 12 or 13, will be set later */ + .lep = 6, + .eptype = EP_ISO_TYPE, + }, + .ep[7] = { + .ep = { + .name = "ep7-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 14, + .hwep_num = 0, + .lep = 7, + .eptype = EP_INT_TYPE, + }, + .ep[8] = { + .ep = { + .name = "ep8-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 16, + .hwep_num = 0, + .lep = 8, + .eptype = EP_BLK_TYPE, + }, + .ep[9] = { + .ep = { + .name = "ep9-iso", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 18, + .hwep_num = 0, + .lep = 9, + .eptype = EP_ISO_TYPE, + }, + .ep[10] = { + .ep = { + .name = "ep10-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 20, + .hwep_num = 0, + .lep = 10, + .eptype = EP_INT_TYPE, + }, + .ep[11] = { + .ep = { + .name = "ep11-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 22, + .hwep_num = 0, + .lep = 11, + .eptype = EP_BLK_TYPE, + }, + .ep[12] = { + .ep = { + .name = "ep12-iso", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 24, + .hwep_num = 0, + .lep = 12, + .eptype = EP_ISO_TYPE, + }, + .ep[13] = { + .ep = { + .name = "ep13-int", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 26, + .hwep_num = 0, + .lep = 13, + .eptype = EP_INT_TYPE, + }, + .ep[14] = { + .ep = { + .name = "ep14-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 64, + .hwep_num_base = 28, + .hwep_num = 0, + .lep = 14, + .eptype = EP_BLK_TYPE, + }, + .ep[15] = { + .ep = { + .name = "ep15-bulk", + .ops = &lpc32xx_ep_ops, + }, + .udc = &controller, + .maxpacket = 1023, + .hwep_num_base = 30, + .hwep_num = 0, + .lep = 15, + .eptype = EP_BLK_TYPE, + }, +}; + +/* ISO and status interrupts */ +static irqreturn_t lpc32xx_usb_lp_irq(int irq, void *_udc) +{ + u32 tmp, devstat; + struct lpc32xx_udc *udc = _udc; + + spin_lock(&udc->lock); + + /* Read the device status register */ + devstat = readl(USBD_DEVINTST(udc->udp_baseaddr)); + + devstat &= ~USBD_EP_FAST; + writel(devstat, USBD_DEVINTCLR(udc->udp_baseaddr)); + devstat = devstat & udc->enabled_devints; + + /* Device specific handling needed? */ + if (devstat & USBD_DEV_STAT) + udc_handle_dev(udc); + + /* Start of frame? (devstat & FRAME_INT): + * The frame interrupt isn't really needed for ISO support, + * as the driver will queue the necessary packets */ + + /* Error? */ + if (devstat & ERR_INT) { + /* All types of errors, from cable removal during transfer to + * misc protocol and bit errors. These are mostly for just info, + * as the USB hardware will work around these. If these errors + * happen alot, something is wrong. */ + udc_protocol_cmd_w(udc, CMD_RD_ERR_STAT); + tmp = udc_protocol_cmd_r(udc, DAT_RD_ERR_STAT); + dev_dbg(udc->dev, "Device error (0x%x)!\n", tmp); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +/* EP interrupts */ +static irqreturn_t lpc32xx_usb_hp_irq(int irq, void *_udc) +{ + u32 tmp; + struct lpc32xx_udc *udc = _udc; + + spin_lock(&udc->lock); + + /* Read the device status register */ + writel(USBD_EP_FAST, USBD_DEVINTCLR(udc->udp_baseaddr)); + + /* Endpoints */ + tmp = readl(USBD_EPINTST(udc->udp_baseaddr)); + + /* Special handling for EP0 */ + if (tmp & (EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) { + /* Handle EP0 IN */ + if (tmp & (EP_MASK_SEL(0, EP_IN))) + udc_handle_ep0_in(udc); + + /* Handle EP0 OUT */ + if (tmp & (EP_MASK_SEL(0, EP_OUT))) + udc_handle_ep0_out(udc); + } + + /* All other EPs */ + if (tmp & ~(EP_MASK_SEL(0, EP_OUT) | EP_MASK_SEL(0, EP_IN))) { + int i; + + /* Handle other EP interrupts */ + for (i = 1; i < NUM_ENDPOINTS; i++) { + if (tmp & (1 << udc->ep[i].hwep_num)) + udc_handle_eps(udc, &udc->ep[i]); + } + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +static irqreturn_t lpc32xx_usb_devdma_irq(int irq, void *_udc) +{ + struct lpc32xx_udc *udc = _udc; + + int i; + u32 tmp; + + spin_lock(&udc->lock); + + /* Handle EP DMA EOT interrupts */ + tmp = readl(USBD_EOTINTST(udc->udp_baseaddr)) | + (readl(USBD_EPDMAST(udc->udp_baseaddr)) & + readl(USBD_NDDRTINTST(udc->udp_baseaddr))) | + readl(USBD_SYSERRTINTST(udc->udp_baseaddr)); + for (i = 1; i < NUM_ENDPOINTS; i++) { + if (tmp & (1 << udc->ep[i].hwep_num)) + udc_handle_dma_ep(udc, &udc->ep[i]); + } + + spin_unlock(&udc->lock); + + return IRQ_HANDLED; +} + +/* + * + * VBUS detection, pullup handler, and Gadget cable state notification + * + */ +static void vbus_work(struct work_struct *work) +{ + u8 value; + struct lpc32xx_udc *udc = container_of(work, struct lpc32xx_udc, + vbus_job); + + if (udc->enabled != 0) { + /* Discharge VBUS real quick */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1, OTG1_VBUS_DISCHRG); + + /* Give VBUS some time (100mS) to discharge */ + msleep(100); + + /* Disable VBUS discharge resistor */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR, + OTG1_VBUS_DISCHRG); + + /* Clear interrupt */ + i2c_smbus_write_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_INTERRUPT_LATCH | + ISP1301_I2C_REG_CLEAR_ADDR, ~0); + + /* Get the VBUS status from the transceiver */ + value = i2c_smbus_read_byte_data(udc->isp1301_i2c_client, + ISP1301_I2C_OTG_CONTROL_2); + + /* VBUS on or off? */ + if (value & OTG_B_SESS_VLD) + udc->vbus = 1; + else + udc->vbus = 0; + + /* VBUS changed? */ + if (udc->last_vbus != udc->vbus) { + udc->last_vbus = udc->vbus; + lpc32xx_vbus_session(&udc->gadget, udc->vbus); + } + } + + /* Re-enable after completion */ + enable_irq(udc->udp_irq[IRQ_USB_ATX]); +} + +static irqreturn_t lpc32xx_usb_vbus_irq(int irq, void *_udc) +{ + struct lpc32xx_udc *udc = _udc; + + /* Defer handling of VBUS IRQ to work queue */ + disable_irq_nosync(udc->udp_irq[IRQ_USB_ATX]); + schedule_work(&udc->vbus_job); + + return IRQ_HANDLED; +} + +static int lpc32xx_start(struct usb_gadget_driver *driver, + int (*bind)(struct usb_gadget *)) +{ + struct lpc32xx_udc *udc = &controller; + int retval, i; + + if (!driver || driver->max_speed < USB_SPEED_FULL || + !bind || !driver->setup) { + dev_err(udc->dev, "bad parameter.\n"); + return -EINVAL; + } + + if (udc->driver) { + dev_err(udc->dev, "UDC already has a gadget driver\n"); + return -EBUSY; + } + + udc->driver = driver; + udc->gadget.dev.driver = &driver->driver; + udc->enabled = 1; + udc->selfpowered = 1; + udc->vbus = 0; + + retval = bind(&udc->gadget); + if (retval) { + dev_err(udc->dev, "bind() returned %d\n", retval); + udc->enabled = 0; + udc->selfpowered = 0; + udc->driver = NULL; + udc->gadget.dev.driver = NULL; + return retval; + } + + dev_dbg(udc->dev, "bound to %s\n", driver->driver.name); + + /* Force VBUS process once to check for cable insertion */ + udc->last_vbus = udc->vbus = 0; + schedule_work(&udc->vbus_job); + + /* Do not re-enable ATX IRQ (3) */ + for (i = IRQ_USB_LP; i < IRQ_USB_ATX; i++) + enable_irq(udc->udp_irq[i]); + + return 0; +} + +static int lpc32xx_stop(struct usb_gadget_driver *driver) +{ + int i; + struct lpc32xx_udc *udc = &controller; + + if (!driver || driver != udc->driver || !driver->unbind) + return -EINVAL; + + /* Disable USB pullup */ + isp1301_pullup_enable(udc, 0, 1); + + for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) + disable_irq(udc->udp_irq[i]); + + if (udc->clocked) { + + spin_lock(&udc->lock); + stop_activity(udc); + spin_unlock(&udc->lock); + + /* + * Wait for all the endpoints to disable, + * before disabling clocks. Don't wait if + * endpoints are not enabled. + */ + if (atomic_read(&udc->enabled_ep_cnt)) + wait_event_interruptible(udc->ep_disable_wait_queue, + (atomic_read(&udc->enabled_ep_cnt) == 0)); + + spin_lock(&udc->lock); + udc_clk_set(udc, 0); + spin_unlock(&udc->lock); + } + + udc->enabled = 0; + pullup(udc, 0); + + driver->unbind(&udc->gadget); + udc->gadget.dev.driver = NULL; + udc->driver = NULL; + + dev_dbg(udc->dev, "unbound from %s\n", driver->driver.name); + return 0; +} + +static void lpc32xx_udc_shutdown(struct platform_device *dev) +{ + /* Force disconnect on reboot */ + struct lpc32xx_udc *udc = &controller; + + pullup(udc, 0); +} + +/* + * Callbacks to be overridden by options passed via OF (TODO) + */ + +static void lpc32xx_usbd_conn_chg(int conn) +{ + /* Do nothing, it might be nice to enable an LED + * based on conn state being !0 */ +} + +static void lpc32xx_usbd_susp_chg(int susp) +{ + /* Device suspend if susp != 0 */ +} + +static void lpc32xx_rmwkup_chg(int remote_wakup_enable) +{ + /* Enable or disable USB remote wakeup */ +} + +struct lpc32xx_usbd_cfg lpc32xx_usbddata = { + .vbus_drv_pol = 0, + .conn_chgb = &lpc32xx_usbd_conn_chg, + .susp_chgb = &lpc32xx_usbd_susp_chg, + .rmwk_chgb = &lpc32xx_rmwkup_chg, +}; + + +static u64 lpc32xx_usbd_dmamask = ~(u32) 0x7F; + +static int __init lpc32xx_udc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct lpc32xx_udc *udc = &controller; + int retval, i; + struct resource *res; + dma_addr_t dma_handle; + struct device_node *isp1301_node; + + /* init software state */ + udc->gadget.dev.parent = dev; + udc->pdev = pdev; + udc->dev = &pdev->dev; + udc->enabled = 0; + + if (pdev->dev.of_node) { + isp1301_node = of_parse_phandle(pdev->dev.of_node, + "transceiver", 0); + } else { + isp1301_node = NULL; + } + + udc->isp1301_i2c_client = isp1301_get_client(isp1301_node); + if (!udc->isp1301_i2c_client) + return -EPROBE_DEFER; + + dev_info(udc->dev, "ISP1301 I2C device at address 0x%x\n", + udc->isp1301_i2c_client->addr); + + pdev->dev.dma_mask = &lpc32xx_usbd_dmamask; + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + udc->board = &lpc32xx_usbddata; + + /* + * Resources are mapped as follows: + * IORESOURCE_MEM, base address and size of USB space + * IORESOURCE_IRQ, USB device low priority interrupt number + * IORESOURCE_IRQ, USB device high priority interrupt number + * IORESOURCE_IRQ, USB device interrupt number + * IORESOURCE_IRQ, USB transceiver interrupt number + */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + spin_lock_init(&udc->lock); + + /* Get IRQs */ + for (i = 0; i < 4; i++) { + udc->udp_irq[i] = platform_get_irq(pdev, i); + if (udc->udp_irq[i] < 0) { + dev_err(udc->dev, + "irq resource %d not available!\n", i); + return udc->udp_irq[i]; + } + } + + udc->io_p_start = res->start; + udc->io_p_size = resource_size(res); + if (!request_mem_region(udc->io_p_start, udc->io_p_size, driver_name)) { + dev_err(udc->dev, "someone's using UDC memory\n"); + return -EBUSY; + } + + udc->udp_baseaddr = ioremap(udc->io_p_start, udc->io_p_size); + if (!udc->udp_baseaddr) { + retval = -ENOMEM; + dev_err(udc->dev, "IO map failure\n"); + goto io_map_fail; + } + + /* Enable AHB slave USB clock, needed for further USB clock control */ + writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL); + + /* Get required clocks */ + udc->usb_pll_clk = clk_get(&pdev->dev, "ck_pll5"); + if (IS_ERR(udc->usb_pll_clk)) { + dev_err(udc->dev, "failed to acquire USB PLL\n"); + retval = PTR_ERR(udc->usb_pll_clk); + goto pll_get_fail; + } + udc->usb_slv_clk = clk_get(&pdev->dev, "ck_usbd"); + if (IS_ERR(udc->usb_slv_clk)) { + dev_err(udc->dev, "failed to acquire USB device clock\n"); + retval = PTR_ERR(udc->usb_slv_clk); + goto usb_clk_get_fail; + } + + /* Setup PLL clock to 48MHz */ + retval = clk_enable(udc->usb_pll_clk); + if (retval < 0) { + dev_err(udc->dev, "failed to start USB PLL\n"); + goto pll_enable_fail; + } + + retval = clk_set_rate(udc->usb_pll_clk, 48000); + if (retval < 0) { + dev_err(udc->dev, "failed to set USB clock rate\n"); + goto pll_set_fail; + } + + writel(readl(USB_CTRL) | USB_DEV_NEED_CLK_EN, USB_CTRL); + + /* Enable USB device clock */ + retval = clk_enable(udc->usb_slv_clk); + if (retval < 0) { + dev_err(udc->dev, "failed to start USB device clock\n"); + goto usb_clk_enable_fail; + } + + /* Set to enable all needed USB OTG clocks */ + writel(USB_CLOCK_MASK, USB_OTG_CLK_CTRL(udc)); + + i = 1000; + while (((readl(USB_OTG_CLK_STAT(udc)) & USB_CLOCK_MASK) != + USB_CLOCK_MASK) && (i > 0)) + i--; + if (!i) + dev_dbg(udc->dev, "USB OTG clocks not correctly enabled\n"); + + /* Setup deferred workqueue data */ + udc->poweron = udc->pullup = 0; + INIT_WORK(&udc->pullup_job, pullup_work); + INIT_WORK(&udc->vbus_job, vbus_work); +#ifdef CONFIG_PM + INIT_WORK(&udc->power_job, power_work); +#endif + + /* All clocks are now on */ + udc->clocked = 1; + + isp1301_udc_configure(udc); + /* Allocate memory for the UDCA */ + udc->udca_v_base = dma_alloc_coherent(&pdev->dev, UDCA_BUFF_SIZE, + &dma_handle, + (GFP_KERNEL | GFP_DMA)); + if (!udc->udca_v_base) { + dev_err(udc->dev, "error getting UDCA region\n"); + retval = -ENOMEM; + goto i2c_fail; + } + udc->udca_p_base = dma_handle; + dev_dbg(udc->dev, "DMA buffer(0x%x bytes), P:0x%08x, V:0x%p\n", + UDCA_BUFF_SIZE, udc->udca_p_base, udc->udca_v_base); + + /* Setup the DD DMA memory pool */ + udc->dd_cache = dma_pool_create("udc_dd", udc->dev, + sizeof(struct lpc32xx_usbd_dd_gad), + sizeof(u32), 0); + if (!udc->dd_cache) { + dev_err(udc->dev, "error getting DD DMA region\n"); + retval = -ENOMEM; + goto dma_alloc_fail; + } + + /* Clear USB peripheral and initialize gadget endpoints */ + udc_disable(udc); + udc_reinit(udc); + + retval = device_register(&udc->gadget.dev); + if (retval < 0) { + dev_err(udc->dev, "Device registration failure\n"); + goto dev_register_fail; + } + + /* Request IRQs - low and high priority USB device IRQs are routed to + * the same handler, while the DMA interrupt is routed elsewhere */ + retval = request_irq(udc->udp_irq[IRQ_USB_LP], lpc32xx_usb_lp_irq, + 0, "udc_lp", udc); + if (retval < 0) { + dev_err(udc->dev, "LP request irq %d failed\n", + udc->udp_irq[IRQ_USB_LP]); + goto irq_lp_fail; + } + retval = request_irq(udc->udp_irq[IRQ_USB_HP], lpc32xx_usb_hp_irq, + 0, "udc_hp", udc); + if (retval < 0) { + dev_err(udc->dev, "HP request irq %d failed\n", + udc->udp_irq[IRQ_USB_HP]); + goto irq_hp_fail; + } + + retval = request_irq(udc->udp_irq[IRQ_USB_DEVDMA], + lpc32xx_usb_devdma_irq, 0, "udc_dma", udc); + if (retval < 0) { + dev_err(udc->dev, "DEV request irq %d failed\n", + udc->udp_irq[IRQ_USB_DEVDMA]); + goto irq_dev_fail; + } + + /* The transceiver interrupt is used for VBUS detection and will + kick off the VBUS handler function */ + retval = request_irq(udc->udp_irq[IRQ_USB_ATX], lpc32xx_usb_vbus_irq, + 0, "udc_otg", udc); + if (retval < 0) { + dev_err(udc->dev, "VBUS request irq %d failed\n", + udc->udp_irq[IRQ_USB_ATX]); + goto irq_xcvr_fail; + } + + /* Initialize wait queue */ + init_waitqueue_head(&udc->ep_disable_wait_queue); + atomic_set(&udc->enabled_ep_cnt, 0); + + /* Keep all IRQs disabled until GadgetFS starts up */ + for (i = IRQ_USB_LP; i <= IRQ_USB_ATX; i++) + disable_irq(udc->udp_irq[i]); + + retval = usb_add_gadget_udc(dev, &udc->gadget); + if (retval < 0) + goto add_gadget_fail; + + dev_set_drvdata(dev, udc); + device_init_wakeup(dev, 1); + create_debug_file(udc); + + /* Disable clocks for now */ + udc_clk_set(udc, 0); + + dev_info(udc->dev, "%s version %s\n", driver_name, DRIVER_VERSION); + return 0; + +add_gadget_fail: + free_irq(udc->udp_irq[IRQ_USB_ATX], udc); +irq_xcvr_fail: + free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc); +irq_dev_fail: + free_irq(udc->udp_irq[IRQ_USB_HP], udc); +irq_hp_fail: + free_irq(udc->udp_irq[IRQ_USB_LP], udc); +irq_lp_fail: + device_unregister(&udc->gadget.dev); +dev_register_fail: + dma_pool_destroy(udc->dd_cache); +dma_alloc_fail: + dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, + udc->udca_v_base, udc->udca_p_base); +i2c_fail: + clk_disable(udc->usb_slv_clk); +usb_clk_enable_fail: +pll_set_fail: + clk_disable(udc->usb_pll_clk); +pll_enable_fail: + clk_put(udc->usb_slv_clk); +usb_clk_get_fail: + clk_put(udc->usb_pll_clk); +pll_get_fail: + iounmap(udc->udp_baseaddr); +io_map_fail: + release_mem_region(udc->io_p_start, udc->io_p_size); + dev_err(udc->dev, "%s probe failed, %d\n", driver_name, retval); + + return retval; +} + +static int __devexit lpc32xx_udc_remove(struct platform_device *pdev) +{ + struct lpc32xx_udc *udc = platform_get_drvdata(pdev); + + usb_del_gadget_udc(&udc->gadget); + if (udc->driver) + return -EBUSY; + + udc_clk_set(udc, 1); + udc_disable(udc); + pullup(udc, 0); + + free_irq(udc->udp_irq[IRQ_USB_ATX], udc); + + device_init_wakeup(&pdev->dev, 0); + remove_debug_file(udc); + + dma_pool_destroy(udc->dd_cache); + dma_free_coherent(&pdev->dev, UDCA_BUFF_SIZE, + udc->udca_v_base, udc->udca_p_base); + free_irq(udc->udp_irq[IRQ_USB_DEVDMA], udc); + free_irq(udc->udp_irq[IRQ_USB_HP], udc); + free_irq(udc->udp_irq[IRQ_USB_LP], udc); + + device_unregister(&udc->gadget.dev); + + clk_disable(udc->usb_slv_clk); + clk_put(udc->usb_slv_clk); + clk_disable(udc->usb_pll_clk); + clk_put(udc->usb_pll_clk); + iounmap(udc->udp_baseaddr); + release_mem_region(udc->io_p_start, udc->io_p_size); + + return 0; +} + +#ifdef CONFIG_PM +static int lpc32xx_udc_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + int to = 1000; + struct lpc32xx_udc *udc = platform_get_drvdata(pdev); + + if (udc->clocked) { + /* Power down ISP */ + udc->poweron = 0; + isp1301_set_powerstate(udc, 0); + + /* Disable clocking */ + udc_clk_set(udc, 0); + + /* Keep clock flag on, so we know to re-enable clocks + on resume */ + udc->clocked = 1; + + /* Kill OTG and I2C clocks */ + writel(0, USB_OTG_CLK_CTRL(udc)); + while (((readl(USB_OTG_CLK_STAT(udc)) & OTGOFF_CLK_MASK) != + OTGOFF_CLK_MASK) && (to > 0)) + to--; + if (!to) + dev_dbg(udc->dev, + "USB OTG clocks not correctly enabled\n"); + + /* Kill global USB clock */ + clk_disable(udc->usb_slv_clk); + } + + return 0; +} + +static int lpc32xx_udc_resume(struct platform_device *pdev) +{ + struct lpc32xx_udc *udc = platform_get_drvdata(pdev); + + if (udc->clocked) { + /* Enable global USB clock */ + clk_enable(udc->usb_slv_clk); + + /* Enable clocking */ + udc_clk_set(udc, 1); + + /* ISP back to normal power mode */ + udc->poweron = 1; + isp1301_set_powerstate(udc, 1); + } + + return 0; +} +#else +#define lpc32xx_udc_suspend NULL +#define lpc32xx_udc_resume NULL +#endif + +#ifdef CONFIG_OF +static struct of_device_id lpc32xx_udc_of_match[] = { + { .compatible = "nxp,lpc3220-udc", }, + { }, +}; +MODULE_DEVICE_TABLE(of, lpc32xx_udc_of_match); +#endif + +static struct platform_driver lpc32xx_udc_driver = { + .remove = __devexit_p(lpc32xx_udc_remove), + .shutdown = lpc32xx_udc_shutdown, + .suspend = lpc32xx_udc_suspend, + .resume = lpc32xx_udc_resume, + .driver = { + .name = (char *) driver_name, + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(lpc32xx_udc_of_match), + }, +}; + +static int __init udc_init_module(void) +{ + return platform_driver_probe(&lpc32xx_udc_driver, lpc32xx_udc_probe); +} +module_init(udc_init_module); + +static void __exit udc_exit_module(void) +{ + platform_driver_unregister(&lpc32xx_udc_driver); +} +module_exit(udc_exit_module); + +MODULE_DESCRIPTION("LPC32XX udc driver"); +MODULE_AUTHOR("Kevin Wells <kevin.wells@nxp.com>"); +MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lpc32xx_udc"); diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c index 3608b3bd5732..8981fbb5748c 100644 --- a/drivers/usb/gadget/m66592-udc.c +++ b/drivers/usb/gadget/m66592-udc.c @@ -390,7 +390,7 @@ static int alloc_pipe_config(struct m66592_ep *ep, int *counter; int ret; - ep->desc = desc; + ep->ep.desc = desc; BUG_ON(ep->pipenum); @@ -558,7 +558,7 @@ static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req) static void start_packet(struct m66592_ep *ep, struct m66592_request *req) { - if (ep->desc->bEndpointAddress & USB_DIR_IN) + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) start_packet_write(ep, req); else start_packet_read(ep, req); @@ -734,7 +734,7 @@ __acquires(m66592->lock) if (restart) { req = list_entry(ep->queue.next, struct m66592_request, queue); - if (ep->desc) + if (ep->ep.desc) start_packet(ep, req); } } @@ -917,7 +917,7 @@ static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb) ep = m66592->pipenum2ep[pipenum]; req = list_entry(ep->queue.next, struct m66592_request, queue); - if (ep->desc->bEndpointAddress & USB_DIR_IN) + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) irq_packet_write(ep, req); else irq_packet_read(ep, req); @@ -1377,7 +1377,7 @@ static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req, req->req.actual = 0; req->req.status = -EINPROGRESS; - if (ep->desc == NULL) /* control */ + if (ep->ep.desc == NULL) /* control */ start_ep0(ep, req); else { if (request && !ep->busy) diff --git a/drivers/usb/gadget/m66592-udc.h b/drivers/usb/gadget/m66592-udc.h index 9d9f7e39f037..88c85b4116a2 100644 --- a/drivers/usb/gadget/m66592-udc.h +++ b/drivers/usb/gadget/m66592-udc.h @@ -456,7 +456,7 @@ struct m66592_ep { unsigned use_dma:1; u16 pipenum; u16 type; - const struct usb_endpoint_descriptor *desc; + /* register address */ unsigned long fifoaddr; unsigned long fifosel; diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h index e2be9519abbe..9073436d8b24 100644 --- a/drivers/usb/gadget/mv_udc.h +++ b/drivers/usb/gadget/mv_udc.h @@ -232,7 +232,6 @@ struct mv_ep { struct mv_udc *udc; struct list_head queue; struct mv_dqh *dqh; - const struct usb_endpoint_descriptor *desc; u32 direction; char name[14]; unsigned stopped:1, diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c index a73cf406e2a4..dbcd1329495e 100644 --- a/drivers/usb/gadget/mv_udc_core.c +++ b/drivers/usb/gadget/mv_udc_core.c @@ -464,7 +464,7 @@ static int mv_ep_enable(struct usb_ep *_ep, ep = container_of(_ep, struct mv_ep, ep); udc = ep->udc; - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; @@ -528,7 +528,7 @@ static int mv_ep_enable(struct usb_ep *_ep, dqh->size_ioc_int_sts = 0; ep->ep.maxpacket = max; - ep->desc = desc; + ep->ep.desc = desc; ep->stopped = 0; /* Enable the endpoint for Rx or Tx and set the endpoint type */ @@ -580,7 +580,7 @@ static int mv_ep_disable(struct usb_ep *_ep) unsigned long flags; ep = container_of(_ep, struct mv_ep, ep); - if ((_ep == NULL) || !ep->desc) + if ((_ep == NULL) || !ep->ep.desc) return -EINVAL; udc = ep->udc; @@ -606,7 +606,6 @@ static int mv_ep_disable(struct usb_ep *_ep) /* nuke all pending requests (does flush) */ nuke(ep, -ESHUTDOWN); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; @@ -651,7 +650,7 @@ static void mv_ep_fifo_flush(struct usb_ep *_ep) return; ep = container_of(_ep, struct mv_ep, ep); - if (!ep->desc) + if (!ep->ep.desc) return; udc = ep->udc; @@ -715,11 +714,11 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) dev_err(&udc->dev->dev, "%s, bad params", __func__); return -EINVAL; } - if (unlikely(!_ep || !ep->desc)) { + if (unlikely(!_ep || !ep->ep.desc)) { dev_err(&udc->dev->dev, "%s, bad ep", __func__); return -EINVAL; } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { if (req->req.length > ep->ep.maxpacket) return -EMSGSIZE; } @@ -925,12 +924,12 @@ static int mv_ep_set_halt_wedge(struct usb_ep *_ep, int halt, int wedge) ep = container_of(_ep, struct mv_ep, ep); udc = ep->udc; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { status = -EINVAL; goto out; } - if (ep->desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { + if (ep->ep.desc->bmAttributes == USB_ENDPOINT_XFER_ISOC) { status = -EOPNOTSUPP; goto out; } @@ -1279,7 +1278,7 @@ static int eps_init(struct mv_udc *udc) ep->stopped = 0; ep->ep.maxpacket = EP0_MAX_PKT_SIZE; ep->ep_num = 0; - ep->desc = &mv_ep0_desc; + ep->ep.desc = &mv_ep0_desc; INIT_LIST_HEAD(&ep->queue); ep->ep_type = USB_ENDPOINT_XFER_CONTROL; diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h index b0e52fc277b4..a19f72dec0cd 100644 --- a/drivers/usb/gadget/ndis.h +++ b/drivers/usb/gadget/ndis.h @@ -15,11 +15,6 @@ #ifndef _LINUX_NDIS_H #define _LINUX_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, @@ -35,11 +30,6 @@ struct NDIS_PM_WAKE_UP_CAPABILITIES { 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; @@ -54,158 +44,4 @@ struct NDIS_PM_PACKET_PATTERN { __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 /* _LINUX_NDIS_H */ diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c index 3b4b6dd0f95a..7ba32469c5bd 100644 --- a/drivers/usb/gadget/omap_udc.c +++ b/drivers/usb/gadget/omap_udc.c @@ -153,7 +153,7 @@ static int omap_ep_enable(struct usb_ep *_ep, u16 maxp; /* catch various bogus parameters */ - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || desc->bDescriptorType != USB_DT_ENDPOINT || ep->bEndpointAddress != desc->bEndpointAddress || ep->maxpacket < usb_endpoint_maxp(desc)) { @@ -200,7 +200,7 @@ static int omap_ep_enable(struct usb_ep *_ep, spin_lock_irqsave(&udc->lock, flags); - ep->desc = desc; + ep->ep.desc = desc; ep->irqs = 0; ep->stopped = 0; ep->ep.maxpacket = maxp; @@ -242,14 +242,13 @@ static int omap_ep_disable(struct usb_ep *_ep) struct omap_ep *ep = container_of(_ep, struct omap_ep, ep); unsigned long flags; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { DBG("%s, %s not enabled\n", __func__, _ep ? ep->ep.name : NULL); return -EINVAL; } spin_lock_irqsave(&ep->udc->lock, flags); - ep->desc = NULL; ep->ep.desc = NULL; nuke (ep, -ESHUTDOWN); ep->ep.maxpacket = ep->maxpacket; @@ -917,7 +916,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) DBG("%s, bad params\n", __func__); return -EINVAL; } - if (!_ep || (!ep->desc && ep->bEndpointAddress)) { + if (!_ep || (!ep->ep.desc && ep->bEndpointAddress)) { DBG("%s, bad ep\n", __func__); return -EINVAL; } @@ -1121,7 +1120,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value) status = 0; /* otherwise, all active non-ISO endpoints can halt */ - } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->desc) { + } else if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC && ep->ep.desc) { /* IN endpoints must already be idle */ if ((ep->bEndpointAddress & USB_DIR_IN) @@ -1625,7 +1624,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - || !ep->desc) + || !ep->ep.desc) goto do_stall; use_ep(ep, 0); omap_writew(udc->clr_halt, UDC_CTRL); @@ -1653,7 +1652,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src) if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - || ep == ep0 || !ep->desc) + || ep == ep0 || !ep->ep.desc) goto do_stall; if (use_dma && ep->has_dma) { /* this has rude side-effects (aborts) and @@ -1688,7 +1687,7 @@ ep0out_status_stage: ep = &udc->ep[w_index & 0xf]; if (w_index & USB_DIR_IN) ep += 16; - if (!ep->desc) + if (!ep->ep.desc) goto do_stall; /* iso never stalls */ @@ -2509,7 +2508,7 @@ static int proc_udc_show(struct seq_file *s, void *_) if (tmp & UDC_ADD) { list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { - if (ep->desc) + if (ep->ep.desc) proc_ep_show(s, ep); } } diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h index 59d3b2213cb1..cfadeb5fc5de 100644 --- a/drivers/usb/gadget/omap_udc.h +++ b/drivers/usb/gadget/omap_udc.h @@ -140,7 +140,6 @@ struct omap_ep { struct list_head queue; unsigned long irqs; struct list_head iso; - const struct usb_endpoint_descriptor *desc; char name[14]; u16 maxpacket; u8 bEndpointAddress; diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c index 65307064a6fd..1cfcc9ecbfbc 100644 --- a/drivers/usb/gadget/pch_udc.c +++ b/drivers/usb/gadget/pch_udc.c @@ -295,7 +295,6 @@ struct pch_udc_ep { struct pch_udc_data_dma_desc *td_data; struct pch_udc_dev *dev; unsigned long offset_addr; - const struct usb_endpoint_descriptor *desc; struct list_head queue; unsigned num:5, in:1, @@ -1705,7 +1704,7 @@ static int pch_udc_pcd_ep_enable(struct usb_ep *usbep, if (!dev->driver || (dev->gadget.speed == USB_SPEED_UNKNOWN)) return -ESHUTDOWN; spin_lock_irqsave(&dev->lock, iflags); - ep->desc = desc; + ep->ep.desc = desc; ep->halted = 0; pch_udc_ep_enable(ep, &ep->dev->cfg_data, desc); ep->ep.maxpacket = usb_endpoint_maxp(desc); @@ -1734,7 +1733,7 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep) ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if ((usbep->name == ep0_string) || !ep->desc) + if ((usbep->name == ep0_string) || !ep->ep.desc) return -EINVAL; spin_lock_irqsave(&ep->dev->lock, iflags); @@ -1742,7 +1741,6 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep) ep->halted = 1; pch_udc_ep_disable(ep); pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num)); - ep->desc = NULL; ep->ep.desc = NULL; INIT_LIST_HEAD(&ep->queue); spin_unlock_irqrestore(&ep->dev->lock, iflags); @@ -1849,7 +1847,7 @@ static int pch_udc_pcd_queue(struct usb_ep *usbep, struct usb_request *usbreq, return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if (!ep->desc && ep->num) + if (!ep->ep.desc && ep->num) return -EINVAL; req = container_of(usbreq, struct pch_udc_request, req); if (!list_empty(&req->queue)) @@ -1949,7 +1947,7 @@ static int pch_udc_pcd_dequeue(struct usb_ep *usbep, ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if (!usbep || !usbreq || (!ep->desc && ep->num)) + if (!usbep || !usbreq || (!ep->ep.desc && ep->num)) return ret; req = container_of(usbreq, struct pch_udc_request, req); spin_lock_irqsave(&ep->dev->lock, flags); @@ -1988,7 +1986,7 @@ static int pch_udc_pcd_set_halt(struct usb_ep *usbep, int halt) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if (!ep->desc && !ep->num) + if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) return -ESHUTDOWN; @@ -2033,7 +2031,7 @@ static int pch_udc_pcd_set_wedge(struct usb_ep *usbep) return -EINVAL; ep = container_of(usbep, struct pch_udc_ep, ep); dev = ep->dev; - if (!ep->desc && !ep->num) + if (!ep->ep.desc && !ep->num) return -EINVAL; if (!ep->dev->driver || (ep->dev->gadget.speed == USB_SPEED_UNKNOWN)) return -ESHUTDOWN; @@ -2065,7 +2063,7 @@ static void pch_udc_pcd_fifo_flush(struct usb_ep *usbep) return; ep = container_of(usbep, struct pch_udc_ep, ep); - if (ep->desc || !ep->num) + if (ep->ep.desc || !ep->num) pch_udc_ep_fifo_flush(ep, ep->in); } @@ -3282,7 +3280,6 @@ static DEFINE_PCI_DEVICE_TABLE(pch_udc_pcidev_id) = { MODULE_DEVICE_TABLE(pci, pch_udc_pcidev_id); - static struct pci_driver pch_udc_driver = { .name = KBUILD_MODNAME, .id_table = pch_udc_pcidev_id, @@ -3293,17 +3290,7 @@ static struct pci_driver pch_udc_driver = { .shutdown = pch_udc_shutdown, }; -static int __init pch_udc_pci_init(void) -{ - return pci_register_driver(&pch_udc_driver); -} -module_init(pch_udc_pci_init); - -static void __exit pch_udc_pci_exit(void) -{ - pci_unregister_driver(&pch_udc_driver); -} -module_exit(pch_udc_pci_exit); +module_pci_driver(pch_udc_driver); MODULE_DESCRIPTION("Intel EG20T USB Device Controller"); MODULE_AUTHOR("LAPIS Semiconductor, <tomoya-linux@dsn.lapis-semi.com>"); diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c index 4e4dc1f5f388..f1f9290a2f47 100644 --- a/drivers/usb/gadget/printer.c +++ b/drivers/usb/gadget/printer.c @@ -51,6 +51,7 @@ * the runtime footprint, and giving us at least some parts of what * a "gcc --combine ... part1.c part2.c part3.c ... " build would. */ +#include "composite.c" #include "usbstring.c" #include "config.c" #include "epautoconf.c" @@ -75,8 +76,6 @@ struct printer_dev { /* lock buffer lists during read/write calls */ struct mutex lock_printer_io; struct usb_gadget *gadget; - struct usb_request *req; /* for control responses */ - u8 config; s8 interface; struct usb_ep *in_ep, *out_ep; @@ -100,6 +99,7 @@ struct printer_dev { struct device *pdev; u8 printer_cdev_open; wait_queue_head_t wait; + struct usb_function function; }; static struct printer_dev usb_printer_gadget; @@ -120,26 +120,6 @@ static struct printer_dev usb_printer_gadget; * parameters are in UTF-8 (superset of ASCII's 7 bit characters). */ -static ushort idVendor; -module_param(idVendor, ushort, S_IRUGO); -MODULE_PARM_DESC(idVendor, "USB Vendor ID"); - -static ushort idProduct; -module_param(idProduct, ushort, S_IRUGO); -MODULE_PARM_DESC(idProduct, "USB Product ID"); - -static ushort bcdDevice; -module_param(bcdDevice, ushort, S_IRUGO); -MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)"); - -static char *iManufacturer; -module_param(iManufacturer, charp, S_IRUGO); -MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string"); - -static char *iProduct; -module_param(iProduct, charp, S_IRUGO); -MODULE_PARM_DESC(iProduct, "USB Product string"); - static char *iSerialNum; module_param(iSerialNum, charp, S_IRUGO); MODULE_PARM_DESC(iSerialNum, "1"); @@ -154,47 +134,8 @@ module_param(qlen, uint, S_IRUGO|S_IWUSR); #define QLEN qlen -#ifdef CONFIG_USB_GADGET_DUALSPEED -#define DEVSPEED USB_SPEED_HIGH -#else /* full speed (low speed doesn't do bulk) */ -#define DEVSPEED USB_SPEED_FULL -#endif - /*-------------------------------------------------------------------------*/ -#define xprintk(d, level, fmt, args...) \ - printk(level "%s: " fmt, DRIVER_DESC, ## args) - -#ifdef DEBUG -#define DBG(dev, fmt, args...) \ - xprintk(dev, KERN_DEBUG, fmt, ## args) -#else -#define DBG(dev, fmt, args...) \ - do { } while (0) -#endif /* DEBUG */ - -#ifdef VERBOSE -#define VDBG(dev, fmt, args...) \ - xprintk(dev, KERN_DEBUG, fmt, ## args) -#else -#define VDBG(dev, fmt, args...) \ - do { } while (0) -#endif /* VERBOSE */ - -#define ERROR(dev, fmt, args...) \ - xprintk(dev, KERN_ERR, fmt, ## args) -#define WARNING(dev, fmt, args...) \ - xprintk(dev, KERN_WARNING, fmt, ## args) -#define INFO(dev, fmt, args...) \ - xprintk(dev, KERN_INFO, fmt, ## args) - -/*-------------------------------------------------------------------------*/ - -/* 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. @@ -227,24 +168,6 @@ static struct usb_device_descriptor device_desc = { .bNumConfigurations = 1 }; -static struct usb_otg_descriptor otg_desc = { - .bLength = sizeof otg_desc, - .bDescriptorType = USB_DT_OTG, - .bmAttributes = USB_OTG_SRP -}; - -static struct usb_config_descriptor config_desc = { - .bLength = sizeof config_desc, - .bDescriptorType = USB_DT_CONFIG, - - /* compute wTotalLength on the fly */ - .bNumInterfaces = 1, - .bConfigurationValue = DEV_CONFIG_VALUE, - .iConfiguration = 0, - .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, - .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -}; - static struct usb_interface_descriptor intf_desc = { .bLength = sizeof intf_desc, .bDescriptorType = USB_DT_INTERFACE, @@ -270,16 +193,13 @@ static struct usb_endpoint_descriptor fs_ep_out_desc = { .bmAttributes = USB_ENDPOINT_XFER_BULK }; -static const struct usb_descriptor_header *fs_printer_function [11] = { - (struct usb_descriptor_header *) &otg_desc, +static struct usb_descriptor_header *fs_printer_function[] = { (struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &fs_ep_in_desc, (struct usb_descriptor_header *) &fs_ep_out_desc, NULL }; -#ifdef CONFIG_USB_GADGET_DUALSPEED - /* * usb 2.0 devices need to expose both high speed and full speed * descriptors, unless they only run at full speed. @@ -307,23 +227,26 @@ static struct usb_qualifier_descriptor dev_qualifier = { .bNumConfigurations = 1 }; -static const struct usb_descriptor_header *hs_printer_function [11] = { - (struct usb_descriptor_header *) &otg_desc, +static struct usb_descriptor_header *hs_printer_function[] = { (struct usb_descriptor_header *) &intf_desc, (struct usb_descriptor_header *) &hs_ep_in_desc, (struct usb_descriptor_header *) &hs_ep_out_desc, NULL }; -/* maxpacket and other transfer characteristics vary by speed. */ -#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs)) - -#else +static struct usb_otg_descriptor otg_descriptor = { + .bLength = sizeof otg_descriptor, + .bDescriptorType = USB_DT_OTG, + .bmAttributes = USB_OTG_SRP, +}; -/* if there's no high speed support, maxpacket doesn't change. */ -#define ep_desc(g, hs, fs) (((void)(g)), (fs)) +static const struct usb_descriptor_header *otg_desc[] = { + (struct usb_descriptor_header *) &otg_descriptor, + NULL, +}; -#endif /* !CONFIG_USB_GADGET_DUALSPEED */ +/* maxpacket and other transfer characteristics vary by speed. */ +#define ep_desc(g, hs, fs) (((g)->speed == USB_SPEED_HIGH)?(hs):(fs)) /*-------------------------------------------------------------------------*/ @@ -343,11 +266,16 @@ static struct usb_string strings [] = { { } /* end of list */ }; -static struct usb_gadget_strings stringtab = { +static struct usb_gadget_strings stringtab_dev = { .language = 0x0409, /* en-us */ .strings = strings, }; +static struct usb_gadget_strings *dev_strings[] = { + &stringtab_dev, + NULL, +}; + /*-------------------------------------------------------------------------*/ static struct usb_request * @@ -937,82 +865,8 @@ static void printer_reset_interface(struct printer_dev *dev) dev->interface = -1; } -/* change our operational config. must agree with the code - * that returns config descriptors, and altsetting code. - */ -static int -printer_set_config(struct printer_dev *dev, unsigned number) -{ - int result = 0; - struct usb_gadget *gadget = dev->gadget; - - switch (number) { - case DEV_CONFIG_VALUE: - result = 0; - break; - default: - result = -EINVAL; - /* FALL THROUGH */ - case 0: - break; - } - - if (result) { - usb_gadget_vbus_draw(dev->gadget, - dev->gadget->is_otg ? 8 : 100); - } else { - unsigned power; - - power = 2 * config_desc.bMaxPower; - usb_gadget_vbus_draw(dev->gadget, power); - - dev->config = number; - INFO(dev, "%s config #%d: %d mA, %s\n", - usb_speed_string(gadget->speed), - number, power, driver_desc); - } - return result; -} - -static int -config_buf(enum usb_device_speed speed, u8 *buf, u8 type, unsigned index, - int is_otg) -{ - int len; - const struct usb_descriptor_header **function; -#ifdef CONFIG_USB_GADGET_DUALSPEED - int hs = (speed == USB_SPEED_HIGH); - - if (type == USB_DT_OTHER_SPEED_CONFIG) - hs = !hs; - - if (hs) { - function = hs_printer_function; - } else { - function = fs_printer_function; - } -#else - function = fs_printer_function; -#endif - - if (index >= device_desc.bNumConfigurations) - return -EINVAL; - - /* for now, don't advertise srp-only devices */ - if (!is_otg) - function++; - - len = usb_gadget_config_buf(&config_desc, buf, USB_DESC_BUFSIZE, - function); - if (len < 0) - return len; - ((struct usb_config_descriptor *) buf)->bDescriptorType = type; - return len; -} - /* Change our operational Interface. */ -static int -set_interface(struct printer_dev *dev, unsigned number) +static int set_interface(struct printer_dev *dev, unsigned number) { int result = 0; @@ -1043,14 +897,6 @@ set_interface(struct printer_dev *dev, unsigned number) return result; } -static void printer_setup_complete(struct usb_ep *ep, struct usb_request *req) -{ - if (req->status || req->actual != req->length) - DBG((struct printer_dev *) ep->driver_data, - "setup complete --> %d, %d/%d\n", - req->status, req->actual, req->length); -} - static void printer_soft_reset(struct printer_dev *dev) { struct usb_request *req; @@ -1107,11 +953,12 @@ static void printer_soft_reset(struct printer_dev *dev) * The setup() callback implements all the ep0 functionality that's not * handled lower down. */ -static int -printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) +static int printer_func_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) { - struct printer_dev *dev = get_gadget_data(gadget); - struct usb_request *req = dev->req; + struct printer_dev *dev = container_of(f, struct printer_dev, function); + struct usb_composite_dev *cdev = f->config->cdev; + struct usb_request *req = cdev->req; int value = -EOPNOTSUPP; u16 wIndex = le16_to_cpu(ctrl->wIndex); u16 wValue = le16_to_cpu(ctrl->wValue); @@ -1120,102 +967,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) DBG(dev, "ctrl req%02x.%02x v%04x i%04x l%d\n", ctrl->bRequestType, ctrl->bRequest, wValue, wIndex, wLength); - req->complete = printer_setup_complete; - switch (ctrl->bRequestType&USB_TYPE_MASK) { - - case USB_TYPE_STANDARD: - switch (ctrl->bRequest) { - - case USB_REQ_GET_DESCRIPTOR: - if (ctrl->bRequestType != USB_DIR_IN) - break; - switch (wValue >> 8) { - - case USB_DT_DEVICE: - device_desc.bMaxPacketSize0 = - gadget->ep0->maxpacket; - value = min(wLength, (u16) sizeof device_desc); - memcpy(req->buf, &device_desc, value); - break; -#ifdef CONFIG_USB_GADGET_DUALSPEED - case USB_DT_DEVICE_QUALIFIER: - if (!gadget_is_dualspeed(gadget)) - break; - /* - * assumes ep0 uses the same value for both - * speeds - */ - dev_qualifier.bMaxPacketSize0 = - gadget->ep0->maxpacket; - 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 */ -#endif /* CONFIG_USB_GADGET_DUALSPEED */ - case USB_DT_CONFIG: - value = config_buf(gadget->speed, req->buf, - wValue >> 8, - wValue & 0xff, - gadget->is_otg); - 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) - DBG(dev, "HNP available\n"); - else if (gadget->a_alt_hnp_support) - DBG(dev, "HNP needs a different root port\n"); - value = printer_set_config(dev, wValue); - if (!value) - value = set_interface(dev, PRINTER_INTERFACE); - 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) - break; - - value = set_interface(dev, PRINTER_INTERFACE); - break; - case USB_REQ_GET_INTERFACE: - if (ctrl->bRequestType != - (USB_DIR_IN|USB_RECIP_INTERFACE) - || !dev->config) - break; - - *(u8 *)req->buf = dev->interface; - value = min(wLength, (u16) 1); - break; - - default: - goto unknown; - } - break; - case USB_TYPE_CLASS: switch (ctrl->bRequest) { case 0: /* Get the IEEE-1284 PNP String */ @@ -1261,44 +1013,50 @@ unknown: wValue, wIndex, wLength); break; } - - /* respond with data transfer before status phase? */ - if (value >= 0) { - req->length = value; - req->zero = value < wLength; - value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); - if (value < 0) { - DBG(dev, "ep_queue --> %d\n", value); - req->status = 0; - printer_setup_complete(gadget->ep0, req); - } - } - /* host either stalls (value < 0) or reports success */ return value; } -static void -printer_disconnect(struct usb_gadget *gadget) +static int __init printer_func_bind(struct usb_configuration *c, + struct usb_function *f) { - struct printer_dev *dev = get_gadget_data(gadget); + return 0; +} + +static void printer_func_unbind(struct usb_configuration *c, + struct usb_function *f) +{ +} + +static int printer_func_set_alt(struct usb_function *f, + unsigned intf, unsigned alt) +{ + struct printer_dev *dev = container_of(f, struct printer_dev, function); + int ret = -ENOTSUPP; + + if (!alt) + ret = set_interface(dev, PRINTER_INTERFACE); + return ret; +} + +static void printer_func_disable(struct usb_function *f) +{ + struct printer_dev *dev = container_of(f, struct printer_dev, function); unsigned long flags; DBG(dev, "%s\n", __func__); spin_lock_irqsave(&dev->lock, flags); - printer_reset_interface(dev); - spin_unlock_irqrestore(&dev->lock, flags); } -static void -printer_unbind(struct usb_gadget *gadget) +static void printer_cfg_unbind(struct usb_configuration *c) { - struct printer_dev *dev = get_gadget_data(gadget); + struct printer_dev *dev; struct usb_request *req; + dev = &usb_printer_gadget; DBG(dev, "%s\n", __func__); @@ -1336,18 +1094,18 @@ printer_unbind(struct usb_gadget *gadget) list_del(&req->list); printer_req_free(dev->out_ep, req); } - - if (dev->req) { - printer_req_free(gadget->ep0, dev->req); - dev->req = NULL; - } - - set_gadget_data(gadget, NULL); } -static int __init -printer_bind(struct usb_gadget *gadget) +static struct usb_configuration printer_cfg_driver = { + .label = "printer", + .unbind = printer_cfg_unbind, + .bConfigurationValue = 1, + .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, +}; + +static int __init printer_bind_config(struct usb_configuration *c) { + struct usb_gadget *gadget = c->cdev->gadget; struct printer_dev *dev; struct usb_ep *in_ep, *out_ep; int status = -ENOMEM; @@ -1358,6 +1116,14 @@ printer_bind(struct usb_gadget *gadget) dev = &usb_printer_gadget; + dev->function.name = shortname; + dev->function.descriptors = fs_printer_function; + dev->function.hs_descriptors = hs_printer_function; + dev->function.bind = printer_func_bind; + dev->function.setup = printer_func_setup; + dev->function.unbind = printer_func_unbind; + dev->function.set_alt = printer_func_set_alt; + dev->function.disable = printer_func_disable; /* Setup the sysfs files for the printer gadget. */ dev->pdev = device_create(usb_gadget_class, NULL, g_printer_devno, @@ -1393,29 +1159,6 @@ printer_bind(struct usb_gadget *gadget) init_utsname()->sysname, init_utsname()->release, gadget->name); - device_desc.idVendor = - cpu_to_le16(PRINTER_VENDOR_NUM); - device_desc.idProduct = - cpu_to_le16(PRINTER_PRODUCT_NUM); - - /* support optional vendor/distro customization */ - if (idVendor) { - if (!idProduct) { - dev_err(&gadget->dev, "idVendor needs idProduct!\n"); - return -ENODEV; - } - device_desc.idVendor = cpu_to_le16(idVendor); - device_desc.idProduct = cpu_to_le16(idProduct); - 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 (iSerialNum) strlcpy(serial_num, iSerialNum, sizeof serial_num); @@ -1442,17 +1185,16 @@ autoconf_fail: goto autoconf_fail; out_ep->driver_data = out_ep; /* claim */ -#ifdef CONFIG_USB_GADGET_DUALSPEED /* assumes that all endpoints are dual-speed */ hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress; hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress; -#endif /* DUALSPEED */ usb_gadget_set_selfpowered(gadget); if (gadget->is_otg) { - otg_desc.bmAttributes |= USB_OTG_HNP, - config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP; + otg_descriptor.bmAttributes |= USB_OTG_HNP; + printer_cfg_driver.descriptors = otg_desc; + printer_cfg_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; } spin_lock_init(&dev->lock); @@ -1466,7 +1208,6 @@ autoconf_fail: init_waitqueue_head(&dev->tx_wait); init_waitqueue_head(&dev->tx_flush_wait); - dev->config = 0; dev->interface = -1; dev->printer_cdev_open = 0; dev->printer_status = PRINTER_NOT_ERROR; @@ -1477,14 +1218,6 @@ autoconf_fail: dev->in_ep = in_ep; dev->out_ep = out_ep; - /* preallocate control message data and buffer */ - dev->req = printer_req_alloc(gadget->ep0, USB_DESC_BUFSIZE, - GFP_KERNEL); - if (!dev->req) { - status = -ENOMEM; - goto fail; - } - for (i = 0; i < QLEN; i++) { req = printer_req_alloc(dev->in_ep, USB_BUFSIZE, GFP_KERNEL); if (!req) { @@ -1513,45 +1246,37 @@ autoconf_fail: list_add(&req->list, &dev->rx_reqs); } - dev->req->complete = printer_setup_complete; - /* finish hookup to lower layer ... */ dev->gadget = gadget; - set_gadget_data(gadget, dev); - gadget->ep0->driver_data = dev; INFO(dev, "%s, version: " DRIVER_VERSION "\n", driver_desc); INFO(dev, "using %s, OUT %s IN %s\n", gadget->name, out_ep->name, in_ep->name); - return 0; fail: - printer_unbind(gadget); + printer_cfg_unbind(c); return status; } -/*-------------------------------------------------------------------------*/ +static int printer_unbind(struct usb_composite_dev *cdev) +{ + return 0; +} -static struct usb_gadget_driver printer_driver = { - .max_speed = DEVSPEED, +static int __init printer_bind(struct usb_composite_dev *cdev) +{ + return usb_add_config(cdev, &printer_cfg_driver, printer_bind_config); +} - .function = (char *) driver_desc, +static struct usb_composite_driver printer_driver = { + .name = shortname, + .dev = &device_desc, + .strings = dev_strings, + .max_speed = USB_SPEED_HIGH, .unbind = printer_unbind, - - .setup = printer_setup, - .disconnect = printer_disconnect, - - .driver = { - .name = (char *) shortname, - .owner = THIS_MODULE, - }, }; -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_AUTHOR("Craig Nadler"); -MODULE_LICENSE("GPL"); - static int __init init(void) { @@ -1560,23 +1285,23 @@ init(void) usb_gadget_class = class_create(THIS_MODULE, "usb_printer_gadget"); if (IS_ERR(usb_gadget_class)) { status = PTR_ERR(usb_gadget_class); - ERROR(dev, "unable to create usb_gadget class %d\n", status); + pr_err("unable to create usb_gadget class %d\n", status); return status; } status = alloc_chrdev_region(&g_printer_devno, 0, 1, "USB printer gadget"); if (status) { - ERROR(dev, "alloc_chrdev_region %d\n", status); + pr_err("alloc_chrdev_region %d\n", status); class_destroy(usb_gadget_class); return status; } - status = usb_gadget_probe_driver(&printer_driver, printer_bind); + status = usb_composite_probe(&printer_driver, printer_bind); if (status) { class_destroy(usb_gadget_class); unregister_chrdev_region(g_printer_devno, 1); - DBG(dev, "usb_gadget_probe_driver %x\n", status); + pr_err("usb_gadget_probe_driver %x\n", status); } return status; @@ -1586,15 +1311,14 @@ module_init(init); static void __exit cleanup(void) { - int status; - mutex_lock(&usb_printer_gadget.lock_printer_io); - status = usb_gadget_unregister_driver(&printer_driver); - if (status) - ERROR(dev, "usb_gadget_unregister_driver %x\n", status); - + usb_composite_unregister(&printer_driver); unregister_chrdev_region(g_printer_devno, 1); class_destroy(usb_gadget_class); mutex_unlock(&usb_printer_gadget.lock_printer_io); } module_exit(cleanup); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_AUTHOR("Craig Nadler"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c index 41ed69c96d8c..d7c8cb3bf759 100644 --- a/drivers/usb/gadget/pxa25x_udc.c +++ b/drivers/usb/gadget/pxa25x_udc.c @@ -218,7 +218,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep, struct pxa25x_udc *dev; ep = container_of (_ep, struct pxa25x_ep, ep); - if (!_ep || !desc || ep->desc || _ep->name == ep0name + if (!_ep || !desc || ep->ep.desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || ep->bEndpointAddress != desc->bEndpointAddress || ep->fifo_size < usb_endpoint_maxp (desc)) { @@ -249,7 +249,7 @@ static int pxa25x_ep_enable (struct usb_ep *_ep, return -ESHUTDOWN; } - ep->desc = desc; + ep->ep.desc = desc; ep->stopped = 0; ep->pio_irqs = 0; ep->ep.maxpacket = usb_endpoint_maxp (desc); @@ -269,7 +269,7 @@ static int pxa25x_ep_disable (struct usb_ep *_ep) unsigned long flags; ep = container_of (_ep, struct pxa25x_ep, ep); - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { DMSG("%s, %s not enabled\n", __func__, _ep ? ep->ep.name : NULL); return -EINVAL; @@ -281,7 +281,6 @@ static int pxa25x_ep_disable (struct usb_ep *_ep) /* flush fifo (mostly for IN buffers) */ pxa25x_ep_fifo_flush (_ep); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 1; @@ -390,7 +389,7 @@ write_fifo (struct pxa25x_ep *ep, struct pxa25x_request *req) { unsigned max; - max = usb_endpoint_maxp(ep->desc); + max = usb_endpoint_maxp(ep->ep.desc); do { unsigned count; int is_last, is_short; @@ -644,7 +643,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) } ep = container_of(_ep, struct pxa25x_ep, ep); - if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { + if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) { DMSG("%s, bad ep\n", __func__); return -EINVAL; } @@ -660,7 +659,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) * we can report per-packet status. that also helps with dma. */ if (unlikely (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC - && req->req.length > usb_endpoint_maxp (ep->desc))) + && req->req.length > usb_endpoint_maxp(ep->ep.desc))) return -EMSGSIZE; DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n", @@ -673,7 +672,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) /* kickstart this i/o queue? */ if (list_empty(&ep->queue) && !ep->stopped) { - if (ep->desc == NULL/* ep0 */) { + if (ep->ep.desc == NULL/* ep0 */) { unsigned length = _req->length; switch (dev->ep0state) { @@ -722,7 +721,7 @@ pxa25x_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags) req = NULL; } - if (likely (req && ep->desc)) + if (likely(req && ep->ep.desc)) pio_irq_enable(ep->bEndpointAddress); } @@ -749,7 +748,7 @@ static void nuke(struct pxa25x_ep *ep, int status) queue); done(ep, req, status); } - if (ep->desc) + if (ep->ep.desc) pio_irq_disable (ep->bEndpointAddress); } @@ -792,7 +791,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value) ep = container_of(_ep, struct pxa25x_ep, ep); if (unlikely (!_ep - || (!ep->desc && ep->ep.name != ep0name)) + || (!ep->ep.desc && ep->ep.name != ep0name)) || ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) { DMSG("%s, bad ep\n", __func__); return -EINVAL; @@ -820,7 +819,7 @@ static int pxa25x_ep_set_halt(struct usb_ep *_ep, int value) *ep->reg_udccs = UDCCS_BI_FST|UDCCS_BI_FTF; /* ep0 needs special care */ - if (!ep->desc) { + if (!ep->ep.desc) { start_watchdog(ep->dev); ep->dev->req_pending = 0; ep->dev->ep0state = EP0_STALL; @@ -1087,7 +1086,7 @@ udc_seq_show(struct seq_file *m, void *_d) if (i != 0) { const struct usb_endpoint_descriptor *desc; - desc = ep->desc; + desc = ep->ep.desc; if (!desc) continue; tmp = *dev->ep [i].reg_udccs; @@ -1191,7 +1190,6 @@ static void udc_reinit(struct pxa25x_udc *dev) if (i != 0) list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); - ep->desc = NULL; ep->ep.desc = NULL; ep->stopped = 0; INIT_LIST_HEAD (&ep->queue); diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h index 893e917f048e..861f4df6ea22 100644 --- a/drivers/usb/gadget/pxa25x_udc.h +++ b/drivers/usb/gadget/pxa25x_udc.h @@ -41,7 +41,6 @@ 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; diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c index c4401e7dd3a6..f3ac2a20c27c 100644 --- a/drivers/usb/gadget/r8a66597-udc.c +++ b/drivers/usb/gadget/r8a66597-udc.c @@ -459,7 +459,7 @@ static int alloc_pipe_config(struct r8a66597_ep *ep, unsigned char *counter; int ret; - ep->desc = desc; + ep->ep.desc = desc; if (ep->pipenum) /* already allocated pipe */ return 0; @@ -648,7 +648,7 @@ static int sudmac_alloc_channel(struct r8a66597 *r8a66597, /* set SUDMAC parameters */ dma = &r8a66597->dma; dma->used = 1; - if (ep->desc->bEndpointAddress & USB_DIR_IN) { + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) { dma->dir = 1; } else { dma->dir = 0; @@ -770,7 +770,7 @@ static void start_packet_read(struct r8a66597_ep *ep, static void start_packet(struct r8a66597_ep *ep, struct r8a66597_request *req) { - if (ep->desc->bEndpointAddress & USB_DIR_IN) + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) start_packet_write(ep, req); else start_packet_read(ep, req); @@ -930,7 +930,7 @@ __acquires(r8a66597->lock) if (restart) { req = get_request_from_ep(ep); - if (ep->desc) + if (ep->ep.desc) start_packet(ep, req); } } @@ -1116,7 +1116,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597, u16 status, u16 enb) r8a66597_write(r8a66597, ~check, BRDYSTS); ep = r8a66597->pipenum2ep[pipenum]; req = get_request_from_ep(ep); - if (ep->desc->bEndpointAddress & USB_DIR_IN) + if (ep->ep.desc->bEndpointAddress & USB_DIR_IN) irq_packet_write(ep, req); else irq_packet_read(ep, req); @@ -1170,7 +1170,7 @@ __acquires(r8a66597->lock) switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: - status = 1 << USB_DEVICE_SELF_POWERED; + status = r8a66597->device_status; break; case USB_RECIP_INTERFACE: status = 0; @@ -1627,7 +1627,7 @@ static int r8a66597_queue(struct usb_ep *_ep, struct usb_request *_req, req->req.actual = 0; req->req.status = -EINPROGRESS; - if (ep->desc == NULL) /* control */ + if (ep->ep.desc == NULL) /* control */ start_ep0(ep, req); else { if (request && !ep->busy) @@ -1692,7 +1692,7 @@ static int r8a66597_set_wedge(struct usb_ep *_ep) ep = container_of(_ep, struct r8a66597_ep, ep); - if (!ep || !ep->desc) + if (!ep || !ep->ep.desc) return -EINVAL; spin_lock_irqsave(&ep->r8a66597->lock, flags); @@ -1800,11 +1800,24 @@ static int r8a66597_pullup(struct usb_gadget *gadget, int is_on) return 0; } +static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self) +{ + struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); + + if (is_self) + r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED; + else + r8a66597->device_status &= ~(1 << USB_DEVICE_SELF_POWERED); + + return 0; +} + static struct usb_gadget_ops r8a66597_gadget_ops = { .get_frame = r8a66597_get_frame, .udc_start = r8a66597_start, .udc_stop = r8a66597_stop, .pullup = r8a66597_pullup, + .set_selfpowered = r8a66597_set_selfpowered, }; static int __exit r8a66597_remove(struct platform_device *pdev) diff --git a/drivers/usb/gadget/r8a66597-udc.h b/drivers/usb/gadget/r8a66597-udc.h index 8e3de61cd4b8..99908c76ccd1 100644 --- a/drivers/usb/gadget/r8a66597-udc.h +++ b/drivers/usb/gadget/r8a66597-udc.h @@ -72,7 +72,7 @@ struct r8a66597_ep { unsigned use_dma:1; u16 pipenum; u16 type; - const struct usb_endpoint_descriptor *desc; + /* register address */ unsigned char fifoaddr; unsigned char fifosel; @@ -111,6 +111,7 @@ struct r8a66597 { u16 old_vbus; u16 scount; u16 old_dvsq; + u16 device_status; /* for GET_STATUS */ /* pipe config */ unsigned char bulk; diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c index 73a934a170d1..b35babed6fcb 100644 --- a/drivers/usb/gadget/rndis.c +++ b/drivers/usb/gadget/rndis.c @@ -73,65 +73,65 @@ static rndis_resp_t *rndis_add_response(int configNr, u32 length); 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, + RNDIS_OID_GEN_SUPPORTED_LIST, + RNDIS_OID_GEN_HARDWARE_STATUS, + RNDIS_OID_GEN_MEDIA_SUPPORTED, + RNDIS_OID_GEN_MEDIA_IN_USE, + RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, + RNDIS_OID_GEN_LINK_SPEED, + RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE, + RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE, + RNDIS_OID_GEN_VENDOR_ID, + RNDIS_OID_GEN_VENDOR_DESCRIPTION, + RNDIS_OID_GEN_VENDOR_DRIVER_VERSION, + RNDIS_OID_GEN_CURRENT_PACKET_FILTER, + RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE, + RNDIS_OID_GEN_MEDIA_CONNECT_STATUS, + RNDIS_OID_GEN_PHYSICAL_MEDIUM, /* the statistical stuff */ - OID_GEN_XMIT_OK, - OID_GEN_RCV_OK, - OID_GEN_XMIT_ERROR, - OID_GEN_RCV_ERROR, - OID_GEN_RCV_NO_BUFFER, + RNDIS_OID_GEN_XMIT_OK, + RNDIS_OID_GEN_RCV_OK, + RNDIS_OID_GEN_XMIT_ERROR, + RNDIS_OID_GEN_RCV_ERROR, + RNDIS_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, + RNDIS_OID_GEN_DIRECTED_BYTES_XMIT, + RNDIS_OID_GEN_DIRECTED_FRAMES_XMIT, + RNDIS_OID_GEN_MULTICAST_BYTES_XMIT, + RNDIS_OID_GEN_MULTICAST_FRAMES_XMIT, + RNDIS_OID_GEN_BROADCAST_BYTES_XMIT, + RNDIS_OID_GEN_BROADCAST_FRAMES_XMIT, + RNDIS_OID_GEN_DIRECTED_BYTES_RCV, + RNDIS_OID_GEN_DIRECTED_FRAMES_RCV, + RNDIS_OID_GEN_MULTICAST_BYTES_RCV, + RNDIS_OID_GEN_MULTICAST_FRAMES_RCV, + RNDIS_OID_GEN_BROADCAST_BYTES_RCV, + RNDIS_OID_GEN_BROADCAST_FRAMES_RCV, + RNDIS_OID_GEN_RCV_CRC_ERROR, + RNDIS_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, + RNDIS_OID_802_3_PERMANENT_ADDRESS, + RNDIS_OID_802_3_CURRENT_ADDRESS, + RNDIS_OID_802_3_MULTICAST_LIST, + RNDIS_OID_802_3_MAC_OPTIONS, + RNDIS_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, + RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT, + RNDIS_OID_802_3_XMIT_ONE_COLLISION, + RNDIS_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, + RNDIS_OID_802_3_XMIT_DEFERRED, + RNDIS_OID_802_3_XMIT_MAX_COLLISIONS, + RNDIS_OID_802_3_RCV_OVERRUN, + RNDIS_OID_802_3_XMIT_UNDERRUN, + RNDIS_OID_802_3_XMIT_HEARTBEAT_FAILURE, + RNDIS_OID_802_3_XMIT_TIMES_CRS_LOST, + RNDIS_OID_802_3_XMIT_LATE_COLLISIONS, #endif /* RNDIS_OPTIONAL_STATS */ #ifdef RNDIS_PM @@ -200,8 +200,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, /* general oids (table 4-1) */ /* mandatory */ - case OID_GEN_SUPPORTED_LIST: - pr_debug("%s: OID_GEN_SUPPORTED_LIST\n", __func__); + case RNDIS_OID_GEN_SUPPORTED_LIST: + pr_debug("%s: RNDIS_OID_GEN_SUPPORTED_LIST\n", __func__); length = sizeof(oid_supported_list); count = length / sizeof(u32); for (i = 0; i < count; i++) @@ -210,8 +210,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_HARDWARE_STATUS: - pr_debug("%s: OID_GEN_HARDWARE_STATUS\n", __func__); + case RNDIS_OID_GEN_HARDWARE_STATUS: + pr_debug("%s: RNDIS_OID_GEN_HARDWARE_STATUS\n", __func__); /* Bogus question! * Hardware must be ready to receive high level protocols. * BTW: @@ -223,23 +223,23 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_MEDIA_SUPPORTED: - pr_debug("%s: OID_GEN_MEDIA_SUPPORTED\n", __func__); + case RNDIS_OID_GEN_MEDIA_SUPPORTED: + pr_debug("%s: RNDIS_OID_GEN_MEDIA_SUPPORTED\n", __func__); *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium); retval = 0; break; /* mandatory */ - case OID_GEN_MEDIA_IN_USE: - pr_debug("%s: OID_GEN_MEDIA_IN_USE\n", __func__); + case RNDIS_OID_GEN_MEDIA_IN_USE: + pr_debug("%s: RNDIS_OID_GEN_MEDIA_IN_USE\n", __func__); /* one medium, one transport... (maybe you do it better) */ *outbuf = cpu_to_le32(rndis_per_dev_params[configNr].medium); retval = 0; break; /* mandatory */ - case OID_GEN_MAXIMUM_FRAME_SIZE: - pr_debug("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__); + case RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE: + pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE\n", __func__); if (rndis_per_dev_params[configNr].dev) { *outbuf = cpu_to_le32( rndis_per_dev_params[configNr].dev->mtu); @@ -248,11 +248,11 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_LINK_SPEED: + case RNDIS_OID_GEN_LINK_SPEED: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_LINK_SPEED\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_LINK_SPEED\n", __func__); if (rndis_per_dev_params[configNr].media_state - == NDIS_MEDIA_STATE_DISCONNECTED) + == RNDIS_MEDIA_STATE_DISCONNECTED) *outbuf = cpu_to_le32(0); else *outbuf = cpu_to_le32( @@ -261,8 +261,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_TRANSMIT_BLOCK_SIZE: - pr_debug("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__); + case RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE: + pr_debug("%s: RNDIS_OID_GEN_TRANSMIT_BLOCK_SIZE\n", __func__); if (rndis_per_dev_params[configNr].dev) { *outbuf = cpu_to_le32( rndis_per_dev_params[configNr].dev->mtu); @@ -271,8 +271,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_RECEIVE_BLOCK_SIZE: - pr_debug("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__); + case RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE: + pr_debug("%s: RNDIS_OID_GEN_RECEIVE_BLOCK_SIZE\n", __func__); if (rndis_per_dev_params[configNr].dev) { *outbuf = cpu_to_le32( rndis_per_dev_params[configNr].dev->mtu); @@ -281,16 +281,16 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_VENDOR_ID: - pr_debug("%s: OID_GEN_VENDOR_ID\n", __func__); + case RNDIS_OID_GEN_VENDOR_ID: + pr_debug("%s: RNDIS_OID_GEN_VENDOR_ID\n", __func__); *outbuf = cpu_to_le32( rndis_per_dev_params[configNr].vendorID); retval = 0; break; /* mandatory */ - case OID_GEN_VENDOR_DESCRIPTION: - pr_debug("%s: OID_GEN_VENDOR_DESCRIPTION\n", __func__); + case RNDIS_OID_GEN_VENDOR_DESCRIPTION: + pr_debug("%s: RNDIS_OID_GEN_VENDOR_DESCRIPTION\n", __func__); if (rndis_per_dev_params[configNr].vendorDescr) { length = strlen(rndis_per_dev_params[configNr]. vendorDescr); @@ -303,38 +303,38 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, retval = 0; break; - case OID_GEN_VENDOR_DRIVER_VERSION: - pr_debug("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __func__); + case RNDIS_OID_GEN_VENDOR_DRIVER_VERSION: + pr_debug("%s: RNDIS_OID_GEN_VENDOR_DRIVER_VERSION\n", __func__); /* Created as LE */ *outbuf = rndis_driver_version; retval = 0; break; /* mandatory */ - case OID_GEN_CURRENT_PACKET_FILTER: - pr_debug("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __func__); + case RNDIS_OID_GEN_CURRENT_PACKET_FILTER: + pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER\n", __func__); *outbuf = cpu_to_le32(*rndis_per_dev_params[configNr].filter); retval = 0; break; /* mandatory */ - case OID_GEN_MAXIMUM_TOTAL_SIZE: - pr_debug("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__); + case RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE: + pr_debug("%s: RNDIS_OID_GEN_MAXIMUM_TOTAL_SIZE\n", __func__); *outbuf = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE); retval = 0; break; /* mandatory */ - case OID_GEN_MEDIA_CONNECT_STATUS: + case RNDIS_OID_GEN_MEDIA_CONNECT_STATUS: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_MEDIA_CONNECT_STATUS\n", __func__); *outbuf = cpu_to_le32(rndis_per_dev_params[configNr] .media_state); retval = 0; break; - case OID_GEN_PHYSICAL_MEDIUM: - pr_debug("%s: OID_GEN_PHYSICAL_MEDIUM\n", __func__); + case RNDIS_OID_GEN_PHYSICAL_MEDIUM: + pr_debug("%s: RNDIS_OID_GEN_PHYSICAL_MEDIUM\n", __func__); *outbuf = cpu_to_le32(0); retval = 0; break; @@ -343,20 +343,20 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, * 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 */ - pr_debug("%s: OID_GEN_MAC_OPTIONS\n", __func__); + case RNDIS_OID_GEN_MAC_OPTIONS: /* from WinME */ + pr_debug("%s: RNDIS_OID_GEN_MAC_OPTIONS\n", __func__); *outbuf = cpu_to_le32( - NDIS_MAC_OPTION_RECEIVE_SERIALIZED - | NDIS_MAC_OPTION_FULL_DUPLEX); + RNDIS_MAC_OPTION_RECEIVE_SERIALIZED + | RNDIS_MAC_OPTION_FULL_DUPLEX); retval = 0; break; /* statistics OIDs (table 4-2) */ /* mandatory */ - case OID_GEN_XMIT_OK: + case RNDIS_OID_GEN_XMIT_OK: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_XMIT_OK\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_XMIT_OK\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->tx_packets - stats->tx_errors - stats->tx_dropped); @@ -365,9 +365,9 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_RCV_OK: + case RNDIS_OID_GEN_RCV_OK: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_RCV_OK\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_RCV_OK\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->rx_packets - stats->rx_errors - stats->rx_dropped); @@ -376,9 +376,9 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_XMIT_ERROR: + case RNDIS_OID_GEN_XMIT_ERROR: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_XMIT_ERROR\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_XMIT_ERROR\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->tx_errors); retval = 0; @@ -386,9 +386,9 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_RCV_ERROR: + case RNDIS_OID_GEN_RCV_ERROR: if (rndis_debug > 1) - pr_debug("%s: OID_GEN_RCV_ERROR\n", __func__); + pr_debug("%s: RNDIS_OID_GEN_RCV_ERROR\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->rx_errors); retval = 0; @@ -396,8 +396,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_GEN_RCV_NO_BUFFER: - pr_debug("%s: OID_GEN_RCV_NO_BUFFER\n", __func__); + case RNDIS_OID_GEN_RCV_NO_BUFFER: + pr_debug("%s: RNDIS_OID_GEN_RCV_NO_BUFFER\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->rx_dropped); retval = 0; @@ -407,8 +407,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, /* ieee802.3 OIDs (table 4-3) */ /* mandatory */ - case OID_802_3_PERMANENT_ADDRESS: - pr_debug("%s: OID_802_3_PERMANENT_ADDRESS\n", __func__); + case RNDIS_OID_802_3_PERMANENT_ADDRESS: + pr_debug("%s: RNDIS_OID_802_3_PERMANENT_ADDRESS\n", __func__); if (rndis_per_dev_params[configNr].dev) { length = ETH_ALEN; memcpy(outbuf, @@ -419,8 +419,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_802_3_CURRENT_ADDRESS: - pr_debug("%s: OID_802_3_CURRENT_ADDRESS\n", __func__); + case RNDIS_OID_802_3_CURRENT_ADDRESS: + pr_debug("%s: RNDIS_OID_802_3_CURRENT_ADDRESS\n", __func__); if (rndis_per_dev_params[configNr].dev) { length = ETH_ALEN; memcpy(outbuf, @@ -431,23 +431,23 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_802_3_MULTICAST_LIST: - pr_debug("%s: OID_802_3_MULTICAST_LIST\n", __func__); + case RNDIS_OID_802_3_MULTICAST_LIST: + pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__); /* Multicast base address only */ *outbuf = cpu_to_le32(0xE0000000); retval = 0; break; /* mandatory */ - case OID_802_3_MAXIMUM_LIST_SIZE: - pr_debug("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __func__); + case RNDIS_OID_802_3_MAXIMUM_LIST_SIZE: + pr_debug("%s: RNDIS_OID_802_3_MAXIMUM_LIST_SIZE\n", __func__); /* Multicast base address only */ *outbuf = cpu_to_le32(1); retval = 0; break; - case OID_802_3_MAC_OPTIONS: - pr_debug("%s: OID_802_3_MAC_OPTIONS\n", __func__); + case RNDIS_OID_802_3_MAC_OPTIONS: + pr_debug("%s: RNDIS_OID_802_3_MAC_OPTIONS\n", __func__); *outbuf = cpu_to_le32(0); retval = 0; break; @@ -455,8 +455,8 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, /* ieee802.3 statistics OIDs (table 4-4) */ /* mandatory */ - case OID_802_3_RCV_ERROR_ALIGNMENT: - pr_debug("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__); + case RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT: + pr_debug("%s: RNDIS_OID_802_3_RCV_ERROR_ALIGNMENT\n", __func__); if (stats) { *outbuf = cpu_to_le32(stats->rx_frame_errors); retval = 0; @@ -464,15 +464,15 @@ static int gen_ndis_query_resp(int configNr, u32 OID, u8 *buf, break; /* mandatory */ - case OID_802_3_XMIT_ONE_COLLISION: - pr_debug("%s: OID_802_3_XMIT_ONE_COLLISION\n", __func__); + case RNDIS_OID_802_3_XMIT_ONE_COLLISION: + pr_debug("%s: RNDIS_OID_802_3_XMIT_ONE_COLLISION\n", __func__); *outbuf = cpu_to_le32(0); retval = 0; break; /* mandatory */ - case OID_802_3_XMIT_MORE_COLLISIONS: - pr_debug("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __func__); + case RNDIS_OID_802_3_XMIT_MORE_COLLISIONS: + pr_debug("%s: RNDIS_OID_802_3_XMIT_MORE_COLLISIONS\n", __func__); *outbuf = cpu_to_le32(0); retval = 0; break; @@ -516,7 +516,7 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, params = &rndis_per_dev_params[configNr]; switch (OID) { - case OID_GEN_CURRENT_PACKET_FILTER: + case RNDIS_OID_GEN_CURRENT_PACKET_FILTER: /* these NDIS_PACKET_TYPE_* bitflags are shared with * cdc_filter; it's not RNDIS-specific @@ -525,7 +525,7 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, * MULTICAST, ALL_MULTICAST, BROADCAST */ *params->filter = (u16)get_unaligned_le32(buf); - pr_debug("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n", + pr_debug("%s: RNDIS_OID_GEN_CURRENT_PACKET_FILTER %08x\n", __func__, *params->filter); /* this call has a significant side effect: it's @@ -545,9 +545,9 @@ static int gen_ndis_set_resp(u8 configNr, u32 OID, u8 *buf, u32 buf_len, } break; - case OID_802_3_MULTICAST_LIST: + case RNDIS_OID_802_3_MULTICAST_LIST: /* I think we can ignore this */ - pr_debug("%s: OID_802_3_MULTICAST_LIST\n", __func__); + pr_debug("%s: RNDIS_OID_802_3_MULTICAST_LIST\n", __func__); retval = 0; break; @@ -577,7 +577,7 @@ static int rndis_init_response(int configNr, rndis_init_msg_type *buf) return -ENOMEM; resp = (rndis_init_cmplt_type *)r->buf; - resp->MessageType = cpu_to_le32(REMOTE_NDIS_INITIALIZE_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_INIT_C); resp->MessageLength = cpu_to_le32(52); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); @@ -621,7 +621,7 @@ static int rndis_query_response(int configNr, rndis_query_msg_type *buf) return -ENOMEM; resp = (rndis_query_cmplt_type *)r->buf; - resp->MessageType = cpu_to_le32(REMOTE_NDIS_QUERY_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_QUERY_C); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ if (gen_ndis_query_resp(configNr, le32_to_cpu(buf->OID), @@ -668,7 +668,7 @@ static int rndis_set_response(int configNr, rndis_set_msg_type *buf) pr_debug("\n"); #endif - resp->MessageType = cpu_to_le32(REMOTE_NDIS_SET_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_SET_C); resp->MessageLength = cpu_to_le32(16); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ if (gen_ndis_set_resp(configNr, le32_to_cpu(buf->OID), @@ -692,7 +692,7 @@ static int rndis_reset_response(int configNr, rndis_reset_msg_type *buf) return -ENOMEM; resp = (rndis_reset_cmplt_type *)r->buf; - resp->MessageType = cpu_to_le32(REMOTE_NDIS_RESET_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_RESET_C); resp->MessageLength = cpu_to_le32(16); resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); /* resent information */ @@ -716,8 +716,7 @@ static int rndis_keepalive_response(int configNr, return -ENOMEM; resp = (rndis_keepalive_cmplt_type *)r->buf; - resp->MessageType = cpu_to_le32( - REMOTE_NDIS_KEEPALIVE_CMPLT); + resp->MessageType = cpu_to_le32(RNDIS_MSG_KEEPALIVE_C); resp->MessageLength = cpu_to_le32(16); resp->RequestID = buf->RequestID; /* Still LE in msg buffer */ resp->Status = cpu_to_le32(RNDIS_STATUS_SUCCESS); @@ -745,7 +744,7 @@ static int rndis_indicate_status_msg(int configNr, u32 status) return -ENOMEM; resp = (rndis_indicate_status_msg_type *)r->buf; - resp->MessageType = cpu_to_le32(REMOTE_NDIS_INDICATE_STATUS_MSG); + resp->MessageType = cpu_to_le32(RNDIS_MSG_INDICATE); resp->MessageLength = cpu_to_le32(20); resp->Status = cpu_to_le32(status); resp->StatusBufferLength = cpu_to_le32(0); @@ -758,7 +757,7 @@ static int rndis_indicate_status_msg(int configNr, u32 status) int rndis_signal_connect(int configNr) { rndis_per_dev_params[configNr].media_state - = NDIS_MEDIA_STATE_CONNECTED; + = RNDIS_MEDIA_STATE_CONNECTED; return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_CONNECT); } @@ -766,7 +765,7 @@ int rndis_signal_connect(int configNr) int rndis_signal_disconnect(int configNr) { rndis_per_dev_params[configNr].media_state - = NDIS_MEDIA_STATE_DISCONNECTED; + = RNDIS_MEDIA_STATE_DISCONNECTED; return rndis_indicate_status_msg(configNr, RNDIS_STATUS_MEDIA_DISCONNECT); } @@ -817,15 +816,15 @@ int rndis_msg_parser(u8 configNr, u8 *buf) /* For USB: responses may take up to 10 seconds */ switch (MsgType) { - case REMOTE_NDIS_INITIALIZE_MSG: - pr_debug("%s: REMOTE_NDIS_INITIALIZE_MSG\n", + case RNDIS_MSG_INIT: + pr_debug("%s: RNDIS_MSG_INIT\n", __func__); params->state = RNDIS_INITIALIZED; return rndis_init_response(configNr, (rndis_init_msg_type *)buf); - case REMOTE_NDIS_HALT_MSG: - pr_debug("%s: REMOTE_NDIS_HALT_MSG\n", + case RNDIS_MSG_HALT: + pr_debug("%s: RNDIS_MSG_HALT\n", __func__); params->state = RNDIS_UNINITIALIZED; if (params->dev) { @@ -834,24 +833,24 @@ int rndis_msg_parser(u8 configNr, u8 *buf) } return 0; - case REMOTE_NDIS_QUERY_MSG: + case RNDIS_MSG_QUERY: return rndis_query_response(configNr, (rndis_query_msg_type *)buf); - case REMOTE_NDIS_SET_MSG: + case RNDIS_MSG_SET: return rndis_set_response(configNr, (rndis_set_msg_type *)buf); - case REMOTE_NDIS_RESET_MSG: - pr_debug("%s: REMOTE_NDIS_RESET_MSG\n", + case RNDIS_MSG_RESET: + pr_debug("%s: RNDIS_MSG_RESET\n", __func__); return rndis_reset_response(configNr, (rndis_reset_msg_type *)buf); - case REMOTE_NDIS_KEEPALIVE_MSG: + case RNDIS_MSG_KEEPALIVE: /* For USB: host does this every 5 seconds */ if (rndis_debug > 1) - pr_debug("%s: REMOTE_NDIS_KEEPALIVE_MSG\n", + pr_debug("%s: RNDIS_MSG_KEEPALIVE\n", __func__); return rndis_keepalive_response(configNr, (rndis_keepalive_msg_type *) @@ -963,7 +962,7 @@ void rndis_add_hdr(struct sk_buff *skb) return; header = (void *)skb_push(skb, sizeof(*header)); memset(header, 0, sizeof *header); - header->MessageType = cpu_to_le32(REMOTE_NDIS_PACKET_MSG); + header->MessageType = cpu_to_le32(RNDIS_MSG_PACKET); header->MessageLength = cpu_to_le32(skb->len); header->DataOffset = cpu_to_le32(36); header->DataLength = cpu_to_le32(skb->len - sizeof(*header)); @@ -1031,7 +1030,7 @@ int rndis_rm_hdr(struct gether *port, __le32 *tmp = (void *)skb->data; /* MessageType, MessageLength */ - if (cpu_to_le32(REMOTE_NDIS_PACKET_MSG) + if (cpu_to_le32(RNDIS_MSG_PACKET) != get_unaligned(tmp++)) { dev_kfree_skb_any(skb); return -EINVAL; @@ -1173,7 +1172,7 @@ int rndis_init(void) 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; + = RNDIS_MEDIA_STATE_DISCONNECTED; INIT_LIST_HEAD(&(rndis_per_dev_params[i].resp_queue)); } diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h index 907c33008118..0647f2f34e89 100644 --- a/drivers/usb/gadget/rndis.h +++ b/drivers/usb/gadget/rndis.h @@ -15,58 +15,12 @@ #ifndef _LINUX_RNDIS_H #define _LINUX_RNDIS_H +#include <linux/rndis.h> #include "ndis.h" #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; diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c index 105b206cd844..f4abb0ed9872 100644 --- a/drivers/usb/gadget/s3c-hsotg.c +++ b/drivers/usb/gadget/s3c-hsotg.c @@ -1,4 +1,5 @@ -/* linux/drivers/usb/gadget/s3c-hsotg.c +/** + * linux/drivers/usb/gadget/s3c-hsotg.c * * Copyright (c) 2011 Samsung Electronics Co., Ltd. * http://www.samsung.com @@ -13,7 +14,7 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. -*/ + */ #include <linux/kernel.h> #include <linux/module.h> @@ -27,21 +28,25 @@ #include <linux/io.h> #include <linux/slab.h> #include <linux/clk.h> +#include <linux/regulator/consumer.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> +#include <linux/platform_data/s3c-hsotg.h> #include <mach/map.h> -#include <plat/regs-usb-hsotg-phy.h> -#include <plat/regs-usb-hsotg.h> -#include <mach/regs-sys.h> -#include <plat/udc-hs.h> -#include <plat/cpu.h> +#include "s3c-hsotg.h" #define DMA_ADDR_INVALID (~((dma_addr_t)0)) -/* EP0_MPS_LIMIT +static const char * const s3c_hsotg_supply_names[] = { + "vusb_d", /* digital USB supply, 1.2V */ + "vusb_a", /* analog USB supply, 1.1V */ +}; + +/* + * EP0_MPS_LIMIT * * Unfortunately there seems to be a limit of the amount of data that can * be transferred by IN transactions on EP0. This is either 127 bytes or 3 @@ -125,8 +130,6 @@ struct s3c_hsotg_ep { char name[10]; }; -#define S3C_HSOTG_EPS (8+1) /* limit to 9 for the moment */ - /** * struct s3c_hsotg - driver state. * @dev: The parent device supplied to the probe function @@ -135,7 +138,9 @@ struct s3c_hsotg_ep { * @regs: The memory area mapped for accessing registers. * @regs_res: The resource that was allocated when claiming register space. * @irq: The IRQ number we are using + * @supplies: Definition of USB power supplies * @dedicated_fifos: Set if the hardware has dedicated IN-EP fifos. + * @num_of_eps: Number of available EPs (excluding EP0) * @debug_root: root directrory for debugfs. * @debug_file: main status file for debugfs. * @debug_fifo: FIFO status file for debugfs. @@ -143,6 +148,8 @@ struct s3c_hsotg_ep { * @ep0_buff: Buffer for EP0 reply data, if needed. * @ctrl_buff: Buffer for EP0 control requests. * @ctrl_req: Request for EP0 control packets. + * @setup: NAK management for EP0 SETUP + * @last_rst: Time of last reset * @eps: The endpoints being supplied to the gadget framework */ struct s3c_hsotg { @@ -155,7 +162,10 @@ struct s3c_hsotg { int irq; struct clk *clk; + struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsotg_supply_names)]; + unsigned int dedicated_fifos:1; + unsigned char num_of_eps; struct dentry *debug_root; struct dentry *debug_file; @@ -167,7 +177,9 @@ struct s3c_hsotg { u8 ctrl_buff[8]; struct usb_gadget gadget; - struct s3c_hsotg_ep eps[]; + unsigned int setup; + unsigned long last_rst; + struct s3c_hsotg_ep *eps; }; /** @@ -244,14 +256,14 @@ static inline bool using_dma(struct s3c_hsotg *hsotg) */ static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) { - u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK); + u32 gsintmsk = readl(hsotg->regs + GINTMSK); u32 new_gsintmsk; new_gsintmsk = gsintmsk | ints; if (new_gsintmsk != gsintmsk) { dev_dbg(hsotg->dev, "gsintmsk now 0x%08x\n", new_gsintmsk); - writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK); + writel(new_gsintmsk, hsotg->regs + GINTMSK); } } @@ -262,13 +274,13 @@ static void s3c_hsotg_en_gsint(struct s3c_hsotg *hsotg, u32 ints) */ static void s3c_hsotg_disable_gsint(struct s3c_hsotg *hsotg, u32 ints) { - u32 gsintmsk = readl(hsotg->regs + S3C_GINTMSK); + u32 gsintmsk = readl(hsotg->regs + GINTMSK); u32 new_gsintmsk; new_gsintmsk = gsintmsk & ~ints; if (new_gsintmsk != gsintmsk) - writel(new_gsintmsk, hsotg->regs + S3C_GINTMSK); + writel(new_gsintmsk, hsotg->regs + GINTMSK); } /** @@ -293,12 +305,12 @@ static void s3c_hsotg_ctrl_epint(struct s3c_hsotg *hsotg, bit <<= 16; local_irq_save(flags); - daint = readl(hsotg->regs + S3C_DAINTMSK); + daint = readl(hsotg->regs + DAINTMSK); if (en) daint |= bit; else daint &= ~bit; - writel(daint, hsotg->regs + S3C_DAINTMSK); + writel(daint, hsotg->regs + DAINTMSK); local_irq_restore(flags); } @@ -314,52 +326,51 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg) int timeout; u32 val; - /* the ryu 2.6.24 release ahs - writel(0x1C0, hsotg->regs + S3C_GRXFSIZ); - writel(S3C_GNPTXFSIZ_NPTxFStAddr(0x200) | - S3C_GNPTXFSIZ_NPTxFDep(0x1C0), - hsotg->regs + S3C_GNPTXFSIZ); - */ - /* set FIFO sizes to 2048/1024 */ - writel(2048, hsotg->regs + S3C_GRXFSIZ); - writel(S3C_GNPTXFSIZ_NPTxFStAddr(2048) | - S3C_GNPTXFSIZ_NPTxFDep(1024), - hsotg->regs + S3C_GNPTXFSIZ); + writel(2048, hsotg->regs + GRXFSIZ); + writel(GNPTXFSIZ_NPTxFStAddr(2048) | + GNPTXFSIZ_NPTxFDep(1024), + hsotg->regs + GNPTXFSIZ); - /* arange all the rest of the TX FIFOs, as some versions of this + /* + * arange all the rest of the TX FIFOs, as some versions of this * block have overlapping default addresses. This also ensures * that if the settings have been changed, then they are set to - * known values. */ + * known values. + */ /* start at the end of the GNPTXFSIZ, rounded up */ addr = 2048 + 1024; size = 768; - /* currently we allocate TX FIFOs for all possible endpoints, - * and assume that they are all the same size. */ + /* + * currently we allocate TX FIFOs for all possible endpoints, + * and assume that they are all the same size. + */ for (ep = 1; ep <= 15; ep++) { val = addr; - val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT; + val |= size << DPTXFSIZn_DPTxFSize_SHIFT; addr += size; - writel(val, hsotg->regs + S3C_DPTXFSIZn(ep)); + writel(val, hsotg->regs + DPTXFSIZn(ep)); } - /* according to p428 of the design guide, we need to ensure that - * all fifos are flushed before continuing */ + /* + * according to p428 of the design guide, we need to ensure that + * all fifos are flushed before continuing + */ - writel(S3C_GRSTCTL_TxFNum(0x10) | S3C_GRSTCTL_TxFFlsh | - S3C_GRSTCTL_RxFFlsh, hsotg->regs + S3C_GRSTCTL); + writel(GRSTCTL_TxFNum(0x10) | GRSTCTL_TxFFlsh | + GRSTCTL_RxFFlsh, hsotg->regs + GRSTCTL); /* wait until the fifos are both flushed */ timeout = 100; while (1) { - val = readl(hsotg->regs + S3C_GRSTCTL); + val = readl(hsotg->regs + GRSTCTL); - if ((val & (S3C_GRSTCTL_TxFFlsh | S3C_GRSTCTL_RxFFlsh)) == 0) + if ((val & (GRSTCTL_TxFFlsh | GRSTCTL_RxFFlsh)) == 0) break; if (--timeout == 0) { @@ -415,7 +426,7 @@ static inline int is_ep_periodic(struct s3c_hsotg_ep *hs_ep) * * This is the reverse of s3c_hsotg_map_dma(), called for the completion * of a request to ensure the buffer is ready for access by the caller. -*/ + */ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req) @@ -456,13 +467,13 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg, * otherwise -ENOSPC is returned if the FIFO space was used up. * * This routine is only needed for PIO -*/ + */ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req) { bool periodic = is_ep_periodic(hs_ep); - u32 gnptxsts = readl(hsotg->regs + S3C_GNPTXSTS); + u32 gnptxsts = readl(hsotg->regs + GNPTXSTS); int buf_pos = hs_req->req.actual; int to_write = hs_ep->size_loaded; void *data; @@ -476,20 +487,23 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, return 0; if (periodic && !hsotg->dedicated_fifos) { - u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); + u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); int size_left; int size_done; - /* work out how much data was loaded so we can calculate - * how much data is left in the fifo. */ + /* + * work out how much data was loaded so we can calculate + * how much data is left in the fifo. + */ - size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); + size_left = DxEPTSIZ_XferSize_GET(epsize); - /* if shared fifo, we cannot write anything until the + /* + * if shared fifo, we cannot write anything until the * previous data has been completely sent. */ if (hs_ep->fifo_load != 0) { - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); return -ENOSPC; } @@ -510,47 +524,50 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, __func__, can_write); if (can_write <= 0) { - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_PTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_PTxFEmp); return -ENOSPC; } } else if (hsotg->dedicated_fifos && hs_ep->index != 0) { - can_write = readl(hsotg->regs + S3C_DTXFSTS(hs_ep->index)); + can_write = readl(hsotg->regs + DTXFSTS(hs_ep->index)); can_write &= 0xffff; can_write *= 4; } else { - if (S3C_GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { + if (GNPTXSTS_NPTxQSpcAvail_GET(gnptxsts) == 0) { dev_dbg(hsotg->dev, "%s: no queue slots available (0x%08x)\n", __func__, gnptxsts); - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_NPTxFEmp); + s3c_hsotg_en_gsint(hsotg, GINTSTS_NPTxFEmp); return -ENOSPC; } - can_write = S3C_GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); + can_write = GNPTXSTS_NPTxFSpcAvail_GET(gnptxsts); can_write *= 4; /* fifo size is in 32bit quantities. */ } dev_dbg(hsotg->dev, "%s: GNPTXSTS=%08x, can=%d, to=%d, mps %d\n", __func__, gnptxsts, can_write, to_write, hs_ep->ep.maxpacket); - /* limit to 512 bytes of data, it seems at least on the non-periodic + /* + * limit to 512 bytes of data, it seems at least on the non-periodic * FIFO, requests of >512 cause the endpoint to get stuck with a * fragment of the end of the transfer in it. */ if (can_write > 512) can_write = 512; - /* limit the write to one max-packet size worth of data, but allow + /* + * limit the write to one max-packet size worth of data, but allow * the transfer to return that it did not run out of fifo space - * doing it. */ + * doing it. + */ if (to_write > hs_ep->ep.maxpacket) { to_write = hs_ep->ep.maxpacket; s3c_hsotg_en_gsint(hsotg, - periodic ? S3C_GINTSTS_PTxFEmp : - S3C_GINTSTS_NPTxFEmp); + periodic ? GINTSTS_PTxFEmp : + GINTSTS_NPTxFEmp); } /* see if we can write data */ @@ -559,8 +576,8 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, to_write = can_write; pkt_round = to_write % hs_ep->ep.maxpacket; - /* Not sure, but we probably shouldn't be writing partial - * packets into the FIFO, so round the write down to an + /* + * Round the write down to an * exact number of packets. * * Note, we do not currently check to see if we can ever @@ -570,12 +587,14 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, if (pkt_round) to_write -= pkt_round; - /* enable correct FIFO interrupt to alert us when there - * is more room left. */ + /* + * enable correct FIFO interrupt to alert us when there + * is more room left. + */ s3c_hsotg_en_gsint(hsotg, - periodic ? S3C_GINTSTS_PTxFEmp : - S3C_GINTSTS_NPTxFEmp); + periodic ? GINTSTS_PTxFEmp : + GINTSTS_NPTxFEmp); } dev_dbg(hsotg->dev, "write %d/%d, can_write %d, done %d\n", @@ -593,7 +612,7 @@ static int s3c_hsotg_write_fifo(struct s3c_hsotg *hsotg, to_write = DIV_ROUND_UP(to_write, 4); data = hs_req->req.buf + buf_pos; - writesl(hsotg->regs + S3C_EPFIFO(hs_ep->index), data, to_write); + writesl(hsotg->regs + EPFIFO(hs_ep->index), data, to_write); return (to_write >= can_write) ? -ENOSPC : 0; } @@ -612,12 +631,12 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) unsigned maxpkt; if (index != 0) { - maxsize = S3C_DxEPTSIZ_XferSize_LIMIT + 1; - maxpkt = S3C_DxEPTSIZ_PktCnt_LIMIT + 1; + maxsize = DxEPTSIZ_XferSize_LIMIT + 1; + maxpkt = DxEPTSIZ_PktCnt_LIMIT + 1; } else { maxsize = 64+64; if (hs_ep->dir_in) - maxpkt = S3C_DIEPTSIZ0_PktCnt_LIMIT + 1; + maxpkt = DIEPTSIZ0_PktCnt_LIMIT + 1; else maxpkt = 2; } @@ -626,8 +645,10 @@ static unsigned get_ep_limit(struct s3c_hsotg_ep *hs_ep) maxpkt--; maxsize--; - /* constrain by packet count if maxpkts*pktsize is greater - * than the length register size. */ + /* + * constrain by packet count if maxpkts*pktsize is greater + * than the length register size. + */ if ((maxpkt * hs_ep->ep.maxpacket) < maxsize) maxsize = maxpkt * hs_ep->ep.maxpacket; @@ -674,8 +695,8 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, } } - epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); - epsize_reg = dir_in ? S3C_DIEPTSIZ(index) : S3C_DOEPTSIZ(index); + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); + epsize_reg = dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index); dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x, ep %d, dir %s\n", __func__, readl(hsotg->regs + epctrl_reg), index, @@ -684,13 +705,14 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, /* If endpoint is stalled, we will restart request later */ ctrl = readl(hsotg->regs + epctrl_reg); - if (ctrl & S3C_DxEPCTL_Stall) { + if (ctrl & DxEPCTL_Stall) { dev_warn(hsotg->dev, "%s: ep%d is stalled\n", __func__, index); return; } length = ureq->length - ureq->actual; - + dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n", + ureq->length, ureq->actual); if (0) dev_dbg(hsotg->dev, "REQ buf %p len %d dma 0x%08x noi=%d zp=%d snok=%d\n", @@ -717,20 +739,22 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, packets = 1; /* send one packet if length is zero. */ if (dir_in && index != 0) - epsize = S3C_DxEPTSIZ_MC(1); + epsize = DxEPTSIZ_MC(1); else epsize = 0; if (index != 0 && ureq->zero) { - /* test for the packets being exactly right for the - * transfer */ + /* + * test for the packets being exactly right for the + * transfer + */ if (length == (packets * hs_ep->ep.maxpacket)) packets++; } - epsize |= S3C_DxEPTSIZ_PktCnt(packets); - epsize |= S3C_DxEPTSIZ_XferSize(length); + epsize |= DxEPTSIZ_PktCnt(packets); + epsize |= DxEPTSIZ_XferSize(length); dev_dbg(hsotg->dev, "%s: %d@%d/%d, 0x%08x => 0x%08x\n", __func__, packets, length, ureq->length, epsize, epsize_reg); @@ -744,26 +768,38 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, if (using_dma(hsotg) && !continuing) { unsigned int dma_reg; - /* write DMA address to control register, buffer already - * synced by s3c_hsotg_ep_queue(). */ + /* + * write DMA address to control register, buffer already + * synced by s3c_hsotg_ep_queue(). + */ - dma_reg = dir_in ? S3C_DIEPDMA(index) : S3C_DOEPDMA(index); + dma_reg = dir_in ? DIEPDMA(index) : DOEPDMA(index); writel(ureq->dma, hsotg->regs + dma_reg); dev_dbg(hsotg->dev, "%s: 0x%08x => 0x%08x\n", __func__, ureq->dma, dma_reg); } - ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= S3C_DxEPCTL_USBActEp; - ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ + ctrl |= DxEPCTL_USBActEp; + + dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup); + + /* For Setup request do not clear NAK */ + if (hsotg->setup && index == 0) + hsotg->setup = 0; + else + ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ + dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); writel(ctrl, hsotg->regs + epctrl_reg); - /* set these, it seems that DMA support increments past the end + /* + * set these, it seems that DMA support increments past the end * of the packet buffer so we need to calculate the length from - * this information. */ + * this information. + */ hs_ep->size_loaded = length; hs_ep->last_load = ureq->actual; @@ -774,17 +810,21 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, s3c_hsotg_write_fifo(hsotg, hs_ep, hs_req); } - /* clear the INTknTXFEmpMsk when we start request, more as a aide - * to debugging to see what is going on. */ + /* + * clear the INTknTXFEmpMsk when we start request, more as a aide + * to debugging to see what is going on. + */ if (dir_in) - writel(S3C_DIEPMSK_INTknTXFEmpMsk, - hsotg->regs + S3C_DIEPINT(index)); + writel(DIEPMSK_INTknTXFEmpMsk, + hsotg->regs + DIEPINT(index)); - /* Note, trying to clear the NAK here causes problems with transmit - * on the S3C6400 ending up with the TXFIFO becoming full. */ + /* + * Note, trying to clear the NAK here causes problems with transmit + * on the S3C6400 ending up with the TXFIFO becoming full. + */ /* check ep is enabled */ - if (!(readl(hsotg->regs + epctrl_reg) & S3C_DxEPCTL_EPEna)) + if (!(readl(hsotg->regs + epctrl_reg) & DxEPCTL_EPEna)) dev_warn(hsotg->dev, "ep%d: failed to become enabled (DxEPCTL=0x%08x)?\n", index, readl(hsotg->regs + epctrl_reg)); @@ -804,7 +844,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg, * then ensure the buffer has been synced to memory. If our buffer has no * DMA memory, then we map the memory and mark our request to allow us to * cleanup on completion. -*/ + */ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct usb_request *req) @@ -922,7 +962,7 @@ static void s3c_hsotg_complete_oursetup(struct usb_ep *ep, * * Convert the given wIndex into a pointer to an driver endpoint * structure, or return NULL if it is not a valid endpoint. -*/ + */ static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, u32 windex) { @@ -933,7 +973,7 @@ static struct s3c_hsotg_ep *ep_from_windex(struct s3c_hsotg *hsotg, if (windex >= 0x100) return NULL; - if (idx > S3C_HSOTG_EPS) + if (idx > hsotg->num_of_eps) return NULL; if (idx && ep->dir_in != dir) @@ -1151,24 +1191,28 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, ctrl->bRequest, ctrl->bRequestType, ctrl->wValue, ctrl->wLength); - /* record the direction of the request, for later use when enquing - * packets onto EP0. */ + /* + * record the direction of the request, for later use when enquing + * packets onto EP0. + */ ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0; dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in); - /* if we've no data with this request, then the last part of the - * transaction is going to implicitly be IN. */ + /* + * if we've no data with this request, then the last part of the + * transaction is going to implicitly be IN. + */ if (ctrl->wLength == 0) ep0->dir_in = 1; if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) { switch (ctrl->bRequest) { case USB_REQ_SET_ADDRESS: - dcfg = readl(hsotg->regs + S3C_DCFG); - dcfg &= ~S3C_DCFG_DevAddr_MASK; - dcfg |= ctrl->wValue << S3C_DCFG_DevAddr_SHIFT; - writel(dcfg, hsotg->regs + S3C_DCFG); + dcfg = readl(hsotg->regs + DCFG); + dcfg &= ~DCFG_DevAddr_MASK; + dcfg |= ctrl->wValue << DCFG_DevAddr_SHIFT; + writel(dcfg, hsotg->regs + DCFG); dev_info(hsotg->dev, "new address %d\n", ctrl->wValue); @@ -1194,7 +1238,8 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, dev_dbg(hsotg->dev, "driver->setup() ret %d\n", ret); } - /* the request is either unhandlable, or is not formatted correctly + /* + * the request is either unhandlable, or is not formatted correctly * so respond with a STALL for the status stage to indicate failure. */ @@ -1203,22 +1248,26 @@ static void s3c_hsotg_process_control(struct s3c_hsotg *hsotg, u32 ctrl; dev_dbg(hsotg->dev, "ep0 stall (dir=%d)\n", ep0->dir_in); - reg = (ep0->dir_in) ? S3C_DIEPCTL0 : S3C_DOEPCTL0; + reg = (ep0->dir_in) ? DIEPCTL0 : DOEPCTL0; - /* S3C_DxEPCTL_Stall will be cleared by EP once it has - * taken effect, so no need to clear later. */ + /* + * DxEPCTL_Stall will be cleared by EP once it has + * taken effect, so no need to clear later. + */ ctrl = readl(hsotg->regs + reg); - ctrl |= S3C_DxEPCTL_Stall; - ctrl |= S3C_DxEPCTL_CNAK; + ctrl |= DxEPCTL_Stall; + ctrl |= DxEPCTL_CNAK; writel(ctrl, hsotg->regs + reg); dev_dbg(hsotg->dev, "written DxEPCTL=0x%08x to %08x (DxEPCTL=0x%08x)\n", ctrl, reg, readl(hsotg->regs + reg)); - /* don't believe we need to anything more to get the EP - * to reply with a STALL packet */ + /* + * don't believe we need to anything more to get the EP + * to reply with a STALL packet + */ } } @@ -1279,8 +1328,10 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC); if (ret < 0) { dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret); - /* Don't think there's much we can do other than watch the - * driver fail. */ + /* + * Don't think there's much we can do other than watch the + * driver fail. + */ } } @@ -1296,7 +1347,7 @@ static void s3c_hsotg_enqueue_setup(struct s3c_hsotg *hsotg) * on the endpoint. * * Note, expects the ep to already be locked as appropriate. -*/ + */ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req, @@ -1312,8 +1363,10 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, dev_dbg(hsotg->dev, "complete: ep %p %s, req %p, %d => %p\n", hs_ep, hs_ep->ep.name, hs_req, result, hs_req->req.complete); - /* only replace the status if we've not already set an error - * from a previous transaction */ + /* + * only replace the status if we've not already set an error + * from a previous transaction + */ if (hs_req->req.status == -EINPROGRESS) hs_req->req.status = result; @@ -1324,8 +1377,10 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, if (using_dma(hsotg)) s3c_hsotg_unmap_dma(hsotg, hs_ep, hs_req); - /* call the complete request with the locks off, just in case the - * request tries to queue more work for this endpoint. */ + /* + * call the complete request with the locks off, just in case the + * request tries to queue more work for this endpoint. + */ if (hs_req->req.complete) { spin_unlock(&hs_ep->lock); @@ -1333,9 +1388,11 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, spin_lock(&hs_ep->lock); } - /* Look to see if there is anything else to do. Note, the completion + /* + * Look to see if there is anything else to do. Note, the completion * of the previous request may have caused a new request to be started - * so be careful when doing this. */ + * so be careful when doing this. + */ if (!hs_ep->req && result >= 0) { restart = !list_empty(&hs_ep->queue); @@ -1355,7 +1412,7 @@ static void s3c_hsotg_complete_request(struct s3c_hsotg *hsotg, * * See s3c_hsotg_complete_request(), but called with the endpoint's * lock held. -*/ + */ static void s3c_hsotg_complete_request_lock(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req, @@ -1382,13 +1439,13 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) { struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx]; struct s3c_hsotg_req *hs_req = hs_ep->req; - void __iomem *fifo = hsotg->regs + S3C_EPFIFO(ep_idx); + void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx); int to_read; int max_req; int read_ptr; if (!hs_req) { - u32 epctl = readl(hsotg->regs + S3C_DOEPCTL(ep_idx)); + u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx)); int ptr; dev_warn(hsotg->dev, @@ -1412,7 +1469,8 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) __func__, to_read, max_req, read_ptr, hs_req->req.length); if (to_read > max_req) { - /* more data appeared than we where willing + /* + * more data appeared than we where willing * to deal with in this request. */ @@ -1424,8 +1482,10 @@ static void s3c_hsotg_rx_data(struct s3c_hsotg *hsotg, int ep_idx, int size) hs_req->req.actual += to_read; to_read = DIV_ROUND_UP(to_read, 4); - /* note, we might over-write the buffer end by 3 bytes depending on - * alignment of the data. */ + /* + * note, we might over-write the buffer end by 3 bytes depending on + * alignment of the data. + */ readsl(fifo, hs_req->req.buf + read_ptr, to_read); spin_unlock(&hs_ep->lock); @@ -1465,14 +1525,14 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, dev_dbg(hsotg->dev, "sending zero-length packet\n"); /* issue a zero-sized packet to terminate this */ - writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) | - S3C_DxEPTSIZ_XferSize(0), hsotg->regs + S3C_DIEPTSIZ(0)); + writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | + DxEPTSIZ_XferSize(0), hsotg->regs + DIEPTSIZ(0)); - ctrl = readl(hsotg->regs + S3C_DIEPCTL0); - ctrl |= S3C_DxEPCTL_CNAK; /* clear NAK set by core */ - ctrl |= S3C_DxEPCTL_EPEna; /* ensure ep enabled */ - ctrl |= S3C_DxEPCTL_USBActEp; - writel(ctrl, hsotg->regs + S3C_DIEPCTL0); + ctrl = readl(hsotg->regs + DIEPCTL0); + ctrl |= DxEPCTL_CNAK; /* clear NAK set by core */ + ctrl |= DxEPCTL_EPEna; /* ensure ep enabled */ + ctrl |= DxEPCTL_USBActEp; + writel(ctrl, hsotg->regs + DIEPCTL0); } /** @@ -1484,15 +1544,15 @@ static void s3c_hsotg_send_zlp(struct s3c_hsotg *hsotg, * The RXFIFO has delivered an OutDone event, which means that the data * transfer for an OUT endpoint has been completed, either by a short * packet or by the finish of a transfer. -*/ + */ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, int epnum, bool was_setup) { - u32 epsize = readl(hsotg->regs + S3C_DOEPTSIZ(epnum)); + u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum)); struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum]; struct s3c_hsotg_req *hs_req = hs_ep->req; struct usb_request *req = &hs_req->req; - unsigned size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); + unsigned size_left = DxEPTSIZ_XferSize_GET(epsize); int result = 0; if (!hs_req) { @@ -1503,7 +1563,8 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, if (using_dma(hsotg)) { unsigned size_done; - /* Calculate the size of the transfer by checking how much + /* + * Calculate the size of the transfer by checking how much * is left in the endpoint size register and then working it * out from the amount we loaded for the transfer. * @@ -1521,17 +1582,29 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, if (req->actual < req->length && size_left == 0) { s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true); return; + } else if (epnum == 0) { + /* + * After was_setup = 1 => + * set CNAK for non Setup requests + */ + hsotg->setup = was_setup ? 0 : 1; } if (req->actual < req->length && req->short_not_ok) { dev_dbg(hsotg->dev, "%s: got %d/%d (short not ok) => error\n", __func__, req->actual, req->length); - /* todo - what should we return here? there's no one else - * even bothering to check the status. */ + /* + * todo - what should we return here? there's no one else + * even bothering to check the status. + */ } if (epnum == 0) { + /* + * Condition req->complete != s3c_hsotg_complete_setup says: + * send ZLP when we have an asynchronous request from gadget + */ if (!was_setup && req->complete != s3c_hsotg_complete_setup) s3c_hsotg_send_zlp(hsotg, hs_req); } @@ -1544,14 +1617,14 @@ static void s3c_hsotg_handle_outdone(struct s3c_hsotg *hsotg, * @hsotg: The device instance * * Return the current frame number -*/ + */ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) { u32 dsts; - dsts = readl(hsotg->regs + S3C_DSTS); - dsts &= S3C_DSTS_SOFFN_MASK; - dsts >>= S3C_DSTS_SOFFN_SHIFT; + dsts = readl(hsotg->regs + DSTS); + dsts &= DSTS_SOFFN_MASK; + dsts >>= DSTS_SOFFN_SHIFT; return dsts; } @@ -1574,29 +1647,29 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg) */ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) { - u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP); + u32 grxstsr = readl(hsotg->regs + GRXSTSP); u32 epnum, status, size; WARN_ON(using_dma(hsotg)); - epnum = grxstsr & S3C_GRXSTS_EPNum_MASK; - status = grxstsr & S3C_GRXSTS_PktSts_MASK; + epnum = grxstsr & GRXSTS_EPNum_MASK; + status = grxstsr & GRXSTS_PktSts_MASK; - size = grxstsr & S3C_GRXSTS_ByteCnt_MASK; - size >>= S3C_GRXSTS_ByteCnt_SHIFT; + size = grxstsr & GRXSTS_ByteCnt_MASK; + size >>= GRXSTS_ByteCnt_SHIFT; if (1) dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n", __func__, grxstsr, size, epnum); -#define __status(x) ((x) >> S3C_GRXSTS_PktSts_SHIFT) +#define __status(x) ((x) >> GRXSTS_PktSts_SHIFT) - switch (status >> S3C_GRXSTS_PktSts_SHIFT) { - case __status(S3C_GRXSTS_PktSts_GlobalOutNAK): + switch (status >> GRXSTS_PktSts_SHIFT) { + case __status(GRXSTS_PktSts_GlobalOutNAK): dev_dbg(hsotg->dev, "GlobalOutNAK\n"); break; - case __status(S3C_GRXSTS_PktSts_OutDone): + case __status(GRXSTS_PktSts_OutDone): dev_dbg(hsotg->dev, "OutDone (Frame=0x%08x)\n", s3c_hsotg_read_frameno(hsotg)); @@ -1604,24 +1677,24 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) s3c_hsotg_handle_outdone(hsotg, epnum, false); break; - case __status(S3C_GRXSTS_PktSts_SetupDone): + case __status(GRXSTS_PktSts_SetupDone): dev_dbg(hsotg->dev, "SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n", s3c_hsotg_read_frameno(hsotg), - readl(hsotg->regs + S3C_DOEPCTL(0))); + readl(hsotg->regs + DOEPCTL(0))); s3c_hsotg_handle_outdone(hsotg, epnum, true); break; - case __status(S3C_GRXSTS_PktSts_OutRX): + case __status(GRXSTS_PktSts_OutRX): s3c_hsotg_rx_data(hsotg, epnum, size); break; - case __status(S3C_GRXSTS_PktSts_SetupRX): + case __status(GRXSTS_PktSts_SetupRX): dev_dbg(hsotg->dev, "SetupRX (Frame=0x%08x, DOPEPCTL=0x%08x)\n", s3c_hsotg_read_frameno(hsotg), - readl(hsotg->regs + S3C_DOEPCTL(0))); + readl(hsotg->regs + DOEPCTL(0))); s3c_hsotg_rx_data(hsotg, epnum, size); break; @@ -1638,18 +1711,18 @@ static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg) /** * s3c_hsotg_ep0_mps - turn max packet size into register setting * @mps: The maximum packet size in bytes. -*/ + */ static u32 s3c_hsotg_ep0_mps(unsigned int mps) { switch (mps) { case 64: - return S3C_D0EPCTL_MPS_64; + return D0EPCTL_MPS_64; case 32: - return S3C_D0EPCTL_MPS_32; + return D0EPCTL_MPS_32; case 16: - return S3C_D0EPCTL_MPS_16; + return D0EPCTL_MPS_16; case 8: - return S3C_D0EPCTL_MPS_8; + return D0EPCTL_MPS_8; } /* bad max packet size, warn and return invalid result */ @@ -1680,7 +1753,7 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, if (mpsval > 3) goto bad_mps; } else { - if (mps >= S3C_DxEPCTL_MPS_LIMIT+1) + if (mps >= DxEPCTL_MPS_LIMIT+1) goto bad_mps; mpsval = mps; @@ -1688,19 +1761,21 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg, hs_ep->ep.maxpacket = mps; - /* update both the in and out endpoint controldir_ registers, even - * if one of the directions may not be in use. */ + /* + * update both the in and out endpoint controldir_ registers, even + * if one of the directions may not be in use. + */ - reg = readl(regs + S3C_DIEPCTL(ep)); - reg &= ~S3C_DxEPCTL_MPS_MASK; + reg = readl(regs + DIEPCTL(ep)); + reg &= ~DxEPCTL_MPS_MASK; reg |= mpsval; - writel(reg, regs + S3C_DIEPCTL(ep)); + writel(reg, regs + DIEPCTL(ep)); if (ep) { - reg = readl(regs + S3C_DOEPCTL(ep)); - reg &= ~S3C_DxEPCTL_MPS_MASK; + reg = readl(regs + DOEPCTL(ep)); + reg &= ~DxEPCTL_MPS_MASK; reg |= mpsval; - writel(reg, regs + S3C_DOEPCTL(ep)); + writel(reg, regs + DOEPCTL(ep)); } return; @@ -1719,16 +1794,16 @@ static void s3c_hsotg_txfifo_flush(struct s3c_hsotg *hsotg, unsigned int idx) int timeout; int val; - writel(S3C_GRSTCTL_TxFNum(idx) | S3C_GRSTCTL_TxFFlsh, - hsotg->regs + S3C_GRSTCTL); + writel(GRSTCTL_TxFNum(idx) | GRSTCTL_TxFFlsh, + hsotg->regs + GRSTCTL); /* wait until the fifo is flushed */ timeout = 100; while (1) { - val = readl(hsotg->regs + S3C_GRSTCTL); + val = readl(hsotg->regs + GRSTCTL); - if ((val & (S3C_GRSTCTL_TxFFlsh)) == 0) + if ((val & (GRSTCTL_TxFFlsh)) == 0) break; if (--timeout == 0) { @@ -1778,7 +1853,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, struct s3c_hsotg_ep *hs_ep) { struct s3c_hsotg_req *hs_req = hs_ep->req; - u32 epsize = readl(hsotg->regs + S3C_DIEPTSIZ(hs_ep->index)); + u32 epsize = readl(hsotg->regs + DIEPTSIZ(hs_ep->index)); int size_left, size_done; if (!hs_req) { @@ -1786,7 +1861,15 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, return; } - /* Calculate the size of the transfer by checking how much is left + /* Finish ZLP handling for IN EP0 transactions */ + if (hsotg->eps[0].sent_zlp) { + dev_dbg(hsotg->dev, "zlp packet received\n"); + s3c_hsotg_complete_request_lock(hsotg, hs_ep, hs_req, 0); + return; + } + + /* + * Calculate the size of the transfer by checking how much is left * in the endpoint size register and then working it out from * the amount we loaded for the transfer. * @@ -1795,7 +1878,7 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, * aligned). */ - size_left = S3C_DxEPTSIZ_XferSize_GET(epsize); + size_left = DxEPTSIZ_XferSize_GET(epsize); size_done = hs_ep->size_loaded - size_left; size_done += hs_ep->last_load; @@ -1805,9 +1888,28 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, __func__, hs_req->req.actual, size_done); hs_req->req.actual = size_done; + dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n", + hs_req->req.length, hs_req->req.actual, hs_req->req.zero); + + /* + * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0 + * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B + * ,256B ... ), after last MPS sized packet send IN ZLP packet to + * inform the host that no more data is available. + * The state of req.zero member is checked to be sure that the value to + * send is smaller than wValue expected from host. + * Check req.length to NOT send another ZLP when the current one is + * under completion (the one for which this completion has been called). + */ + if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero && + hs_req->req.length == hs_req->req.actual && + !(hs_req->req.length % hs_ep->ep.maxpacket)) { - /* if we did all of the transfer, and there is more data left - * around, then try restarting the rest of the request */ + dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n"); + s3c_hsotg_send_zlp(hsotg, hs_req); + + return; + } if (!size_left && hs_req->req.actual < hs_req->req.length) { dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__); @@ -1823,14 +1925,14 @@ static void s3c_hsotg_complete_in(struct s3c_hsotg *hsotg, * @dir_in: Set if this is an IN endpoint * * Process and clear any interrupt pending for an individual endpoint -*/ + */ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, int dir_in) { struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx]; - u32 epint_reg = dir_in ? S3C_DIEPINT(idx) : S3C_DOEPINT(idx); - u32 epctl_reg = dir_in ? S3C_DIEPCTL(idx) : S3C_DOEPCTL(idx); - u32 epsiz_reg = dir_in ? S3C_DIEPTSIZ(idx) : S3C_DOEPTSIZ(idx); + u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx); + u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx); + u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx); u32 ints; ints = readl(hsotg->regs + epint_reg); @@ -1841,28 +1943,32 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n", __func__, idx, dir_in ? "in" : "out", ints); - if (ints & S3C_DxEPINT_XferCompl) { + if (ints & DxEPINT_XferCompl) { dev_dbg(hsotg->dev, "%s: XferCompl: DxEPCTL=0x%08x, DxEPTSIZ=%08x\n", __func__, readl(hsotg->regs + epctl_reg), readl(hsotg->regs + epsiz_reg)); - /* we get OutDone from the FIFO, so we only need to look - * at completing IN requests here */ + /* + * we get OutDone from the FIFO, so we only need to look + * at completing IN requests here + */ if (dir_in) { s3c_hsotg_complete_in(hsotg, hs_ep); if (idx == 0 && !hs_ep->req) s3c_hsotg_enqueue_setup(hsotg); } else if (using_dma(hsotg)) { - /* We're using DMA, we need to fire an OutDone here - * as we ignore the RXFIFO. */ + /* + * We're using DMA, we need to fire an OutDone here + * as we ignore the RXFIFO. + */ s3c_hsotg_handle_outdone(hsotg, idx, false); } } - if (ints & S3C_DxEPINT_EPDisbld) { + if (ints & DxEPINT_EPDisbld) { dev_dbg(hsotg->dev, "%s: EPDisbld\n", __func__); if (dir_in) { @@ -1870,27 +1976,29 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, s3c_hsotg_txfifo_flush(hsotg, idx); - if ((epctl & S3C_DxEPCTL_Stall) && - (epctl & S3C_DxEPCTL_EPType_Bulk)) { - int dctl = readl(hsotg->regs + S3C_DCTL); + if ((epctl & DxEPCTL_Stall) && + (epctl & DxEPCTL_EPType_Bulk)) { + int dctl = readl(hsotg->regs + DCTL); - dctl |= S3C_DCTL_CGNPInNAK; - writel(dctl, hsotg->regs + S3C_DCTL); + dctl |= DCTL_CGNPInNAK; + writel(dctl, hsotg->regs + DCTL); } } } - if (ints & S3C_DxEPINT_AHBErr) + if (ints & DxEPINT_AHBErr) dev_dbg(hsotg->dev, "%s: AHBErr\n", __func__); - if (ints & S3C_DxEPINT_Setup) { /* Setup or Timeout */ + if (ints & DxEPINT_Setup) { /* Setup or Timeout */ dev_dbg(hsotg->dev, "%s: Setup/Timeout\n", __func__); if (using_dma(hsotg) && idx == 0) { - /* this is the notification we've received a + /* + * this is the notification we've received a * setup packet. In non-DMA mode we'd get this * from the RXFIFO, instead we need to process - * the setup here. */ + * the setup here. + */ if (dir_in) WARN_ON_ONCE(1); @@ -1899,26 +2007,25 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, } } - if (ints & S3C_DxEPINT_Back2BackSetup) + if (ints & DxEPINT_Back2BackSetup) dev_dbg(hsotg->dev, "%s: B2BSetup/INEPNakEff\n", __func__); if (dir_in) { - /* not sure if this is important, but we'll clear it anyway - */ - if (ints & S3C_DIEPMSK_INTknTXFEmpMsk) { + /* not sure if this is important, but we'll clear it anyway */ + if (ints & DIEPMSK_INTknTXFEmpMsk) { dev_dbg(hsotg->dev, "%s: ep%d: INTknTXFEmpMsk\n", __func__, idx); } /* this probably means something bad is happening */ - if (ints & S3C_DIEPMSK_INTknEPMisMsk) { + if (ints & DIEPMSK_INTknEPMisMsk) { dev_warn(hsotg->dev, "%s: ep%d: INTknEP\n", __func__, idx); } /* FIFO has space or is empty (see GAHBCFG) */ if (hsotg->dedicated_fifos && - ints & S3C_DIEPMSK_TxFIFOEmpty) { + ints & DIEPMSK_TxFIFOEmpty) { dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n", __func__, idx); if (!using_dma(hsotg)) @@ -1933,40 +2040,45 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx, * * Handle updating the device settings after the enumeration phase has * been completed. -*/ + */ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) { - u32 dsts = readl(hsotg->regs + S3C_DSTS); + u32 dsts = readl(hsotg->regs + DSTS); int ep0_mps = 0, ep_mps; - /* This should signal the finish of the enumeration phase + /* + * This should signal the finish of the enumeration phase * of the USB handshaking, so we should now know what rate - * we connected at. */ + * we connected at. + */ dev_dbg(hsotg->dev, "EnumDone (DSTS=0x%08x)\n", dsts); - /* note, since we're limited by the size of transfer on EP0, and + /* + * note, since we're limited by the size of transfer on EP0, and * it seems IN transfers must be a even number of packets we do - * not advertise a 64byte MPS on EP0. */ + * not advertise a 64byte MPS on EP0. + */ /* catch both EnumSpd_FS and EnumSpd_FS48 */ - switch (dsts & S3C_DSTS_EnumSpd_MASK) { - case S3C_DSTS_EnumSpd_FS: - case S3C_DSTS_EnumSpd_FS48: + switch (dsts & DSTS_EnumSpd_MASK) { + case DSTS_EnumSpd_FS: + case DSTS_EnumSpd_FS48: hsotg->gadget.speed = USB_SPEED_FULL; ep0_mps = EP0_MPS_LIMIT; ep_mps = 64; break; - case S3C_DSTS_EnumSpd_HS: + case DSTS_EnumSpd_HS: hsotg->gadget.speed = USB_SPEED_HIGH; ep0_mps = EP0_MPS_LIMIT; ep_mps = 512; break; - case S3C_DSTS_EnumSpd_LS: + case DSTS_EnumSpd_LS: hsotg->gadget.speed = USB_SPEED_LOW; - /* note, we don't actually support LS in this driver at the + /* + * note, we don't actually support LS in this driver at the * moment, and the documentation seems to imply that it isn't * supported by the PHYs on some of the devices. */ @@ -1975,13 +2087,15 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) dev_info(hsotg->dev, "new device is %s\n", usb_speed_string(hsotg->gadget.speed)); - /* we should now know the maximum packet size for an - * endpoint, so set the endpoints to a default value. */ + /* + * we should now know the maximum packet size for an + * endpoint, so set the endpoints to a default value. + */ if (ep0_mps) { int i; s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps); - for (i = 1; i < S3C_HSOTG_EPS; i++) + for (i = 1; i < hsotg->num_of_eps; i++) s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps); } @@ -1990,8 +2104,8 @@ static void s3c_hsotg_irq_enumdone(struct s3c_hsotg *hsotg) s3c_hsotg_enqueue_setup(hsotg); dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - readl(hsotg->regs + S3C_DIEPCTL0), - readl(hsotg->regs + S3C_DOEPCTL0)); + readl(hsotg->regs + DIEPCTL0), + readl(hsotg->regs + DOEPCTL0)); } /** @@ -2014,8 +2128,10 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, spin_lock_irqsave(&ep->lock, flags); list_for_each_entry_safe(req, treq, &ep->queue, queue) { - /* currently, we can't do much about an already - * running request on an in endpoint */ + /* + * currently, we can't do much about an already + * running request on an in endpoint + */ if (ep->req == req && ep->dir_in && !force) continue; @@ -2033,18 +2149,18 @@ static void kill_all_requests(struct s3c_hsotg *hsotg, (_hs)->driver->_entry(&(_hs)->gadget); /** - * s3c_hsotg_disconnect_irq - disconnect irq service + * s3c_hsotg_disconnect - disconnect service * @hsotg: The device state. * - * A disconnect IRQ has been received, meaning that the host has - * lost contact with the bus. Remove all current transactions - * and signal the gadget driver that this has happened. -*/ -static void s3c_hsotg_disconnect_irq(struct s3c_hsotg *hsotg) + * The device has been disconnected. Remove all current + * transactions and signal the gadget driver that this + * has happened. + */ +static void s3c_hsotg_disconnect(struct s3c_hsotg *hsotg) { unsigned ep; - for (ep = 0; ep < S3C_HSOTG_EPS; ep++) + for (ep = 0; ep < hsotg->num_of_eps; ep++) kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true); call_gadget(hsotg, disconnect); @@ -2062,7 +2178,7 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) /* look through for any more data to transmit */ - for (epno = 0; epno < S3C_HSOTG_EPS; epno++) { + for (epno = 0; epno < hsotg->num_of_eps; epno++) { ep = &hsotg->eps[epno]; if (!ep->dir_in) @@ -2078,12 +2194,187 @@ static void s3c_hsotg_irq_fifoempty(struct s3c_hsotg *hsotg, bool periodic) } } -static struct s3c_hsotg *our_hsotg; - /* IRQ flags which will trigger a retry around the IRQ loop */ -#define IRQ_RETRY_MASK (S3C_GINTSTS_NPTxFEmp | \ - S3C_GINTSTS_PTxFEmp | \ - S3C_GINTSTS_RxFLvl) +#define IRQ_RETRY_MASK (GINTSTS_NPTxFEmp | \ + GINTSTS_PTxFEmp | \ + GINTSTS_RxFLvl) + +/** + * s3c_hsotg_corereset - issue softreset to the core + * @hsotg: The device state + * + * Issue a soft reset to the core, and await the core finishing it. + */ +static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) +{ + int timeout; + u32 grstctl; + + dev_dbg(hsotg->dev, "resetting core\n"); + + /* issue soft reset */ + writel(GRSTCTL_CSftRst, hsotg->regs + GRSTCTL); + + timeout = 1000; + do { + grstctl = readl(hsotg->regs + GRSTCTL); + } while ((grstctl & GRSTCTL_CSftRst) && timeout-- > 0); + + if (grstctl & GRSTCTL_CSftRst) { + dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); + return -EINVAL; + } + + timeout = 1000; + + while (1) { + u32 grstctl = readl(hsotg->regs + GRSTCTL); + + if (timeout-- < 0) { + dev_info(hsotg->dev, + "%s: reset failed, GRSTCTL=%08x\n", + __func__, grstctl); + return -ETIMEDOUT; + } + + if (!(grstctl & GRSTCTL_AHBIdle)) + continue; + + break; /* reset done */ + } + + dev_dbg(hsotg->dev, "reset successful\n"); + return 0; +} + +/** + * s3c_hsotg_core_init - issue softreset to the core + * @hsotg: The device state + * + * Issue a soft reset to the core, and await the core finishing it. + */ +static void s3c_hsotg_core_init(struct s3c_hsotg *hsotg) +{ + s3c_hsotg_corereset(hsotg); + + /* + * we must now enable ep0 ready for host detection and then + * set configuration. + */ + + /* set the PLL on, remove the HNP/SRP and set the PHY */ + writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | + (0x5 << 10), hsotg->regs + GUSBCFG); + + s3c_hsotg_init_fifo(hsotg); + + __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); + + writel(1 << 18 | DCFG_DevSpd_HS, hsotg->regs + DCFG); + + /* Clear any pending OTG interrupts */ + writel(0xffffffff, hsotg->regs + GOTGINT); + + /* Clear any pending interrupts */ + writel(0xffffffff, hsotg->regs + GINTSTS); + + writel(GINTSTS_ErlySusp | GINTSTS_SessReqInt | + GINTSTS_GOUTNakEff | GINTSTS_GINNakEff | + GINTSTS_ConIDStsChng | GINTSTS_USBRst | + GINTSTS_EnumDone | GINTSTS_OTGInt | + GINTSTS_USBSusp | GINTSTS_WkUpInt, + hsotg->regs + GINTMSK); + + if (using_dma(hsotg)) + writel(GAHBCFG_GlblIntrEn | GAHBCFG_DMAEn | + GAHBCFG_HBstLen_Incr4, + hsotg->regs + GAHBCFG); + else + writel(GAHBCFG_GlblIntrEn, hsotg->regs + GAHBCFG); + + /* + * Enabling INTknTXFEmpMsk here seems to be a big mistake, we end + * up being flooded with interrupts if the host is polling the + * endpoint to try and read data. + */ + + writel(((hsotg->dedicated_fifos) ? DIEPMSK_TxFIFOEmpty : 0) | + DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk | + DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | + DIEPMSK_INTknEPMisMsk, + hsotg->regs + DIEPMSK); + + /* + * don't need XferCompl, we get that from RXFIFO in slave mode. In + * DMA mode we may need this. + */ + writel((using_dma(hsotg) ? (DIEPMSK_XferComplMsk | + DIEPMSK_TimeOUTMsk) : 0) | + DOEPMSK_EPDisbldMsk | DOEPMSK_AHBErrMsk | + DOEPMSK_SetupMsk, + hsotg->regs + DOEPMSK); + + writel(0, hsotg->regs + DAINTMSK); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + DIEPCTL0), + readl(hsotg->regs + DOEPCTL0)); + + /* enable in and out endpoint interrupts */ + s3c_hsotg_en_gsint(hsotg, GINTSTS_OEPInt | GINTSTS_IEPInt); + + /* + * Enable the RXFIFO when in slave mode, as this is how we collect + * the data. In DMA mode, we get events from the FIFO but also + * things we cannot process, so do not use it. + */ + if (!using_dma(hsotg)) + s3c_hsotg_en_gsint(hsotg, GINTSTS_RxFLvl); + + /* Enable interrupts for EP0 in and out */ + s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1); + s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); + + __orr32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); + udelay(10); /* see openiboot */ + __bic32(hsotg->regs + DCTL, DCTL_PWROnPrgDone); + + dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL)); + + /* + * DxEPCTL_USBActEp says RO in manual, but seems to be set by + * writing to the EPCTL register.. + */ + + /* set to read 1 8byte packet */ + writel(DxEPTSIZ_MC(1) | DxEPTSIZ_PktCnt(1) | + DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); + + writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | + DxEPCTL_CNAK | DxEPCTL_EPEna | + DxEPCTL_USBActEp, + hsotg->regs + DOEPCTL0); + + /* enable, but don't activate EP0in */ + writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | + DxEPCTL_USBActEp, hsotg->regs + DIEPCTL0); + + s3c_hsotg_enqueue_setup(hsotg); + + dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", + readl(hsotg->regs + DIEPCTL0), + readl(hsotg->regs + DOEPCTL0)); + + /* clear global NAKs */ + writel(DCTL_CGOUTNak | DCTL_CGNPInNAK, + hsotg->regs + DCTL); + + /* must be at-least 3ms to allow bus to see disconnect */ + mdelay(3); + + /* remove the soft-disconnect and let's go */ + __bic32(hsotg->regs + DCTL, DCTL_SftDiscon); +} /** * s3c_hsotg_irq - handle device interrupt @@ -2098,52 +2389,45 @@ static irqreturn_t s3c_hsotg_irq(int irq, void *pw) u32 gintmsk; irq_retry: - gintsts = readl(hsotg->regs + S3C_GINTSTS); - gintmsk = readl(hsotg->regs + S3C_GINTMSK); + gintsts = readl(hsotg->regs + GINTSTS); + gintmsk = readl(hsotg->regs + GINTMSK); dev_dbg(hsotg->dev, "%s: %08x %08x (%08x) retry %d\n", __func__, gintsts, gintsts & gintmsk, gintmsk, retry_count); gintsts &= gintmsk; - if (gintsts & S3C_GINTSTS_OTGInt) { - u32 otgint = readl(hsotg->regs + S3C_GOTGINT); + if (gintsts & GINTSTS_OTGInt) { + u32 otgint = readl(hsotg->regs + GOTGINT); dev_info(hsotg->dev, "OTGInt: %08x\n", otgint); - writel(otgint, hsotg->regs + S3C_GOTGINT); - } - - if (gintsts & S3C_GINTSTS_DisconnInt) { - dev_dbg(hsotg->dev, "%s: DisconnInt\n", __func__); - writel(S3C_GINTSTS_DisconnInt, hsotg->regs + S3C_GINTSTS); - - s3c_hsotg_disconnect_irq(hsotg); + writel(otgint, hsotg->regs + GOTGINT); } - if (gintsts & S3C_GINTSTS_SessReqInt) { + if (gintsts & GINTSTS_SessReqInt) { dev_dbg(hsotg->dev, "%s: SessReqInt\n", __func__); - writel(S3C_GINTSTS_SessReqInt, hsotg->regs + S3C_GINTSTS); + writel(GINTSTS_SessReqInt, hsotg->regs + GINTSTS); } - if (gintsts & S3C_GINTSTS_EnumDone) { - writel(S3C_GINTSTS_EnumDone, hsotg->regs + S3C_GINTSTS); + if (gintsts & GINTSTS_EnumDone) { + writel(GINTSTS_EnumDone, hsotg->regs + GINTSTS); s3c_hsotg_irq_enumdone(hsotg); } - if (gintsts & S3C_GINTSTS_ConIDStsChng) { + if (gintsts & GINTSTS_ConIDStsChng) { dev_dbg(hsotg->dev, "ConIDStsChg (DSTS=0x%08x, GOTCTL=%08x)\n", - readl(hsotg->regs + S3C_DSTS), - readl(hsotg->regs + S3C_GOTGCTL)); + readl(hsotg->regs + DSTS), + readl(hsotg->regs + GOTGCTL)); - writel(S3C_GINTSTS_ConIDStsChng, hsotg->regs + S3C_GINTSTS); + writel(GINTSTS_ConIDStsChng, hsotg->regs + GINTSTS); } - if (gintsts & (S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt)) { - u32 daint = readl(hsotg->regs + S3C_DAINT); - u32 daint_out = daint >> S3C_DAINT_OutEP_SHIFT; - u32 daint_in = daint & ~(daint_out << S3C_DAINT_OutEP_SHIFT); + if (gintsts & (GINTSTS_OEPInt | GINTSTS_IEPInt)) { + u32 daint = readl(hsotg->regs + DAINT); + u32 daint_out = daint >> DAINT_OutEP_SHIFT; + u32 daint_in = daint & ~(daint_out << DAINT_OutEP_SHIFT); int ep; dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint); @@ -2159,102 +2443,116 @@ irq_retry: } } - if (gintsts & S3C_GINTSTS_USBRst) { + if (gintsts & GINTSTS_USBRst) { + + u32 usb_status = readl(hsotg->regs + GOTGCTL); + dev_info(hsotg->dev, "%s: USBRst\n", __func__); dev_dbg(hsotg->dev, "GNPTXSTS=%08x\n", - readl(hsotg->regs + S3C_GNPTXSTS)); + readl(hsotg->regs + GNPTXSTS)); - writel(S3C_GINTSTS_USBRst, hsotg->regs + S3C_GINTSTS); + writel(GINTSTS_USBRst, hsotg->regs + GINTSTS); - kill_all_requests(hsotg, &hsotg->eps[0], -ECONNRESET, true); + if (usb_status & GOTGCTL_BSESVLD) { + if (time_after(jiffies, hsotg->last_rst + + msecs_to_jiffies(200))) { - /* it seems after a reset we can end up with a situation - * where the TXFIFO still has data in it... the docs - * suggest resetting all the fifos, so use the init_fifo - * code to relayout and flush the fifos. - */ + kill_all_requests(hsotg, &hsotg->eps[0], + -ECONNRESET, true); - s3c_hsotg_init_fifo(hsotg); - - s3c_hsotg_enqueue_setup(hsotg); + s3c_hsotg_core_init(hsotg); + hsotg->last_rst = jiffies; + } + } } /* check both FIFOs */ - if (gintsts & S3C_GINTSTS_NPTxFEmp) { + if (gintsts & GINTSTS_NPTxFEmp) { dev_dbg(hsotg->dev, "NPTxFEmp\n"); - /* Disable the interrupt to stop it happening again + /* + * Disable the interrupt to stop it happening again * unless one of these endpoint routines decides that - * it needs re-enabling */ + * it needs re-enabling + */ - s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_NPTxFEmp); + s3c_hsotg_disable_gsint(hsotg, GINTSTS_NPTxFEmp); s3c_hsotg_irq_fifoempty(hsotg, false); } - if (gintsts & S3C_GINTSTS_PTxFEmp) { + if (gintsts & GINTSTS_PTxFEmp) { dev_dbg(hsotg->dev, "PTxFEmp\n"); - /* See note in S3C_GINTSTS_NPTxFEmp */ + /* See note in GINTSTS_NPTxFEmp */ - s3c_hsotg_disable_gsint(hsotg, S3C_GINTSTS_PTxFEmp); + s3c_hsotg_disable_gsint(hsotg, GINTSTS_PTxFEmp); s3c_hsotg_irq_fifoempty(hsotg, true); } - if (gintsts & S3C_GINTSTS_RxFLvl) { - /* note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, + if (gintsts & GINTSTS_RxFLvl) { + /* + * note, since GINTSTS_RxFLvl doubles as FIFO-not-empty, * we need to retry s3c_hsotg_handle_rx if this is still - * set. */ + * set. + */ s3c_hsotg_handle_rx(hsotg); } - if (gintsts & S3C_GINTSTS_ModeMis) { + if (gintsts & GINTSTS_ModeMis) { dev_warn(hsotg->dev, "warning, mode mismatch triggered\n"); - writel(S3C_GINTSTS_ModeMis, hsotg->regs + S3C_GINTSTS); + writel(GINTSTS_ModeMis, hsotg->regs + GINTSTS); } - if (gintsts & S3C_GINTSTS_USBSusp) { - dev_info(hsotg->dev, "S3C_GINTSTS_USBSusp\n"); - writel(S3C_GINTSTS_USBSusp, hsotg->regs + S3C_GINTSTS); + if (gintsts & GINTSTS_USBSusp) { + dev_info(hsotg->dev, "GINTSTS_USBSusp\n"); + writel(GINTSTS_USBSusp, hsotg->regs + GINTSTS); call_gadget(hsotg, suspend); + s3c_hsotg_disconnect(hsotg); } - if (gintsts & S3C_GINTSTS_WkUpInt) { - dev_info(hsotg->dev, "S3C_GINTSTS_WkUpIn\n"); - writel(S3C_GINTSTS_WkUpInt, hsotg->regs + S3C_GINTSTS); + if (gintsts & GINTSTS_WkUpInt) { + dev_info(hsotg->dev, "GINTSTS_WkUpIn\n"); + writel(GINTSTS_WkUpInt, hsotg->regs + GINTSTS); call_gadget(hsotg, resume); } - if (gintsts & S3C_GINTSTS_ErlySusp) { - dev_dbg(hsotg->dev, "S3C_GINTSTS_ErlySusp\n"); - writel(S3C_GINTSTS_ErlySusp, hsotg->regs + S3C_GINTSTS); + if (gintsts & GINTSTS_ErlySusp) { + dev_dbg(hsotg->dev, "GINTSTS_ErlySusp\n"); + writel(GINTSTS_ErlySusp, hsotg->regs + GINTSTS); + + s3c_hsotg_disconnect(hsotg); } - /* these next two seem to crop-up occasionally causing the core + /* + * these next two seem to crop-up occasionally causing the core * to shutdown the USB transfer, so try clearing them and logging - * the occurrence. */ + * the occurrence. + */ - if (gintsts & S3C_GINTSTS_GOUTNakEff) { + if (gintsts & GINTSTS_GOUTNakEff) { dev_info(hsotg->dev, "GOUTNakEff triggered\n"); - writel(S3C_DCTL_CGOUTNak, hsotg->regs + S3C_DCTL); + writel(DCTL_CGOUTNak, hsotg->regs + DCTL); s3c_hsotg_dump(hsotg); } - if (gintsts & S3C_GINTSTS_GINNakEff) { + if (gintsts & GINTSTS_GINNakEff) { dev_info(hsotg->dev, "GINNakEff triggered\n"); - writel(S3C_DCTL_CGNPInNAK, hsotg->regs + S3C_DCTL); + writel(DCTL_CGNPInNAK, hsotg->regs + DCTL); s3c_hsotg_dump(hsotg); } - /* if we've had fifo events, we should try and go around the - * loop again to see if there's any point in returning yet. */ + /* + * if we've had fifo events, we should try and go around the + * loop again to see if there's any point in returning yet. + */ if (gintsts & IRQ_RETRY_MASK && --retry_count > 0) goto irq_retry; @@ -2268,7 +2566,7 @@ irq_retry: * @desc: The USB endpoint descriptor to configure with. * * This is called from the USB gadget code's usb_ep_enable(). -*/ + */ static int s3c_hsotg_ep_enable(struct usb_ep *ep, const struct usb_endpoint_descriptor *desc) { @@ -2300,7 +2598,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, /* note, we handle this here instead of s3c_hsotg_set_ep_maxpacket */ - epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); epctrl = readl(hsotg->regs + epctrl_reg); dev_dbg(hsotg->dev, "%s: read DxEPCTL=0x%08x from 0x%08x\n", @@ -2308,20 +2606,23 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, spin_lock_irqsave(&hs_ep->lock, flags); - epctrl &= ~(S3C_DxEPCTL_EPType_MASK | S3C_DxEPCTL_MPS_MASK); - epctrl |= S3C_DxEPCTL_MPS(mps); + epctrl &= ~(DxEPCTL_EPType_MASK | DxEPCTL_MPS_MASK); + epctrl |= DxEPCTL_MPS(mps); - /* mark the endpoint as active, otherwise the core may ignore - * transactions entirely for this endpoint */ - epctrl |= S3C_DxEPCTL_USBActEp; + /* + * mark the endpoint as active, otherwise the core may ignore + * transactions entirely for this endpoint + */ + epctrl |= DxEPCTL_USBActEp; - /* set the NAK status on the endpoint, otherwise we might try and + /* + * set the NAK status on the endpoint, otherwise we might try and * do something with data that we've yet got a request to process * since the RXFIFO will take data for an endpoint even if the * size register hasn't been set. */ - epctrl |= S3C_DxEPCTL_SNAK; + epctrl |= DxEPCTL_SNAK; /* update the endpoint state */ hs_ep->ep.maxpacket = mps; @@ -2336,37 +2637,40 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep, goto out; case USB_ENDPOINT_XFER_BULK: - epctrl |= S3C_DxEPCTL_EPType_Bulk; + epctrl |= DxEPCTL_EPType_Bulk; break; case USB_ENDPOINT_XFER_INT: if (dir_in) { - /* Allocate our TxFNum by simply using the index + /* + * Allocate our TxFNum by simply using the index * of the endpoint for the moment. We could do * something better if the host indicates how - * many FIFOs we are expecting to use. */ + * many FIFOs we are expecting to use. + */ hs_ep->periodic = 1; - epctrl |= S3C_DxEPCTL_TxFNum(index); + epctrl |= DxEPCTL_TxFNum(index); } - epctrl |= S3C_DxEPCTL_EPType_Intterupt; + epctrl |= DxEPCTL_EPType_Intterupt; break; case USB_ENDPOINT_XFER_CONTROL: - epctrl |= S3C_DxEPCTL_EPType_Control; + epctrl |= DxEPCTL_EPType_Control; break; } - /* if the hardware has dedicated fifos, we must give each IN EP + /* + * if the hardware has dedicated fifos, we must give each IN EP * a unique tx-fifo even if it is non-periodic. */ if (dir_in && hsotg->dedicated_fifos) - epctrl |= S3C_DxEPCTL_TxFNum(index); + epctrl |= DxEPCTL_TxFNum(index); /* for non control endpoints, set PID to D0 */ if (index) - epctrl |= S3C_DxEPCTL_SetD0PID; + epctrl |= DxEPCTL_SetD0PID; dev_dbg(hsotg->dev, "%s: write DxEPCTL=0x%08x\n", __func__, epctrl); @@ -2383,6 +2687,10 @@ out: return ret; } +/** + * s3c_hsotg_ep_disable - disable given endpoint + * @ep: The endpoint to disable. + */ static int s3c_hsotg_ep_disable(struct usb_ep *ep) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); @@ -2400,7 +2708,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep) return -EINVAL; } - epctrl_reg = dir_in ? S3C_DIEPCTL(index) : S3C_DOEPCTL(index); + epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index); /* terminate all requests with shutdown */ kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, false); @@ -2408,9 +2716,9 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep) spin_lock_irqsave(&hs_ep->lock, flags); ctrl = readl(hsotg->regs + epctrl_reg); - ctrl &= ~S3C_DxEPCTL_EPEna; - ctrl &= ~S3C_DxEPCTL_USBActEp; - ctrl |= S3C_DxEPCTL_SNAK; + ctrl &= ~DxEPCTL_EPEna; + ctrl &= ~DxEPCTL_USBActEp; + ctrl |= DxEPCTL_SNAK; dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl); writel(ctrl, hsotg->regs + epctrl_reg); @@ -2426,7 +2734,7 @@ static int s3c_hsotg_ep_disable(struct usb_ep *ep) * on_list - check request is on the given endpoint * @ep: The endpoint to check. * @test: The request to test if it is on the endpoint. -*/ + */ static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test) { struct s3c_hsotg_req *req, *treq; @@ -2439,6 +2747,11 @@ static bool on_list(struct s3c_hsotg_ep *ep, struct s3c_hsotg_req *test) return false; } +/** + * s3c_hsotg_ep_dequeue - dequeue given endpoint + * @ep: The endpoint to dequeue. + * @req: The request to be removed from a queue. + */ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) { struct s3c_hsotg_req *hs_req = our_req(req); @@ -2461,6 +2774,11 @@ static int s3c_hsotg_ep_dequeue(struct usb_ep *ep, struct usb_request *req) return 0; } +/** + * s3c_hsotg_ep_sethalt - set halt on a given endpoint + * @ep: The endpoint to set halt. + * @value: Set or unset the halt. + */ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) { struct s3c_hsotg_ep *hs_ep = our_ep(ep); @@ -2477,34 +2795,34 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value) /* write both IN and OUT control registers */ - epreg = S3C_DIEPCTL(index); + epreg = DIEPCTL(index); epctl = readl(hs->regs + epreg); if (value) { - epctl |= S3C_DxEPCTL_Stall + S3C_DxEPCTL_SNAK; - if (epctl & S3C_DxEPCTL_EPEna) - epctl |= S3C_DxEPCTL_EPDis; + epctl |= DxEPCTL_Stall + DxEPCTL_SNAK; + if (epctl & DxEPCTL_EPEna) + epctl |= DxEPCTL_EPDis; } else { - epctl &= ~S3C_DxEPCTL_Stall; - xfertype = epctl & S3C_DxEPCTL_EPType_MASK; - if (xfertype == S3C_DxEPCTL_EPType_Bulk || - xfertype == S3C_DxEPCTL_EPType_Intterupt) - epctl |= S3C_DxEPCTL_SetD0PID; + epctl &= ~DxEPCTL_Stall; + xfertype = epctl & DxEPCTL_EPType_MASK; + if (xfertype == DxEPCTL_EPType_Bulk || + xfertype == DxEPCTL_EPType_Intterupt) + epctl |= DxEPCTL_SetD0PID; } writel(epctl, hs->regs + epreg); - epreg = S3C_DOEPCTL(index); + epreg = DOEPCTL(index); epctl = readl(hs->regs + epreg); if (value) - epctl |= S3C_DxEPCTL_Stall; + epctl |= DxEPCTL_Stall; else { - epctl &= ~S3C_DxEPCTL_Stall; - xfertype = epctl & S3C_DxEPCTL_EPType_MASK; - if (xfertype == S3C_DxEPCTL_EPType_Bulk || - xfertype == S3C_DxEPCTL_EPType_Intterupt) - epctl |= S3C_DxEPCTL_SetD0PID; + epctl &= ~DxEPCTL_Stall; + xfertype = epctl & DxEPCTL_EPType_MASK; + if (xfertype == DxEPCTL_EPType_Bulk || + xfertype == DxEPCTL_EPType_Intterupt) + epctl |= DxEPCTL_SetD0PID; } writel(epctl, hs->regs + epreg); @@ -2526,57 +2844,91 @@ static struct usb_ep_ops s3c_hsotg_ep_ops = { }; /** - * s3c_hsotg_corereset - issue softreset to the core - * @hsotg: The device state + * s3c_hsotg_phy_enable - enable platform phy dev + * @hsotg: The driver state * - * Issue a soft reset to the core, and await the core finishing it. -*/ -static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg) + * A wrapper for platform code responsible for controlling + * low-level USB code + */ +static void s3c_hsotg_phy_enable(struct s3c_hsotg *hsotg) { - int timeout; - u32 grstctl; + struct platform_device *pdev = to_platform_device(hsotg->dev); - dev_dbg(hsotg->dev, "resetting core\n"); + dev_dbg(hsotg->dev, "pdev 0x%p\n", pdev); + if (hsotg->plat->phy_init) + hsotg->plat->phy_init(pdev, hsotg->plat->phy_type); +} - /* issue soft reset */ - writel(S3C_GRSTCTL_CSftRst, hsotg->regs + S3C_GRSTCTL); +/** + * s3c_hsotg_phy_disable - disable platform phy dev + * @hsotg: The driver state + * + * A wrapper for platform code responsible for controlling + * low-level USB code + */ +static void s3c_hsotg_phy_disable(struct s3c_hsotg *hsotg) +{ + struct platform_device *pdev = to_platform_device(hsotg->dev); - timeout = 1000; - do { - grstctl = readl(hsotg->regs + S3C_GRSTCTL); - } while ((grstctl & S3C_GRSTCTL_CSftRst) && timeout-- > 0); + if (hsotg->plat->phy_exit) + hsotg->plat->phy_exit(pdev, hsotg->plat->phy_type); +} - if (grstctl & S3C_GRSTCTL_CSftRst) { - dev_err(hsotg->dev, "Failed to get CSftRst asserted\n"); - return -EINVAL; - } +/** + * s3c_hsotg_init - initalize the usb core + * @hsotg: The driver state + */ +static void s3c_hsotg_init(struct s3c_hsotg *hsotg) +{ + /* unmask subset of endpoint interrupts */ - timeout = 1000; + writel(DIEPMSK_TimeOUTMsk | DIEPMSK_AHBErrMsk | + DIEPMSK_EPDisbldMsk | DIEPMSK_XferComplMsk, + hsotg->regs + DIEPMSK); - while (1) { - u32 grstctl = readl(hsotg->regs + S3C_GRSTCTL); + writel(DOEPMSK_SetupMsk | DOEPMSK_AHBErrMsk | + DOEPMSK_EPDisbldMsk | DOEPMSK_XferComplMsk, + hsotg->regs + DOEPMSK); - if (timeout-- < 0) { - dev_info(hsotg->dev, - "%s: reset failed, GRSTCTL=%08x\n", - __func__, grstctl); - return -ETIMEDOUT; - } + writel(0, hsotg->regs + DAINTMSK); - if (!(grstctl & S3C_GRSTCTL_AHBIdle)) - continue; + /* Be in disconnected state until gadget is registered */ + __orr32(hsotg->regs + DCTL, DCTL_SftDiscon); - break; /* reset done */ + if (0) { + /* post global nak until we're ready */ + writel(DCTL_SGNPInNAK | DCTL_SGOUTNak, + hsotg->regs + DCTL); } - dev_dbg(hsotg->dev, "reset successful\n"); - return 0; + /* setup fifos */ + + dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", + readl(hsotg->regs + GRXFSIZ), + readl(hsotg->regs + GNPTXFSIZ)); + + s3c_hsotg_init_fifo(hsotg); + + /* set the PLL on, remove the HNP/SRP and set the PHY */ + writel(GUSBCFG_PHYIf16 | GUSBCFG_TOutCal(7) | (0x5 << 10), + hsotg->regs + GUSBCFG); + + writel(using_dma(hsotg) ? GAHBCFG_DMAEn : 0x0, + hsotg->regs + GAHBCFG); } -static int s3c_hsotg_start(struct usb_gadget_driver *driver, - int (*bind)(struct usb_gadget *)) +/** + * s3c_hsotg_udc_start - prepare the udc for work + * @gadget: The usb gadget state + * @driver: The usb gadget driver + * + * Perform initialization to prepare udc device and driver + * to work. + */ +static int s3c_hsotg_udc_start(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct s3c_hsotg *hsotg = our_hsotg; + struct s3c_hsotg *hsotg = to_hsotg(gadget); int ret; if (!hsotg) { @@ -2592,7 +2944,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, if (driver->max_speed < USB_SPEED_FULL) dev_err(hsotg->dev, "%s: bad speed\n", __func__); - if (!bind || !driver->setup) { + if (!driver->setup) { dev_err(hsotg->dev, "%s: missing entry points\n", __func__); return -EINVAL; } @@ -2605,135 +2957,17 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, hsotg->gadget.dev.dma_mask = hsotg->dev->dma_mask; hsotg->gadget.speed = USB_SPEED_UNKNOWN; - ret = device_add(&hsotg->gadget.dev); + ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); if (ret) { - dev_err(hsotg->dev, "failed to register gadget device\n"); + dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); goto err; } - ret = bind(&hsotg->gadget); - if (ret) { - dev_err(hsotg->dev, "failed bind %s\n", driver->driver.name); - - hsotg->gadget.dev.driver = NULL; - hsotg->driver = NULL; - goto err; - } - - /* we must now enable ep0 ready for host detection and then - * set configuration. */ - - s3c_hsotg_corereset(hsotg); - - /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | - (0x5 << 10), hsotg->regs + S3C_GUSBCFG); - - /* looks like soft-reset changes state of FIFOs */ - s3c_hsotg_init_fifo(hsotg); - - __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); - - writel(1 << 18 | S3C_DCFG_DevSpd_HS, hsotg->regs + S3C_DCFG); - - /* Clear any pending OTG interrupts */ - writel(0xffffffff, hsotg->regs + S3C_GOTGINT); - - /* Clear any pending interrupts */ - writel(0xffffffff, hsotg->regs + S3C_GINTSTS); - - writel(S3C_GINTSTS_DisconnInt | S3C_GINTSTS_SessReqInt | - S3C_GINTSTS_ConIDStsChng | S3C_GINTSTS_USBRst | - S3C_GINTSTS_EnumDone | S3C_GINTSTS_OTGInt | - S3C_GINTSTS_USBSusp | S3C_GINTSTS_WkUpInt | - S3C_GINTSTS_GOUTNakEff | S3C_GINTSTS_GINNakEff | - S3C_GINTSTS_ErlySusp, - hsotg->regs + S3C_GINTMSK); - - if (using_dma(hsotg)) - writel(S3C_GAHBCFG_GlblIntrEn | S3C_GAHBCFG_DMAEn | - S3C_GAHBCFG_HBstLen_Incr4, - hsotg->regs + S3C_GAHBCFG); - else - writel(S3C_GAHBCFG_GlblIntrEn, hsotg->regs + S3C_GAHBCFG); - - /* Enabling INTknTXFEmpMsk here seems to be a big mistake, we end - * up being flooded with interrupts if the host is polling the - * endpoint to try and read data. */ - - writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | - S3C_DIEPMSK_INTknEPMisMsk | - S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk | - ((hsotg->dedicated_fifos) ? S3C_DIEPMSK_TxFIFOEmpty : 0), - hsotg->regs + S3C_DIEPMSK); - - /* don't need XferCompl, we get that from RXFIFO in slave mode. In - * DMA mode we may need this. */ - writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | - S3C_DOEPMSK_EPDisbldMsk | - (using_dma(hsotg) ? (S3C_DIEPMSK_XferComplMsk | - S3C_DIEPMSK_TimeOUTMsk) : 0), - hsotg->regs + S3C_DOEPMSK); - - writel(0, hsotg->regs + S3C_DAINTMSK); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - readl(hsotg->regs + S3C_DIEPCTL0), - readl(hsotg->regs + S3C_DOEPCTL0)); - - /* enable in and out endpoint interrupts */ - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_OEPInt | S3C_GINTSTS_IEPInt); - - /* Enable the RXFIFO when in slave mode, as this is how we collect - * the data. In DMA mode, we get events from the FIFO but also - * things we cannot process, so do not use it. */ - if (!using_dma(hsotg)) - s3c_hsotg_en_gsint(hsotg, S3C_GINTSTS_RxFLvl); - - /* Enable interrupts for EP0 in and out */ - s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1); - s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1); - - __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone); - udelay(10); /* see openiboot */ - __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_PWROnPrgDone); - - dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + S3C_DCTL)); - - /* S3C_DxEPCTL_USBActEp says RO in manual, but seems to be set by - writing to the EPCTL register.. */ - - /* set to read 1 8byte packet */ - writel(S3C_DxEPTSIZ_MC(1) | S3C_DxEPTSIZ_PktCnt(1) | - S3C_DxEPTSIZ_XferSize(8), hsotg->regs + DOEPTSIZ0); - - writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - S3C_DxEPCTL_CNAK | S3C_DxEPCTL_EPEna | - S3C_DxEPCTL_USBActEp, - hsotg->regs + S3C_DOEPCTL0); - - /* enable, but don't activate EP0in */ - writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) | - S3C_DxEPCTL_USBActEp, hsotg->regs + S3C_DIEPCTL0); - - s3c_hsotg_enqueue_setup(hsotg); - - dev_dbg(hsotg->dev, "EP0: DIEPCTL0=0x%08x, DOEPCTL0=0x%08x\n", - readl(hsotg->regs + S3C_DIEPCTL0), - readl(hsotg->regs + S3C_DOEPCTL0)); - - /* clear global NAKs */ - writel(S3C_DCTL_CGOUTNak | S3C_DCTL_CGNPInNAK, - hsotg->regs + S3C_DCTL); - - /* must be at-least 3ms to allow bus to see disconnect */ - msleep(3); - - /* remove the soft-disconnect and let's go */ - __bic32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); - - /* report to the user, and return */ + s3c_hsotg_phy_enable(hsotg); + s3c_hsotg_core_init(hsotg); + hsotg->last_rst = jiffies; dev_info(hsotg->dev, "bound driver %s\n", driver->driver.name); return 0; @@ -2743,9 +2977,17 @@ err: return ret; } -static int s3c_hsotg_stop(struct usb_gadget_driver *driver) +/** + * s3c_hsotg_udc_stop - stop the udc + * @gadget: The usb gadget state + * @driver: The usb gadget driver + * + * Stop udc hw block and stay tunned for future transmissions + */ +static int s3c_hsotg_udc_stop(struct usb_gadget *gadget, + struct usb_gadget_driver *driver) { - struct s3c_hsotg *hsotg = our_hsotg; + struct s3c_hsotg *hsotg = to_hsotg(gadget); int ep; if (!hsotg) @@ -2755,16 +2997,15 @@ static int s3c_hsotg_stop(struct usb_gadget_driver *driver) return -EINVAL; /* all endpoints should be shutdown */ - for (ep = 0; ep < S3C_HSOTG_EPS; ep++) + for (ep = 0; ep < hsotg->num_of_eps; ep++) s3c_hsotg_ep_disable(&hsotg->eps[ep].ep); - call_gadget(hsotg, disconnect); + s3c_hsotg_phy_disable(hsotg); + regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); - driver->unbind(&hsotg->gadget); hsotg->driver = NULL; hsotg->gadget.speed = USB_SPEED_UNKNOWN; - - device_del(&hsotg->gadget.dev); + hsotg->gadget.dev.driver = NULL; dev_info(hsotg->dev, "unregistered gadget driver '%s'\n", driver->driver.name); @@ -2772,6 +3013,12 @@ static int s3c_hsotg_stop(struct usb_gadget_driver *driver) return 0; } +/** + * s3c_hsotg_gadget_getframe - read the frame number + * @gadget: The usb gadget state + * + * Read the {micro} frame number + */ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) { return s3c_hsotg_read_frameno(to_hsotg(gadget)); @@ -2779,8 +3026,8 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget) static struct usb_gadget_ops s3c_hsotg_gadget_ops = { .get_frame = s3c_hsotg_gadget_getframe, - .start = s3c_hsotg_start, - .stop = s3c_hsotg_stop, + .udc_start = s3c_hsotg_udc_start, + .udc_stop = s3c_hsotg_udc_stop, }; /** @@ -2827,111 +3074,42 @@ static void __devinit s3c_hsotg_initep(struct s3c_hsotg *hsotg, hs_ep->ep.maxpacket = epnum ? 512 : EP0_MPS_LIMIT; hs_ep->ep.ops = &s3c_hsotg_ep_ops; - /* Read the FIFO size for the Periodic TX FIFO, even if we're + /* + * Read the FIFO size for the Periodic TX FIFO, even if we're * an OUT endpoint, we may as well do this if in future the * code is changed to make each endpoint's direction changeable. */ - ptxfifo = readl(hsotg->regs + S3C_DPTXFSIZn(epnum)); - hs_ep->fifo_size = S3C_DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; + ptxfifo = readl(hsotg->regs + DPTXFSIZn(epnum)); + hs_ep->fifo_size = DPTXFSIZn_DPTxFSize_GET(ptxfifo) * 4; - /* if we're using dma, we need to set the next-endpoint pointer + /* + * if we're using dma, we need to set the next-endpoint pointer * to be something valid. */ if (using_dma(hsotg)) { - u32 next = S3C_DxEPCTL_NextEp((epnum + 1) % 15); - writel(next, hsotg->regs + S3C_DIEPCTL(epnum)); - writel(next, hsotg->regs + S3C_DOEPCTL(epnum)); + u32 next = DxEPCTL_NextEp((epnum + 1) % 15); + writel(next, hsotg->regs + DIEPCTL(epnum)); + writel(next, hsotg->regs + DOEPCTL(epnum)); } } /** - * s3c_hsotg_otgreset - reset the OtG phy block - * @hsotg: The host state. + * s3c_hsotg_hw_cfg - read HW configuration registers + * @param: The device state * - * Power up the phy, set the basic configuration and start the PHY. + * Read the USB core HW configuration registers */ -static void s3c_hsotg_otgreset(struct s3c_hsotg *hsotg) -{ - struct clk *xusbxti; - u32 pwr, osc; - - pwr = readl(S3C_PHYPWR); - pwr &= ~0x19; - writel(pwr, S3C_PHYPWR); - mdelay(1); - - osc = hsotg->plat->is_osc ? S3C_PHYCLK_EXT_OSC : 0; - - xusbxti = clk_get(hsotg->dev, "xusbxti"); - if (xusbxti && !IS_ERR(xusbxti)) { - switch (clk_get_rate(xusbxti)) { - case 12*MHZ: - osc |= S3C_PHYCLK_CLKSEL_12M; - break; - case 24*MHZ: - osc |= S3C_PHYCLK_CLKSEL_24M; - break; - default: - case 48*MHZ: - /* default reference clock */ - break; - } - clk_put(xusbxti); - } - - writel(osc | 0x10, S3C_PHYCLK); - - /* issue a full set of resets to the otg and core */ - - writel(S3C_RSTCON_PHY, S3C_RSTCON); - udelay(20); /* at-least 10uS */ - writel(0, S3C_RSTCON); -} - - -static void s3c_hsotg_init(struct s3c_hsotg *hsotg) +static void s3c_hsotg_hw_cfg(struct s3c_hsotg *hsotg) { - u32 cfg4; - - /* unmask subset of endpoint interrupts */ - - writel(S3C_DIEPMSK_TimeOUTMsk | S3C_DIEPMSK_AHBErrMsk | - S3C_DIEPMSK_EPDisbldMsk | S3C_DIEPMSK_XferComplMsk, - hsotg->regs + S3C_DIEPMSK); - - writel(S3C_DOEPMSK_SetupMsk | S3C_DOEPMSK_AHBErrMsk | - S3C_DOEPMSK_EPDisbldMsk | S3C_DOEPMSK_XferComplMsk, - hsotg->regs + S3C_DOEPMSK); - - writel(0, hsotg->regs + S3C_DAINTMSK); - - /* Be in disconnected state until gadget is registered */ - __orr32(hsotg->regs + S3C_DCTL, S3C_DCTL_SftDiscon); - - if (0) { - /* post global nak until we're ready */ - writel(S3C_DCTL_SGNPInNAK | S3C_DCTL_SGOUTNak, - hsotg->regs + S3C_DCTL); - } - - /* setup fifos */ - - dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", - readl(hsotg->regs + S3C_GRXFSIZ), - readl(hsotg->regs + S3C_GNPTXFSIZ)); - - s3c_hsotg_init_fifo(hsotg); - - /* set the PLL on, remove the HNP/SRP and set the PHY */ - writel(S3C_GUSBCFG_PHYIf16 | S3C_GUSBCFG_TOutCal(7) | (0x5 << 10), - hsotg->regs + S3C_GUSBCFG); + u32 cfg2, cfg4; + /* check hardware configuration */ - writel(using_dma(hsotg) ? S3C_GAHBCFG_DMAEn : 0x0, - hsotg->regs + S3C_GAHBCFG); + cfg2 = readl(hsotg->regs + 0x48); + hsotg->num_of_eps = (cfg2 >> 10) & 0xF; - /* check hardware configuration */ + dev_info(hsotg->dev, "EPs:%d\n", hsotg->num_of_eps); cfg4 = readl(hsotg->regs + 0x50); hsotg->dedicated_fifos = (cfg4 >> 25) & 1; @@ -2940,6 +3118,10 @@ static void s3c_hsotg_init(struct s3c_hsotg *hsotg) hsotg->dedicated_fifos ? "dedicated" : "shared"); } +/** + * s3c_hsotg_dump - dump state of the udc + * @param: The device state + */ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) { #ifdef DEBUG @@ -2949,46 +3131,45 @@ static void s3c_hsotg_dump(struct s3c_hsotg *hsotg) int idx; dev_info(dev, "DCFG=0x%08x, DCTL=0x%08x, DIEPMSK=%08x\n", - readl(regs + S3C_DCFG), readl(regs + S3C_DCTL), - readl(regs + S3C_DIEPMSK)); + readl(regs + DCFG), readl(regs + DCTL), + readl(regs + DIEPMSK)); dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n", - readl(regs + S3C_GAHBCFG), readl(regs + 0x44)); + readl(regs + GAHBCFG), readl(regs + 0x44)); dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n", - readl(regs + S3C_GRXFSIZ), readl(regs + S3C_GNPTXFSIZ)); + readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ)); /* show periodic fifo settings */ for (idx = 1; idx <= 15; idx++) { - val = readl(regs + S3C_DPTXFSIZn(idx)); + val = readl(regs + DPTXFSIZn(idx)); dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx, - val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT, - val & S3C_DPTXFSIZn_DPTxFStAddr_MASK); + val >> DPTXFSIZn_DPTxFSize_SHIFT, + val & DPTXFSIZn_DPTxFStAddr_MASK); } for (idx = 0; idx < 15; idx++) { dev_info(dev, "ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx, - readl(regs + S3C_DIEPCTL(idx)), - readl(regs + S3C_DIEPTSIZ(idx)), - readl(regs + S3C_DIEPDMA(idx))); + readl(regs + DIEPCTL(idx)), + readl(regs + DIEPTSIZ(idx)), + readl(regs + DIEPDMA(idx))); - val = readl(regs + S3C_DOEPCTL(idx)); + val = readl(regs + DOEPCTL(idx)); dev_info(dev, "ep%d-out: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", - idx, readl(regs + S3C_DOEPCTL(idx)), - readl(regs + S3C_DOEPTSIZ(idx)), - readl(regs + S3C_DOEPDMA(idx))); + idx, readl(regs + DOEPCTL(idx)), + readl(regs + DOEPTSIZ(idx)), + readl(regs + DOEPDMA(idx))); } dev_info(dev, "DVBUSDIS=0x%08x, DVBUSPULSE=%08x\n", - readl(regs + S3C_DVBUSDIS), readl(regs + S3C_DVBUSPULSE)); + readl(regs + DVBUSDIS), readl(regs + DVBUSPULSE)); #endif } - /** * state_show - debugfs: show overall driver and device state. * @seq: The seq file to write to. @@ -3005,38 +3186,38 @@ static int state_show(struct seq_file *seq, void *v) int idx; seq_printf(seq, "DCFG=0x%08x, DCTL=0x%08x, DSTS=0x%08x\n", - readl(regs + S3C_DCFG), - readl(regs + S3C_DCTL), - readl(regs + S3C_DSTS)); + readl(regs + DCFG), + readl(regs + DCTL), + readl(regs + DSTS)); seq_printf(seq, "DIEPMSK=0x%08x, DOEPMASK=0x%08x\n", - readl(regs + S3C_DIEPMSK), readl(regs + S3C_DOEPMSK)); + readl(regs + DIEPMSK), readl(regs + DOEPMSK)); seq_printf(seq, "GINTMSK=0x%08x, GINTSTS=0x%08x\n", - readl(regs + S3C_GINTMSK), - readl(regs + S3C_GINTSTS)); + readl(regs + GINTMSK), + readl(regs + GINTSTS)); seq_printf(seq, "DAINTMSK=0x%08x, DAINT=0x%08x\n", - readl(regs + S3C_DAINTMSK), - readl(regs + S3C_DAINT)); + readl(regs + DAINTMSK), + readl(regs + DAINT)); seq_printf(seq, "GNPTXSTS=0x%08x, GRXSTSR=%08x\n", - readl(regs + S3C_GNPTXSTS), - readl(regs + S3C_GRXSTSR)); + readl(regs + GNPTXSTS), + readl(regs + GRXSTSR)); seq_printf(seq, "\nEndpoint status:\n"); for (idx = 0; idx < 15; idx++) { u32 in, out; - in = readl(regs + S3C_DIEPCTL(idx)); - out = readl(regs + S3C_DOEPCTL(idx)); + in = readl(regs + DIEPCTL(idx)); + out = readl(regs + DOEPCTL(idx)); seq_printf(seq, "ep%d: DIEPCTL=0x%08x, DOEPCTL=0x%08x", idx, in, out); - in = readl(regs + S3C_DIEPTSIZ(idx)); - out = readl(regs + S3C_DOEPTSIZ(idx)); + in = readl(regs + DIEPTSIZ(idx)); + out = readl(regs + DOEPTSIZ(idx)); seq_printf(seq, ", DIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x", in, out); @@ -3067,7 +3248,7 @@ static const struct file_operations state_fops = { * * Show the FIFO information for the overall fifo and all the * periodic transmission FIFOs. -*/ + */ static int fifo_show(struct seq_file *seq, void *v) { struct s3c_hsotg *hsotg = seq->private; @@ -3076,21 +3257,21 @@ static int fifo_show(struct seq_file *seq, void *v) int idx; seq_printf(seq, "Non-periodic FIFOs:\n"); - seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + S3C_GRXFSIZ)); + seq_printf(seq, "RXFIFO: Size %d\n", readl(regs + GRXFSIZ)); - val = readl(regs + S3C_GNPTXFSIZ); + val = readl(regs + GNPTXFSIZ); seq_printf(seq, "NPTXFIFO: Size %d, Start 0x%08x\n", - val >> S3C_GNPTXFSIZ_NPTxFDep_SHIFT, - val & S3C_GNPTXFSIZ_NPTxFStAddr_MASK); + val >> GNPTXFSIZ_NPTxFDep_SHIFT, + val & GNPTXFSIZ_NPTxFStAddr_MASK); seq_printf(seq, "\nPeriodic TXFIFOs:\n"); for (idx = 1; idx <= 15; idx++) { - val = readl(regs + S3C_DPTXFSIZn(idx)); + val = readl(regs + DPTXFSIZn(idx)); seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx, - val >> S3C_DPTXFSIZn_DPTxFSize_SHIFT, - val & S3C_DPTXFSIZn_DPTxFStAddr_MASK); + val >> DPTXFSIZn_DPTxFSize_SHIFT, + val & DPTXFSIZn_DPTxFStAddr_MASK); } return 0; @@ -3122,7 +3303,7 @@ static const char *decode_direction(int is_in) * * This debugfs entry shows the state of the given endpoint (one is * registered for each available). -*/ + */ static int ep_show(struct seq_file *seq, void *v) { struct s3c_hsotg_ep *ep = seq->private; @@ -3139,20 +3320,20 @@ static int ep_show(struct seq_file *seq, void *v) /* first show the register state */ seq_printf(seq, "\tDIEPCTL=0x%08x, DOEPCTL=0x%08x\n", - readl(regs + S3C_DIEPCTL(index)), - readl(regs + S3C_DOEPCTL(index))); + readl(regs + DIEPCTL(index)), + readl(regs + DOEPCTL(index))); seq_printf(seq, "\tDIEPDMA=0x%08x, DOEPDMA=0x%08x\n", - readl(regs + S3C_DIEPDMA(index)), - readl(regs + S3C_DOEPDMA(index))); + readl(regs + DIEPDMA(index)), + readl(regs + DOEPDMA(index))); seq_printf(seq, "\tDIEPINT=0x%08x, DOEPINT=0x%08x\n", - readl(regs + S3C_DIEPINT(index)), - readl(regs + S3C_DOEPINT(index))); + readl(regs + DIEPINT(index)), + readl(regs + DOEPINT(index))); seq_printf(seq, "\tDIEPTSIZ=0x%08x, DOEPTSIZ=0x%08x\n", - readl(regs + S3C_DIEPTSIZ(index)), - readl(regs + S3C_DOEPTSIZ(index))); + readl(regs + DIEPTSIZ(index)), + readl(regs + DOEPTSIZ(index))); seq_printf(seq, "\n"); seq_printf(seq, "mps %d\n", ep->ep.maxpacket); @@ -3202,7 +3383,7 @@ static const struct file_operations ep_fops = { * about the state of the system. The directory name is created * with the same name as the device itself, in case we end up * with multiple blocks in future systems. -*/ + */ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) { struct dentry *root; @@ -3231,7 +3412,7 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) /* create one file for each endpoint */ - for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { + for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; ep->debugfs = debugfs_create_file(ep->name, 0444, @@ -3248,12 +3429,12 @@ static void __devinit s3c_hsotg_create_debug(struct s3c_hsotg *hsotg) * @hsotg: The driver state * * Cleanup (remove) the debugfs files for use on module exit. -*/ + */ static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) { unsigned epidx; - for (epidx = 0; epidx < S3C_HSOTG_EPS; epidx++) { + for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) { struct s3c_hsotg_ep *ep = &hsotg->eps[epidx]; debugfs_remove(ep->debugfs); } @@ -3264,48 +3445,39 @@ static void __devexit s3c_hsotg_delete_debug(struct s3c_hsotg *hsotg) } /** - * s3c_hsotg_gate - set the hardware gate for the block - * @pdev: The device we bound to - * @on: On or off. - * - * Set the hardware gate setting into the block. If we end up on - * something other than an S3C64XX, then we might need to change this - * to using a platform data callback, or some other mechanism. + * s3c_hsotg_release - release callback for hsotg device + * @dev: Device to for which release is called */ -static void s3c_hsotg_gate(struct platform_device *pdev, bool on) +static void s3c_hsotg_release(struct device *dev) { - unsigned long flags; - u32 others; - - local_irq_save(flags); - - others = __raw_readl(S3C64XX_OTHERS); - if (on) - others |= S3C64XX_OTHERS_USBMASK; - else - others &= ~S3C64XX_OTHERS_USBMASK; - __raw_writel(others, S3C64XX_OTHERS); + struct s3c_hsotg *hsotg = dev_get_drvdata(dev); - local_irq_restore(flags); + kfree(hsotg); } -static struct s3c_hsotg_plat s3c_hsotg_default_pdata; +/** + * s3c_hsotg_probe - probe function for hsotg driver + * @pdev: The platform information for the driver + */ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) { struct s3c_hsotg_plat *plat = pdev->dev.platform_data; struct device *dev = &pdev->dev; + struct s3c_hsotg_ep *eps; struct s3c_hsotg *hsotg; struct resource *res; int epnum; int ret; + int i; - if (!plat) - plat = &s3c_hsotg_default_pdata; + plat = pdev->dev.platform_data; + if (!plat) { + dev_err(&pdev->dev, "no platform data defined\n"); + return -EINVAL; + } - hsotg = kzalloc(sizeof(struct s3c_hsotg) + - sizeof(struct s3c_hsotg_ep) * S3C_HSOTG_EPS, - GFP_KERNEL); + hsotg = kzalloc(sizeof(struct s3c_hsotg), GFP_KERNEL); if (!hsotg) { dev_err(dev, "cannot get memory\n"); return -ENOMEM; @@ -3371,6 +3543,54 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) hsotg->gadget.dev.parent = dev; hsotg->gadget.dev.dma_mask = dev->dma_mask; + hsotg->gadget.dev.release = s3c_hsotg_release; + + /* reset the system */ + + clk_prepare_enable(hsotg->clk); + + /* regulators */ + + for (i = 0; i < ARRAY_SIZE(hsotg->supplies); i++) + hsotg->supplies[i].supply = s3c_hsotg_supply_names[i]; + + ret = regulator_bulk_get(dev, ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + if (ret) { + dev_err(dev, "failed to request supplies: %d\n", ret); + goto err_irq; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + + if (ret) { + dev_err(hsotg->dev, "failed to enable supplies: %d\n", ret); + goto err_supplies; + } + + /* usb phy enable */ + s3c_hsotg_phy_enable(hsotg); + + s3c_hsotg_corereset(hsotg); + s3c_hsotg_init(hsotg); + s3c_hsotg_hw_cfg(hsotg); + + /* hsotg->num_of_eps holds number of EPs other than ep0 */ + + if (hsotg->num_of_eps == 0) { + dev_err(dev, "wrong number of EPs (zero)\n"); + goto err_supplies; + } + + eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep), + GFP_KERNEL); + if (!eps) { + dev_err(dev, "cannot get memory\n"); + goto err_supplies; + } + + hsotg->eps = eps; /* setup endpoint information */ @@ -3383,39 +3603,47 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev) GFP_KERNEL); if (!hsotg->ctrl_req) { dev_err(dev, "failed to allocate ctrl req\n"); - goto err_regs; + goto err_ep_mem; } - /* reset the system */ + /* initialise the endpoints now the core has been initialised */ + for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) + s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); - clk_enable(hsotg->clk); + /* disable power and clock */ - s3c_hsotg_gate(pdev, true); + ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), + hsotg->supplies); + if (ret) { + dev_err(hsotg->dev, "failed to disable supplies: %d\n", ret); + goto err_ep_mem; + } - s3c_hsotg_otgreset(hsotg); - s3c_hsotg_corereset(hsotg); - s3c_hsotg_init(hsotg); + s3c_hsotg_phy_disable(hsotg); - /* initialise the endpoints now the core has been initialised */ - for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++) - s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum); + ret = device_add(&hsotg->gadget.dev); + if (ret) { + put_device(&hsotg->gadget.dev); + goto err_ep_mem; + } ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget); if (ret) - goto err_add_udc; + goto err_ep_mem; s3c_hsotg_create_debug(hsotg); s3c_hsotg_dump(hsotg); - our_hsotg = hsotg; return 0; -err_add_udc: - s3c_hsotg_gate(pdev, false); - clk_disable(hsotg->clk); - clk_put(hsotg->clk); - +err_ep_mem: + kfree(eps); +err_supplies: + s3c_hsotg_phy_disable(hsotg); + regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); +err_irq: + free_irq(hsotg->irq, hsotg); err_regs: iounmap(hsotg->regs); @@ -3423,12 +3651,17 @@ err_regs_res: release_resource(hsotg->regs_res); kfree(hsotg->regs_res); err_clk: + clk_disable_unprepare(hsotg->clk); clk_put(hsotg->clk); err_mem: kfree(hsotg); return ret; } +/** + * s3c_hsotg_remove - remove function for hsotg driver + * @pdev: The platform information for the driver + */ static int __devexit s3c_hsotg_remove(struct platform_device *pdev) { struct s3c_hsotg *hsotg = platform_get_drvdata(pdev); @@ -3437,7 +3670,10 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev) s3c_hsotg_delete_debug(hsotg); - usb_gadget_unregister_driver(hsotg->driver); + if (hsotg->driver) { + /* should have been done already by driver model core */ + usb_gadget_unregister_driver(hsotg->driver); + } free_irq(hsotg->irq, hsotg); iounmap(hsotg->regs); @@ -3445,12 +3681,13 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev) release_resource(hsotg->regs_res); kfree(hsotg->regs_res); - s3c_hsotg_gate(pdev, false); + s3c_hsotg_phy_disable(hsotg); + regulator_bulk_free(ARRAY_SIZE(hsotg->supplies), hsotg->supplies); - clk_disable(hsotg->clk); + clk_disable_unprepare(hsotg->clk); clk_put(hsotg->clk); - kfree(hsotg); + device_unregister(&hsotg->gadget.dev); return 0; } diff --git a/drivers/usb/gadget/s3c-hsotg.h b/drivers/usb/gadget/s3c-hsotg.h new file mode 100644 index 000000000000..d650b1295831 --- /dev/null +++ b/drivers/usb/gadget/s3c-hsotg.h @@ -0,0 +1,377 @@ +/* drivers/usb/gadget/s3c-hsotg.h + * + * Copyright 2008 Openmoko, Inc. + * Copyright 2008 Simtec Electronics + * http://armlinux.simtec.co.uk/ + * Ben Dooks <ben@simtec.co.uk> + * + * USB2.0 Highspeed/OtG Synopsis DWC2 device block registers + * + * 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. +*/ + +#ifndef __REGS_USB_HSOTG_H +#define __REGS_USB_HSOTG_H __FILE__ + +#define HSOTG_REG(x) (x) + +#define GOTGCTL HSOTG_REG(0x000) +#define GOTGCTL_BSESVLD (1 << 19) +#define GOTGCTL_ASESVLD (1 << 18) +#define GOTGCTL_DBNC_SHORT (1 << 17) +#define GOTGCTL_CONID_B (1 << 16) +#define GOTGCTL_DEVHNPEN (1 << 11) +#define GOTGCTL_HSSETHNPEN (1 << 10) +#define GOTGCTL_HNPREQ (1 << 9) +#define GOTGCTL_HSTNEGSCS (1 << 8) +#define GOTGCTL_SESREQ (1 << 1) +#define GOTGCTL_SESREQSCS (1 << 0) + +#define GOTGINT HSOTG_REG(0x004) +#define GOTGINT_DbnceDone (1 << 19) +#define GOTGINT_ADevTOUTChg (1 << 18) +#define GOTGINT_HstNegDet (1 << 17) +#define GOTGINT_HstnegSucStsChng (1 << 9) +#define GOTGINT_SesReqSucStsChng (1 << 8) +#define GOTGINT_SesEndDet (1 << 2) + +#define GAHBCFG HSOTG_REG(0x008) +#define GAHBCFG_PTxFEmpLvl (1 << 8) +#define GAHBCFG_NPTxFEmpLvl (1 << 7) +#define GAHBCFG_DMAEn (1 << 5) +#define GAHBCFG_HBstLen_MASK (0xf << 1) +#define GAHBCFG_HBstLen_SHIFT (1) +#define GAHBCFG_HBstLen_Single (0x0 << 1) +#define GAHBCFG_HBstLen_Incr (0x1 << 1) +#define GAHBCFG_HBstLen_Incr4 (0x3 << 1) +#define GAHBCFG_HBstLen_Incr8 (0x5 << 1) +#define GAHBCFG_HBstLen_Incr16 (0x7 << 1) +#define GAHBCFG_GlblIntrEn (1 << 0) + +#define GUSBCFG HSOTG_REG(0x00C) +#define GUSBCFG_PHYLPClkSel (1 << 15) +#define GUSBCFG_HNPCap (1 << 9) +#define GUSBCFG_SRPCap (1 << 8) +#define GUSBCFG_PHYIf16 (1 << 3) +#define GUSBCFG_TOutCal_MASK (0x7 << 0) +#define GUSBCFG_TOutCal_SHIFT (0) +#define GUSBCFG_TOutCal_LIMIT (0x7) +#define GUSBCFG_TOutCal(_x) ((_x) << 0) + +#define GRSTCTL HSOTG_REG(0x010) + +#define GRSTCTL_AHBIdle (1 << 31) +#define GRSTCTL_DMAReq (1 << 30) +#define GRSTCTL_TxFNum_MASK (0x1f << 6) +#define GRSTCTL_TxFNum_SHIFT (6) +#define GRSTCTL_TxFNum_LIMIT (0x1f) +#define GRSTCTL_TxFNum(_x) ((_x) << 6) +#define GRSTCTL_TxFFlsh (1 << 5) +#define GRSTCTL_RxFFlsh (1 << 4) +#define GRSTCTL_INTknQFlsh (1 << 3) +#define GRSTCTL_FrmCntrRst (1 << 2) +#define GRSTCTL_HSftRst (1 << 1) +#define GRSTCTL_CSftRst (1 << 0) + +#define GINTSTS HSOTG_REG(0x014) +#define GINTMSK HSOTG_REG(0x018) + +#define GINTSTS_WkUpInt (1 << 31) +#define GINTSTS_SessReqInt (1 << 30) +#define GINTSTS_DisconnInt (1 << 29) +#define GINTSTS_ConIDStsChng (1 << 28) +#define GINTSTS_PTxFEmp (1 << 26) +#define GINTSTS_HChInt (1 << 25) +#define GINTSTS_PrtInt (1 << 24) +#define GINTSTS_FetSusp (1 << 22) +#define GINTSTS_incompIP (1 << 21) +#define GINTSTS_IncomplSOIN (1 << 20) +#define GINTSTS_OEPInt (1 << 19) +#define GINTSTS_IEPInt (1 << 18) +#define GINTSTS_EPMis (1 << 17) +#define GINTSTS_EOPF (1 << 15) +#define GINTSTS_ISOutDrop (1 << 14) +#define GINTSTS_EnumDone (1 << 13) +#define GINTSTS_USBRst (1 << 12) +#define GINTSTS_USBSusp (1 << 11) +#define GINTSTS_ErlySusp (1 << 10) +#define GINTSTS_GOUTNakEff (1 << 7) +#define GINTSTS_GINNakEff (1 << 6) +#define GINTSTS_NPTxFEmp (1 << 5) +#define GINTSTS_RxFLvl (1 << 4) +#define GINTSTS_SOF (1 << 3) +#define GINTSTS_OTGInt (1 << 2) +#define GINTSTS_ModeMis (1 << 1) +#define GINTSTS_CurMod_Host (1 << 0) + +#define GRXSTSR HSOTG_REG(0x01C) +#define GRXSTSP HSOTG_REG(0x020) + +#define GRXSTS_FN_MASK (0x7f << 25) +#define GRXSTS_FN_SHIFT (25) + +#define GRXSTS_PktSts_MASK (0xf << 17) +#define GRXSTS_PktSts_SHIFT (17) +#define GRXSTS_PktSts_GlobalOutNAK (0x1 << 17) +#define GRXSTS_PktSts_OutRX (0x2 << 17) +#define GRXSTS_PktSts_OutDone (0x3 << 17) +#define GRXSTS_PktSts_SetupDone (0x4 << 17) +#define GRXSTS_PktSts_SetupRX (0x6 << 17) + +#define GRXSTS_DPID_MASK (0x3 << 15) +#define GRXSTS_DPID_SHIFT (15) +#define GRXSTS_ByteCnt_MASK (0x7ff << 4) +#define GRXSTS_ByteCnt_SHIFT (4) +#define GRXSTS_EPNum_MASK (0xf << 0) +#define GRXSTS_EPNum_SHIFT (0) + +#define GRXFSIZ HSOTG_REG(0x024) + +#define GNPTXFSIZ HSOTG_REG(0x028) + +#define GNPTXFSIZ_NPTxFDep_MASK (0xffff << 16) +#define GNPTXFSIZ_NPTxFDep_SHIFT (16) +#define GNPTXFSIZ_NPTxFDep_LIMIT (0xffff) +#define GNPTXFSIZ_NPTxFDep(_x) ((_x) << 16) +#define GNPTXFSIZ_NPTxFStAddr_MASK (0xffff << 0) +#define GNPTXFSIZ_NPTxFStAddr_SHIFT (0) +#define GNPTXFSIZ_NPTxFStAddr_LIMIT (0xffff) +#define GNPTXFSIZ_NPTxFStAddr(_x) ((_x) << 0) + +#define GNPTXSTS HSOTG_REG(0x02C) + +#define GNPTXSTS_NPtxQTop_MASK (0x7f << 24) +#define GNPTXSTS_NPtxQTop_SHIFT (24) + +#define GNPTXSTS_NPTxQSpcAvail_MASK (0xff << 16) +#define GNPTXSTS_NPTxQSpcAvail_SHIFT (16) +#define GNPTXSTS_NPTxQSpcAvail_GET(_v) (((_v) >> 16) & 0xff) + +#define GNPTXSTS_NPTxFSpcAvail_MASK (0xffff << 0) +#define GNPTXSTS_NPTxFSpcAvail_SHIFT (0) +#define GNPTXSTS_NPTxFSpcAvail_GET(_v) (((_v) >> 0) & 0xffff) + + +#define HPTXFSIZ HSOTG_REG(0x100) + +#define DPTXFSIZn(_a) HSOTG_REG(0x104 + (((_a) - 1) * 4)) + +#define DPTXFSIZn_DPTxFSize_MASK (0xffff << 16) +#define DPTXFSIZn_DPTxFSize_SHIFT (16) +#define DPTXFSIZn_DPTxFSize_GET(_v) (((_v) >> 16) & 0xffff) +#define DPTXFSIZn_DPTxFSize_LIMIT (0xffff) +#define DPTXFSIZn_DPTxFSize(_x) ((_x) << 16) + +#define DPTXFSIZn_DPTxFStAddr_MASK (0xffff << 0) +#define DPTXFSIZn_DPTxFStAddr_SHIFT (0) + +/* Device mode registers */ +#define DCFG HSOTG_REG(0x800) + +#define DCFG_EPMisCnt_MASK (0x1f << 18) +#define DCFG_EPMisCnt_SHIFT (18) +#define DCFG_EPMisCnt_LIMIT (0x1f) +#define DCFG_EPMisCnt(_x) ((_x) << 18) + +#define DCFG_PerFrInt_MASK (0x3 << 11) +#define DCFG_PerFrInt_SHIFT (11) +#define DCFG_PerFrInt_LIMIT (0x3) +#define DCFG_PerFrInt(_x) ((_x) << 11) + +#define DCFG_DevAddr_MASK (0x7f << 4) +#define DCFG_DevAddr_SHIFT (4) +#define DCFG_DevAddr_LIMIT (0x7f) +#define DCFG_DevAddr(_x) ((_x) << 4) + +#define DCFG_NZStsOUTHShk (1 << 2) + +#define DCFG_DevSpd_MASK (0x3 << 0) +#define DCFG_DevSpd_SHIFT (0) +#define DCFG_DevSpd_HS (0x0 << 0) +#define DCFG_DevSpd_FS (0x1 << 0) +#define DCFG_DevSpd_LS (0x2 << 0) +#define DCFG_DevSpd_FS48 (0x3 << 0) + +#define DCTL HSOTG_REG(0x804) + +#define DCTL_PWROnPrgDone (1 << 11) +#define DCTL_CGOUTNak (1 << 10) +#define DCTL_SGOUTNak (1 << 9) +#define DCTL_CGNPInNAK (1 << 8) +#define DCTL_SGNPInNAK (1 << 7) +#define DCTL_TstCtl_MASK (0x7 << 4) +#define DCTL_TstCtl_SHIFT (4) +#define DCTL_GOUTNakSts (1 << 3) +#define DCTL_GNPINNakSts (1 << 2) +#define DCTL_SftDiscon (1 << 1) +#define DCTL_RmtWkUpSig (1 << 0) + +#define DSTS HSOTG_REG(0x808) + +#define DSTS_SOFFN_MASK (0x3fff << 8) +#define DSTS_SOFFN_SHIFT (8) +#define DSTS_SOFFN_LIMIT (0x3fff) +#define DSTS_SOFFN(_x) ((_x) << 8) +#define DSTS_ErraticErr (1 << 3) +#define DSTS_EnumSpd_MASK (0x3 << 1) +#define DSTS_EnumSpd_SHIFT (1) +#define DSTS_EnumSpd_HS (0x0 << 1) +#define DSTS_EnumSpd_FS (0x1 << 1) +#define DSTS_EnumSpd_LS (0x2 << 1) +#define DSTS_EnumSpd_FS48 (0x3 << 1) + +#define DSTS_SuspSts (1 << 0) + +#define DIEPMSK HSOTG_REG(0x810) + +#define DIEPMSK_TxFIFOEmpty (1 << 7) +#define DIEPMSK_INEPNakEffMsk (1 << 6) +#define DIEPMSK_INTknEPMisMsk (1 << 5) +#define DIEPMSK_INTknTXFEmpMsk (1 << 4) +#define DIEPMSK_TimeOUTMsk (1 << 3) +#define DIEPMSK_AHBErrMsk (1 << 2) +#define DIEPMSK_EPDisbldMsk (1 << 1) +#define DIEPMSK_XferComplMsk (1 << 0) + +#define DOEPMSK HSOTG_REG(0x814) + +#define DOEPMSK_Back2BackSetup (1 << 6) +#define DOEPMSK_OUTTknEPdisMsk (1 << 4) +#define DOEPMSK_SetupMsk (1 << 3) +#define DOEPMSK_AHBErrMsk (1 << 2) +#define DOEPMSK_EPDisbldMsk (1 << 1) +#define DOEPMSK_XferComplMsk (1 << 0) + +#define DAINT HSOTG_REG(0x818) +#define DAINTMSK HSOTG_REG(0x81C) + +#define DAINT_OutEP_SHIFT (16) +#define DAINT_OutEP(x) (1 << ((x) + 16)) +#define DAINT_InEP(x) (1 << (x)) + +#define DTKNQR1 HSOTG_REG(0x820) +#define DTKNQR2 HSOTG_REG(0x824) +#define DTKNQR3 HSOTG_REG(0x830) +#define DTKNQR4 HSOTG_REG(0x834) + +#define DVBUSDIS HSOTG_REG(0x828) +#define DVBUSPULSE HSOTG_REG(0x82C) + +#define DIEPCTL0 HSOTG_REG(0x900) +#define DOEPCTL0 HSOTG_REG(0xB00) +#define DIEPCTL(_a) HSOTG_REG(0x900 + ((_a) * 0x20)) +#define DOEPCTL(_a) HSOTG_REG(0xB00 + ((_a) * 0x20)) + +/* EP0 specialness: + * bits[29..28] - reserved (no SetD0PID, SetD1PID) + * bits[25..22] - should always be zero, this isn't a periodic endpoint + * bits[10..0] - MPS setting differenct for EP0 + */ +#define D0EPCTL_MPS_MASK (0x3 << 0) +#define D0EPCTL_MPS_SHIFT (0) +#define D0EPCTL_MPS_64 (0x0 << 0) +#define D0EPCTL_MPS_32 (0x1 << 0) +#define D0EPCTL_MPS_16 (0x2 << 0) +#define D0EPCTL_MPS_8 (0x3 << 0) + +#define DxEPCTL_EPEna (1 << 31) +#define DxEPCTL_EPDis (1 << 30) +#define DxEPCTL_SetD1PID (1 << 29) +#define DxEPCTL_SetOddFr (1 << 29) +#define DxEPCTL_SetD0PID (1 << 28) +#define DxEPCTL_SetEvenFr (1 << 28) +#define DxEPCTL_SNAK (1 << 27) +#define DxEPCTL_CNAK (1 << 26) +#define DxEPCTL_TxFNum_MASK (0xf << 22) +#define DxEPCTL_TxFNum_SHIFT (22) +#define DxEPCTL_TxFNum_LIMIT (0xf) +#define DxEPCTL_TxFNum(_x) ((_x) << 22) + +#define DxEPCTL_Stall (1 << 21) +#define DxEPCTL_Snp (1 << 20) +#define DxEPCTL_EPType_MASK (0x3 << 18) +#define DxEPCTL_EPType_SHIFT (18) +#define DxEPCTL_EPType_Control (0x0 << 18) +#define DxEPCTL_EPType_Iso (0x1 << 18) +#define DxEPCTL_EPType_Bulk (0x2 << 18) +#define DxEPCTL_EPType_Intterupt (0x3 << 18) + +#define DxEPCTL_NAKsts (1 << 17) +#define DxEPCTL_DPID (1 << 16) +#define DxEPCTL_EOFrNum (1 << 16) +#define DxEPCTL_USBActEp (1 << 15) +#define DxEPCTL_NextEp_MASK (0xf << 11) +#define DxEPCTL_NextEp_SHIFT (11) +#define DxEPCTL_NextEp_LIMIT (0xf) +#define DxEPCTL_NextEp(_x) ((_x) << 11) + +#define DxEPCTL_MPS_MASK (0x7ff << 0) +#define DxEPCTL_MPS_SHIFT (0) +#define DxEPCTL_MPS_LIMIT (0x7ff) +#define DxEPCTL_MPS(_x) ((_x) << 0) + +#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20)) +#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20)) + +#define DxEPINT_INEPNakEff (1 << 6) +#define DxEPINT_Back2BackSetup (1 << 6) +#define DxEPINT_INTknEPMis (1 << 5) +#define DxEPINT_INTknTXFEmp (1 << 4) +#define DxEPINT_OUTTknEPdis (1 << 4) +#define DxEPINT_Timeout (1 << 3) +#define DxEPINT_Setup (1 << 3) +#define DxEPINT_AHBErr (1 << 2) +#define DxEPINT_EPDisbld (1 << 1) +#define DxEPINT_XferCompl (1 << 0) + +#define DIEPTSIZ0 HSOTG_REG(0x910) + +#define DIEPTSIZ0_PktCnt_MASK (0x3 << 19) +#define DIEPTSIZ0_PktCnt_SHIFT (19) +#define DIEPTSIZ0_PktCnt_LIMIT (0x3) +#define DIEPTSIZ0_PktCnt(_x) ((_x) << 19) + +#define DIEPTSIZ0_XferSize_MASK (0x7f << 0) +#define DIEPTSIZ0_XferSize_SHIFT (0) +#define DIEPTSIZ0_XferSize_LIMIT (0x7f) +#define DIEPTSIZ0_XferSize(_x) ((_x) << 0) + +#define DOEPTSIZ0 HSOTG_REG(0xB10) +#define DOEPTSIZ0_SUPCnt_MASK (0x3 << 29) +#define DOEPTSIZ0_SUPCnt_SHIFT (29) +#define DOEPTSIZ0_SUPCnt_LIMIT (0x3) +#define DOEPTSIZ0_SUPCnt(_x) ((_x) << 29) + +#define DOEPTSIZ0_PktCnt (1 << 19) +#define DOEPTSIZ0_XferSize_MASK (0x7f << 0) +#define DOEPTSIZ0_XferSize_SHIFT (0) + +#define DIEPTSIZ(_a) HSOTG_REG(0x910 + ((_a) * 0x20)) +#define DOEPTSIZ(_a) HSOTG_REG(0xB10 + ((_a) * 0x20)) + +#define DxEPTSIZ_MC_MASK (0x3 << 29) +#define DxEPTSIZ_MC_SHIFT (29) +#define DxEPTSIZ_MC_LIMIT (0x3) +#define DxEPTSIZ_MC(_x) ((_x) << 29) + +#define DxEPTSIZ_PktCnt_MASK (0x3ff << 19) +#define DxEPTSIZ_PktCnt_SHIFT (19) +#define DxEPTSIZ_PktCnt_GET(_v) (((_v) >> 19) & 0x3ff) +#define DxEPTSIZ_PktCnt_LIMIT (0x3ff) +#define DxEPTSIZ_PktCnt(_x) ((_x) << 19) + +#define DxEPTSIZ_XferSize_MASK (0x7ffff << 0) +#define DxEPTSIZ_XferSize_SHIFT (0) +#define DxEPTSIZ_XferSize_GET(_v) (((_v) >> 0) & 0x7ffff) +#define DxEPTSIZ_XferSize_LIMIT (0x7ffff) +#define DxEPTSIZ_XferSize(_x) ((_x) << 0) + +#define DIEPDMA(_a) HSOTG_REG(0x914 + ((_a) * 0x20)) +#define DOEPDMA(_a) HSOTG_REG(0xB14 + ((_a) * 0x20)) +#define DTXFSTS(_a) HSOTG_REG(0x918 + ((_a) * 0x20)) + +#define EPFIFO(_a) HSOTG_REG(0x1000 + ((_a) * 0x1000)) + +#endif /* __REGS_USB_HSOTG_H */ diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c index cef9b82ff911..36c6836eeb0f 100644 --- a/drivers/usb/gadget/s3c-hsudc.c +++ b/drivers/usb/gadget/s3c-hsudc.c @@ -110,7 +110,6 @@ struct s3c_hsudc_ep { struct usb_ep ep; char name[20]; struct s3c_hsudc *dev; - const struct usb_endpoint_descriptor *desc; struct list_head queue; u8 stopped; u8 wedge; @@ -761,7 +760,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep, u32 ecr = 0; hsep = our_ep(_ep); - if (!_ep || !desc || hsep->desc || _ep->name == ep0name + if (!_ep || !desc || hsep->ep.desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT || hsep->bEndpointAddress != desc->bEndpointAddress || ep_maxpacket(hsep) < usb_endpoint_maxp(desc)) @@ -783,7 +782,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep, writel(ecr, hsudc->regs + S3C_ECR); hsep->stopped = hsep->wedge = 0; - hsep->desc = desc; + hsep->ep.desc = desc; hsep->ep.maxpacket = usb_endpoint_maxp(desc); s3c_hsudc_set_halt(_ep, 0); @@ -806,7 +805,7 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep) struct s3c_hsudc *hsudc = hsep->dev; unsigned long flags; - if (!_ep || !hsep->desc) + if (!_ep || !hsep->ep.desc) return -EINVAL; spin_lock_irqsave(&hsudc->lock, flags); @@ -816,7 +815,6 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep) s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN); - hsep->desc = 0; hsep->ep.desc = NULL; hsep->stopped = 1; @@ -1006,7 +1004,6 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc, hsep->ep.maxpacket = epnum ? 512 : 64; hsep->ep.ops = &s3c_hsudc_ep_ops; hsep->fifo = hsudc->regs + S3C_BR(epnum); - hsep->desc = 0; hsep->ep.desc = NULL; hsep->stopped = 0; hsep->wedge = 0; diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c index 195524cde6c3..3de71d37d75e 100644 --- a/drivers/usb/gadget/s3c2410_udc.c +++ b/drivers/usb/gadget/s3c2410_udc.c @@ -1062,7 +1062,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep, ep = to_s3c2410_ep(_ep); - if (!_ep || !desc || ep->desc + if (!_ep || !desc || ep->ep.desc || _ep->name == ep0name || desc->bDescriptorType != USB_DT_ENDPOINT) return -EINVAL; @@ -1075,7 +1075,7 @@ static int s3c2410_udc_ep_enable(struct usb_ep *_ep, local_irq_save (flags); _ep->maxpacket = max & 0x7ff; - ep->desc = desc; + ep->ep.desc = desc; ep->halted = 0; ep->bEndpointAddress = desc->bEndpointAddress; @@ -1136,7 +1136,7 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep) unsigned long flags; u32 int_en_reg; - if (!_ep || !ep->desc) { + if (!_ep || !ep->ep.desc) { dprintk(DEBUG_NORMAL, "%s not enabled\n", _ep ? ep->ep.name : NULL); return -EINVAL; @@ -1146,7 +1146,6 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep) dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name); - ep->desc = NULL; ep->ep.desc = NULL; ep->halted = 1; @@ -1195,7 +1194,7 @@ s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req) dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req); - if (!ep || !_req || (!ep->desc && _ep->name != ep0name)) + if (!ep || !_req || (!ep->ep.desc && _ep->name != ep0name)) return; WARN_ON (!list_empty (&req->queue)); @@ -1215,7 +1214,7 @@ static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req, int fifo_count = 0; unsigned long flags; - if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { + if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) { dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__); return -EINVAL; } @@ -1363,7 +1362,7 @@ static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value) unsigned long flags; u32 idx; - if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) { + if (unlikely(!_ep || (!ep->ep.desc && ep->ep.name != ep0name))) { dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__); return -EINVAL; } @@ -1629,7 +1628,6 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev) list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list); ep->dev = dev; - ep->desc = NULL; ep->ep.desc = NULL; ep->halted = 0; INIT_LIST_HEAD (&ep->queue); diff --git a/drivers/usb/gadget/s3c2410_udc.h b/drivers/usb/gadget/s3c2410_udc.h index 1653bae08b80..3e80fd5c820f 100644 --- a/drivers/usb/gadget/s3c2410_udc.h +++ b/drivers/usb/gadget/s3c2410_udc.h @@ -19,7 +19,6 @@ struct s3c2410_ep { unsigned long last_io; /* jiffies timestamp */ struct usb_gadget *gadget; struct s3c2410_udc *dev; - const struct usb_endpoint_descriptor *desc; struct usb_ep ep; u8 num; diff --git a/drivers/usb/gadget/tcm_usb_gadget.c b/drivers/usb/gadget/tcm_usb_gadget.c new file mode 100644 index 000000000000..c46439c8dd74 --- /dev/null +++ b/drivers/usb/gadget/tcm_usb_gadget.c @@ -0,0 +1,2480 @@ +/* Target based USB-Gadget + * + * UAS protocol handling, target callbacks, configfs handling, + * BBB (USB Mass Storage Class Bulk-Only (BBB) and Transport protocol handling. + * + * Author: Sebastian Andrzej Siewior <bigeasy at linutronix dot de> + * License: GPLv2 as published by FSF. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/configfs.h> +#include <linux/ctype.h> +#include <linux/usb/ch9.h> +#include <linux/usb/composite.h> +#include <linux/usb/gadget.h> +#include <linux/usb/storage.h> +#include <scsi/scsi.h> +#include <scsi/scsi_tcq.h> +#include <target/target_core_base.h> +#include <target/target_core_fabric.h> +#include <target/target_core_fabric_configfs.h> +#include <target/target_core_configfs.h> +#include <target/configfs_macros.h> +#include <asm/unaligned.h> + +#include "usbstring.c" +#include "epautoconf.c" +#include "config.c" +#include "composite.c" + +#include "tcm_usb_gadget.h" + +static struct target_fabric_configfs *usbg_fabric_configfs; + +static inline struct f_uas *to_f_uas(struct usb_function *f) +{ + return container_of(f, struct f_uas, function); +} + +static void usbg_cmd_release(struct kref *); + +static inline void usbg_cleanup_cmd(struct usbg_cmd *cmd) +{ + kref_put(&cmd->ref, usbg_cmd_release); +} + +/* Start bot.c code */ + +static int bot_enqueue_cmd_cbw(struct f_uas *fu) +{ + int ret; + + if (fu->flags & USBG_BOT_CMD_PEND) + return 0; + + ret = usb_ep_queue(fu->ep_out, fu->cmd.req, GFP_ATOMIC); + if (!ret) + fu->flags |= USBG_BOT_CMD_PEND; + return ret; +} + +static void bot_status_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + struct f_uas *fu = cmd->fu; + + usbg_cleanup_cmd(cmd); + if (req->status < 0) { + pr_err("ERR %s(%d)\n", __func__, __LINE__); + return; + } + + /* CSW completed, wait for next CBW */ + bot_enqueue_cmd_cbw(fu); +} + +static void bot_enqueue_sense_code(struct f_uas *fu, struct usbg_cmd *cmd) +{ + struct bulk_cs_wrap *csw = &fu->bot_status.csw; + int ret; + u8 *sense; + unsigned int csw_stat; + + csw_stat = cmd->csw_code; + + /* + * We can't send SENSE as a response. So we take ASC & ASCQ from our + * sense buffer and queue it and hope the host sends a REQUEST_SENSE + * command where it learns why we failed. + */ + sense = cmd->sense_iu.sense; + + csw->Tag = cmd->bot_tag; + csw->Status = csw_stat; + fu->bot_status.req->context = cmd; + ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_ATOMIC); + if (ret) + pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret); +} + +static void bot_err_compl(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + struct f_uas *fu = cmd->fu; + + if (req->status < 0) + pr_err("ERR %s(%d)\n", __func__, __LINE__); + + if (cmd->data_len) { + if (cmd->data_len > ep->maxpacket) { + req->length = ep->maxpacket; + cmd->data_len -= ep->maxpacket; + } else { + req->length = cmd->data_len; + cmd->data_len = 0; + } + + usb_ep_queue(ep, req, GFP_ATOMIC); + return ; + } + bot_enqueue_sense_code(fu, cmd); +} + +static void bot_send_bad_status(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct bulk_cs_wrap *csw = &fu->bot_status.csw; + struct usb_request *req; + struct usb_ep *ep; + + csw->Residue = cpu_to_le32(cmd->data_len); + + if (cmd->data_len) { + if (cmd->is_read) { + ep = fu->ep_in; + req = fu->bot_req_in; + } else { + ep = fu->ep_out; + req = fu->bot_req_out; + } + + if (cmd->data_len > fu->ep_in->maxpacket) { + req->length = ep->maxpacket; + cmd->data_len -= ep->maxpacket; + } else { + req->length = cmd->data_len; + cmd->data_len = 0; + } + req->complete = bot_err_compl; + req->context = cmd; + req->buf = fu->cmd.buf; + usb_ep_queue(ep, req, GFP_KERNEL); + } else { + bot_enqueue_sense_code(fu, cmd); + } +} + +static int bot_send_status(struct usbg_cmd *cmd, bool moved_data) +{ + struct f_uas *fu = cmd->fu; + struct bulk_cs_wrap *csw = &fu->bot_status.csw; + int ret; + + if (cmd->se_cmd.scsi_status == SAM_STAT_GOOD) { + if (!moved_data && cmd->data_len) { + /* + * the host wants to move data, we don't. Fill / empty + * the pipe and then send the csw with reside set. + */ + cmd->csw_code = US_BULK_STAT_OK; + bot_send_bad_status(cmd); + return 0; + } + + csw->Tag = cmd->bot_tag; + csw->Residue = cpu_to_le32(0); + csw->Status = US_BULK_STAT_OK; + fu->bot_status.req->context = cmd; + + ret = usb_ep_queue(fu->ep_in, fu->bot_status.req, GFP_KERNEL); + if (ret) + pr_err("%s(%d) ERR: %d\n", __func__, __LINE__, ret); + } else { + cmd->csw_code = US_BULK_STAT_FAIL; + bot_send_bad_status(cmd); + } + return 0; +} + +/* + * Called after command (no data transfer) or after the write (to device) + * operation is completed + */ +static int bot_send_status_response(struct usbg_cmd *cmd) +{ + bool moved_data = false; + + if (!cmd->is_read) + moved_data = true; + return bot_send_status(cmd, moved_data); +} + +/* Read request completed, now we have to send the CSW */ +static void bot_read_compl(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + + if (req->status < 0) + pr_err("ERR %s(%d)\n", __func__, __LINE__); + + bot_send_status(cmd, true); +} + +static int bot_send_read_response(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct se_cmd *se_cmd = &cmd->se_cmd; + struct usb_gadget *gadget = fuas_to_gadget(fu); + int ret; + + if (!cmd->data_len) { + cmd->csw_code = US_BULK_STAT_PHASE; + bot_send_bad_status(cmd); + return 0; + } + + if (!gadget->sg_supported) { + cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC); + if (!cmd->data_buf) + return -ENOMEM; + + sg_copy_to_buffer(se_cmd->t_data_sg, + se_cmd->t_data_nents, + cmd->data_buf, + se_cmd->data_length); + + fu->bot_req_in->buf = cmd->data_buf; + } else { + fu->bot_req_in->buf = NULL; + fu->bot_req_in->num_sgs = se_cmd->t_data_nents; + fu->bot_req_in->sg = se_cmd->t_data_sg; + } + + fu->bot_req_in->complete = bot_read_compl; + fu->bot_req_in->length = se_cmd->data_length; + fu->bot_req_in->context = cmd; + ret = usb_ep_queue(fu->ep_in, fu->bot_req_in, GFP_ATOMIC); + if (ret) + pr_err("%s(%d)\n", __func__, __LINE__); + return 0; +} + +static void usbg_data_write_cmpl(struct usb_ep *, struct usb_request *); +static int usbg_prepare_w_request(struct usbg_cmd *, struct usb_request *); + +static int bot_send_write_request(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct se_cmd *se_cmd = &cmd->se_cmd; + struct usb_gadget *gadget = fuas_to_gadget(fu); + int ret; + + init_completion(&cmd->write_complete); + cmd->fu = fu; + + if (!cmd->data_len) { + cmd->csw_code = US_BULK_STAT_PHASE; + return -EINVAL; + } + + if (!gadget->sg_supported) { + cmd->data_buf = kmalloc(se_cmd->data_length, GFP_KERNEL); + if (!cmd->data_buf) + return -ENOMEM; + + fu->bot_req_out->buf = cmd->data_buf; + } else { + fu->bot_req_out->buf = NULL; + fu->bot_req_out->num_sgs = se_cmd->t_data_nents; + fu->bot_req_out->sg = se_cmd->t_data_sg; + } + + fu->bot_req_out->complete = usbg_data_write_cmpl; + fu->bot_req_out->length = se_cmd->data_length; + fu->bot_req_out->context = cmd; + + ret = usbg_prepare_w_request(cmd, fu->bot_req_out); + if (ret) + goto cleanup; + ret = usb_ep_queue(fu->ep_out, fu->bot_req_out, GFP_KERNEL); + if (ret) + pr_err("%s(%d)\n", __func__, __LINE__); + + wait_for_completion(&cmd->write_complete); + transport_generic_process_write(se_cmd); +cleanup: + return ret; +} + +static int bot_submit_command(struct f_uas *, void *, unsigned int); + +static void bot_cmd_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_uas *fu = req->context; + int ret; + + fu->flags &= ~USBG_BOT_CMD_PEND; + + if (req->status < 0) + return; + + ret = bot_submit_command(fu, req->buf, req->actual); + if (ret) + pr_err("%s(%d): %d\n", __func__, __LINE__, ret); +} + +static int bot_prepare_reqs(struct f_uas *fu) +{ + int ret; + + fu->bot_req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL); + if (!fu->bot_req_in) + goto err; + + fu->bot_req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL); + if (!fu->bot_req_out) + goto err_out; + + fu->cmd.req = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL); + if (!fu->cmd.req) + goto err_cmd; + + fu->bot_status.req = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL); + if (!fu->bot_status.req) + goto err_sts; + + fu->bot_status.req->buf = &fu->bot_status.csw; + fu->bot_status.req->length = US_BULK_CS_WRAP_LEN; + fu->bot_status.req->complete = bot_status_complete; + fu->bot_status.csw.Signature = cpu_to_le32(US_BULK_CS_SIGN); + + fu->cmd.buf = kmalloc(fu->ep_out->maxpacket, GFP_KERNEL); + if (!fu->cmd.buf) + goto err_buf; + + fu->cmd.req->complete = bot_cmd_complete; + fu->cmd.req->buf = fu->cmd.buf; + fu->cmd.req->length = fu->ep_out->maxpacket; + fu->cmd.req->context = fu; + + ret = bot_enqueue_cmd_cbw(fu); + if (ret) + goto err_queue; + return 0; +err_queue: + kfree(fu->cmd.buf); + fu->cmd.buf = NULL; +err_buf: + usb_ep_free_request(fu->ep_in, fu->bot_status.req); +err_sts: + usb_ep_free_request(fu->ep_out, fu->cmd.req); + fu->cmd.req = NULL; +err_cmd: + usb_ep_free_request(fu->ep_out, fu->bot_req_out); + fu->bot_req_out = NULL; +err_out: + usb_ep_free_request(fu->ep_in, fu->bot_req_in); + fu->bot_req_in = NULL; +err: + pr_err("BOT: endpoint setup failed\n"); + return -ENOMEM; +} + +void bot_cleanup_old_alt(struct f_uas *fu) +{ + if (!(fu->flags & USBG_ENABLED)) + return; + + usb_ep_disable(fu->ep_in); + usb_ep_disable(fu->ep_out); + + if (!fu->bot_req_in) + return; + + usb_ep_free_request(fu->ep_in, fu->bot_req_in); + usb_ep_free_request(fu->ep_out, fu->bot_req_out); + usb_ep_free_request(fu->ep_out, fu->cmd.req); + usb_ep_free_request(fu->ep_out, fu->bot_status.req); + + kfree(fu->cmd.buf); + + fu->bot_req_in = NULL; + fu->bot_req_out = NULL; + fu->cmd.req = NULL; + fu->bot_status.req = NULL; + fu->cmd.buf = NULL; +} + +static void bot_set_alt(struct f_uas *fu) +{ + struct usb_function *f = &fu->function; + struct usb_gadget *gadget = f->config->cdev->gadget; + int ret; + + fu->flags = USBG_IS_BOT; + + config_ep_by_speed(gadget, f, fu->ep_in); + ret = usb_ep_enable(fu->ep_in); + if (ret) + goto err_b_in; + + config_ep_by_speed(gadget, f, fu->ep_out); + ret = usb_ep_enable(fu->ep_out); + if (ret) + goto err_b_out; + + ret = bot_prepare_reqs(fu); + if (ret) + goto err_wq; + fu->flags |= USBG_ENABLED; + pr_info("Using the BOT protocol\n"); + return; +err_wq: + usb_ep_disable(fu->ep_out); +err_b_out: + usb_ep_disable(fu->ep_in); +err_b_in: + fu->flags = USBG_IS_BOT; +} + +static int usbg_bot_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct f_uas *fu = to_f_uas(f); + struct usb_composite_dev *cdev = f->config->cdev; + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + int luns; + u8 *ret_lun; + + switch (ctrl->bRequest) { + case US_BULK_GET_MAX_LUN: + if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_CLASS | + USB_RECIP_INTERFACE)) + return -ENOTSUPP; + + if (w_length < 1) + return -EINVAL; + if (w_value != 0) + return -EINVAL; + luns = atomic_read(&fu->tpg->tpg_port_count); + if (!luns) { + pr_err("No LUNs configured?\n"); + return -EINVAL; + } + /* + * If 4 LUNs are present we return 3 i.e. LUN 0..3 can be + * accessed. The upper limit is 0xf + */ + luns--; + if (luns > 0xf) { + pr_info_once("Limiting the number of luns to 16\n"); + luns = 0xf; + } + ret_lun = cdev->req->buf; + *ret_lun = luns; + cdev->req->length = 1; + return usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC); + break; + + case US_BULK_RESET_REQUEST: + /* XXX maybe we should remove previous requests for IN + OUT */ + bot_enqueue_cmd_cbw(fu); + return 0; + break; + }; + return -ENOTSUPP; +} + +/* Start uas.c code */ + +static void uasp_cleanup_one_stream(struct f_uas *fu, struct uas_stream *stream) +{ + /* We have either all three allocated or none */ + if (!stream->req_in) + return; + + usb_ep_free_request(fu->ep_in, stream->req_in); + usb_ep_free_request(fu->ep_out, stream->req_out); + usb_ep_free_request(fu->ep_status, stream->req_status); + + stream->req_in = NULL; + stream->req_out = NULL; + stream->req_status = NULL; +} + +static void uasp_free_cmdreq(struct f_uas *fu) +{ + usb_ep_free_request(fu->ep_cmd, fu->cmd.req); + kfree(fu->cmd.buf); + fu->cmd.req = NULL; + fu->cmd.buf = NULL; +} + +static void uasp_cleanup_old_alt(struct f_uas *fu) +{ + int i; + + if (!(fu->flags & USBG_ENABLED)) + return; + + usb_ep_disable(fu->ep_in); + usb_ep_disable(fu->ep_out); + usb_ep_disable(fu->ep_status); + usb_ep_disable(fu->ep_cmd); + + for (i = 0; i < UASP_SS_EP_COMP_NUM_STREAMS; i++) + uasp_cleanup_one_stream(fu, &fu->stream[i]); + uasp_free_cmdreq(fu); +} + +static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req); + +static int uasp_prepare_r_request(struct usbg_cmd *cmd) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct f_uas *fu = cmd->fu; + struct usb_gadget *gadget = fuas_to_gadget(fu); + struct uas_stream *stream = cmd->stream; + + if (!gadget->sg_supported) { + cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC); + if (!cmd->data_buf) + return -ENOMEM; + + sg_copy_to_buffer(se_cmd->t_data_sg, + se_cmd->t_data_nents, + cmd->data_buf, + se_cmd->data_length); + + stream->req_in->buf = cmd->data_buf; + } else { + stream->req_in->buf = NULL; + stream->req_in->num_sgs = se_cmd->t_data_nents; + stream->req_in->sg = se_cmd->t_data_sg; + } + + stream->req_in->complete = uasp_status_data_cmpl; + stream->req_in->length = se_cmd->data_length; + stream->req_in->context = cmd; + + cmd->state = UASP_SEND_STATUS; + return 0; +} + +static void uasp_prepare_status(struct usbg_cmd *cmd) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct sense_iu *iu = &cmd->sense_iu; + struct uas_stream *stream = cmd->stream; + + cmd->state = UASP_QUEUE_COMMAND; + iu->iu_id = IU_ID_STATUS; + iu->tag = cpu_to_be16(cmd->tag); + + /* + * iu->status_qual = cpu_to_be16(STATUS QUALIFIER SAM-4. Where R U?); + */ + iu->len = cpu_to_be16(se_cmd->scsi_sense_length); + iu->status = se_cmd->scsi_status; + stream->req_status->context = cmd; + stream->req_status->length = se_cmd->scsi_sense_length + 16; + stream->req_status->buf = iu; + stream->req_status->complete = uasp_status_data_cmpl; +} + +static void uasp_status_data_cmpl(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + struct uas_stream *stream = cmd->stream; + struct f_uas *fu = cmd->fu; + int ret; + + if (req->status < 0) + goto cleanup; + + switch (cmd->state) { + case UASP_SEND_DATA: + ret = uasp_prepare_r_request(cmd); + if (ret) + goto cleanup; + ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC); + if (ret) + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + break; + + case UASP_RECEIVE_DATA: + ret = usbg_prepare_w_request(cmd, stream->req_out); + if (ret) + goto cleanup; + ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC); + if (ret) + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + break; + + case UASP_SEND_STATUS: + uasp_prepare_status(cmd); + ret = usb_ep_queue(fu->ep_status, stream->req_status, + GFP_ATOMIC); + if (ret) + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + break; + + case UASP_QUEUE_COMMAND: + usbg_cleanup_cmd(cmd); + usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC); + break; + + default: + BUG(); + }; + return; + +cleanup: + usbg_cleanup_cmd(cmd); +} + +static int uasp_send_status_response(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct uas_stream *stream = cmd->stream; + struct sense_iu *iu = &cmd->sense_iu; + + iu->tag = cpu_to_be16(cmd->tag); + stream->req_status->complete = uasp_status_data_cmpl; + stream->req_status->context = cmd; + cmd->fu = fu; + uasp_prepare_status(cmd); + return usb_ep_queue(fu->ep_status, stream->req_status, GFP_ATOMIC); +} + +static int uasp_send_read_response(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct uas_stream *stream = cmd->stream; + struct sense_iu *iu = &cmd->sense_iu; + int ret; + + cmd->fu = fu; + + iu->tag = cpu_to_be16(cmd->tag); + if (fu->flags & USBG_USE_STREAMS) { + + ret = uasp_prepare_r_request(cmd); + if (ret) + goto out; + ret = usb_ep_queue(fu->ep_in, stream->req_in, GFP_ATOMIC); + if (ret) { + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + kfree(cmd->data_buf); + cmd->data_buf = NULL; + } + + } else { + + iu->iu_id = IU_ID_READ_READY; + iu->tag = cpu_to_be16(cmd->tag); + + stream->req_status->complete = uasp_status_data_cmpl; + stream->req_status->context = cmd; + + cmd->state = UASP_SEND_DATA; + stream->req_status->buf = iu; + stream->req_status->length = sizeof(struct iu); + + ret = usb_ep_queue(fu->ep_status, stream->req_status, + GFP_ATOMIC); + if (ret) + pr_err("%s(%d) => %d\n", __func__, __LINE__, ret); + } +out: + return ret; +} + +static int uasp_send_write_request(struct usbg_cmd *cmd) +{ + struct f_uas *fu = cmd->fu; + struct se_cmd *se_cmd = &cmd->se_cmd; + struct uas_stream *stream = cmd->stream; + struct sense_iu *iu = &cmd->sense_iu; + int ret; + + init_completion(&cmd->write_complete); + cmd->fu = fu; + + iu->tag = cpu_to_be16(cmd->tag); + + if (fu->flags & USBG_USE_STREAMS) { + + ret = usbg_prepare_w_request(cmd, stream->req_out); + if (ret) + goto cleanup; + ret = usb_ep_queue(fu->ep_out, stream->req_out, GFP_ATOMIC); + if (ret) + pr_err("%s(%d)\n", __func__, __LINE__); + + } else { + + iu->iu_id = IU_ID_WRITE_READY; + iu->tag = cpu_to_be16(cmd->tag); + + stream->req_status->complete = uasp_status_data_cmpl; + stream->req_status->context = cmd; + + cmd->state = UASP_RECEIVE_DATA; + stream->req_status->buf = iu; + stream->req_status->length = sizeof(struct iu); + + ret = usb_ep_queue(fu->ep_status, stream->req_status, + GFP_ATOMIC); + if (ret) + pr_err("%s(%d)\n", __func__, __LINE__); + } + + wait_for_completion(&cmd->write_complete); + transport_generic_process_write(se_cmd); +cleanup: + return ret; +} + +static int usbg_submit_command(struct f_uas *, void *, unsigned int); + +static void uasp_cmd_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_uas *fu = req->context; + int ret; + + if (req->status < 0) + return; + + ret = usbg_submit_command(fu, req->buf, req->actual); + /* + * Once we tune for performance enqueue the command req here again so + * we can receive a second command while we processing this one. Pay + * attention to properly sync STAUS endpoint with DATA IN + OUT so you + * don't break HS. + */ + if (!ret) + return; + usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC); +} + +static int uasp_alloc_stream_res(struct f_uas *fu, struct uas_stream *stream) +{ + stream->req_in = usb_ep_alloc_request(fu->ep_in, GFP_KERNEL); + if (!stream->req_in) + goto out; + + stream->req_out = usb_ep_alloc_request(fu->ep_out, GFP_KERNEL); + if (!stream->req_out) + goto err_out; + + stream->req_status = usb_ep_alloc_request(fu->ep_status, GFP_KERNEL); + if (!stream->req_status) + goto err_sts; + + return 0; +err_sts: + usb_ep_free_request(fu->ep_status, stream->req_status); + stream->req_status = NULL; +err_out: + usb_ep_free_request(fu->ep_out, stream->req_out); + stream->req_out = NULL; +out: + return -ENOMEM; +} + +static int uasp_alloc_cmd(struct f_uas *fu) +{ + fu->cmd.req = usb_ep_alloc_request(fu->ep_cmd, GFP_KERNEL); + if (!fu->cmd.req) + goto err; + + fu->cmd.buf = kmalloc(fu->ep_cmd->maxpacket, GFP_KERNEL); + if (!fu->cmd.buf) + goto err_buf; + + fu->cmd.req->complete = uasp_cmd_complete; + fu->cmd.req->buf = fu->cmd.buf; + fu->cmd.req->length = fu->ep_cmd->maxpacket; + fu->cmd.req->context = fu; + return 0; + +err_buf: + usb_ep_free_request(fu->ep_cmd, fu->cmd.req); +err: + return -ENOMEM; +} + +static void uasp_setup_stream_res(struct f_uas *fu, int max_streams) +{ + int i; + + for (i = 0; i < max_streams; i++) { + struct uas_stream *s = &fu->stream[i]; + + s->req_in->stream_id = i + 1; + s->req_out->stream_id = i + 1; + s->req_status->stream_id = i + 1; + } +} + +static int uasp_prepare_reqs(struct f_uas *fu) +{ + int ret; + int i; + int max_streams; + + if (fu->flags & USBG_USE_STREAMS) + max_streams = UASP_SS_EP_COMP_NUM_STREAMS; + else + max_streams = 1; + + for (i = 0; i < max_streams; i++) { + ret = uasp_alloc_stream_res(fu, &fu->stream[i]); + if (ret) + goto err_cleanup; + } + + ret = uasp_alloc_cmd(fu); + if (ret) + goto err_free_stream; + uasp_setup_stream_res(fu, max_streams); + + ret = usb_ep_queue(fu->ep_cmd, fu->cmd.req, GFP_ATOMIC); + if (ret) + goto err_free_stream; + + return 0; + +err_free_stream: + uasp_free_cmdreq(fu); + +err_cleanup: + if (i) { + do { + uasp_cleanup_one_stream(fu, &fu->stream[i - 1]); + i--; + } while (i); + } + pr_err("UASP: endpoint setup failed\n"); + return ret; +} + +static void uasp_set_alt(struct f_uas *fu) +{ + struct usb_function *f = &fu->function; + struct usb_gadget *gadget = f->config->cdev->gadget; + int ret; + + fu->flags = USBG_IS_UAS; + + if (gadget->speed == USB_SPEED_SUPER) + fu->flags |= USBG_USE_STREAMS; + + config_ep_by_speed(gadget, f, fu->ep_in); + ret = usb_ep_enable(fu->ep_in); + if (ret) + goto err_b_in; + + config_ep_by_speed(gadget, f, fu->ep_out); + ret = usb_ep_enable(fu->ep_out); + if (ret) + goto err_b_out; + + config_ep_by_speed(gadget, f, fu->ep_cmd); + ret = usb_ep_enable(fu->ep_cmd); + if (ret) + goto err_cmd; + config_ep_by_speed(gadget, f, fu->ep_status); + ret = usb_ep_enable(fu->ep_status); + if (ret) + goto err_status; + + ret = uasp_prepare_reqs(fu); + if (ret) + goto err_wq; + fu->flags |= USBG_ENABLED; + + pr_info("Using the UAS protocol\n"); + return; +err_wq: + usb_ep_disable(fu->ep_status); +err_status: + usb_ep_disable(fu->ep_cmd); +err_cmd: + usb_ep_disable(fu->ep_out); +err_b_out: + usb_ep_disable(fu->ep_in); +err_b_in: + fu->flags = 0; +} + +static int get_cmd_dir(const unsigned char *cdb) +{ + int ret; + + switch (cdb[0]) { + case READ_6: + case READ_10: + case READ_12: + case READ_16: + case INQUIRY: + case MODE_SENSE: + case MODE_SENSE_10: + case SERVICE_ACTION_IN: + case MAINTENANCE_IN: + case PERSISTENT_RESERVE_IN: + case SECURITY_PROTOCOL_IN: + case ACCESS_CONTROL_IN: + case REPORT_LUNS: + case READ_BLOCK_LIMITS: + case READ_POSITION: + case READ_CAPACITY: + case READ_TOC: + case READ_FORMAT_CAPACITIES: + case REQUEST_SENSE: + ret = DMA_FROM_DEVICE; + break; + + case WRITE_6: + case WRITE_10: + case WRITE_12: + case WRITE_16: + case MODE_SELECT: + case MODE_SELECT_10: + case WRITE_VERIFY: + case WRITE_VERIFY_12: + case PERSISTENT_RESERVE_OUT: + case MAINTENANCE_OUT: + case SECURITY_PROTOCOL_OUT: + case ACCESS_CONTROL_OUT: + ret = DMA_TO_DEVICE; + break; + case ALLOW_MEDIUM_REMOVAL: + case TEST_UNIT_READY: + case SYNCHRONIZE_CACHE: + case START_STOP: + case ERASE: + case REZERO_UNIT: + case SEEK_10: + case SPACE: + case VERIFY: + case WRITE_FILEMARKS: + ret = DMA_NONE; + break; + default: + pr_warn("target: Unknown data direction for SCSI Opcode " + "0x%02x\n", cdb[0]); + ret = -EINVAL; + } + return ret; +} + +static void usbg_data_write_cmpl(struct usb_ep *ep, struct usb_request *req) +{ + struct usbg_cmd *cmd = req->context; + struct se_cmd *se_cmd = &cmd->se_cmd; + + if (req->status < 0) { + pr_err("%s() state %d transfer failed\n", __func__, cmd->state); + goto cleanup; + } + + if (req->num_sgs == 0) { + sg_copy_from_buffer(se_cmd->t_data_sg, + se_cmd->t_data_nents, + cmd->data_buf, + se_cmd->data_length); + } + + complete(&cmd->write_complete); + return; + +cleanup: + usbg_cleanup_cmd(cmd); +} + +static int usbg_prepare_w_request(struct usbg_cmd *cmd, struct usb_request *req) +{ + struct se_cmd *se_cmd = &cmd->se_cmd; + struct f_uas *fu = cmd->fu; + struct usb_gadget *gadget = fuas_to_gadget(fu); + + if (!gadget->sg_supported) { + cmd->data_buf = kmalloc(se_cmd->data_length, GFP_ATOMIC); + if (!cmd->data_buf) + return -ENOMEM; + + req->buf = cmd->data_buf; + } else { + req->buf = NULL; + req->num_sgs = se_cmd->t_data_nents; + req->sg = se_cmd->t_data_sg; + } + + req->complete = usbg_data_write_cmpl; + req->length = se_cmd->data_length; + req->context = cmd; + return 0; +} + +static int usbg_send_status_response(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + struct f_uas *fu = cmd->fu; + + if (fu->flags & USBG_IS_BOT) + return bot_send_status_response(cmd); + else + return uasp_send_status_response(cmd); +} + +static int usbg_send_write_request(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + struct f_uas *fu = cmd->fu; + + if (fu->flags & USBG_IS_BOT) + return bot_send_write_request(cmd); + else + return uasp_send_write_request(cmd); +} + +static int usbg_send_read_response(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + struct f_uas *fu = cmd->fu; + + if (fu->flags & USBG_IS_BOT) + return bot_send_read_response(cmd); + else + return uasp_send_read_response(cmd); +} + +static void usbg_cmd_work(struct work_struct *work) +{ + struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work); + struct se_cmd *se_cmd; + struct tcm_usbg_nexus *tv_nexus; + struct usbg_tpg *tpg; + int dir; + + se_cmd = &cmd->se_cmd; + tpg = cmd->fu->tpg; + tv_nexus = tpg->tpg_nexus; + dir = get_cmd_dir(cmd->cmd_buf); + if (dir < 0) { + transport_init_se_cmd(se_cmd, + tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, + tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, + cmd->prio_attr, cmd->sense_iu.sense); + + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); + return; + } + + target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, + 0, cmd->prio_attr, dir, TARGET_SCF_UNKNOWN_SIZE); +} + +static int usbg_submit_command(struct f_uas *fu, + void *cmdbuf, unsigned int len) +{ + struct command_iu *cmd_iu = cmdbuf; + struct usbg_cmd *cmd; + struct usbg_tpg *tpg; + struct se_cmd *se_cmd; + struct tcm_usbg_nexus *tv_nexus; + u32 cmd_len; + int ret; + + if (cmd_iu->iu_id != IU_ID_COMMAND) { + pr_err("Unsupported type %d\n", cmd_iu->iu_id); + return -EINVAL; + } + + cmd = kzalloc(sizeof *cmd, GFP_ATOMIC); + if (!cmd) + return -ENOMEM; + + cmd->fu = fu; + + /* XXX until I figure out why I can't free in on complete */ + kref_init(&cmd->ref); + kref_get(&cmd->ref); + + tpg = fu->tpg; + cmd_len = (cmd_iu->len & ~0x3) + 16; + if (cmd_len > USBG_MAX_CMD) + goto err; + + memcpy(cmd->cmd_buf, cmd_iu->cdb, cmd_len); + + cmd->tag = be16_to_cpup(&cmd_iu->tag); + if (fu->flags & USBG_USE_STREAMS) { + if (cmd->tag > UASP_SS_EP_COMP_NUM_STREAMS) + goto err; + if (!cmd->tag) + cmd->stream = &fu->stream[0]; + else + cmd->stream = &fu->stream[cmd->tag - 1]; + } else { + cmd->stream = &fu->stream[0]; + } + + tv_nexus = tpg->tpg_nexus; + if (!tv_nexus) { + pr_err("Missing nexus, ignoring command\n"); + goto err; + } + + switch (cmd_iu->prio_attr & 0x7) { + case UAS_HEAD_TAG: + cmd->prio_attr = MSG_HEAD_TAG; + break; + case UAS_ORDERED_TAG: + cmd->prio_attr = MSG_ORDERED_TAG; + break; + case UAS_ACA: + cmd->prio_attr = MSG_ACA_TAG; + break; + default: + pr_debug_once("Unsupported prio_attr: %02x.\n", + cmd_iu->prio_attr); + case UAS_SIMPLE_TAG: + cmd->prio_attr = MSG_SIMPLE_TAG; + break; + } + + se_cmd = &cmd->se_cmd; + cmd->unpacked_lun = scsilun_to_int(&cmd_iu->lun); + + INIT_WORK(&cmd->work, usbg_cmd_work); + ret = queue_work(tpg->workqueue, &cmd->work); + if (ret < 0) + goto err; + + return 0; +err: + kfree(cmd); + return -EINVAL; +} + +static void bot_cmd_work(struct work_struct *work) +{ + struct usbg_cmd *cmd = container_of(work, struct usbg_cmd, work); + struct se_cmd *se_cmd; + struct tcm_usbg_nexus *tv_nexus; + struct usbg_tpg *tpg; + int dir; + + se_cmd = &cmd->se_cmd; + tpg = cmd->fu->tpg; + tv_nexus = tpg->tpg_nexus; + dir = get_cmd_dir(cmd->cmd_buf); + if (dir < 0) { + transport_init_se_cmd(se_cmd, + tv_nexus->tvn_se_sess->se_tpg->se_tpg_tfo, + tv_nexus->tvn_se_sess, cmd->data_len, DMA_NONE, + cmd->prio_attr, cmd->sense_iu.sense); + + transport_send_check_condition_and_sense(se_cmd, + TCM_UNSUPPORTED_SCSI_OPCODE, 1); + usbg_cleanup_cmd(cmd); + return; + } + + target_submit_cmd(se_cmd, tv_nexus->tvn_se_sess, + cmd->cmd_buf, cmd->sense_iu.sense, cmd->unpacked_lun, + cmd->data_len, cmd->prio_attr, dir, 0); +} + +static int bot_submit_command(struct f_uas *fu, + void *cmdbuf, unsigned int len) +{ + struct bulk_cb_wrap *cbw = cmdbuf; + struct usbg_cmd *cmd; + struct usbg_tpg *tpg; + struct se_cmd *se_cmd; + struct tcm_usbg_nexus *tv_nexus; + u32 cmd_len; + int ret; + + if (cbw->Signature != cpu_to_le32(US_BULK_CB_SIGN)) { + pr_err("Wrong signature on CBW\n"); + return -EINVAL; + } + if (len != 31) { + pr_err("Wrong length for CBW\n"); + return -EINVAL; + } + + cmd_len = cbw->Length; + if (cmd_len < 1 || cmd_len > 16) + return -EINVAL; + + cmd = kzalloc(sizeof *cmd, GFP_ATOMIC); + if (!cmd) + return -ENOMEM; + + cmd->fu = fu; + + /* XXX until I figure out why I can't free in on complete */ + kref_init(&cmd->ref); + kref_get(&cmd->ref); + + tpg = fu->tpg; + + memcpy(cmd->cmd_buf, cbw->CDB, cmd_len); + + cmd->bot_tag = cbw->Tag; + + tv_nexus = tpg->tpg_nexus; + if (!tv_nexus) { + pr_err("Missing nexus, ignoring command\n"); + goto err; + } + + cmd->prio_attr = MSG_SIMPLE_TAG; + se_cmd = &cmd->se_cmd; + cmd->unpacked_lun = cbw->Lun; + cmd->is_read = cbw->Flags & US_BULK_FLAG_IN ? 1 : 0; + cmd->data_len = le32_to_cpu(cbw->DataTransferLength); + + INIT_WORK(&cmd->work, bot_cmd_work); + ret = queue_work(tpg->workqueue, &cmd->work); + if (ret < 0) + goto err; + + return 0; +err: + kfree(cmd); + return -EINVAL; +} + +/* Start fabric.c code */ + +static int usbg_check_true(struct se_portal_group *se_tpg) +{ + return 1; +} + +static int usbg_check_false(struct se_portal_group *se_tpg) +{ + return 0; +} + +static char *usbg_get_fabric_name(void) +{ + return "usb_gadget"; +} + +static u8 usbg_get_fabric_proto_ident(struct se_portal_group *se_tpg) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + u8 proto_id; + + switch (tport->tport_proto_id) { + case SCSI_PROTOCOL_SAS: + default: + proto_id = sas_get_fabric_proto_ident(se_tpg); + break; + } + + return proto_id; +} + +static char *usbg_get_fabric_wwn(struct se_portal_group *se_tpg) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + + return &tport->tport_name[0]; +} + +static u16 usbg_get_tag(struct se_portal_group *se_tpg) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + return tpg->tport_tpgt; +} + +static u32 usbg_get_default_depth(struct se_portal_group *se_tpg) +{ + return 1; +} + +static u32 usbg_get_pr_transport_id( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code, + unsigned char *buf) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + int ret = 0; + + switch (tport->tport_proto_id) { + case SCSI_PROTOCOL_SAS: + default: + ret = sas_get_pr_transport_id(se_tpg, se_nacl, pr_reg, + format_code, buf); + break; + } + + return ret; +} + +static u32 usbg_get_pr_transport_id_len( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl, + struct t10_pr_registration *pr_reg, + int *format_code) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + int ret = 0; + + switch (tport->tport_proto_id) { + case SCSI_PROTOCOL_SAS: + default: + ret = sas_get_pr_transport_id_len(se_tpg, se_nacl, pr_reg, + format_code); + break; + } + + return ret; +} + +static char *usbg_parse_pr_out_transport_id( + struct se_portal_group *se_tpg, + const char *buf, + u32 *out_tid_len, + char **port_nexus_ptr) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + struct usbg_tport *tport = tpg->tport; + char *tid = NULL; + + switch (tport->tport_proto_id) { + case SCSI_PROTOCOL_SAS: + default: + tid = sas_parse_pr_out_transport_id(se_tpg, buf, out_tid_len, + port_nexus_ptr); + } + + return tid; +} + +static struct se_node_acl *usbg_alloc_fabric_acl(struct se_portal_group *se_tpg) +{ + struct usbg_nacl *nacl; + + nacl = kzalloc(sizeof(struct usbg_nacl), GFP_KERNEL); + if (!nacl) { + printk(KERN_ERR "Unable to alocate struct usbg_nacl\n"); + return NULL; + } + + return &nacl->se_node_acl; +} + +static void usbg_release_fabric_acl( + struct se_portal_group *se_tpg, + struct se_node_acl *se_nacl) +{ + struct usbg_nacl *nacl = container_of(se_nacl, + struct usbg_nacl, se_node_acl); + kfree(nacl); +} + +static u32 usbg_tpg_get_inst_index(struct se_portal_group *se_tpg) +{ + return 1; +} + +static int usbg_new_cmd(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + int ret; + + ret = target_setup_cmd_from_cdb(se_cmd, cmd->cmd_buf); + if (ret) + return ret; + + return transport_generic_map_mem_to_cmd(se_cmd, NULL, 0, NULL, 0); +} + +static void usbg_cmd_release(struct kref *ref) +{ + struct usbg_cmd *cmd = container_of(ref, struct usbg_cmd, + ref); + + transport_generic_free_cmd(&cmd->se_cmd, 0); +} + +static void usbg_release_cmd(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + kfree(cmd->data_buf); + kfree(cmd); + return; +} + +static int usbg_shutdown_session(struct se_session *se_sess) +{ + return 0; +} + +static void usbg_close_session(struct se_session *se_sess) +{ + return; +} + +static u32 usbg_sess_get_index(struct se_session *se_sess) +{ + return 0; +} + +/* + * XXX Error recovery: return != 0 if we expect writes. Dunno when that could be + */ +static int usbg_write_pending_status(struct se_cmd *se_cmd) +{ + return 0; +} + +static void usbg_set_default_node_attrs(struct se_node_acl *nacl) +{ + return; +} + +static u32 usbg_get_task_tag(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + struct f_uas *fu = cmd->fu; + + if (fu->flags & USBG_IS_BOT) + return le32_to_cpu(cmd->bot_tag); + else + return cmd->tag; +} + +static int usbg_get_cmd_state(struct se_cmd *se_cmd) +{ + return 0; +} + +static int usbg_queue_tm_rsp(struct se_cmd *se_cmd) +{ + return 0; +} + +static u16 usbg_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length) +{ + return 0; +} + +static u16 usbg_get_fabric_sense_len(void) +{ + return 0; +} + +static const char *usbg_check_wwn(const char *name) +{ + const char *n; + unsigned int len; + + n = strstr(name, "naa."); + if (!n) + return NULL; + n += 4; + len = strlen(n); + if (len == 0 || len > USBG_NAMELEN - 1) + return NULL; + return n; +} + +static struct se_node_acl *usbg_make_nodeacl( + struct se_portal_group *se_tpg, + struct config_group *group, + const char *name) +{ + struct se_node_acl *se_nacl, *se_nacl_new; + struct usbg_nacl *nacl; + u64 wwpn = 0; + u32 nexus_depth; + const char *wnn_name; + + wnn_name = usbg_check_wwn(name); + if (!wnn_name) + return ERR_PTR(-EINVAL); + se_nacl_new = usbg_alloc_fabric_acl(se_tpg); + if (!(se_nacl_new)) + return ERR_PTR(-ENOMEM); + + nexus_depth = 1; + /* + * se_nacl_new may be released by core_tpg_add_initiator_node_acl() + * when converting a NodeACL from demo mode -> explict + */ + se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, + name, nexus_depth); + if (IS_ERR(se_nacl)) { + usbg_release_fabric_acl(se_tpg, se_nacl_new); + return se_nacl; + } + /* + * Locate our struct usbg_nacl and set the FC Nport WWPN + */ + nacl = container_of(se_nacl, struct usbg_nacl, se_node_acl); + nacl->iport_wwpn = wwpn; + snprintf(nacl->iport_name, sizeof(nacl->iport_name), "%s", name); + return se_nacl; +} + +static void usbg_drop_nodeacl(struct se_node_acl *se_acl) +{ + struct usbg_nacl *nacl = container_of(se_acl, + struct usbg_nacl, se_node_acl); + core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1); + kfree(nacl); +} + +struct usbg_tpg *the_only_tpg_I_currently_have; + +static struct se_portal_group *usbg_make_tpg( + struct se_wwn *wwn, + struct config_group *group, + const char *name) +{ + struct usbg_tport *tport = container_of(wwn, struct usbg_tport, + tport_wwn); + struct usbg_tpg *tpg; + unsigned long tpgt; + int ret; + + if (strstr(name, "tpgt_") != name) + return ERR_PTR(-EINVAL); + if (kstrtoul(name + 5, 0, &tpgt) || tpgt > UINT_MAX) + return ERR_PTR(-EINVAL); + if (the_only_tpg_I_currently_have) { + pr_err("Until the gadget framework can't handle multiple\n"); + pr_err("gadgets, you can't do this here.\n"); + return ERR_PTR(-EBUSY); + } + + tpg = kzalloc(sizeof(struct usbg_tpg), GFP_KERNEL); + if (!tpg) { + printk(KERN_ERR "Unable to allocate struct usbg_tpg"); + return ERR_PTR(-ENOMEM); + } + mutex_init(&tpg->tpg_mutex); + atomic_set(&tpg->tpg_port_count, 0); + tpg->workqueue = alloc_workqueue("tcm_usb_gadget", 0, 1); + if (!tpg->workqueue) { + kfree(tpg); + return NULL; + } + + tpg->tport = tport; + tpg->tport_tpgt = tpgt; + + ret = core_tpg_register(&usbg_fabric_configfs->tf_ops, wwn, + &tpg->se_tpg, tpg, + TRANSPORT_TPG_TYPE_NORMAL); + if (ret < 0) { + destroy_workqueue(tpg->workqueue); + kfree(tpg); + return NULL; + } + the_only_tpg_I_currently_have = tpg; + return &tpg->se_tpg; +} + +static void usbg_drop_tpg(struct se_portal_group *se_tpg) +{ + struct usbg_tpg *tpg = container_of(se_tpg, + struct usbg_tpg, se_tpg); + + core_tpg_deregister(se_tpg); + destroy_workqueue(tpg->workqueue); + kfree(tpg); + the_only_tpg_I_currently_have = NULL; +} + +static struct se_wwn *usbg_make_tport( + struct target_fabric_configfs *tf, + struct config_group *group, + const char *name) +{ + struct usbg_tport *tport; + const char *wnn_name; + u64 wwpn = 0; + + wnn_name = usbg_check_wwn(name); + if (!wnn_name) + return ERR_PTR(-EINVAL); + + tport = kzalloc(sizeof(struct usbg_tport), GFP_KERNEL); + if (!(tport)) { + printk(KERN_ERR "Unable to allocate struct usbg_tport"); + return ERR_PTR(-ENOMEM); + } + tport->tport_wwpn = wwpn; + snprintf(tport->tport_name, sizeof(tport->tport_name), wnn_name); + return &tport->tport_wwn; +} + +static void usbg_drop_tport(struct se_wwn *wwn) +{ + struct usbg_tport *tport = container_of(wwn, + struct usbg_tport, tport_wwn); + kfree(tport); +} + +/* + * If somebody feels like dropping the version property, go ahead. + */ +static ssize_t usbg_wwn_show_attr_version( + struct target_fabric_configfs *tf, + char *page) +{ + return sprintf(page, "usb-gadget fabric module\n"); +} +TF_WWN_ATTR_RO(usbg, version); + +static struct configfs_attribute *usbg_wwn_attrs[] = { + &usbg_wwn_version.attr, + NULL, +}; + +static ssize_t tcm_usbg_tpg_show_enable( + struct se_portal_group *se_tpg, + char *page) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + + return snprintf(page, PAGE_SIZE, "%u\n", tpg->gadget_connect); +} + +static int usbg_attach(struct usbg_tpg *); +static void usbg_detach(struct usbg_tpg *); + +static ssize_t tcm_usbg_tpg_store_enable( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + unsigned long op; + ssize_t ret; + + ret = kstrtoul(page, 0, &op); + if (ret < 0) + return -EINVAL; + if (op > 1) + return -EINVAL; + + if (op && tpg->gadget_connect) + goto out; + if (!op && !tpg->gadget_connect) + goto out; + + if (op) { + ret = usbg_attach(tpg); + if (ret) + goto out; + } else { + usbg_detach(tpg); + } + tpg->gadget_connect = op; +out: + return count; +} +TF_TPG_BASE_ATTR(tcm_usbg, enable, S_IRUGO | S_IWUSR); + +static ssize_t tcm_usbg_tpg_show_nexus( + struct se_portal_group *se_tpg, + char *page) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + struct tcm_usbg_nexus *tv_nexus; + ssize_t ret; + + mutex_lock(&tpg->tpg_mutex); + tv_nexus = tpg->tpg_nexus; + if (!tv_nexus) { + ret = -ENODEV; + goto out; + } + ret = snprintf(page, PAGE_SIZE, "%s\n", + tv_nexus->tvn_se_sess->se_node_acl->initiatorname); +out: + mutex_unlock(&tpg->tpg_mutex); + return ret; +} + +static int tcm_usbg_make_nexus(struct usbg_tpg *tpg, char *name) +{ + struct se_portal_group *se_tpg; + struct tcm_usbg_nexus *tv_nexus; + int ret; + + mutex_lock(&tpg->tpg_mutex); + if (tpg->tpg_nexus) { + ret = -EEXIST; + pr_debug("tpg->tpg_nexus already exists\n"); + goto err_unlock; + } + se_tpg = &tpg->se_tpg; + + ret = -ENOMEM; + tv_nexus = kzalloc(sizeof(*tv_nexus), GFP_KERNEL); + if (!tv_nexus) { + pr_err("Unable to allocate struct tcm_vhost_nexus\n"); + goto err_unlock; + } + tv_nexus->tvn_se_sess = transport_init_session(); + if (IS_ERR(tv_nexus->tvn_se_sess)) + goto err_free; + + /* + * Since we are running in 'demo mode' this call with generate a + * struct se_node_acl for the tcm_vhost struct se_portal_group with + * the SCSI Initiator port name of the passed configfs group 'name'. + */ + tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl( + se_tpg, name); + if (!tv_nexus->tvn_se_sess->se_node_acl) { + pr_debug("core_tpg_check_initiator_node_acl() failed" + " for %s\n", name); + goto err_session; + } + /* + * Now register the TCM vHost virtual I_T Nexus as active with the + * call to __transport_register_session() + */ + __transport_register_session(se_tpg, tv_nexus->tvn_se_sess->se_node_acl, + tv_nexus->tvn_se_sess, tv_nexus); + tpg->tpg_nexus = tv_nexus; + mutex_unlock(&tpg->tpg_mutex); + return 0; + +err_session: + transport_free_session(tv_nexus->tvn_se_sess); +err_free: + kfree(tv_nexus); +err_unlock: + mutex_unlock(&tpg->tpg_mutex); + return ret; +} + +static int tcm_usbg_drop_nexus(struct usbg_tpg *tpg) +{ + struct se_session *se_sess; + struct tcm_usbg_nexus *tv_nexus; + int ret = -ENODEV; + + mutex_lock(&tpg->tpg_mutex); + tv_nexus = tpg->tpg_nexus; + if (!tv_nexus) + goto out; + + se_sess = tv_nexus->tvn_se_sess; + if (!se_sess) + goto out; + + if (atomic_read(&tpg->tpg_port_count)) { + ret = -EPERM; + pr_err("Unable to remove Host I_T Nexus with" + " active TPG port count: %d\n", + atomic_read(&tpg->tpg_port_count)); + goto out; + } + + pr_debug("Removing I_T Nexus to Initiator Port: %s\n", + tv_nexus->tvn_se_sess->se_node_acl->initiatorname); + /* + * Release the SCSI I_T Nexus to the emulated vHost Target Port + */ + transport_deregister_session(tv_nexus->tvn_se_sess); + tpg->tpg_nexus = NULL; + + kfree(tv_nexus); +out: + mutex_unlock(&tpg->tpg_mutex); + return 0; +} + +static ssize_t tcm_usbg_tpg_store_nexus( + struct se_portal_group *se_tpg, + const char *page, + size_t count) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + unsigned char i_port[USBG_NAMELEN], *ptr; + int ret; + + if (!strncmp(page, "NULL", 4)) { + ret = tcm_usbg_drop_nexus(tpg); + return (!ret) ? count : ret; + } + if (strlen(page) > USBG_NAMELEN) { + pr_err("Emulated NAA Sas Address: %s, exceeds" + " max: %d\n", page, USBG_NAMELEN); + return -EINVAL; + } + snprintf(i_port, USBG_NAMELEN, "%s", page); + + ptr = strstr(i_port, "naa."); + if (!ptr) { + pr_err("Missing 'naa.' prefix\n"); + return -EINVAL; + } + + if (i_port[strlen(i_port) - 1] == '\n') + i_port[strlen(i_port) - 1] = '\0'; + + ret = tcm_usbg_make_nexus(tpg, &i_port[4]); + if (ret < 0) + return ret; + return count; +} +TF_TPG_BASE_ATTR(tcm_usbg, nexus, S_IRUGO | S_IWUSR); + +static struct configfs_attribute *usbg_base_attrs[] = { + &tcm_usbg_tpg_enable.attr, + &tcm_usbg_tpg_nexus.attr, + NULL, +}; + +static int usbg_port_link(struct se_portal_group *se_tpg, struct se_lun *lun) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + + atomic_inc(&tpg->tpg_port_count); + smp_mb__after_atomic_inc(); + return 0; +} + +static void usbg_port_unlink(struct se_portal_group *se_tpg, + struct se_lun *se_lun) +{ + struct usbg_tpg *tpg = container_of(se_tpg, struct usbg_tpg, se_tpg); + + atomic_dec(&tpg->tpg_port_count); + smp_mb__after_atomic_dec(); +} + +static int usbg_check_stop_free(struct se_cmd *se_cmd) +{ + struct usbg_cmd *cmd = container_of(se_cmd, struct usbg_cmd, + se_cmd); + + kref_put(&cmd->ref, usbg_cmd_release); + return 1; +} + +static struct target_core_fabric_ops usbg_ops = { + .get_fabric_name = usbg_get_fabric_name, + .get_fabric_proto_ident = usbg_get_fabric_proto_ident, + .tpg_get_wwn = usbg_get_fabric_wwn, + .tpg_get_tag = usbg_get_tag, + .tpg_get_default_depth = usbg_get_default_depth, + .tpg_get_pr_transport_id = usbg_get_pr_transport_id, + .tpg_get_pr_transport_id_len = usbg_get_pr_transport_id_len, + .tpg_parse_pr_out_transport_id = usbg_parse_pr_out_transport_id, + .tpg_check_demo_mode = usbg_check_true, + .tpg_check_demo_mode_cache = usbg_check_false, + .tpg_check_demo_mode_write_protect = usbg_check_false, + .tpg_check_prod_mode_write_protect = usbg_check_false, + .tpg_alloc_fabric_acl = usbg_alloc_fabric_acl, + .tpg_release_fabric_acl = usbg_release_fabric_acl, + .tpg_get_inst_index = usbg_tpg_get_inst_index, + .new_cmd_map = usbg_new_cmd, + .release_cmd = usbg_release_cmd, + .shutdown_session = usbg_shutdown_session, + .close_session = usbg_close_session, + .sess_get_index = usbg_sess_get_index, + .sess_get_initiator_sid = NULL, + .write_pending = usbg_send_write_request, + .write_pending_status = usbg_write_pending_status, + .set_default_node_attributes = usbg_set_default_node_attrs, + .get_task_tag = usbg_get_task_tag, + .get_cmd_state = usbg_get_cmd_state, + .queue_data_in = usbg_send_read_response, + .queue_status = usbg_send_status_response, + .queue_tm_rsp = usbg_queue_tm_rsp, + .get_fabric_sense_len = usbg_get_fabric_sense_len, + .set_fabric_sense_len = usbg_set_fabric_sense_len, + .check_stop_free = usbg_check_stop_free, + + .fabric_make_wwn = usbg_make_tport, + .fabric_drop_wwn = usbg_drop_tport, + .fabric_make_tpg = usbg_make_tpg, + .fabric_drop_tpg = usbg_drop_tpg, + .fabric_post_link = usbg_port_link, + .fabric_pre_unlink = usbg_port_unlink, + .fabric_make_np = NULL, + .fabric_drop_np = NULL, + .fabric_make_nodeacl = usbg_make_nodeacl, + .fabric_drop_nodeacl = usbg_drop_nodeacl, +}; + +static int usbg_register_configfs(void) +{ + struct target_fabric_configfs *fabric; + int ret; + + fabric = target_fabric_configfs_init(THIS_MODULE, "usb_gadget"); + if (IS_ERR(fabric)) { + printk(KERN_ERR "target_fabric_configfs_init() failed\n"); + return PTR_ERR(fabric); + } + + fabric->tf_ops = usbg_ops; + TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = usbg_wwn_attrs; + TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = usbg_base_attrs; + TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = NULL; + TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = NULL; + ret = target_fabric_configfs_register(fabric); + if (ret < 0) { + printk(KERN_ERR "target_fabric_configfs_register() failed" + " for usb-gadget\n"); + return ret; + } + usbg_fabric_configfs = fabric; + return 0; +}; + +static void usbg_deregister_configfs(void) +{ + if (!(usbg_fabric_configfs)) + return; + + target_fabric_configfs_deregister(usbg_fabric_configfs); + usbg_fabric_configfs = NULL; +}; + +/* Start gadget.c code */ + +static struct usb_interface_descriptor bot_intf_desc = { + .bLength = sizeof(bot_intf_desc), + .bDescriptorType = USB_DT_INTERFACE, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bAlternateSetting = USB_G_ALT_INT_BBB, + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = USB_SC_SCSI, + .bInterfaceProtocol = USB_PR_BULK, + .iInterface = USB_G_STR_INT_UAS, +}; + +static struct usb_interface_descriptor uasp_intf_desc = { + .bLength = sizeof(uasp_intf_desc), + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 4, + .bAlternateSetting = USB_G_ALT_INT_UAS, + .bInterfaceClass = USB_CLASS_MASS_STORAGE, + .bInterfaceSubClass = USB_SC_SCSI, + .bInterfaceProtocol = USB_PR_UAS, + .iInterface = USB_G_STR_INT_BBB, +}; + +static struct usb_endpoint_descriptor uasp_bi_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor uasp_fs_bi_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_pipe_usage_descriptor uasp_bi_pipe_desc = { + .bLength = sizeof(uasp_bi_pipe_desc), + .bDescriptorType = USB_DT_PIPE_USAGE, + .bPipeID = DATA_IN_PIPE_ID, +}; + +static struct usb_endpoint_descriptor uasp_ss_bi_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor uasp_bi_ep_comp_desc = { + .bLength = sizeof(uasp_bi_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, + .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS, + .wBytesPerInterval = 0, +}; + +static struct usb_ss_ep_comp_descriptor bot_bi_ep_comp_desc = { + .bLength = sizeof(bot_bi_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bMaxBurst = 0, +}; + +static struct usb_endpoint_descriptor uasp_bo_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor uasp_fs_bo_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_pipe_usage_descriptor uasp_bo_pipe_desc = { + .bLength = sizeof(uasp_bo_pipe_desc), + .bDescriptorType = USB_DT_PIPE_USAGE, + .bPipeID = DATA_OUT_PIPE_ID, +}; + +static struct usb_endpoint_descriptor uasp_ss_bo_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(0x400), +}; + +static struct usb_ss_ep_comp_descriptor uasp_bo_ep_comp_desc = { + .bLength = sizeof(uasp_bo_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS, +}; + +static struct usb_ss_ep_comp_descriptor bot_bo_ep_comp_desc = { + .bLength = sizeof(bot_bo_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_endpoint_descriptor uasp_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor uasp_fs_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_pipe_usage_descriptor uasp_status_pipe_desc = { + .bLength = sizeof(uasp_status_pipe_desc), + .bDescriptorType = USB_DT_PIPE_USAGE, + .bPipeID = STATUS_PIPE_ID, +}; + +static struct usb_endpoint_descriptor uasp_ss_status_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor uasp_status_in_ep_comp_desc = { + .bLength = sizeof(uasp_status_in_ep_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, + .bmAttributes = UASP_SS_EP_COMP_LOG_STREAMS, +}; + +static struct usb_endpoint_descriptor uasp_cmd_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor uasp_fs_cmd_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_pipe_usage_descriptor uasp_cmd_pipe_desc = { + .bLength = sizeof(uasp_cmd_pipe_desc), + .bDescriptorType = USB_DT_PIPE_USAGE, + .bPipeID = CMD_PIPE_ID, +}; + +static struct usb_endpoint_descriptor uasp_ss_cmd_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = cpu_to_le16(1024), +}; + +static struct usb_ss_ep_comp_descriptor uasp_cmd_comp_desc = { + .bLength = sizeof(uasp_cmd_comp_desc), + .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, +}; + +static struct usb_descriptor_header *uasp_fs_function_desc[] = { + (struct usb_descriptor_header *) &bot_intf_desc, + (struct usb_descriptor_header *) &uasp_fs_bi_desc, + (struct usb_descriptor_header *) &uasp_fs_bo_desc, + + (struct usb_descriptor_header *) &uasp_intf_desc, + (struct usb_descriptor_header *) &uasp_fs_bi_desc, + (struct usb_descriptor_header *) &uasp_bi_pipe_desc, + (struct usb_descriptor_header *) &uasp_fs_bo_desc, + (struct usb_descriptor_header *) &uasp_bo_pipe_desc, + (struct usb_descriptor_header *) &uasp_fs_status_desc, + (struct usb_descriptor_header *) &uasp_status_pipe_desc, + (struct usb_descriptor_header *) &uasp_fs_cmd_desc, + (struct usb_descriptor_header *) &uasp_cmd_pipe_desc, +}; + +static struct usb_descriptor_header *uasp_hs_function_desc[] = { + (struct usb_descriptor_header *) &bot_intf_desc, + (struct usb_descriptor_header *) &uasp_bi_desc, + (struct usb_descriptor_header *) &uasp_bo_desc, + + (struct usb_descriptor_header *) &uasp_intf_desc, + (struct usb_descriptor_header *) &uasp_bi_desc, + (struct usb_descriptor_header *) &uasp_bi_pipe_desc, + (struct usb_descriptor_header *) &uasp_bo_desc, + (struct usb_descriptor_header *) &uasp_bo_pipe_desc, + (struct usb_descriptor_header *) &uasp_status_desc, + (struct usb_descriptor_header *) &uasp_status_pipe_desc, + (struct usb_descriptor_header *) &uasp_cmd_desc, + (struct usb_descriptor_header *) &uasp_cmd_pipe_desc, + NULL, +}; + +static struct usb_descriptor_header *uasp_ss_function_desc[] = { + (struct usb_descriptor_header *) &bot_intf_desc, + (struct usb_descriptor_header *) &uasp_ss_bi_desc, + (struct usb_descriptor_header *) &bot_bi_ep_comp_desc, + (struct usb_descriptor_header *) &uasp_ss_bo_desc, + (struct usb_descriptor_header *) &bot_bo_ep_comp_desc, + + (struct usb_descriptor_header *) &uasp_intf_desc, + (struct usb_descriptor_header *) &uasp_ss_bi_desc, + (struct usb_descriptor_header *) &uasp_bi_ep_comp_desc, + (struct usb_descriptor_header *) &uasp_bi_pipe_desc, + (struct usb_descriptor_header *) &uasp_ss_bo_desc, + (struct usb_descriptor_header *) &uasp_bo_ep_comp_desc, + (struct usb_descriptor_header *) &uasp_bo_pipe_desc, + (struct usb_descriptor_header *) &uasp_ss_status_desc, + (struct usb_descriptor_header *) &uasp_status_in_ep_comp_desc, + (struct usb_descriptor_header *) &uasp_status_pipe_desc, + (struct usb_descriptor_header *) &uasp_ss_cmd_desc, + (struct usb_descriptor_header *) &uasp_cmd_comp_desc, + (struct usb_descriptor_header *) &uasp_cmd_pipe_desc, + NULL, +}; + +#define UAS_VENDOR_ID 0x0525 /* NetChip */ +#define UAS_PRODUCT_ID 0xa4a5 /* Linux-USB File-backed Storage Gadget */ + +static struct usb_device_descriptor usbg_device_desc = { + .bLength = sizeof(usbg_device_desc), + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = cpu_to_le16(0x0200), + .bDeviceClass = USB_CLASS_PER_INTERFACE, + .idVendor = cpu_to_le16(UAS_VENDOR_ID), + .idProduct = cpu_to_le16(UAS_PRODUCT_ID), + .iManufacturer = USB_G_STR_MANUFACTOR, + .iProduct = USB_G_STR_PRODUCT, + .iSerialNumber = USB_G_STR_SERIAL, + + .bNumConfigurations = 1, +}; + +static struct usb_string usbg_us_strings[] = { + { USB_G_STR_MANUFACTOR, "Target Manufactor"}, + { USB_G_STR_PRODUCT, "Target Product"}, + { USB_G_STR_SERIAL, "000000000001"}, + { USB_G_STR_CONFIG, "default config"}, + { USB_G_STR_INT_UAS, "USB Attached SCSI"}, + { USB_G_STR_INT_BBB, "Bulk Only Transport"}, + { }, +}; + +static struct usb_gadget_strings usbg_stringtab = { + .language = 0x0409, + .strings = usbg_us_strings, +}; + +static struct usb_gadget_strings *usbg_strings[] = { + &usbg_stringtab, + NULL, +}; + +static int guas_unbind(struct usb_composite_dev *cdev) +{ + return 0; +} + +static struct usb_configuration usbg_config_driver = { + .label = "Linux Target", + .bConfigurationValue = 1, + .iConfiguration = USB_G_STR_CONFIG, + .bmAttributes = USB_CONFIG_ATT_SELFPOWER, +}; + +static void give_back_ep(struct usb_ep **pep) +{ + struct usb_ep *ep = *pep; + if (!ep) + return; + ep->driver_data = NULL; +} + +static int usbg_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_uas *fu = to_f_uas(f); + struct usb_gadget *gadget = c->cdev->gadget; + struct usb_ep *ep; + int iface; + + iface = usb_interface_id(c, f); + if (iface < 0) + return iface; + + bot_intf_desc.bInterfaceNumber = iface; + uasp_intf_desc.bInterfaceNumber = iface; + fu->iface = iface; + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bi_desc, + &uasp_bi_ep_comp_desc); + if (!ep) + goto ep_fail; + + ep->driver_data = fu; + fu->ep_in = ep; + + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_bo_desc, + &uasp_bo_ep_comp_desc); + if (!ep) + goto ep_fail; + ep->driver_data = fu; + fu->ep_out = ep; + + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_status_desc, + &uasp_status_in_ep_comp_desc); + if (!ep) + goto ep_fail; + ep->driver_data = fu; + fu->ep_status = ep; + + ep = usb_ep_autoconfig_ss(gadget, &uasp_ss_cmd_desc, + &uasp_cmd_comp_desc); + if (!ep) + goto ep_fail; + ep->driver_data = fu; + fu->ep_cmd = ep; + + /* Assume endpoint addresses are the same for both speeds */ + uasp_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress; + uasp_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress; + uasp_status_desc.bEndpointAddress = + uasp_ss_status_desc.bEndpointAddress; + uasp_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; + + uasp_fs_bi_desc.bEndpointAddress = uasp_ss_bi_desc.bEndpointAddress; + uasp_fs_bo_desc.bEndpointAddress = uasp_ss_bo_desc.bEndpointAddress; + uasp_fs_status_desc.bEndpointAddress = + uasp_ss_status_desc.bEndpointAddress; + uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress; + + return 0; +ep_fail: + pr_err("Can't claim all required eps\n"); + + give_back_ep(&fu->ep_in); + give_back_ep(&fu->ep_out); + give_back_ep(&fu->ep_status); + give_back_ep(&fu->ep_cmd); + return -ENOTSUPP; +} + +static void usbg_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_uas *fu = to_f_uas(f); + + kfree(fu); +} + +struct guas_setup_wq { + struct work_struct work; + struct f_uas *fu; + unsigned int alt; +}; + +static void usbg_delayed_set_alt(struct work_struct *wq) +{ + struct guas_setup_wq *work = container_of(wq, struct guas_setup_wq, + work); + struct f_uas *fu = work->fu; + int alt = work->alt; + + kfree(work); + + if (fu->flags & USBG_IS_BOT) + bot_cleanup_old_alt(fu); + if (fu->flags & USBG_IS_UAS) + uasp_cleanup_old_alt(fu); + + if (alt == USB_G_ALT_INT_BBB) + bot_set_alt(fu); + else if (alt == USB_G_ALT_INT_UAS) + uasp_set_alt(fu); + usb_composite_setup_continue(fu->function.config->cdev); +} + +static int usbg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) +{ + struct f_uas *fu = to_f_uas(f); + + if ((alt == USB_G_ALT_INT_BBB) || (alt == USB_G_ALT_INT_UAS)) { + struct guas_setup_wq *work; + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (!work) + return -ENOMEM; + INIT_WORK(&work->work, usbg_delayed_set_alt); + work->fu = fu; + work->alt = alt; + schedule_work(&work->work); + return USB_GADGET_DELAYED_STATUS; + } + return -EOPNOTSUPP; +} + +static void usbg_disable(struct usb_function *f) +{ + struct f_uas *fu = to_f_uas(f); + + if (fu->flags & USBG_IS_UAS) + uasp_cleanup_old_alt(fu); + else if (fu->flags & USBG_IS_BOT) + bot_cleanup_old_alt(fu); + fu->flags = 0; +} + +static int usbg_setup(struct usb_function *f, + const struct usb_ctrlrequest *ctrl) +{ + struct f_uas *fu = to_f_uas(f); + + if (!(fu->flags & USBG_IS_BOT)) + return -EOPNOTSUPP; + + return usbg_bot_setup(f, ctrl); +} + +static int usbg_cfg_bind(struct usb_configuration *c) +{ + struct f_uas *fu; + int ret; + + fu = kzalloc(sizeof(*fu), GFP_KERNEL); + if (!fu) + return -ENOMEM; + fu->function.name = "Target Function"; + fu->function.descriptors = uasp_fs_function_desc; + fu->function.hs_descriptors = uasp_hs_function_desc; + fu->function.ss_descriptors = uasp_ss_function_desc; + fu->function.bind = usbg_bind; + fu->function.unbind = usbg_unbind; + fu->function.set_alt = usbg_set_alt; + fu->function.setup = usbg_setup; + fu->function.disable = usbg_disable; + fu->tpg = the_only_tpg_I_currently_have; + + ret = usb_add_function(c, &fu->function); + if (ret) + goto err; + + return 0; +err: + kfree(fu); + return ret; +} + +static int usb_target_bind(struct usb_composite_dev *cdev) +{ + int ret; + + ret = usb_add_config(cdev, &usbg_config_driver, + usbg_cfg_bind); + return 0; +} + +static struct usb_composite_driver usbg_driver = { + .name = "g_target", + .dev = &usbg_device_desc, + .strings = usbg_strings, + .max_speed = USB_SPEED_SUPER, + .unbind = guas_unbind, +}; + +static int usbg_attach(struct usbg_tpg *tpg) +{ + return usb_composite_probe(&usbg_driver, usb_target_bind); +} + +static void usbg_detach(struct usbg_tpg *tpg) +{ + usb_composite_unregister(&usbg_driver); +} + +static int __init usb_target_gadget_init(void) +{ + int ret; + + ret = usbg_register_configfs(); + return ret; +} +module_init(usb_target_gadget_init); + +static void __exit usb_target_gadget_exit(void) +{ + usbg_deregister_configfs(); +} +module_exit(usb_target_gadget_exit); + +MODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>"); +MODULE_DESCRIPTION("usb-gadget fabric"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/gadget/tcm_usb_gadget.h b/drivers/usb/gadget/tcm_usb_gadget.h new file mode 100644 index 000000000000..bb18999a9a8d --- /dev/null +++ b/drivers/usb/gadget/tcm_usb_gadget.h @@ -0,0 +1,146 @@ +#ifndef __TARGET_USB_GADGET_H__ +#define __TARGET_USB_GADGET_H__ + +#include <linux/kref.h> +/* #include <linux/usb/uas.h> */ +#include <linux/usb/composite.h> +#include <linux/usb/uas.h> +#include <linux/usb/storage.h> +#include <scsi/scsi.h> +#include <target/target_core_base.h> +#include <target/target_core_fabric.h> + +#define USBG_NAMELEN 32 + +#define fuas_to_gadget(f) (f->function.config->cdev->gadget) +#define UASP_SS_EP_COMP_LOG_STREAMS 4 +#define UASP_SS_EP_COMP_NUM_STREAMS (1 << UASP_SS_EP_COMP_LOG_STREAMS) + +#define USB_G_STR_MANUFACTOR 1 +#define USB_G_STR_PRODUCT 2 +#define USB_G_STR_SERIAL 3 +#define USB_G_STR_CONFIG 4 +#define USB_G_STR_INT_UAS 5 +#define USB_G_STR_INT_BBB 6 + +#define USB_G_ALT_INT_BBB 0 +#define USB_G_ALT_INT_UAS 1 + +struct usbg_nacl { + /* Binary World Wide unique Port Name for SAS Initiator port */ + u64 iport_wwpn; + /* ASCII formatted WWPN for Sas Initiator port */ + char iport_name[USBG_NAMELEN]; + /* Returned by usbg_make_nodeacl() */ + struct se_node_acl se_node_acl; +}; + +struct tcm_usbg_nexus { + struct se_session *tvn_se_sess; +}; + +struct usbg_tpg { + struct mutex tpg_mutex; + /* SAS port target portal group tag for TCM */ + u16 tport_tpgt; + /* Pointer back to usbg_tport */ + struct usbg_tport *tport; + struct workqueue_struct *workqueue; + /* Returned by usbg_make_tpg() */ + struct se_portal_group se_tpg; + u32 gadget_connect; + struct tcm_usbg_nexus *tpg_nexus; + atomic_t tpg_port_count; +}; + +struct usbg_tport { + /* SCSI protocol the tport is providing */ + u8 tport_proto_id; + /* Binary World Wide unique Port Name for SAS Target port */ + u64 tport_wwpn; + /* ASCII formatted WWPN for SAS Target port */ + char tport_name[USBG_NAMELEN]; + /* Returned by usbg_make_tport() */ + struct se_wwn tport_wwn; +}; + +enum uas_state { + UASP_SEND_DATA, + UASP_RECEIVE_DATA, + UASP_SEND_STATUS, + UASP_QUEUE_COMMAND, +}; + +#define USBG_MAX_CMD 64 +struct usbg_cmd { + /* common */ + u8 cmd_buf[USBG_MAX_CMD]; + u32 data_len; + struct work_struct work; + int unpacked_lun; + struct se_cmd se_cmd; + void *data_buf; /* used if no sg support available */ + struct f_uas *fu; + struct completion write_complete; + struct kref ref; + + /* UAS only */ + u16 tag; + u16 prio_attr; + struct sense_iu sense_iu; + enum uas_state state; + struct uas_stream *stream; + + /* BOT only */ + __le32 bot_tag; + unsigned int csw_code; + unsigned is_read:1; + +}; + +struct uas_stream { + struct usb_request *req_in; + struct usb_request *req_out; + struct usb_request *req_status; +}; + +struct usbg_cdb { + struct usb_request *req; + void *buf; +}; + +struct bot_status { + struct usb_request *req; + struct bulk_cs_wrap csw; +}; + +struct f_uas { + struct usbg_tpg *tpg; + struct usb_function function; + u16 iface; + + u32 flags; +#define USBG_ENABLED (1 << 0) +#define USBG_IS_UAS (1 << 1) +#define USBG_USE_STREAMS (1 << 2) +#define USBG_IS_BOT (1 << 3) +#define USBG_BOT_CMD_PEND (1 << 4) + + struct usbg_cdb cmd; + struct usb_ep *ep_in; + struct usb_ep *ep_out; + + /* UAS */ + struct usb_ep *ep_status; + struct usb_ep *ep_cmd; + struct uas_stream stream[UASP_SS_EP_COMP_NUM_STREAMS]; + + /* BOT */ + struct bot_status bot_status; + struct usb_request *bot_req_in; + struct usb_request *bot_req_out; +}; + +extern struct usbg_tpg *the_only_tpg_I_currently_have; + +#endif diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 29c854bbca44..47cf48b51c9d 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -744,10 +744,11 @@ static struct device_type gadget_type = { }; /** - * gether_setup - initialize one ethernet-over-usb link + * gether_setup_name - initialize one ethernet-over-usb link * @g: gadget to associated with these links * @ethaddr: NULL, or a buffer in which the ethernet address of the * host side of the link is recorded + * @netname: name for network device (for example, "usb") * Context: may sleep * * This sets up the single network link that may be exported by a @@ -756,7 +757,8 @@ static struct device_type gadget_type = { * * Returns negative errno, or zero on success */ -int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) +int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], + const char *netname) { struct eth_dev *dev; struct net_device *net; @@ -780,7 +782,7 @@ int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) /* network device setup */ dev->net = net; - strcpy(net->name, "usb%d"); + snprintf(net->name, sizeof(net->name), "%s%%d", netname); if (get_ether_addr(dev_addr, net->dev_addr)) dev_warn(&g->dev, diff --git a/drivers/usb/gadget/u_ether.h b/drivers/usb/gadget/u_ether.h index 8012357e98aa..6f4a1623d854 100644 --- a/drivers/usb/gadget/u_ether.h +++ b/drivers/usb/gadget/u_ether.h @@ -69,9 +69,28 @@ struct gether { |USB_CDC_PACKET_TYPE_PROMISCUOUS \ |USB_CDC_PACKET_TYPE_DIRECTED) +/* variant of gether_setup that allows customizing network device name */ +int gether_setup_name(struct usb_gadget *g, u8 ethaddr[ETH_ALEN], + const char *netname); /* netdev setup/teardown as directed by the gadget driver */ -int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]); +/* gether_setup - initialize one ethernet-over-usb link + * @g: gadget to associated with these links + * @ethaddr: NULL, or a buffer in which the ethernet address of the + * host side of the link is recorded + * Context: may sleep + * + * This sets up the single network link that may be exported by a + * gadget driver using this framework. The link layer addresses are + * set up using module parameters. + * + * Returns negative errno, or zero on success + */ +static inline int gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) +{ + return gether_setup_name(g, ethaddr, "usb"); +} + void gether_cleanup(void); /* connect/disconnect is handled by individual functions */ @@ -99,16 +118,37 @@ int eem_bind_config(struct usb_configuration *c); #ifdef USB_ETH_RNDIS -int rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]); +int rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer); #else static inline int -rndis_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN]) +rndis_bind_config_vendor(struct usb_configuration *c, u8 ethaddr[ETH_ALEN], + u32 vendorID, const char *manufacturer) { return 0; } #endif +/** + * rndis_bind_config - add RNDIS network link to a configuration + * @c: the configuration to support the network link + * @ethaddr: a buffer in which the ethernet address of the host side + * side of the link was recorded + * Context: single threaded during gadget setup + * + * Returns zero on success, else negative errno. + * + * Caller must have called @gether_setup(). Caller is also responsible + * for calling @gether_cleanup() before module unload. + */ +static inline int rndis_bind_config(struct usb_configuration *c, + u8 ethaddr[ETH_ALEN]) +{ + return rndis_bind_config_vendor(c, ethaddr, 0, NULL); +} + + #endif /* __U_ETHER_H */ diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c index 6c23938d2711..15a42c8c1943 100644 --- a/drivers/usb/gadget/u_serial.c +++ b/drivers/usb/gadget/u_serial.c @@ -94,17 +94,14 @@ struct gs_buf { * (and thus for each /dev/ node). */ struct gs_port { + struct tty_port port; spinlock_t port_lock; /* guard port_* access */ struct gserial *port_usb; - struct tty_struct *port_tty; - unsigned open_count; bool openclose; /* open/close in progress */ u8 port_num; - wait_queue_head_t close_wait; /* wait for last close */ - struct list_head read_pool; int read_started; int read_allocated; @@ -412,8 +409,8 @@ __acquires(&port->port_lock) break; } - if (do_tty_wake && port->port_tty) - tty_wakeup(port->port_tty); + if (do_tty_wake && port->port.tty) + tty_wakeup(port->port.tty); return status; } @@ -435,7 +432,7 @@ __acquires(&port->port_lock) struct tty_struct *tty; /* no more rx if closed */ - tty = port->port_tty; + tty = port->port.tty; if (!tty) break; @@ -488,7 +485,7 @@ static void gs_rx_push(unsigned long _port) /* hand any queued data to the tty */ spin_lock_irq(&port->port_lock); - tty = port->port_tty; + tty = port->port.tty; while (!list_empty(queue)) { struct usb_request *req; @@ -699,7 +696,7 @@ static int gs_start_io(struct gs_port *port) /* unblock any pending writes into our circular buffer */ if (started) { - tty_wakeup(port->port_tty); + tty_wakeup(port->port.tty); } else { gs_free_requests(ep, head, &port->read_allocated); gs_free_requests(port->port_usb->in, &port->write_pool, @@ -734,9 +731,9 @@ static int gs_open(struct tty_struct *tty, struct file *file) spin_lock_irq(&port->port_lock); /* already open? Great. */ - if (port->open_count) { + if (port->port.count) { status = 0; - port->open_count++; + port->port.count++; /* currently opening/closing? wait ... */ } else if (port->openclose) { @@ -793,9 +790,9 @@ static int gs_open(struct tty_struct *tty, struct file *file) /* REVISIT maybe wait for "carrier detect" */ tty->driver_data = port; - port->port_tty = tty; + port->port.tty = tty; - port->open_count = 1; + port->port.count = 1; port->openclose = false; /* if connected, start the I/O stream */ @@ -837,11 +834,11 @@ static void gs_close(struct tty_struct *tty, struct file *file) spin_lock_irq(&port->port_lock); - if (port->open_count != 1) { - if (port->open_count == 0) + if (port->port.count != 1) { + if (port->port.count == 0) WARN_ON(1); else - --port->open_count; + --port->port.count; goto exit; } @@ -851,7 +848,7 @@ static void gs_close(struct tty_struct *tty, struct file *file) * and sleep if necessary */ port->openclose = true; - port->open_count = 0; + port->port.count = 0; gser = port->port_usb; if (gser && gser->disconnect) @@ -879,14 +876,14 @@ static void gs_close(struct tty_struct *tty, struct file *file) gs_buf_clear(&port->port_write_buf); tty->driver_data = NULL; - port->port_tty = NULL; + port->port.tty = NULL; port->openclose = false; pr_debug("gs_close: ttyGS%d (%p,%p) done!\n", port->port_num, tty, file); - wake_up_interruptible(&port->close_wait); + wake_up_interruptible(&port->port.close_wait); exit: spin_unlock_irq(&port->port_lock); } @@ -1025,7 +1022,7 @@ static const struct tty_operations gs_tty_ops = { static struct tty_driver *gs_tty_driver; -static int __init +static int gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) { struct gs_port *port; @@ -1034,8 +1031,8 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) if (port == NULL) return -ENOMEM; + tty_port_init(&port->port); spin_lock_init(&port->port_lock); - init_waitqueue_head(&port->close_wait); init_waitqueue_head(&port->drain_wait); tasklet_init(&port->push, gs_rx_push, (unsigned long) port); @@ -1071,7 +1068,7 @@ gs_port_alloc(unsigned port_num, struct usb_cdc_line_coding *coding) * * Returns negative errno or zero. */ -int __init gserial_setup(struct usb_gadget *g, unsigned count) +int gserial_setup(struct usb_gadget *g, unsigned count) { unsigned i; struct usb_cdc_line_coding coding; @@ -1155,7 +1152,7 @@ static int gs_closed(struct gs_port *port) int cond; spin_lock_irq(&port->port_lock); - cond = (port->open_count == 0) && !port->openclose; + cond = (port->port.count == 0) && !port->openclose; spin_unlock_irq(&port->port_lock); return cond; } @@ -1194,7 +1191,7 @@ void gserial_cleanup(void) tasklet_kill(&port->push); /* wait for old opens to finish */ - wait_event(port->close_wait, gs_closed(port)); + wait_event(port->port.close_wait, gs_closed(port)); WARN_ON(port->port_usb != NULL); @@ -1268,7 +1265,7 @@ int gserial_connect(struct gserial *gser, u8 port_num) /* if it's already open, start I/O ... and notify the serial * protocol about open/close status (connect/disconnect). */ - if (port->open_count) { + if (port->port.count) { pr_debug("gserial_connect: start ttyGS%d\n", port->port_num); gs_start_io(port); if (gser->connect) @@ -1315,10 +1312,10 @@ void gserial_disconnect(struct gserial *gser) port->port_usb = NULL; gser->ioport = NULL; - if (port->open_count > 0 || port->openclose) { + if (port->port.count > 0 || port->openclose) { wake_up_interruptible(&port->drain_wait); - if (port->port_tty) - tty_hangup(port->port_tty); + if (port->port.tty) + tty_hangup(port->port.tty); } spin_unlock_irqrestore(&port->port_lock, flags); @@ -1331,7 +1328,7 @@ void gserial_disconnect(struct gserial *gser) /* finally, free any unused/unusable I/O buffers */ spin_lock_irqsave(&port->port_lock, flags); - if (port->open_count == 0 && !port->openclose) + if (port->port.count == 0 && !port->openclose) gs_buf_free(&port->port_write_buf); gs_free_requests(gser->out, &port->read_pool, NULL); gs_free_requests(gser->out, &port->read_queue, NULL); diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c index 31d34832907e..12ad516ada77 100644 --- a/drivers/usb/gadget/zero.c +++ b/drivers/usb/gadget/zero.c @@ -72,7 +72,7 @@ static const char longname[] = "Gadget Zero"; -unsigned buflen = 4096; +unsigned buflen = 4096; /* only used for bulk endpoints */ module_param(buflen, uint, 0); /* @@ -170,14 +170,17 @@ static struct usb_gadget_strings *dev_strings[] = { /*-------------------------------------------------------------------------*/ -struct usb_request *alloc_ep_req(struct usb_ep *ep) +struct usb_request *alloc_ep_req(struct usb_ep *ep, int len) { struct usb_request *req; req = usb_ep_alloc_request(ep, GFP_ATOMIC); if (req) { - req->length = buflen; - req->buf = kmalloc(buflen, GFP_ATOMIC); + if (len) + req->length = len; + else + req->length = buflen; + req->buf = kmalloc(req->length, GFP_ATOMIC); if (!req->buf) { usb_ep_free_request(ep, req); req = NULL; @@ -206,10 +209,15 @@ static void disable_ep(struct usb_composite_dev *cdev, struct usb_ep *ep) } void disable_endpoints(struct usb_composite_dev *cdev, - struct usb_ep *in, struct usb_ep *out) + struct usb_ep *in, struct usb_ep *out, + struct usb_ep *iso_in, struct usb_ep *iso_out) { disable_ep(cdev, in); disable_ep(cdev, out); + if (iso_in) + disable_ep(cdev, iso_in); + if (iso_out) + disable_ep(cdev, iso_out); } /*-------------------------------------------------------------------------*/ @@ -311,7 +319,6 @@ static int __init zero_bind(struct usb_composite_dev *cdev) device_desc.bcdDevice = cpu_to_le16(0x9999); } - INFO(cdev, "%s, version: " DRIVER_VERSION "\n", longname); snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index f788eb86707c..74a14f6ed34c 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -65,7 +65,7 @@ config USB_EHCI_HCD config USB_EHCI_ROOT_HUB_TT bool "Root Hub Transaction Translators" - depends on USB_EHCI_HCD + depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST ---help--- Some EHCI chips have vendor-specific extensions to integrate transaction translators, so that no OHCI or UHCI companion @@ -77,7 +77,7 @@ config USB_EHCI_ROOT_HUB_TT config USB_EHCI_TT_NEWSCHED bool "Improved Transaction Translator scheduling" - depends on USB_EHCI_HCD + depends on USB_EHCI_HCD || USB_CHIPIDEA_HOST default y ---help--- This changes the periodic scheduling code to fill more of the low @@ -110,13 +110,14 @@ config USB_EHCI_BIG_ENDIAN_MMIO depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX || \ ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ PPC_MPC512x || CPU_CAVIUM_OCTEON || \ - PMC_MSP || SPARC_LEON) + PMC_MSP || SPARC_LEON || MIPS_SEAD3) default y config USB_EHCI_BIG_ENDIAN_DESC bool depends on USB_EHCI_HCD && (440EPX || ARCH_IXP4XX || XPS_USB_HCD_XILINX || \ - PPC_MPC512x || PMC_MSP || SPARC_LEON) + PPC_MPC512x || PMC_MSP || SPARC_LEON || \ + MIPS_SEAD3) default y config XPS_USB_HCD_XILINX @@ -291,6 +292,7 @@ config USB_OHCI_HCD depends on USB && USB_ARCH_HAS_OHCI select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 select USB_OTG_UTILS if ARCH_OMAP + select USB_ISP1301 if ARCH_LPC32XX || ARCH_PNX4008 ---help--- The Open Host Controller Interface (OHCI) is a standard for accessing USB 1.1 host controller hardware. It does more in hardware than Intel's @@ -373,10 +375,15 @@ config USB_OHCI_HCD_PCI If unsure, say Y. config USB_OHCI_HCD_SSB - bool "OHCI support for Broadcom SSB OHCI core" + bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)" depends on USB_OHCI_HCD && (SSB = y || SSB = USB_OHCI_HCD) && EXPERIMENTAL + select USB_HCD_SSB + select USB_OHCI_HCD_PLATFORM default n ---help--- + This option is deprecated now and the driver was removed, use + USB_HCD_SSB and USB_OHCI_HCD_PLATFORM instead. + Support for the Sonics Silicon Backplane (SSB) attached Broadcom USB OHCI core. @@ -638,3 +645,27 @@ config USB_OCTEON_OHCI config USB_OCTEON2_COMMON bool default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI + +config USB_HCD_BCMA + tristate "BCMA usb host driver" + depends on BCMA && EXPERIMENTAL + select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD + select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD + help + Enbale support for the EHCI and OCHI host controller on an bcma bus. + It converts the bcma driver into two platform device drivers + for ehci and ohci. + + If unsure, say N. + +config USB_HCD_SSB + tristate "SSB usb host driver" + depends on SSB && EXPERIMENTAL + select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD + select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD + help + Enbale support for the EHCI and OCHI host controller on an bcma bus. + It converts the bcma driver into two platform device drivers + for ehci and ohci. + + If unsure, say N. diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 0982bcc140bd..9e0a89ced15c 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -41,3 +41,5 @@ obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o obj-$(CONFIG_USB_OCTEON2_COMMON) += octeon2-common.o obj-$(CONFIG_MIPS_ALCHEMY) += alchemy-common.o +obj-$(CONFIG_USB_HCD_BCMA) += bcma-hcd.o +obj-$(CONFIG_USB_HCD_SSB) += ssb-hcd.o diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c new file mode 100644 index 000000000000..443da21d73ca --- /dev/null +++ b/drivers/usb/host/bcma-hcd.c @@ -0,0 +1,335 @@ +/* + * Broadcom specific Advanced Microcontroller Bus + * Broadcom USB-core driver (BCMA bus glue) + * + * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de> + * + * Based on ssb-ohci driver + * Copyright 2007 Michael Buesch <m@bues.ch> + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005-2011 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include <linux/bcma/bcma.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb/ehci_pdriver.h> +#include <linux/usb/ohci_pdriver.h> + +MODULE_AUTHOR("Hauke Mehrtens"); +MODULE_DESCRIPTION("Common USB driver for BCMA Bus"); +MODULE_LICENSE("GPL"); + +struct bcma_hcd_device { + struct platform_device *ehci_dev; + struct platform_device *ohci_dev; +}; + +/* Wait for bitmask in a register to get set or cleared. + * timeout is in units of ten-microseconds. + */ +static int bcma_wait_bits(struct bcma_device *dev, u16 reg, u32 bitmask, + int timeout) +{ + int i; + u32 val; + + for (i = 0; i < timeout; i++) { + val = bcma_read32(dev, reg); + if ((val & bitmask) == bitmask) + return 0; + udelay(10); + } + + return -ETIMEDOUT; +} + +static void __devinit bcma_hcd_4716wa(struct bcma_device *dev) +{ +#ifdef CONFIG_BCMA_DRIVER_MIPS + /* Work around for 4716 failures. */ + if (dev->bus->chipinfo.id == 0x4716) { + u32 tmp; + + tmp = bcma_cpu_clock(&dev->bus->drv_mips); + if (tmp >= 480000000) + tmp = 0x1846b; /* set CDR to 0x11(fast) */ + else if (tmp == 453000000) + tmp = 0x1046b; /* set CDR to 0x10(slow) */ + else + tmp = 0; + + /* Change Shim mdio control reg to fix host not acking at + * high frequencies + */ + if (tmp) { + bcma_write32(dev, 0x524, 0x1); /* write sel to enable */ + udelay(500); + + bcma_write32(dev, 0x524, tmp); + udelay(500); + bcma_write32(dev, 0x524, 0x4ab); + udelay(500); + bcma_read32(dev, 0x528); + bcma_write32(dev, 0x528, 0x80000000); + } + } +#endif /* CONFIG_BCMA_DRIVER_MIPS */ +} + +/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */ +static void __devinit bcma_hcd_init_chip(struct bcma_device *dev) +{ + u32 tmp; + + /* + * USB 2.0 special considerations: + * + * 1. Since the core supports both OHCI and EHCI functions, it must + * only be reset once. + * + * 2. In addition to the standard SI reset sequence, the Host Control + * Register must be programmed to bring the USB core and various + * phy components out of reset. + */ + if (!bcma_core_is_enabled(dev)) { + bcma_core_enable(dev, 0); + mdelay(10); + if (dev->id.rev >= 5) { + /* Enable Misc PLL */ + tmp = bcma_read32(dev, 0x1e0); + tmp |= 0x100; + bcma_write32(dev, 0x1e0, tmp); + if (bcma_wait_bits(dev, 0x1e0, 1 << 24, 100)) + printk(KERN_EMERG "Failed to enable misc PPL!\n"); + + /* Take out of resets */ + bcma_write32(dev, 0x200, 0x4ff); + udelay(25); + bcma_write32(dev, 0x200, 0x6ff); + udelay(25); + + /* Make sure digital and AFE are locked in USB PHY */ + bcma_write32(dev, 0x524, 0x6b); + udelay(50); + tmp = bcma_read32(dev, 0x524); + udelay(50); + bcma_write32(dev, 0x524, 0xab); + udelay(50); + tmp = bcma_read32(dev, 0x524); + udelay(50); + bcma_write32(dev, 0x524, 0x2b); + udelay(50); + tmp = bcma_read32(dev, 0x524); + udelay(50); + bcma_write32(dev, 0x524, 0x10ab); + udelay(50); + tmp = bcma_read32(dev, 0x524); + + if (bcma_wait_bits(dev, 0x528, 0xc000, 10000)) { + tmp = bcma_read32(dev, 0x528); + printk(KERN_EMERG + "USB20H mdio_rddata 0x%08x\n", tmp); + } + bcma_write32(dev, 0x528, 0x80000000); + tmp = bcma_read32(dev, 0x314); + udelay(265); + bcma_write32(dev, 0x200, 0x7ff); + udelay(10); + + /* Take USB and HSIC out of non-driving modes */ + bcma_write32(dev, 0x510, 0); + } else { + bcma_write32(dev, 0x200, 0x7ff); + + udelay(1); + } + + bcma_hcd_4716wa(dev); + } +} + +static const struct usb_ehci_pdata ehci_pdata = { +}; + +static const struct usb_ohci_pdata ohci_pdata = { +}; + +static struct platform_device * __devinit +bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr) +{ + struct platform_device *hci_dev; + struct resource hci_res[2]; + int ret = -ENOMEM; + + memset(hci_res, 0, sizeof(hci_res)); + + hci_res[0].start = addr; + hci_res[0].end = hci_res[0].start + 0x1000 - 1; + hci_res[0].flags = IORESOURCE_MEM; + + hci_res[1].start = dev->irq; + hci_res[1].flags = IORESOURCE_IRQ; + + hci_dev = platform_device_alloc(ohci ? "ohci-platform" : + "ehci-platform" , 0); + if (!hci_dev) + return NULL; + + hci_dev->dev.parent = &dev->dev; + hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask; + + ret = platform_device_add_resources(hci_dev, hci_res, + ARRAY_SIZE(hci_res)); + if (ret) + goto err_alloc; + if (ohci) + ret = platform_device_add_data(hci_dev, &ohci_pdata, + sizeof(ohci_pdata)); + else + ret = platform_device_add_data(hci_dev, &ehci_pdata, + sizeof(ehci_pdata)); + if (ret) + goto err_alloc; + ret = platform_device_add(hci_dev); + if (ret) + goto err_alloc; + + return hci_dev; + +err_alloc: + platform_device_put(hci_dev); + return ERR_PTR(ret); +} + +static int __devinit bcma_hcd_probe(struct bcma_device *dev) +{ + int err; + u16 chipid_top; + u32 ohci_addr; + struct bcma_hcd_device *usb_dev; + struct bcma_chipinfo *chipinfo; + + chipinfo = &dev->bus->chipinfo; + /* USBcores are only connected on embedded devices. */ + chipid_top = (chipinfo->id & 0xFF00); + if (chipid_top != 0x4700 && chipid_top != 0x5300) + return -ENODEV; + + /* TODO: Probably need checks here; is the core connected? */ + + if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || + dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) + return -EOPNOTSUPP; + + usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL); + if (!usb_dev) + return -ENOMEM; + + bcma_hcd_init_chip(dev); + + /* In AI chips EHCI is addrspace 0, OHCI is 1 */ + ohci_addr = dev->addr1; + if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749) + && chipinfo->rev == 0) + ohci_addr = 0x18009000; + + usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr); + if (IS_ERR(usb_dev->ohci_dev)) { + err = PTR_ERR(usb_dev->ohci_dev); + goto err_free_usb_dev; + } + + usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr); + if (IS_ERR(usb_dev->ehci_dev)) { + err = PTR_ERR(usb_dev->ehci_dev); + goto err_unregister_ohci_dev; + } + + bcma_set_drvdata(dev, usb_dev); + return 0; + +err_unregister_ohci_dev: + platform_device_unregister(usb_dev->ohci_dev); +err_free_usb_dev: + kfree(usb_dev); + return err; +} + +static void __devexit bcma_hcd_remove(struct bcma_device *dev) +{ + struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev); + struct platform_device *ohci_dev = usb_dev->ohci_dev; + struct platform_device *ehci_dev = usb_dev->ehci_dev; + + if (ohci_dev) + platform_device_unregister(ohci_dev); + if (ehci_dev) + platform_device_unregister(ehci_dev); + + bcma_core_disable(dev, 0); +} + +static void bcma_hcd_shutdown(struct bcma_device *dev) +{ + bcma_core_disable(dev, 0); +} + +#ifdef CONFIG_PM + +static int bcma_hcd_suspend(struct bcma_device *dev) +{ + bcma_core_disable(dev, 0); + + return 0; +} + +static int bcma_hcd_resume(struct bcma_device *dev) +{ + bcma_core_enable(dev, 0); + + return 0; +} + +#else /* !CONFIG_PM */ +#define bcma_hcd_suspend NULL +#define bcma_hcd_resume NULL +#endif /* CONFIG_PM */ + +static const struct bcma_device_id bcma_hcd_table[] __devinitconst = { + BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS), + BCMA_CORETABLE_END +}; +MODULE_DEVICE_TABLE(bcma, bcma_hcd_table); + +static struct bcma_driver bcma_hcd_driver = { + .name = KBUILD_MODNAME, + .id_table = bcma_hcd_table, + .probe = bcma_hcd_probe, + .remove = __devexit_p(bcma_hcd_remove), + .shutdown = bcma_hcd_shutdown, + .suspend = bcma_hcd_suspend, + .resume = bcma_hcd_resume, +}; + +static int __init bcma_hcd_init(void) +{ + return bcma_driver_register(&bcma_hcd_driver); +} +module_init(bcma_hcd_init); + +static void __exit bcma_hcd_exit(void) +{ + bcma_driver_unregister(&bcma_hcd_driver); +} +module_exit(bcma_hcd_exit); diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c index 680e1a31fb87..7561966fbdc4 100644 --- a/drivers/usb/host/ehci-dbg.c +++ b/drivers/usb/host/ehci-dbg.c @@ -1025,10 +1025,8 @@ static ssize_t debug_lpm_write(struct file *file, const char __user *user_buf, if (strict_strtoul(buf + 5, 16, &hird)) return -EINVAL; printk(KERN_INFO "setting hird %s %lu\n", buf + 6, hird); - temp = ehci_readl(ehci, &ehci->regs->command); - temp &= ~CMD_HIRD; - temp |= hird << 24; - ehci_writel(ehci, temp, &ehci->regs->command); + ehci->command = (ehci->command & ~CMD_HIRD) | (hird << 24); + ehci_writel(ehci, ehci->command, &ehci->regs->command); } else if (strncmp(buf, "disable", 7) == 0) { if (strict_strtoul(buf + 8, 10, &port)) return -EINVAL; diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c index d0a84bd3f3eb..43362577b54a 100644 --- a/drivers/usb/host/ehci-fsl.c +++ b/drivers/usb/host/ehci-fsl.c @@ -1,6 +1,6 @@ /* * Copyright 2005-2009 MontaVista Software, Inc. - * Copyright 2008 Freescale Semiconductor, Inc. + * Copyright 2008,2012 Freescale Semiconductor, Inc. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -150,8 +150,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver, retval = otg_set_host(ehci->transceiver->otg, &ehci_to_hcd(ehci)->self); if (retval) { - if (ehci->transceiver) - put_device(ehci->transceiver->dev); + usb_put_transceiver(ehci->transceiver); goto err4; } } else { @@ -195,7 +194,7 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, if (ehci->transceiver) { otg_set_host(ehci->transceiver->otg, NULL); - put_device(ehci->transceiver->dev); + usb_put_transceiver(ehci->transceiver); } usb_remove_hcd(hcd); @@ -211,22 +210,32 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd, usb_put_hcd(hcd); } -static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, +static void ehci_fsl_setup_phy(struct usb_hcd *hcd, enum fsl_usb2_phy_modes phy_mode, unsigned int port_offset) { - u32 portsc; - struct usb_hcd *hcd = ehci_to_hcd(ehci); + u32 portsc, temp; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); void __iomem *non_ehci = hcd->regs; - struct fsl_usb2_platform_data *pdata; + struct device *dev = hcd->self.controller; + struct fsl_usb2_platform_data *pdata = dev->platform_data; - pdata = hcd->self.controller->platform_data; + if (pdata->controller_ver < 0) { + dev_warn(hcd->self.controller, "Could not get controller version\n"); + return; + } portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]); portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW); switch (phy_mode) { case FSL_USB2_PHY_ULPI: + if (pdata->controller_ver) { + /* controller version 1.6 or above */ + temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); + out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | + USB_CTRL_USB_EN | ULPI_PHY_CLK_SEL); + } portsc |= PORT_PTS_ULPI; break; case FSL_USB2_PHY_SERIAL: @@ -236,6 +245,14 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci, portsc |= PORT_PTS_PTW; /* fall through */ case FSL_USB2_PHY_UTMI: + if (pdata->controller_ver) { + /* controller version 1.6 or above */ + temp = in_be32(non_ehci + FSL_SOC_USB_CTRL); + out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | + UTMI_PHY_EN | USB_CTRL_USB_EN); + mdelay(FSL_UTMI_PHY_DLY); /* Delay for UTMI PHY CLK to + become stable - 10ms*/ + } /* enable UTMI PHY */ if (pdata->have_sysif_regs) setbits32(non_ehci + FSL_SOC_USB_CTRL, @@ -276,7 +293,7 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) if ((pdata->operating_mode == FSL_USB2_DR_HOST) || (pdata->operating_mode == FSL_USB2_DR_OTG)) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); + ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); if (pdata->operating_mode == FSL_USB2_MPH_HOST) { unsigned int chip, rev, svr; @@ -290,9 +307,9 @@ static void ehci_fsl_usb_setup(struct ehci_hcd *ehci) ehci->has_fsl_port_bug = 1; if (pdata->port_enables & FSL_USB2_PORT0_ENABLED) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0); + ehci_fsl_setup_phy(hcd, pdata->phy_mode, 0); if (pdata->port_enables & FSL_USB2_PORT1_ENABLED) - ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1); + ehci_fsl_setup_phy(hcd, pdata->phy_mode, 1); } if (pdata->have_sysif_regs) { diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h index 863fb0c080d7..88403684d10b 100644 --- a/drivers/usb/host/ehci-fsl.h +++ b/drivers/usb/host/ehci-fsl.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2005-2010 Freescale Semiconductor, Inc. +/* Copyright (C) 2005-2010,2012 Freescale Semiconductor, Inc. * Copyright (c) 2005 MontaVista Software * * This program is free software; you can redistribute it and/or modify it @@ -50,4 +50,15 @@ #define CTRL_UTMI_PHY_EN (1<<9) #define CTRL_PHY_CLK_VALID (1 << 17) #define SNOOP_SIZE_2GB 0x1e + +/* control Register Bit Masks */ +#define ULPI_INT_EN (1<<0) +#define WU_INT_EN (1<<1) +#define USB_CTRL_USB_EN (1<<2) +#define LINE_STATE_FILTER__EN (1<<3) +#define KEEP_OTG_ON (1<<4) +#define OTG_PORT (1<<5) +#define PLL_RESET (1<<8) +#define UTMI_PHY_EN (1<<9) +#define ULPI_PHY_CLK_SEL (1<<10) #endif /* _EHCI_FSL_H */ diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 4a3bc5b7a06f..b100f5f9f4b6 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -226,8 +226,13 @@ static int ehci_halt (struct ehci_hcd *ehci) if ((temp & STS_HALT) != 0) return 0; + /* + * This routine gets called during probe before ehci->command + * has been initialized, so we can't rely on its value. + */ + ehci->command &= ~CMD_RUN; temp = ehci_readl(ehci, &ehci->regs->command); - temp &= ~CMD_RUN; + temp &= ~(CMD_RUN | CMD_IAAD); ehci_writel(ehci, temp, &ehci->regs->command); return handshake (ehci, &ehci->regs->status, STS_HALT, STS_HALT, 16 * 125); @@ -363,16 +368,14 @@ static void ehci_quiesce (struct ehci_hcd *ehci) #endif /* wait for any schedule enables/disables to take effect */ - temp = ehci_readl(ehci, &ehci->regs->command) << 10; - temp &= STS_ASS | STS_PSS; + temp = (ehci->command << 10) & (STS_ASS | STS_PSS); if (handshake_on_error_set_halt(ehci, &ehci->regs->status, STS_ASS | STS_PSS, temp, 16 * 125)) return; /* then disable anything that's still active */ - temp = ehci_readl(ehci, &ehci->regs->command); - temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE); - ehci_writel(ehci, temp, &ehci->regs->command); + ehci->command &= ~(CMD_ASE | CMD_PSE); + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* hardware can take 16 microframes to turn off ... */ handshake_on_error_set_halt(ehci, &ehci->regs->status, @@ -417,9 +420,6 @@ static void ehci_iaa_watchdog(unsigned long param) * CMD_IAAD when it sets STS_IAA.) */ cmd = ehci_readl(ehci, &ehci->regs->command); - if (cmd & CMD_IAAD) - ehci_writel(ehci, cmd & ~CMD_IAAD, - &ehci->regs->command); /* If IAA is set here it either legitimately triggered * before we cleared IAAD above (but _way_ late, so we'll @@ -894,11 +894,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) /* complete the unlinking of some qh [4.15.2.3] */ if (status & STS_IAA) { /* guard against (alleged) silicon errata */ - if (cmd & CMD_IAAD) { - ehci_writel(ehci, cmd & ~CMD_IAAD, - &ehci->regs->command); + if (cmd & CMD_IAAD) ehci_dbg(ehci, "IAA with IAAD still set?\n"); - } if (ehci->reclaim) { COUNT(ehci->stats.reclaim); end_unlink_async(ehci); @@ -1248,6 +1245,13 @@ static int ehci_get_frame (struct usb_hcd *hcd) } /*-------------------------------------------------------------------------*/ +/* + * The EHCI in ChipIdea HDRC cannot be a separate module or device, + * because its registers (and irq) are shared between host/gadget/otg + * functions and in order to facilitate role switching we cannot + * give the ehci driver exclusive access to those. + */ +#ifndef CHIPIDEA_EHCI MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR (DRIVER_AUTHOR); @@ -1378,6 +1382,11 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_ls1x_driver #endif +#ifdef CONFIG_MIPS_SEAD3 +#include "ehci-sead3.c" +#define PLATFORM_DRIVER ehci_hcd_sead3_driver +#endif + #ifdef CONFIG_USB_EHCI_HCD_PLATFORM #include "ehci-platform.c" #define PLATFORM_DRIVER ehci_platform_driver @@ -1501,3 +1510,4 @@ static void __exit ehci_hcd_cleanup(void) } module_exit(ehci_hcd_cleanup); +#endif /* CHIPIDEA_EHCI */ diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 38fe07623152..fc9e7cc6ac9b 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -233,7 +233,6 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) /* stop schedules, clean any completed work */ if (ehci->rh_state == EHCI_RH_RUNNING) ehci_quiesce (ehci); - ehci->command = ehci_readl(ehci, &ehci->regs->command); ehci_work(ehci); /* Unlike other USB host controller types, EHCI doesn't have @@ -374,6 +373,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next); /* restore CMD_RUN, framelist size, and irq threshold */ + ehci->command |= CMD_RUN; ehci_writel(ehci, ehci->command, &ehci->regs->command); ehci->rh_state = EHCI_RH_RUNNING; @@ -531,7 +531,8 @@ static int check_reset_complete ( if (ehci->has_amcc_usb23) set_ohci_hcfs(ehci, 1); } else { - ehci_dbg (ehci, "port %d high speed\n", index + 1); + ehci_dbg(ehci, "port %d reset complete, port enabled\n", + index + 1); /* ensure 440EPx ohci controller state is suspended */ if (ehci->has_amcc_usb23) set_ohci_hcfs(ehci, 0); @@ -699,6 +700,7 @@ static int ehci_hub_control ( goto error; wIndex--; temp = ehci_readl(ehci, status_reg); + temp &= ~PORT_RWC_BITS; /* * Even if OWNER is set, so the port is owned by the @@ -712,8 +714,7 @@ static int ehci_hub_control ( ehci_writel(ehci, temp & ~PORT_PE, status_reg); break; case USB_PORT_FEAT_C_ENABLE: - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC, - status_reg); + ehci_writel(ehci, temp | PORT_PEC, status_reg); break; case USB_PORT_FEAT_SUSPEND: if (temp & PORT_RESET) @@ -742,7 +743,7 @@ static int ehci_hub_control ( spin_lock_irqsave(&ehci->lock, flags); } /* resume signaling for 20 msec */ - temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); + temp &= ~PORT_WAKE_BITS; ehci_writel(ehci, temp | PORT_RESUME, status_reg); ehci->reset_done[wIndex] = jiffies + msecs_to_jiffies(20); @@ -752,9 +753,8 @@ static int ehci_hub_control ( break; case USB_PORT_FEAT_POWER: if (HCS_PPC (ehci->hcs_params)) - ehci_writel(ehci, - temp & ~(PORT_RWC_BITS | PORT_POWER), - status_reg); + ehci_writel(ehci, temp & ~PORT_POWER, + status_reg); break; case USB_PORT_FEAT_C_CONNECTION: if (ehci->has_lpm) { @@ -762,12 +762,10 @@ static int ehci_hub_control ( temp &= ~PORT_LPM; temp &= ~PORT_DEV_ADDR; } - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, - status_reg); + ehci_writel(ehci, temp | PORT_CSC, status_reg); break; case USB_PORT_FEAT_C_OVER_CURRENT: - ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC, - status_reg); + ehci_writel(ehci, temp | PORT_OCC, status_reg); break; case USB_PORT_FEAT_C_RESET: /* GetPortStatus clears reset */ diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 5c78f9e71466..a44294d13494 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -242,15 +242,6 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) ehci_reset(omap_ehci); - ret = usb_add_hcd(hcd, irq, IRQF_SHARED); - if (ret) { - dev_err(dev, "failed to add hcd with err %d\n", ret); - goto err_add_hcd; - } - - /* root ports should always stay powered */ - ehci_port_power(omap_ehci, 1); - if (pdata->phy_reset) { /* Hold the PHY in RESET for enough time till * PHY is settled and ready @@ -258,12 +249,21 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev) udelay(10); if (gpio_is_valid(pdata->reset_gpio_port[0])) - gpio_set_value(pdata->reset_gpio_port[0], 1); + gpio_set_value_cansleep(pdata->reset_gpio_port[0], 1); if (gpio_is_valid(pdata->reset_gpio_port[1])) - gpio_set_value(pdata->reset_gpio_port[1], 1); + gpio_set_value_cansleep(pdata->reset_gpio_port[1], 1); } + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); + if (ret) { + dev_err(dev, "failed to add hcd with err %d\n", ret); + goto err_add_hcd; + } + + /* root ports should always stay powered */ + ehci_port_power(omap_ehci, 1); + return 0; err_add_hcd: diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c index fe8dc069164e..bc94d7bf072d 100644 --- a/drivers/usb/host/ehci-pci.c +++ b/drivers/usb/host/ehci-pci.c @@ -368,7 +368,9 @@ static bool usb_is_intel_switchable_ehci(struct pci_dev *pdev) { return pdev->class == PCI_CLASS_SERIAL_USB_EHCI && pdev->vendor == PCI_VENDOR_ID_INTEL && - pdev->device == 0x1E26; + (pdev->device == 0x1E26 || + pdev->device == 0x8C2D || + pdev->device == 0x8C26); } static void ehci_enable_xhci_companion(void) diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index d238b4e24bb6..dfe881a34ae2 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -75,8 +75,6 @@ static const struct hc_driver ehci_platform_hc_driver = { .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, - .update_device = ehci_update_device, - .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, }; @@ -94,12 +92,12 @@ static int __devinit ehci_platform_probe(struct platform_device *dev) irq = platform_get_irq(dev, 0); if (irq < 0) { - pr_err("no irq provieded"); + pr_err("no irq provided"); return irq; } res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res_mem) { - pr_err("no memory recourse provieded"); + pr_err("no memory recourse provided"); return -ENXIO; } diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c index 36ca5077cdf7..4378bf72bbac 100644 --- a/drivers/usb/host/ehci-q.c +++ b/drivers/usb/host/ehci-q.c @@ -943,7 +943,8 @@ qh_make ( } break; default: - dbg ("bogus dev %p speed %d", urb->dev, urb->dev->speed); + ehci_dbg(ehci, "bogus dev %p speed %d\n", urb->dev, + urb->dev->speed); done: qh_put (qh); return NULL; @@ -981,14 +982,12 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh) head = ehci->async; timer_action_done (ehci, TIMER_ASYNC_OFF); if (!head->qh_next.qh) { - u32 cmd = ehci_readl(ehci, &ehci->regs->command); - - if (!(cmd & CMD_ASE)) { + if (!(ehci->command & CMD_ASE)) { /* in case a clear of CMD_ASE didn't take yet */ (void)handshake(ehci, &ehci->regs->status, STS_ASS, 0, 150); - cmd |= CMD_ASE; - ehci_writel(ehci, cmd, &ehci->regs->command); + ehci->command |= CMD_ASE; + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* posted write need not be known to HC yet ... */ } } @@ -1204,7 +1203,6 @@ static void end_unlink_async (struct ehci_hcd *ehci) static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) { - int cmd = ehci_readl(ehci, &ehci->regs->command); struct ehci_qh *prev; #ifdef DEBUG @@ -1222,8 +1220,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) if (ehci->rh_state != EHCI_RH_HALTED && !ehci->reclaim) { /* ... and CMD_IAAD clear */ - ehci_writel(ehci, cmd & ~CMD_ASE, - &ehci->regs->command); + ehci->command &= ~CMD_ASE; + ehci_writel(ehci, ehci->command, &ehci->regs->command); wmb (); // handshake later, if we need to timer_action_done (ehci, TIMER_ASYNC_OFF); @@ -1253,8 +1251,7 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) return; } - cmd |= CMD_IAAD; - ehci_writel(ehci, cmd, &ehci->regs->command); + ehci_writel(ehci, ehci->command | CMD_IAAD, &ehci->regs->command); (void)ehci_readl(ehci, &ehci->regs->command); iaa_watchdog_start(ehci); } diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index f098e2a291a0..c474cec064e4 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -232,6 +232,8 @@ static int s5p_ehci_suspend(struct device *dev) if (pdata && pdata->phy_exit) pdata->phy_exit(pdev, S5P_USB_PHY_HOST); + clk_disable(s5p_ehci->clk); + return rc; } @@ -243,6 +245,8 @@ static int s5p_ehci_resume(struct device *dev) struct platform_device *pdev = to_platform_device(dev); struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; + clk_enable(s5p_ehci->clk); + if (pdata && pdata->phy_init) pdata->phy_init(pdev, S5P_USB_PHY_HOST); diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c index a60679cbbf85..33182c6d1ff9 100644 --- a/drivers/usb/host/ehci-sched.c +++ b/drivers/usb/host/ehci-sched.c @@ -481,7 +481,6 @@ static int tt_no_collision ( static int enable_periodic (struct ehci_hcd *ehci) { - u32 cmd; int status; if (ehci->periodic_sched++) @@ -497,8 +496,8 @@ static int enable_periodic (struct ehci_hcd *ehci) return status; } - cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE; - ehci_writel(ehci, cmd, &ehci->regs->command); + ehci->command |= CMD_PSE; + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* posted write ... PSS happens later */ /* make sure ehci_work scans these */ @@ -511,7 +510,6 @@ static int enable_periodic (struct ehci_hcd *ehci) static int disable_periodic (struct ehci_hcd *ehci) { - u32 cmd; int status; if (--ehci->periodic_sched) @@ -537,8 +535,8 @@ static int disable_periodic (struct ehci_hcd *ehci) return status; } - cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE; - ehci_writel(ehci, cmd, &ehci->regs->command); + ehci->command &= ~CMD_PSE; + ehci_writel(ehci, ehci->command, &ehci->regs->command); /* posted write ... */ free_cached_lists(ehci); @@ -1333,34 +1331,36 @@ sitd_slot_ok ( if (mask & ~0xffff) return 0; + /* check bandwidth */ + uframe %= period_uframes; + frame = uframe >> 3; + +#ifdef CONFIG_USB_EHCI_TT_NEWSCHED + /* The tt's fullspeed bus bandwidth must be available. + * tt_available scheduling guarantees 10+% for control/bulk. + */ + uf = uframe & 7; + if (!tt_available(ehci, period_uframes >> 3, + stream->udev, frame, uf, stream->tt_usecs)) + return 0; +#else + /* tt must be idle for start(s), any gap, and csplit. + * assume scheduling slop leaves 10+% for control/bulk. + */ + if (!tt_no_collision(ehci, period_uframes >> 3, + stream->udev, frame, mask)) + return 0; +#endif + /* this multi-pass logic is simple, but performance may * suffer when the schedule data isn't cached. */ - - /* check bandwidth */ - uframe %= period_uframes; do { u32 max_used; frame = uframe >> 3; uf = uframe & 7; -#ifdef CONFIG_USB_EHCI_TT_NEWSCHED - /* The tt's fullspeed bus bandwidth must be available. - * tt_available scheduling guarantees 10+% for control/bulk. - */ - if (!tt_available (ehci, period_uframes << 3, - stream->udev, frame, uf, stream->tt_usecs)) - return 0; -#else - /* tt must be idle for start(s), any gap, and csplit. - * assume scheduling slop leaves 10+% for control/bulk. - */ - if (!tt_no_collision (ehci, period_uframes << 3, - stream->udev, frame, mask)) - return 0; -#endif - /* check starts (OUT uses more than one) */ max_used = ehci->uframe_periodic_max - stream->usecs; for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) { @@ -2358,7 +2358,8 @@ restart: * in the previous frame for completions. */ if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) { - dbg ("ignoring completions from FSTNs"); + ehci_dbg(ehci, + "ignoring completions from FSTNs\n"); } type = Q_NEXT_TYPE(ehci, q.fstn->hw_next); q = q.fstn->fstn_next; @@ -2441,7 +2442,7 @@ restart: q = *q_p; break; default: - dbg ("corrupt type %d frame %d shadow %p", + ehci_dbg(ehci, "corrupt type %d frame %d shadow %p\n", type, frame, q.ptr); // BUG (); q.ptr = NULL; diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c new file mode 100644 index 000000000000..cc199e87a7a9 --- /dev/null +++ b/drivers/usb/host/ehci-sead3.c @@ -0,0 +1,266 @@ +/* + * MIPS CI13320A EHCI Host Controller driver + * Based on "ehci-au1xxx.c" by K.Boge <karsten.boge@amd.com> + * + * Copyright (C) 2012 MIPS Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <linux/platform_device.h> + +static int ehci_sead3_setup(struct usb_hcd *hcd) +{ + int ret; + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + ehci->caps = hcd->regs + 0x100; + +#ifdef __BIG_ENDIAN + ehci->big_endian_mmio = 1; + ehci->big_endian_desc = 1; +#endif + + ret = ehci_setup(hcd); + if (ret) + return ret; + + ehci->need_io_watchdog = 0; + + /* Set burst length to 16 words. */ + ehci_writel(ehci, 0x1010, &ehci->regs->reserved[1]); + + return ret; +} + +const struct hc_driver ehci_sead3_hc_driver = { + .description = hcd_name, + .product_desc = "SEAD-3 EHCI", + .hcd_priv_size = sizeof(struct ehci_hcd), + + /* + * generic hardware linkage + */ + .irq = ehci_irq, + .flags = HCD_MEMORY | HCD_USB2, + + /* + * basic lifecycle operations + * + */ + .reset = ehci_sead3_setup, + .start = ehci_run, + .stop = ehci_stop, + .shutdown = ehci_shutdown, + + /* + * managing i/o requests and associated device resources + */ + .urb_enqueue = ehci_urb_enqueue, + .urb_dequeue = ehci_urb_dequeue, + .endpoint_disable = ehci_endpoint_disable, + .endpoint_reset = ehci_endpoint_reset, + + /* + * scheduling support + */ + .get_frame_number = ehci_get_frame, + + /* + * root hub support + */ + .hub_status_data = ehci_hub_status_data, + .hub_control = ehci_hub_control, + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, + .relinquish_port = ehci_relinquish_port, + .port_handed_over = ehci_port_handed_over, + + .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, +}; + +static int ehci_hcd_sead3_drv_probe(struct platform_device *pdev) +{ + struct usb_hcd *hcd; + struct resource *res; + int ret; + + if (usb_disabled()) + return -ENODEV; + + if (pdev->resource[1].flags != IORESOURCE_IRQ) { + pr_debug("resource[1] is not IORESOURCE_IRQ"); + return -ENOMEM; + } + hcd = usb_create_hcd(&ehci_sead3_hc_driver, &pdev->dev, "SEAD-3"); + if (!hcd) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); + + if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { + pr_debug("request_mem_region failed"); + ret = -EBUSY; + goto err1; + } + + hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); + if (!hcd->regs) { + pr_debug("ioremap failed"); + ret = -ENOMEM; + goto err2; + } + + /* Root hub has integrated TT. */ + hcd->has_tt = 1; + + ret = usb_add_hcd(hcd, pdev->resource[1].start, + IRQF_SHARED); + if (ret == 0) { + platform_set_drvdata(pdev, hcd); + return ret; + } + + iounmap(hcd->regs); +err2: + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); +err1: + usb_put_hcd(hcd); + return ret; +} + +static int ehci_hcd_sead3_drv_remove(struct platform_device *pdev) +{ + struct usb_hcd *hcd = platform_get_drvdata(pdev); + + usb_remove_hcd(hcd); + iounmap(hcd->regs); + release_mem_region(hcd->rsrc_start, hcd->rsrc_len); + usb_put_hcd(hcd); + platform_set_drvdata(pdev, NULL); + + return 0; +} + +#ifdef CONFIG_PM +static int ehci_hcd_sead3_drv_suspend(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + unsigned long flags; + int rc = 0; + + if (time_before(jiffies, ehci->next_statechange)) + msleep(20); + + /* Root hub was already suspended. Disable irq emission and + * mark HW unaccessible. The PM and USB cores make sure that + * the root hub is either suspended or stopped. + */ + ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev)); + spin_lock_irqsave(&ehci->lock, flags); + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + (void)ehci_readl(ehci, &ehci->regs->intr_enable); + + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + spin_unlock_irqrestore(&ehci->lock, flags); + + /* could save FLADJ in case of Vaux power loss + * ... we'd only use it to handle clock skew + */ + + return rc; +} + +static int ehci_hcd_sead3_drv_resume(struct device *dev) +{ + struct usb_hcd *hcd = dev_get_drvdata(dev); + struct ehci_hcd *ehci = hcd_to_ehci(hcd); + + /* maybe restore FLADJ. */ + + if (time_before(jiffies, ehci->next_statechange)) + msleep(100); + + /* Mark hardware accessible again as we are out of D3 state by now */ + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + /* If CF is still set, we maintained PCI Vaux power. + * Just undo the effect of ehci_pci_suspend(). + */ + if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) { + int mask = INTR_MASK; + + ehci_prepare_ports_for_controller_resume(ehci); + if (!hcd->self.root_hub->do_remote_wakeup) + mask &= ~STS_PCD; + ehci_writel(ehci, mask, &ehci->regs->intr_enable); + ehci_readl(ehci, &ehci->regs->intr_enable); + return 0; + } + + ehci_dbg(ehci, "lost power, restarting\n"); + usb_root_hub_lost_power(hcd->self.root_hub); + + /* Else reset, to cope with power loss or flush-to-storage + * style "resume" having let BIOS kick in during reboot. + */ + (void) ehci_halt(ehci); + (void) ehci_reset(ehci); + + /* emptying the schedule aborts any urbs */ + spin_lock_irq(&ehci->lock); + if (ehci->reclaim) + end_unlink_async(ehci); + ehci_work(ehci); + spin_unlock_irq(&ehci->lock); + + ehci_writel(ehci, ehci->command, &ehci->regs->command); + ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag); + ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */ + + /* here we "know" root ports should always stay powered */ + ehci_port_power(ehci, 1); + + ehci->rh_state = EHCI_RH_SUSPENDED; + + return 0; +} + +static const struct dev_pm_ops sead3_ehci_pmops = { + .suspend = ehci_hcd_sead3_drv_suspend, + .resume = ehci_hcd_sead3_drv_resume, +}; + +#define SEAD3_EHCI_PMOPS (&sead3_ehci_pmops) + +#else +#define SEAD3_EHCI_PMOPS NULL +#endif + +static struct platform_driver ehci_hcd_sead3_driver = { + .probe = ehci_hcd_sead3_drv_probe, + .remove = ehci_hcd_sead3_drv_remove, + .shutdown = usb_hcd_platform_shutdown, + .driver = { + .name = "sead3-ehci", + .owner = THIS_MODULE, + .pm = SEAD3_EHCI_PMOPS, + } +}; + +MODULE_ALIAS("platform:sead3-ehci"); diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c index 9d9cf47d80da..ca819cdd0c5e 100644 --- a/drivers/usb/host/ehci-sh.c +++ b/drivers/usb/host/ehci-sh.c @@ -11,6 +11,7 @@ */ #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/platform_data/ehci-sh.h> struct ehci_sh_priv { struct clk *iclk, *fclk; @@ -100,6 +101,7 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) const struct hc_driver *driver = &ehci_sh_hc_driver; struct resource *res; struct ehci_sh_priv *priv; + struct ehci_sh_platdata *pdata; struct usb_hcd *hcd; int irq, ret; @@ -124,6 +126,9 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) goto fail_create_hcd; } + if (pdev->dev.platform_data != NULL) + pdata = pdev->dev.platform_data; + /* initialize hcd */ hcd = usb_create_hcd(&ehci_sh_hc_driver, &pdev->dev, dev_name(&pdev->dev)); @@ -168,6 +173,9 @@ static int ehci_hcd_sh_probe(struct platform_device *pdev) clk_enable(priv->fclk); clk_enable(priv->iclk); + if (pdata && pdata->phy_init) + pdata->phy_init(); + ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret != 0) { dev_err(&pdev->dev, "Failed to add hcd"); diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c index 6e928559169c..37ba8c8d2fd0 100644 --- a/drivers/usb/host/ehci-spear.c +++ b/drivers/usb/host/ehci-spear.c @@ -13,6 +13,7 @@ #include <linux/clk.h> #include <linux/jiffies.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm.h> @@ -25,12 +26,12 @@ struct spear_ehci { static void spear_start_ehci(struct spear_ehci *ehci) { - clk_enable(ehci->clk); + clk_prepare_enable(ehci->clk); } static void spear_stop_ehci(struct spear_ehci *ehci) { - clk_disable(ehci->clk); + clk_disable_unprepare(ehci->clk); } static int ehci_spear_setup(struct usb_hcd *hcd) @@ -168,6 +169,8 @@ static int ehci_spear_drv_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend, ehci_spear_drv_resume); +static u64 spear_ehci_dma_mask = DMA_BIT_MASK(32); + static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) { struct usb_hcd *hcd ; @@ -175,12 +178,9 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) struct resource *res; struct clk *usbh_clk; const struct hc_driver *driver = &ehci_spear_hc_driver; - int *pdata = pdev->dev.platform_data; int irq, retval; char clk_name[20] = "usbh_clk"; - - if (pdata == NULL) - return -EFAULT; + static int instance = -1; if (usb_disabled()) return -ENODEV; @@ -191,8 +191,22 @@ static int spear_ehci_hcd_drv_probe(struct platform_device *pdev) goto fail_irq_get; } - if (*pdata >= 0) - sprintf(clk_name, "usbh.%01d_clk", *pdata); + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &spear_ehci_dma_mask; + + /* + * Increment the device instance, when probing via device-tree + */ + if (pdev->id < 0) + instance++; + else + instance = pdev->id; + sprintf(clk_name, "usbh.%01d_clk", instance); usbh_clk = clk_get(NULL, clk_name); if (IS_ERR(usbh_clk)) { @@ -277,6 +291,11 @@ static int spear_ehci_hcd_drv_remove(struct platform_device *pdev) return 0; } +static struct of_device_id spear_ehci_id_table[] __devinitdata = { + { .compatible = "st,spear600-ehci", }, + { }, +}; + static struct platform_driver spear_ehci_hcd_driver = { .probe = spear_ehci_hcd_drv_probe, .remove = spear_ehci_hcd_drv_remove, @@ -285,6 +304,7 @@ static struct platform_driver spear_ehci_hcd_driver = { .name = "spear-ehci", .bus = &platform_bus_type, .pm = &ehci_spear_pm_ops, + .of_match_table = of_match_ptr(spear_ehci_id_table), } }; diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 86183366647f..4a44bf833611 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -24,6 +24,7 @@ #include <linux/gpio.h> #include <linux/of.h> #include <linux/of_gpio.h> +#include <linux/pm_runtime.h> #include <mach/usb_phy.h> #include <mach/iomap.h> @@ -37,9 +38,7 @@ struct tegra_ehci_hcd { struct clk *emc_clk; struct usb_phy *transceiver; int host_resumed; - int bus_suspended; int port_resuming; - int power_down_on_bus_suspend; enum tegra_usb_phy_port_speed port_speed; }; @@ -148,18 +147,7 @@ static int tegra_ehci_hub_control( spin_lock_irqsave(&ehci->lock, flags); - /* - * In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits - * that are write on clear, by writing back the register read value, so - * USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits - */ - if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) { - temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS; - ehci_writel(ehci, temp & ~PORT_PE, status_reg); - goto done; - } - - else if (typeReq == GetPortStatus) { + if (typeReq == GetPortStatus) { temp = ehci_readl(ehci, status_reg); if (tegra->port_resuming && !(temp & PORT_SUSPEND)) { /* Resume completed, re-enable disconnect detection */ @@ -175,7 +163,7 @@ static int tegra_ehci_hub_control( goto done; } - temp &= ~PORT_WKCONN_E; + temp &= ~(PORT_RWC_BITS | PORT_WKCONN_E); temp |= PORT_WKDISC_E | PORT_WKOC_E; ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); @@ -273,120 +261,6 @@ static void tegra_ehci_restart(struct usb_hcd *hcd) up_write(&ehci_cf_port_reset_rwsem); } -static int tegra_usb_suspend(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - struct ehci_regs __iomem *hw = tegra->ehci->regs; - unsigned long flags; - - spin_lock_irqsave(&tegra->ehci->lock, flags); - - tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3; - ehci_halt(tegra->ehci); - clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - - spin_unlock_irqrestore(&tegra->ehci->lock, flags); - - tegra_ehci_power_down(hcd); - return 0; -} - -static int tegra_usb_resume(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - struct ehci_hcd *ehci = hcd_to_ehci(hcd); - struct ehci_regs __iomem *hw = ehci->regs; - unsigned long val; - - set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); - tegra_ehci_power_up(hcd); - - if (tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) { - /* Wait for the phy to detect new devices - * before we restart the controller */ - msleep(10); - goto restart; - } - - /* Force the phy to keep data lines in suspend state */ - tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed); - - /* Enable host mode */ - tdi_reset(ehci); - - /* Enable Port Power */ - val = readl(&hw->port_status[0]); - val |= PORT_POWER; - writel(val, &hw->port_status[0]); - udelay(10); - - /* Check if the phy resume from LP0. When the phy resume from LP0 - * USB register will be reset. */ - if (!readl(&hw->async_next)) { - /* Program the field PTC based on the saved speed mode */ - val = readl(&hw->port_status[0]); - val &= ~PORT_TEST(~0); - if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH) - val |= PORT_TEST_FORCE; - else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) - val |= PORT_TEST(6); - else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) - val |= PORT_TEST(7); - writel(val, &hw->port_status[0]); - udelay(10); - - /* Disable test mode by setting PTC field to NORMAL_OP */ - val = readl(&hw->port_status[0]); - val &= ~PORT_TEST(~0); - writel(val, &hw->port_status[0]); - udelay(10); - } - - /* Poll until CCS is enabled */ - if (handshake(ehci, &hw->port_status[0], PORT_CONNECT, - PORT_CONNECT, 2000)) { - pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__); - goto restart; - } - - /* Poll until PE is enabled */ - if (handshake(ehci, &hw->port_status[0], PORT_PE, - PORT_PE, 2000)) { - pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__); - goto restart; - } - - /* Clear the PCI status, to avoid an interrupt taken upon resume */ - val = readl(&hw->status); - val |= STS_PCD; - writel(val, &hw->status); - - /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */ - val = readl(&hw->port_status[0]); - if ((val & PORT_POWER) && (val & PORT_PE)) { - val |= PORT_SUSPEND; - writel(val, &hw->port_status[0]); - - /* Wait until port suspend completes */ - if (handshake(ehci, &hw->port_status[0], PORT_SUSPEND, - PORT_SUSPEND, 1000)) { - pr_err("%s: timeout waiting for PORT_SUSPEND\n", - __func__); - goto restart; - } - } - - tegra_ehci_phy_restore_end(tegra->phy); - return 0; - -restart: - if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) - tegra_ehci_phy_restore_end(tegra->phy); - - tegra_ehci_restart(hcd); - return 0; -} - static void tegra_ehci_shutdown(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); @@ -434,56 +308,23 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) return retval; } -#ifdef CONFIG_PM -static int tegra_ehci_bus_suspend(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - int error_status = 0; - - error_status = ehci_bus_suspend(hcd); - if (!error_status && tegra->power_down_on_bus_suspend) { - tegra_usb_suspend(hcd); - tegra->bus_suspended = 1; - } - - return error_status; -} - -static int tegra_ehci_bus_resume(struct usb_hcd *hcd) -{ - struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); - - if (tegra->bus_suspended && tegra->power_down_on_bus_suspend) { - tegra_usb_resume(hcd); - tegra->bus_suspended = 0; - } - - tegra_usb_phy_preresume(tegra->phy); - tegra->port_resuming = 1; - return ehci_bus_resume(hcd); -} -#endif - -struct temp_buffer { +struct dma_aligned_buffer { void *kmalloc_ptr; void *old_xfer_buffer; u8 data[0]; }; -static void free_temp_buffer(struct urb *urb) +static void free_dma_aligned_buffer(struct urb *urb) { - enum dma_data_direction dir; - struct temp_buffer *temp; + struct dma_aligned_buffer *temp; if (!(urb->transfer_flags & URB_ALIGNED_TEMP_BUFFER)) return; - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; + temp = container_of(urb->transfer_buffer, + struct dma_aligned_buffer, data); - temp = container_of(urb->transfer_buffer, struct temp_buffer, - data); - - if (dir == DMA_FROM_DEVICE) + if (usb_urb_dir_in(urb)) memcpy(temp->old_xfer_buffer, temp->data, urb->transfer_buffer_length); urb->transfer_buffer = temp->old_xfer_buffer; @@ -492,10 +333,9 @@ static void free_temp_buffer(struct urb *urb) urb->transfer_flags &= ~URB_ALIGNED_TEMP_BUFFER; } -static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) +static int alloc_dma_aligned_buffer(struct urb *urb, gfp_t mem_flags) { - enum dma_data_direction dir; - struct temp_buffer *temp, *kmalloc_ptr; + struct dma_aligned_buffer *temp, *kmalloc_ptr; size_t kmalloc_size; if (urb->num_sgs || urb->sg || @@ -503,22 +343,19 @@ static int alloc_temp_buffer(struct urb *urb, gfp_t mem_flags) !((uintptr_t)urb->transfer_buffer & (TEGRA_USB_DMA_ALIGN - 1))) return 0; - dir = usb_urb_dir_in(urb) ? DMA_FROM_DEVICE : DMA_TO_DEVICE; - /* Allocate a buffer with enough padding for alignment */ kmalloc_size = urb->transfer_buffer_length + - sizeof(struct temp_buffer) + TEGRA_USB_DMA_ALIGN - 1; + sizeof(struct dma_aligned_buffer) + TEGRA_USB_DMA_ALIGN - 1; kmalloc_ptr = kmalloc(kmalloc_size, mem_flags); if (!kmalloc_ptr) return -ENOMEM; - /* Position our struct temp_buffer such that data is aligned */ + /* Position our struct dma_aligned_buffer such that data is aligned */ temp = PTR_ALIGN(kmalloc_ptr + 1, TEGRA_USB_DMA_ALIGN) - 1; - temp->kmalloc_ptr = kmalloc_ptr; temp->old_xfer_buffer = urb->transfer_buffer; - if (dir == DMA_TO_DEVICE) + if (usb_urb_dir_out(urb)) memcpy(temp->data, urb->transfer_buffer, urb->transfer_buffer_length); urb->transfer_buffer = temp->data; @@ -533,13 +370,13 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, { int ret; - ret = alloc_temp_buffer(urb, mem_flags); + ret = alloc_dma_aligned_buffer(urb, mem_flags); if (ret) return ret; ret = usb_hcd_map_urb_for_dma(hcd, urb, mem_flags); if (ret) - free_temp_buffer(urb); + free_dma_aligned_buffer(urb); return ret; } @@ -547,49 +384,51 @@ static int tegra_ehci_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, static void tegra_ehci_unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb) { usb_hcd_unmap_urb_for_dma(hcd, urb); - free_temp_buffer(urb); + free_dma_aligned_buffer(urb); } static const struct hc_driver tegra_ehci_hc_driver = { .description = hcd_name, .product_desc = "Tegra EHCI Host Controller", .hcd_priv_size = sizeof(struct ehci_hcd), - .flags = HCD_USB2 | HCD_MEMORY, - .reset = tegra_ehci_setup, + /* standard ehci functions */ .irq = ehci_irq, - .start = ehci_run, .stop = ehci_stop, - .shutdown = tegra_ehci_shutdown, .urb_enqueue = ehci_urb_enqueue, .urb_dequeue = ehci_urb_dequeue, - .map_urb_for_dma = tegra_ehci_map_urb_for_dma, - .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, .endpoint_disable = ehci_endpoint_disable, .endpoint_reset = ehci_endpoint_reset, .get_frame_number = ehci_get_frame, .hub_status_data = ehci_hub_status_data, - .hub_control = tegra_ehci_hub_control, .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete, -#ifdef CONFIG_PM - .bus_suspend = tegra_ehci_bus_suspend, - .bus_resume = tegra_ehci_bus_resume, -#endif .relinquish_port = ehci_relinquish_port, .port_handed_over = ehci_port_handed_over, + + /* modified ehci functions for tegra */ + .reset = tegra_ehci_setup, + .shutdown = tegra_ehci_shutdown, + .map_urb_for_dma = tegra_ehci_map_urb_for_dma, + .unmap_urb_for_dma = tegra_ehci_unmap_urb_for_dma, + .hub_control = tegra_ehci_hub_control, +#ifdef CONFIG_PM + .bus_suspend = ehci_bus_suspend, + .bus_resume = ehci_bus_resume, +#endif }; -static int setup_vbus_gpio(struct platform_device *pdev) +static int setup_vbus_gpio(struct platform_device *pdev, + struct tegra_ehci_platform_data *pdata) { int err = 0; int gpio; - if (!pdev->dev.of_node) - return 0; - - gpio = of_get_named_gpio(pdev->dev.of_node, "nvidia,vbus-gpio", 0); + gpio = pdata->vbus_gpio; + if (!gpio_is_valid(gpio)) + gpio = of_get_named_gpio(pdev->dev.of_node, + "nvidia,vbus-gpio", 0); if (!gpio_is_valid(gpio)) return 0; @@ -603,11 +442,187 @@ static int setup_vbus_gpio(struct platform_device *pdev) dev_err(&pdev->dev, "can't enable vbus\n"); return err; } - gpio_set_value(gpio, 1); return err; } +#ifdef CONFIG_PM + +static int controller_suspend(struct device *dev) +{ + struct tegra_ehci_hcd *tegra = + platform_get_drvdata(to_platform_device(dev)); + struct ehci_hcd *ehci = tegra->ehci; + struct usb_hcd *hcd = ehci_to_hcd(ehci); + struct ehci_regs __iomem *hw = ehci->regs; + unsigned long flags; + + if (time_before(jiffies, ehci->next_statechange)) + msleep(10); + + spin_lock_irqsave(&ehci->lock, flags); + + tegra->port_speed = (readl(&hw->port_status[0]) >> 26) & 0x3; + ehci_halt(ehci); + clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + + spin_unlock_irqrestore(&ehci->lock, flags); + + tegra_ehci_power_down(hcd); + return 0; +} + +static int controller_resume(struct device *dev) +{ + struct tegra_ehci_hcd *tegra = + platform_get_drvdata(to_platform_device(dev)); + struct ehci_hcd *ehci = tegra->ehci; + struct usb_hcd *hcd = ehci_to_hcd(ehci); + struct ehci_regs __iomem *hw = ehci->regs; + unsigned long val; + + set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); + tegra_ehci_power_up(hcd); + + if (tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) { + /* Wait for the phy to detect new devices + * before we restart the controller */ + msleep(10); + goto restart; + } + + /* Force the phy to keep data lines in suspend state */ + tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed); + + /* Enable host mode */ + tdi_reset(ehci); + + /* Enable Port Power */ + val = readl(&hw->port_status[0]); + val |= PORT_POWER; + writel(val, &hw->port_status[0]); + udelay(10); + + /* Check if the phy resume from LP0. When the phy resume from LP0 + * USB register will be reset. */ + if (!readl(&hw->async_next)) { + /* Program the field PTC based on the saved speed mode */ + val = readl(&hw->port_status[0]); + val &= ~PORT_TEST(~0); + if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH) + val |= PORT_TEST_FORCE; + else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) + val |= PORT_TEST(6); + else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) + val |= PORT_TEST(7); + writel(val, &hw->port_status[0]); + udelay(10); + + /* Disable test mode by setting PTC field to NORMAL_OP */ + val = readl(&hw->port_status[0]); + val &= ~PORT_TEST(~0); + writel(val, &hw->port_status[0]); + udelay(10); + } + + /* Poll until CCS is enabled */ + if (handshake(ehci, &hw->port_status[0], PORT_CONNECT, + PORT_CONNECT, 2000)) { + pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__); + goto restart; + } + + /* Poll until PE is enabled */ + if (handshake(ehci, &hw->port_status[0], PORT_PE, + PORT_PE, 2000)) { + pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__); + goto restart; + } + + /* Clear the PCI status, to avoid an interrupt taken upon resume */ + val = readl(&hw->status); + val |= STS_PCD; + writel(val, &hw->status); + + /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */ + val = readl(&hw->port_status[0]); + if ((val & PORT_POWER) && (val & PORT_PE)) { + val |= PORT_SUSPEND; + writel(val, &hw->port_status[0]); + + /* Wait until port suspend completes */ + if (handshake(ehci, &hw->port_status[0], PORT_SUSPEND, + PORT_SUSPEND, 1000)) { + pr_err("%s: timeout waiting for PORT_SUSPEND\n", + __func__); + goto restart; + } + } + + tegra_ehci_phy_restore_end(tegra->phy); + goto done; + + restart: + if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) + tegra_ehci_phy_restore_end(tegra->phy); + + tegra_ehci_restart(hcd); + + done: + tegra_usb_phy_preresume(tegra->phy); + tegra->port_resuming = 1; + return 0; +} + +static int tegra_ehci_suspend(struct device *dev) +{ + struct tegra_ehci_hcd *tegra = + platform_get_drvdata(to_platform_device(dev)); + struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); + int rc = 0; + + /* + * When system sleep is supported and USB controller wakeup is + * implemented: If the controller is runtime-suspended and the + * wakeup setting needs to be changed, call pm_runtime_resume(). + */ + if (HCD_HW_ACCESSIBLE(hcd)) + rc = controller_suspend(dev); + return rc; +} + +static int tegra_ehci_resume(struct device *dev) +{ + int rc; + + rc = controller_resume(dev); + if (rc == 0) { + pm_runtime_disable(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + } + return rc; +} + +static int tegra_ehci_runtime_suspend(struct device *dev) +{ + return controller_suspend(dev); +} + +static int tegra_ehci_runtime_resume(struct device *dev) +{ + return controller_resume(dev); +} + +static const struct dev_pm_ops tegra_ehci_pm_ops = { + .suspend = tegra_ehci_suspend, + .resume = tegra_ehci_resume, + .runtime_suspend = tegra_ehci_runtime_suspend, + .runtime_resume = tegra_ehci_runtime_resume, +}; + +#endif + static u64 tegra_ehci_dma_mask = DMA_BIT_MASK(32); static int tegra_ehci_probe(struct platform_device *pdev) @@ -633,7 +648,7 @@ static int tegra_ehci_probe(struct platform_device *pdev) if (!pdev->dev.dma_mask) pdev->dev.dma_mask = &tegra_ehci_dma_mask; - setup_vbus_gpio(pdev); + setup_vbus_gpio(pdev, pdata); tegra = kzalloc(sizeof(struct tegra_ehci_hcd), GFP_KERNEL); if (!tegra) @@ -722,7 +737,6 @@ static int tegra_ehci_probe(struct platform_device *pdev) } tegra->host_resumed = 1; - tegra->power_down_on_bus_suspend = pdata->power_down_on_bus_suspend; tegra->ehci = hcd_to_ehci(hcd); irq = platform_get_irq(pdev, 0); @@ -746,6 +760,14 @@ static int tegra_ehci_probe(struct platform_device *pdev) goto fail; } + pm_runtime_set_active(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + + /* Don't skip the pm_runtime_forbid call if wakeup isn't working */ + /* if (!pdata->power_down_on_bus_suspend) */ + pm_runtime_forbid(&pdev->dev); + pm_runtime_enable(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); return err; fail: @@ -772,33 +794,6 @@ fail_hcd: return err; } -#ifdef CONFIG_PM -static int tegra_ehci_resume(struct platform_device *pdev) -{ - struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); - - if (tegra->bus_suspended) - return 0; - - return tegra_usb_resume(hcd); -} - -static int tegra_ehci_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); - struct usb_hcd *hcd = ehci_to_hcd(tegra->ehci); - - if (tegra->bus_suspended) - return 0; - - if (time_before(jiffies, tegra->ehci->next_statechange)) - msleep(10); - - return tegra_usb_suspend(hcd); -} -#endif - static int tegra_ehci_remove(struct platform_device *pdev) { struct tegra_ehci_hcd *tegra = platform_get_drvdata(pdev); @@ -807,6 +802,10 @@ static int tegra_ehci_remove(struct platform_device *pdev) if (tegra == NULL || hcd == NULL) return -EINVAL; + pm_runtime_get_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + #ifdef CONFIG_USB_OTG_UTILS if (tegra->transceiver) { otg_set_host(tegra->transceiver->otg, NULL); @@ -847,13 +846,12 @@ static struct of_device_id tegra_ehci_of_match[] __devinitdata = { static struct platform_driver tegra_ehci_driver = { .probe = tegra_ehci_probe, .remove = tegra_ehci_remove, -#ifdef CONFIG_PM - .suspend = tegra_ehci_suspend, - .resume = tegra_ehci_resume, -#endif .shutdown = tegra_ehci_hcd_shutdown, .driver = { .name = "tegra-ehci", .of_match_table = tegra_ehci_of_match, +#ifdef CONFIG_PM + .pm = &tegra_ehci_pm_ops, +#endif } }; diff --git a/drivers/usb/host/fhci-tds.c b/drivers/usb/host/fhci-tds.c index 0ea577bfca2a..c5ed88199292 100644 --- a/drivers/usb/host/fhci-tds.c +++ b/drivers/usb/host/fhci-tds.c @@ -155,7 +155,7 @@ u32 fhci_create_ep(struct fhci_usb *usb, enum fhci_mem_alloc data_mem, struct endpoint *ep; struct usb_td __iomem *td; unsigned long ep_offset; - char *err_for = "enpoint PRAM"; + char *err_for = "endpoint PRAM"; int ep_mem_size; u32 i; diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index ab333ac6071d..22ff6b3a676f 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -119,6 +119,39 @@ error: static const struct of_device_id fsl_usb2_mph_dr_of_match[]; +static int usb_get_ver_info(struct device_node *np) +{ + int ver = -1; + + /* + * returns 1 for usb controller version 1.6 + * returns 2 for usb controller version 2.2 + * returns 0 otherwise + */ + if (of_device_is_compatible(np, "fsl-usb2-dr")) { + if (of_device_is_compatible(np, "fsl-usb2-dr-v1.6")) + ver = FSL_USB_VER_1_6; + else if (of_device_is_compatible(np, "fsl-usb2-dr-v2.2")) + ver = FSL_USB_VER_2_2; + else /* for previous controller versions */ + ver = FSL_USB_VER_OLD; + + if (ver > -1) + return ver; + } + + if (of_device_is_compatible(np, "fsl-usb2-mph")) { + if (of_device_is_compatible(np, "fsl-usb2-mph-v1.6")) + ver = FSL_USB_VER_1_6; + else if (of_device_is_compatible(np, "fsl-usb2-mph-v2.2")) + ver = FSL_USB_VER_2_2; + else /* for previous controller versions */ + ver = FSL_USB_VER_OLD; + } + + return ver; +} + static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) { struct device_node *np = ofdev->dev.of_node; @@ -166,6 +199,14 @@ static int __devinit fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) prop = of_get_property(np, "phy_type", NULL); pdata->phy_mode = determine_usb_phy(prop); + pdata->controller_ver = usb_get_ver_info(np); + + if (pdata->have_sysif_regs) { + if (pdata->controller_ver < 0) { + dev_warn(&ofdev->dev, "Could not get controller version\n"); + return -ENODEV; + } + } for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) { if (!dev_data->drivers[i]) diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c index fc72d44bf787..a35bbddf8968 100644 --- a/drivers/usb/host/isp1760-hcd.c +++ b/drivers/usb/host/isp1760-hcd.c @@ -1562,11 +1562,14 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { retval = -ESHUTDOWN; + qtd_list_free(&new_qtds); goto out; } retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval) + if (retval) { + qtd_list_free(&new_qtds); goto out; + } qh = urb->ep->hcpriv; if (qh) { @@ -1584,6 +1587,7 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, if (!qh) { retval = -ENOMEM; usb_hcd_unlink_urb_from_ep(hcd, urb); + qtd_list_free(&new_qtds); goto out; } list_add_tail(&qh->qh_list, ep_queue); @@ -1683,6 +1687,7 @@ static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, list_for_each_entry(qtd, &qh->qtd_list, qtd_list) if (qtd->urb == urb) { dequeue_urb_from_qtd(hcd, qh, qtd); + list_move(&qtd->qtd_list, &qh->qtd_list); break; } @@ -2176,7 +2181,7 @@ static const struct hc_driver isp1760_hc_driver = { int __init init_kmem_once(void) { - urb_listitem_cachep = kmem_cache_create("isp1760 urb_listitem", + urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem", sizeof(struct urb_listitem), 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c index 4592dc17a9f9..fff114fd5461 100644 --- a/drivers/usb/host/isp1760-if.c +++ b/drivers/usb/host/isp1760-if.c @@ -398,6 +398,9 @@ static int __devinit isp1760_plat_probe(struct platform_device *pdev) hcd = isp1760_register(mem_res->start, mem_size, irq_res->start, irqflags, -ENOENT, &pdev->dev, dev_name(&pdev->dev), devflags); + + dev_set_drvdata(&pdev->dev, hcd); + if (IS_ERR(hcd)) { pr_warning("isp1760: Failed to register the HCD device\n"); ret = -ENODEV; @@ -417,11 +420,16 @@ static int __devexit isp1760_plat_remove(struct platform_device *pdev) { struct resource *mem_res; resource_size_t mem_size; + struct usb_hcd *hcd = dev_get_drvdata(&pdev->dev); + + usb_remove_hcd(hcd); mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mem_size = resource_size(mem_res); release_mem_region(mem_res->start, mem_size); + usb_put_hcd(hcd); + return 0; } diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index 13ebeca8e73e..a665b3eaa746 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -129,7 +129,7 @@ static int __devinit usb_hcd_at91_probe(const struct hc_driver *driver, if (!hcd) return -ENOMEM; hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; + hcd->rsrc_len = resource_size(&pdev->resource[0]); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { pr_debug("request_mem_region failed\n"); @@ -223,7 +223,7 @@ static void __devexit usb_hcd_at91_remove(struct usb_hcd *hcd, /*-------------------------------------------------------------------------*/ static int __devinit -ohci_at91_start (struct usb_hcd *hcd) +ohci_at91_reset (struct usb_hcd *hcd) { struct at91_usbh_data *board = hcd->self.controller->platform_data; struct ohci_hcd *ohci = hcd_to_ohci (hcd); @@ -233,9 +233,18 @@ ohci_at91_start (struct usb_hcd *hcd) return ret; ohci->num_ports = board->ports; + return 0; +} + +static int __devinit +ohci_at91_start (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } @@ -418,6 +427,7 @@ static const struct hc_driver ohci_at91_hc_driver = { /* * basic lifecycle operations */ + .reset = ohci_at91_reset, .start = ohci_at91_start, .stop = ohci_stop, .shutdown = ohci_shutdown, diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c index 4ea63b2cac42..c611699b4aa6 100644 --- a/drivers/usb/host/ohci-au1xxx.c +++ b/drivers/usb/host/ohci-au1xxx.c @@ -37,7 +37,8 @@ static int __devinit ohci_au1xxx_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/drivers/usb/host/ohci-cns3xxx.c b/drivers/usb/host/ohci-cns3xxx.c index 5a00a1e1c6ca..2c9f233047be 100644 --- a/drivers/usb/host/ohci-cns3xxx.c +++ b/drivers/usb/host/ohci-cns3xxx.c @@ -41,7 +41,8 @@ cns3xxx_ohci_start(struct usb_hcd *hcd) ret = ohci_run(ohci); if (ret < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c index 843509778a33..269b1e0f7691 100644 --- a/drivers/usb/host/ohci-da8xx.c +++ b/drivers/usb/host/ohci-da8xx.c @@ -454,3 +454,5 @@ static struct platform_driver ohci_hcd_da8xx_driver = { .name = "ohci", }, }; + +MODULE_ALIAS("platform:ohci"); diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c index e4bcb62b930a..31b81f9eacdc 100644 --- a/drivers/usb/host/ohci-dbg.c +++ b/drivers/usb/host/ohci-dbg.c @@ -29,14 +29,14 @@ urb_print(struct urb * urb, char * str, int small, int status) unsigned int pipe= urb->pipe; if (!urb->dev || !urb->dev->bus) { - dbg("%s URB: no dev", str); + printk(KERN_DEBUG "%s URB: no dev\n", str); return; } #ifndef OHCI_VERBOSE_DEBUG if (status != 0) #endif - dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d", + printk(KERN_DEBUG "%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d\n", str, urb, usb_pipedevice (pipe), diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c index 3d63574d2c7e..dbfbd1dfd2e2 100644 --- a/drivers/usb/host/ohci-ep93xx.c +++ b/drivers/usb/host/ohci-ep93xx.c @@ -47,7 +47,7 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, struct usb_hcd *hcd; if (pdev->resource[1].flags != IORESOURCE_IRQ) { - dbg("resource[1] is not IORESOURCE_IRQ"); + dev_dbg(&pdev->dev, "resource[1] is not IORESOURCE_IRQ\n"); return -ENOMEM; } @@ -65,14 +65,14 @@ static int usb_hcd_ep93xx_probe(const struct hc_driver *driver, hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (hcd->regs == NULL) { - dbg("ioremap failed"); + dev_dbg(&pdev->dev, "ioremap failed\n"); retval = -ENOMEM; goto err2; } usb_host_clock = clk_get(&pdev->dev, NULL); if (IS_ERR(usb_host_clock)) { - dbg("clk_get failed"); + dev_dbg(&pdev->dev, "clk_get failed\n"); retval = PTR_ERR(usb_host_clock); goto err3; } @@ -116,7 +116,8 @@ static int __devinit ohci_ep93xx_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c index 37bb20ebb6fc..2909621ea196 100644 --- a/drivers/usb/host/ohci-exynos.c +++ b/drivers/usb/host/ohci-exynos.c @@ -35,7 +35,8 @@ static int ohci_exynos_start(struct usb_hcd *hcd) ret = ohci_run(ohci); if (ret < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 235171f29460..e0adf5c0cf55 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -1080,11 +1080,6 @@ MODULE_LICENSE ("GPL"); #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver #endif -#ifdef CONFIG_USB_OHCI_HCD_SSB -#include "ohci-ssb.c" -#define SSB_OHCI_DRIVER ssb_ohci_driver -#endif - #ifdef CONFIG_MFD_SM501 #include "ohci-sm501.c" #define SM501_OHCI_DRIVER ohci_hcd_sm501_driver @@ -1128,8 +1123,7 @@ MODULE_LICENSE ("GPL"); !defined(SA1111_DRIVER) && \ !defined(PS3_SYSTEM_BUS_DRIVER) && \ !defined(SM501_OHCI_DRIVER) && \ - !defined(TMIO_OHCI_DRIVER) && \ - !defined(SSB_OHCI_DRIVER) + !defined(TMIO_OHCI_DRIVER) #error "missing bus glue for ohci-hcd" #endif @@ -1195,12 +1189,6 @@ static int __init ohci_hcd_mod_init(void) goto error_pci; #endif -#ifdef SSB_OHCI_DRIVER - retval = ssb_driver_register(&SSB_OHCI_DRIVER); - if (retval) - goto error_ssb; -#endif - #ifdef SM501_OHCI_DRIVER retval = platform_driver_register(&SM501_OHCI_DRIVER); if (retval < 0) @@ -1224,10 +1212,6 @@ static int __init ohci_hcd_mod_init(void) platform_driver_unregister(&SM501_OHCI_DRIVER); error_sm501: #endif -#ifdef SSB_OHCI_DRIVER - ssb_driver_unregister(&SSB_OHCI_DRIVER); - error_ssb: -#endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); error_pci: @@ -1275,9 +1259,6 @@ static void __exit ohci_hcd_mod_exit(void) #ifdef SM501_OHCI_DRIVER platform_driver_unregister(&SM501_OHCI_DRIVER); #endif -#ifdef SSB_OHCI_DRIVER - ssb_driver_unregister(&SSB_OHCI_DRIVER); -#endif #ifdef PCI_DRIVER pci_unregister_driver(&PCI_DRIVER); #endif diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index 6618de1d881d..1e364ec962fb 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -22,6 +22,8 @@ #include <linux/clk.h> #include <linux/platform_device.h> #include <linux/i2c.h> +#include <linux/of.h> +#include <linux/usb/isp1301.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -29,7 +31,6 @@ #include <mach/platform.h> #include <mach/irqs.h> -#include <asm/gpio.h> #define USB_CONFIG_BASE 0x31020000 #define PWRMAN_BASE 0x40004000 @@ -38,7 +39,9 @@ /* USB_CTRL bit defines */ #define USB_SLAVE_HCLK_EN (1 << 24) +#define USB_DEV_NEED_CLK_EN (1 << 22) #define USB_HOST_NEED_CLK_EN (1 << 21) +#define PAD_CONTROL_LAST_DRIVEN (1 << 19) #define USB_OTG_CLK_CTRL IO_ADDRESS(USB_CONFIG_BASE + 0xFF4) #define USB_OTG_CLK_STAT IO_ADDRESS(USB_CONFIG_BASE + 0xFF8) @@ -56,54 +59,6 @@ #define TRANSPARENT_I2C_EN (1 << 7) #define HOST_EN (1 << 0) -/* ISP1301 USB transceiver I2C registers */ -#define ISP1301_MODE_CONTROL_1 0x04 /* u8 read, set, +1 clear */ - -#define MC1_SPEED_REG (1 << 0) -#define MC1_SUSPEND_REG (1 << 1) -#define MC1_DAT_SE0 (1 << 2) -#define MC1_TRANSPARENT (1 << 3) -#define MC1_BDIS_ACON_EN (1 << 4) -#define MC1_OE_INT_EN (1 << 5) -#define MC1_UART_EN (1 << 6) -#define MC1_MASK 0x7f - -#define ISP1301_MODE_CONTROL_2 0x12 /* u8 read, set, +1 clear */ - -#define MC2_GLOBAL_PWR_DN (1 << 0) -#define MC2_SPD_SUSP_CTRL (1 << 1) -#define MC2_BI_DI (1 << 2) -#define MC2_TRANSP_BDIR0 (1 << 3) -#define MC2_TRANSP_BDIR1 (1 << 4) -#define MC2_AUDIO_EN (1 << 5) -#define MC2_PSW_EN (1 << 6) -#define MC2_EN2V7 (1 << 7) - -#define ISP1301_OTG_CONTROL_1 0x06 /* u8 read, set, +1 clear */ -# define OTG1_DP_PULLUP (1 << 0) -# define OTG1_DM_PULLUP (1 << 1) -# define OTG1_DP_PULLDOWN (1 << 2) -# define OTG1_DM_PULLDOWN (1 << 3) -# define OTG1_ID_PULLDOWN (1 << 4) -# define OTG1_VBUS_DRV (1 << 5) -# define OTG1_VBUS_DISCHRG (1 << 6) -# define OTG1_VBUS_CHRG (1 << 7) -#define ISP1301_OTG_STATUS 0x10 /* u8 readonly */ -# define OTG_B_SESS_END (1 << 6) -# define OTG_B_SESS_VLD (1 << 7) - -#define ISP1301_I2C_ADDR 0x2C - -#define ISP1301_I2C_MODE_CONTROL_1 0x4 -#define ISP1301_I2C_MODE_CONTROL_2 0x12 -#define ISP1301_I2C_OTG_CONTROL_1 0x6 -#define ISP1301_I2C_OTG_CONTROL_2 0x10 -#define ISP1301_I2C_INTERRUPT_SOURCE 0x8 -#define ISP1301_I2C_INTERRUPT_LATCH 0xA -#define ISP1301_I2C_INTERRUPT_FALLING 0xC -#define ISP1301_I2C_INTERRUPT_RISING 0xE -#define ISP1301_I2C_REG_CLEAR_ADDR 1 - /* On LPC32xx, those are undefined */ #ifndef start_int_set_falling_edge #define start_int_set_falling_edge(irq) @@ -113,42 +68,12 @@ #define start_int_umask(irq) #endif -static struct i2c_driver isp1301_driver; static struct i2c_client *isp1301_i2c_client; extern int usb_disabled(void); -extern int ocpi_enable(void); static struct clk *usb_clk; -static const unsigned short normal_i2c[] = - { ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END }; - -static int isp1301_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return 0; -} - -static int isp1301_remove(struct i2c_client *client) -{ - return 0; -} - -static const struct i2c_device_id isp1301_id[] = { - { "isp1301_nxp", 0 }, - { } -}; - -static struct i2c_driver isp1301_driver = { - .driver = { - .name = "isp1301_nxp", - }, - .probe = isp1301_probe, - .remove = isp1301_remove, - .id_table = isp1301_id, -}; - static void isp1301_configure_pnx4008(void) { /* PNX4008 only supports DAT_SE0 USB mode */ @@ -220,7 +145,7 @@ static void isp1301_configure_lpc32xx(void) ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0); /* Enable usb_need_clk clock after transceiver is initialized */ - __raw_writel((__raw_readl(USB_CTRL) | (1 << 22)), USB_CTRL); + __raw_writel(__raw_readl(USB_CTRL) | USB_HOST_NEED_CLK_EN, USB_CTRL); printk(KERN_INFO "ISP1301 Vendor ID : 0x%04x\n", i2c_smbus_read_word_data(isp1301_i2c_client, 0x00)); @@ -372,65 +297,55 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) struct usb_hcd *hcd = 0; struct ohci_hcd *ohci; const struct hc_driver *driver = &ohci_nxp_hc_driver; - struct i2c_adapter *i2c_adap; - struct i2c_board_info i2c_info; - + struct resource *res; int ret = 0, irq; + struct device_node *isp1301_node; - dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); - if (usb_disabled()) { - err("USB is disabled"); - ret = -ENODEV; - goto out; + if (pdev->dev.of_node) { + isp1301_node = of_parse_phandle(pdev->dev.of_node, + "transceiver", 0); + } else { + isp1301_node = NULL; } - if (pdev->num_resources != 2 - || pdev->resource[0].flags != IORESOURCE_MEM - || pdev->resource[1].flags != IORESOURCE_IRQ) { - err("Invalid resource configuration"); - ret = -ENODEV; + isp1301_i2c_client = isp1301_get_client(isp1301_node); + if (!isp1301_i2c_client) { + ret = -EPROBE_DEFER; goto out; } - /* Enable AHB slave USB clock, needed for further USB clock control */ - __raw_writel(USB_SLAVE_HCLK_EN | (1 << 19), USB_CTRL); + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; - ret = i2c_add_driver(&isp1301_driver); - if (ret < 0) { - err("failed to add ISP1301 driver"); - goto out; - } - i2c_adap = i2c_get_adapter(2); - memset(&i2c_info, 0, sizeof(struct i2c_board_info)); - strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE); - isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info, - normal_i2c, NULL); - i2c_put_adapter(i2c_adap); - if (!isp1301_i2c_client) { - err("failed to connect I2C to ISP1301 USB Transceiver"); + dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name); + if (usb_disabled()) { + dev_err(&pdev->dev, "USB is disabled\n"); ret = -ENODEV; - goto out_i2c_driver; + goto out; } + /* Enable AHB slave USB clock, needed for further USB clock control */ + __raw_writel(USB_SLAVE_HCLK_EN | PAD_CONTROL_LAST_DRIVEN, USB_CTRL); + isp1301_configure(); /* Enable USB PLL */ usb_clk = clk_get(&pdev->dev, "ck_pll5"); if (IS_ERR(usb_clk)) { - err("failed to acquire USB PLL"); + dev_err(&pdev->dev, "failed to acquire USB PLL\n"); ret = PTR_ERR(usb_clk); goto out1; } ret = clk_enable(usb_clk); if (ret < 0) { - err("failed to start USB PLL"); + dev_err(&pdev->dev, "failed to start USB PLL\n"); goto out2; } ret = clk_set_rate(usb_clk, 48000); if (ret < 0) { - err("failed to set USB clock rate"); + dev_err(&pdev->dev, "failed to set USB clock rate\n"); goto out3; } @@ -442,9 +357,9 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) while ((__raw_readl(USB_OTG_CLK_STAT) & USB_CLOCK_MASK) != USB_CLOCK_MASK) ; - hcd = usb_create_hcd (driver, &pdev->dev, dev_name(&pdev->dev)); + hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev)); if (!hcd) { - err("Failed to allocate HC buffer"); + dev_err(&pdev->dev, "Failed to allocate HC buffer\n"); ret = -ENOMEM; goto out3; } @@ -452,14 +367,21 @@ static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev) /* Set all USB bits in the Start Enable register */ nxp_set_usb_bits(); - hcd->rsrc_start = pdev->resource[0].start; - hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; - if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dev_dbg(&pdev->dev, "request_mem_region failed\n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "Failed to get MEM resource\n"); + ret = -ENOMEM; + goto out4; + } + + hcd->regs = devm_request_and_ioremap(&pdev->dev, res); + if (!hcd->regs) { + dev_err(&pdev->dev, "Failed to devm_request_and_ioremap\n"); ret = -ENOMEM; goto out4; } - hcd->regs = (void __iomem *)pdev->resource[0].start; + hcd->rsrc_start = res->start; + hcd->rsrc_len = resource_size(res); irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -486,10 +408,7 @@ out3: out2: clk_put(usb_clk); out1: - i2c_unregister_device(isp1301_i2c_client); isp1301_i2c_client = NULL; -out_i2c_driver: - i2c_del_driver(&isp1301_driver); out: return ret; } @@ -507,7 +426,6 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev) clk_put(usb_clk); i2c_unregister_device(isp1301_i2c_client); isp1301_i2c_client = NULL; - i2c_del_driver(&isp1301_driver); platform_set_drvdata(pdev, NULL); @@ -517,10 +435,19 @@ static int usb_hcd_nxp_remove(struct platform_device *pdev) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:usb-ohci"); +#ifdef CONFIG_OF +static const struct of_device_id usb_hcd_nxp_match[] = { + { .compatible = "nxp,ohci-nxp" }, + {}, +}; +MODULE_DEVICE_TABLE(of, usb_hcd_nxp_match); +#endif + static struct platform_driver usb_hcd_nxp_driver = { .driver = { .name = "usb-ohci", .owner = THIS_MODULE, + .of_match_table = of_match_ptr(usb_hcd_nxp_match), }, .probe = usb_hcd_nxp_probe, .remove = usb_hcd_nxp_remove, diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 96451e41ee8a..9ce35d0d9d5d 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c @@ -205,8 +205,9 @@ static int ohci_omap_init(struct usb_hcd *hcd) need_transceiver = need_transceiver || machine_is_omap_h2() || machine_is_omap_h3(); - if (cpu_is_omap16xx()) - ocpi_enable(); + /* XXX OMAP16xx only */ + if (config->ocpi_enable) + config->ocpi_enable(); #ifdef CONFIG_USB_OTG if (need_transceiver) { @@ -217,8 +218,7 @@ static int ohci_omap_init(struct usb_hcd *hcd) dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n", ohci->transceiver->label, status); if (status) { - if (ohci->transceiver) - put_device(ohci->transceiver->dev); + usb_put_transceiver(ohci->transceiver); return status; } } else { @@ -405,7 +405,7 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev) usb_remove_hcd(hcd); if (ohci->transceiver) { (void) otg_set_host(ohci->transceiver->otg, 0); - put_device(ohci->transceiver->dev); + usb_put_transceiver(ohci->transceiver); } if (machine_is_omap_osk()) gpio_free(9); diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index ec5c6791c8b4..670c7059c9ae 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -93,13 +93,13 @@ static int __devinit ohci_platform_probe(struct platform_device *dev) irq = platform_get_irq(dev, 0); if (irq < 0) { - pr_err("no irq provieded"); + pr_err("no irq provided"); return irq; } res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res_mem) { - pr_err("no memory recourse provieded"); + pr_err("no memory recourse provided"); return -ENXIO; } diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c index f13d08f94d6b..148d27d6a67c 100644 --- a/drivers/usb/host/ohci-pnx8550.c +++ b/drivers/usb/host/ohci-pnx8550.c @@ -157,7 +157,8 @@ ohci_pnx8550_start (struct usb_hcd *hcd) return ret; if ((ret = ohci_run (ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s", + hcd->self.bus_name); ohci_stop (hcd); return ret; } diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c index d24cc89de16f..e27d5ae2b9eb 100644 --- a/drivers/usb/host/ohci-ppc-of.c +++ b/drivers/usb/host/ohci-ppc-of.c @@ -29,7 +29,8 @@ ohci_ppc_of_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } @@ -236,7 +237,7 @@ MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match); #if !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \ !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE) -#error "No endianess selected for ppc-of-ohci" +#error "No endianness selected for ppc-of-ohci" #endif diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c index 1514b7067470..185c39ed81b7 100644 --- a/drivers/usb/host/ohci-ppc-soc.c +++ b/drivers/usb/host/ohci-ppc-soc.c @@ -130,7 +130,8 @@ ohci_ppc_soc_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", ohci_to_hcd(ohci)->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c index 6fd4fa1f19bb..2ee1d8d713d2 100644 --- a/drivers/usb/host/ohci-ps3.c +++ b/drivers/usb/host/ohci-ps3.c @@ -45,7 +45,8 @@ static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd) result = ohci_run(ohci); if (result < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); } diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index c31b2815be1c..e1a3cc6d28dc 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c @@ -419,7 +419,8 @@ ohci_pxa27x_start (struct usb_hcd *hcd) return ret; if ((ret = ohci_run (ohci)) < 0) { - err ("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s", + hcd->self.bus_name); ohci_stop (hcd); return ret; } diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c index 56dcf069246d..664c869eb096 100644 --- a/drivers/usb/host/ohci-s3c2410.c +++ b/drivers/usb/host/ohci-s3c2410.c @@ -420,7 +420,8 @@ ohci_s3c2410_start(struct usb_hcd *hcd) ret = ohci_run(ohci); if (ret < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c index e1004fb37bd9..b6cc92520924 100644 --- a/drivers/usb/host/ohci-sa1111.c +++ b/drivers/usb/host/ohci-sa1111.c @@ -46,7 +46,7 @@ static void dump_hci_status(struct usb_hcd *hcd, const char *label) { unsigned long status = sa1111_readl(hcd->regs + USB_STATUS); - dbg("%s USB_STATUS = { %s%s%s%s%s}", label, + printk(KERN_DEBUG "%s USB_STATUS = { %s%s%s%s%s}\n", label, ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""), ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""), ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "), @@ -193,7 +193,7 @@ static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev) hcd->rsrc_len = resource_size(&dev->res); if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { - dbg("request_mem_region failed"); + dev_dbg(&dev->dev, "request_mem_region failed\n"); ret = -EBUSY; goto err1; } diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c index 84686d90805b..76a20c278362 100644 --- a/drivers/usb/host/ohci-sh.c +++ b/drivers/usb/host/ohci-sh.c @@ -88,20 +88,20 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { - err("platform_get_resource error."); + dev_err(&pdev->dev, "platform_get_resource error.\n"); return -ENODEV; } irq = platform_get_irq(pdev, 0); if (irq < 0) { - err("platform_get_irq error."); + dev_err(&pdev->dev, "platform_get_irq error.\n"); return -ENODEV; } /* initialize hcd */ hcd = usb_create_hcd(&ohci_sh_hc_driver, &pdev->dev, (char *)hcd_name); if (!hcd) { - err("Failed to create hcd"); + dev_err(&pdev->dev, "Failed to create hcd\n"); return -ENOMEM; } @@ -110,7 +110,7 @@ static int ohci_hcd_sh_probe(struct platform_device *pdev) hcd->rsrc_len = resource_size(res); ret = usb_add_hcd(hcd, irq, IRQF_SHARED); if (ret != 0) { - err("Failed to add hcd"); + dev_err(&pdev->dev, "Failed to add hcd\n"); usb_put_hcd(hcd); return ret; } diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c index 95c16489e883..fc7305ee3c9c 100644 --- a/drivers/usb/host/ohci-spear.c +++ b/drivers/usb/host/ohci-spear.c @@ -14,6 +14,7 @@ #include <linux/signal.h> #include <linux/platform_device.h> #include <linux/clk.h> +#include <linux/of.h> struct spear_ohci { struct ohci_hcd ohci; @@ -24,12 +25,12 @@ struct spear_ohci { static void spear_start_ohci(struct spear_ohci *ohci) { - clk_enable(ohci->clk); + clk_prepare_enable(ohci->clk); } static void spear_stop_ohci(struct spear_ohci *ohci) { - clk_disable(ohci->clk); + clk_disable_unprepare(ohci->clk); } static int __devinit ohci_spear_start(struct usb_hcd *hcd) @@ -90,6 +91,8 @@ static const struct hc_driver ohci_spear_hc_driver = { .start_port_reset = ohci_start_port_reset, }; +static u64 spear_ohci_dma_mask = DMA_BIT_MASK(32); + static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) { const struct hc_driver *driver = &ohci_spear_hc_driver; @@ -98,11 +101,8 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) struct spear_ohci *ohci_p; struct resource *res; int retval, irq; - int *pdata = pdev->dev.platform_data; char clk_name[20] = "usbh_clk"; - - if (pdata == NULL) - return -EFAULT; + static int instance = -1; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -110,8 +110,22 @@ static int spear_ohci_hcd_drv_probe(struct platform_device *pdev) goto fail_irq_get; } - if (*pdata >= 0) - sprintf(clk_name, "usbh.%01d_clk", *pdata); + /* + * Right now device-tree probed devices don't get dma_mask set. + * Since shared usb code relies on it, set it here for now. + * Once we have dma capability bindings this can go away. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &spear_ohci_dma_mask; + + /* + * Increment the device instance, when probing via device-tree + */ + if (pdev->id < 0) + instance++; + else + instance = pdev->id; + sprintf(clk_name, "usbh.%01d_clk", instance); usbh_clk = clk_get(NULL, clk_name); if (IS_ERR(usbh_clk)) { @@ -222,6 +236,11 @@ static int spear_ohci_hcd_drv_resume(struct platform_device *dev) } #endif +static struct of_device_id spear_ohci_id_table[] __devinitdata = { + { .compatible = "st,spear600-ohci", }, + { }, +}; + /* Driver definition to register with the platform bus */ static struct platform_driver spear_ohci_hcd_driver = { .probe = spear_ohci_hcd_drv_probe, @@ -233,6 +252,7 @@ static struct platform_driver spear_ohci_hcd_driver = { .driver = { .owner = THIS_MODULE, .name = "spear-ohci", + .of_match_table = of_match_ptr(spear_ohci_id_table), }, }; diff --git a/drivers/usb/host/ohci-ssb.c b/drivers/usb/host/ohci-ssb.c deleted file mode 100644 index 5ba18595d6f7..000000000000 --- a/drivers/usb/host/ohci-ssb.c +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Sonics Silicon Backplane - * Broadcom USB-core OHCI driver - * - * Copyright 2007 Michael Buesch <m@bues.ch> - * - * Derived from the OHCI-PCI driver - * Copyright 1999 Roman Weissgaerber - * Copyright 2000-2002 David Brownell - * Copyright 1999 Linus Torvalds - * Copyright 1999 Gregory P. Smith - * - * Derived from the USBcore related parts of Broadcom-SB - * Copyright 2005 Broadcom Corporation - * - * Licensed under the GNU/GPL. See COPYING for details. - */ -#include <linux/ssb/ssb.h> - - -#define SSB_OHCI_TMSLOW_HOSTMODE (1 << 29) - -struct ssb_ohci_device { - struct ohci_hcd ohci; /* _must_ be at the beginning. */ - - u32 enable_flags; -}; - -static inline -struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd) -{ - return (struct ssb_ohci_device *)(hcd->hcd_priv); -} - - -static int ssb_ohci_reset(struct usb_hcd *hcd) -{ - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - struct ohci_hcd *ohci = &ohcidev->ohci; - int err; - - ohci_hcd_init(ohci); - err = ohci_init(ohci); - - return err; -} - -static int ssb_ohci_start(struct usb_hcd *hcd) -{ - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - struct ohci_hcd *ohci = &ohcidev->ohci; - int err; - - err = ohci_run(ohci); - if (err < 0) { - ohci_err(ohci, "can't start\n"); - ohci_stop(hcd); - } - - return err; -} - -static const struct hc_driver ssb_ohci_hc_driver = { - .description = "ssb-usb-ohci", - .product_desc = "SSB OHCI Controller", - .hcd_priv_size = sizeof(struct ssb_ohci_device), - - .irq = ohci_irq, - .flags = HCD_MEMORY | HCD_USB11, - - .reset = ssb_ohci_reset, - .start = ssb_ohci_start, - .stop = ohci_stop, - .shutdown = ohci_shutdown, - - .urb_enqueue = ohci_urb_enqueue, - .urb_dequeue = ohci_urb_dequeue, - .endpoint_disable = ohci_endpoint_disable, - - .get_frame_number = ohci_get_frame, - - .hub_status_data = ohci_hub_status_data, - .hub_control = ohci_hub_control, -#ifdef CONFIG_PM - .bus_suspend = ohci_bus_suspend, - .bus_resume = ohci_bus_resume, -#endif - - .start_port_reset = ohci_start_port_reset, -}; - -static void ssb_ohci_detach(struct ssb_device *dev) -{ - struct usb_hcd *hcd = ssb_get_drvdata(dev); - - if (hcd->driver->shutdown) - hcd->driver->shutdown(hcd); - usb_remove_hcd(hcd); - iounmap(hcd->regs); - release_mem_region(hcd->rsrc_start, hcd->rsrc_len); - usb_put_hcd(hcd); - ssb_device_disable(dev, 0); -} - -static int ssb_ohci_attach(struct ssb_device *dev) -{ - struct ssb_ohci_device *ohcidev; - struct usb_hcd *hcd; - int err = -ENOMEM; - u32 tmp, flags = 0; - - if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || - dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) - return -EOPNOTSUPP; - - if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) { - /* Put the device into host-mode. */ - flags |= SSB_OHCI_TMSLOW_HOSTMODE; - ssb_device_enable(dev, flags); - } else if (dev->id.coreid == SSB_DEV_USB20_HOST) { - /* - * USB 2.0 special considerations: - * - * In addition to the standard SSB reset sequence, the Host - * Control Register must be programmed to bring the USB core - * and various phy components out of reset. - */ - ssb_device_enable(dev, 0); - ssb_write32(dev, 0x200, 0x7ff); - - /* Change Flush control reg */ - tmp = ssb_read32(dev, 0x400); - tmp &= ~8; - ssb_write32(dev, 0x400, tmp); - tmp = ssb_read32(dev, 0x400); - - /* Change Shim control reg */ - tmp = ssb_read32(dev, 0x304); - tmp &= ~0x100; - ssb_write32(dev, 0x304, tmp); - tmp = ssb_read32(dev, 0x304); - - udelay(1); - - /* Work around for 5354 failures */ - if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) { - /* Change syn01 reg */ - tmp = 0x00fe00fe; - ssb_write32(dev, 0x894, tmp); - - /* Change syn03 reg */ - tmp = ssb_read32(dev, 0x89c); - tmp |= 0x1; - ssb_write32(dev, 0x89c, tmp); - } - } else - ssb_device_enable(dev, 0); - - hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev, - dev_name(dev->dev)); - if (!hcd) - goto err_dev_disable; - ohcidev = hcd_to_ssb_ohci(hcd); - ohcidev->enable_flags = flags; - - tmp = ssb_read32(dev, SSB_ADMATCH0); - hcd->rsrc_start = ssb_admatch_base(tmp); - hcd->rsrc_len = ssb_admatch_size(tmp); - hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len); - if (!hcd->regs) - goto err_put_hcd; - err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED); - if (err) - goto err_iounmap; - - ssb_set_drvdata(dev, hcd); - - return err; - -err_iounmap: - iounmap(hcd->regs); -err_put_hcd: - usb_put_hcd(hcd); -err_dev_disable: - ssb_device_disable(dev, flags); - return err; -} - -static int ssb_ohci_probe(struct ssb_device *dev, - const struct ssb_device_id *id) -{ - int err; - u16 chipid_top; - - /* USBcores are only connected on embedded devices. */ - chipid_top = (dev->bus->chip_id & 0xFF00); - if (chipid_top != 0x4700 && chipid_top != 0x5300) - return -ENODEV; - - /* TODO: Probably need checks here; is the core connected? */ - - if (usb_disabled()) - return -ENODEV; - - /* We currently always attach SSB_DEV_USB11_HOSTDEV - * as HOST OHCI. If we want to attach it as Client device, - * we must branch here and call into the (yet to - * be written) Client mode driver. Same for remove(). */ - - err = ssb_ohci_attach(dev); - - return err; -} - -static void ssb_ohci_remove(struct ssb_device *dev) -{ - ssb_ohci_detach(dev); -} - -#ifdef CONFIG_PM - -static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state) -{ - ssb_device_disable(dev, 0); - - return 0; -} - -static int ssb_ohci_resume(struct ssb_device *dev) -{ - struct usb_hcd *hcd = ssb_get_drvdata(dev); - struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd); - - ssb_device_enable(dev, ohcidev->enable_flags); - - ohci_finish_controller_resume(hcd); - return 0; -} - -#else /* !CONFIG_PM */ -#define ssb_ohci_suspend NULL -#define ssb_ohci_resume NULL -#endif /* CONFIG_PM */ - -static const struct ssb_device_id ssb_ohci_table[] = { - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), - SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), - SSB_DEVTABLE_END -}; -MODULE_DEVICE_TABLE(ssb, ssb_ohci_table); - -static struct ssb_driver ssb_ohci_driver = { - .name = KBUILD_MODNAME, - .id_table = ssb_ohci_table, - .probe = ssb_ohci_probe, - .remove = ssb_ohci_remove, - .suspend = ssb_ohci_suspend, - .resume = ssb_ohci_resume, -}; diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c index 120bfe6ede38..60c2b0722f2e 100644 --- a/drivers/usb/host/ohci-tmio.c +++ b/drivers/usb/host/ohci-tmio.c @@ -140,7 +140,8 @@ static int ohci_tmio_start(struct usb_hcd *hcd) return ret; if ((ret = ohci_run(ohci)) < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c index a2247867af86..41e378f17c66 100644 --- a/drivers/usb/host/ohci-xls.c +++ b/drivers/usb/host/ohci-xls.c @@ -88,7 +88,8 @@ static int __devinit ohci_xls_start(struct usb_hcd *hcd) ohci = hcd_to_ohci(hcd); ret = ohci_run(ohci); if (ret < 0) { - err("can't start %s", hcd->self.bus_name); + dev_err(hcd->self.controller, "can't start %s\n", + hcd->self.bus_name); ohci_stop(hcd); return ret; } diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 3b38030b02a8..4f0f0339532f 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -1399,8 +1399,8 @@ static struct ehci_qh *qh_make(struct oxu_hcd *oxu, * But interval 1 scheduling is simpler, and * includes high bandwidth. */ - dbg("intr period %d uframes, NYET!", - urb->interval); + oxu_dbg(oxu, "intr period %d uframes, NYET!\n", + urb->interval); goto done; } } else { @@ -1471,7 +1471,7 @@ static struct ehci_qh *qh_make(struct oxu_hcd *oxu, } break; default: - dbg("bogus dev %p speed %d", urb->dev, urb->dev->speed); + oxu_dbg(oxu, "bogus dev %p speed %d\n", urb->dev, urb->dev->speed); done: qh_put(qh); return NULL; @@ -2307,7 +2307,7 @@ restart: qh_put(temp.qh); break; default: - dbg("corrupt type %d frame %d shadow %p", + oxu_dbg(oxu, "corrupt type %d frame %d shadow %p\n", type, frame, q.ptr); q.ptr = NULL; } @@ -2991,8 +2991,9 @@ static int oxu_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) /* shouldn't happen often, but ... * FIXME kill those tds' urbs */ - err("can't reschedule qh %p, err %d", - qh, status); + dev_err(hcd->self.controller, + "can't reschedule qh %p, err %d\n", qh, + status); } return status; } diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index 32dada8c8b4f..df0828cb2aa3 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -9,6 +9,7 @@ */ #include <linux/types.h> +#include <linux/kconfig.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/init.h> @@ -712,12 +713,28 @@ static int handshake(void __iomem *ptr, u32 mask, u32 done, return -ETIMEDOUT; } -bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) +#define PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI 0x8C31 + +bool usb_is_intel_ppt_switchable_xhci(struct pci_dev *pdev) { return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI; } + +/* The Intel Lynx Point chipset also has switchable ports. */ +bool usb_is_intel_lpt_switchable_xhci(struct pci_dev *pdev) +{ + return pdev->class == PCI_CLASS_SERIAL_USB_XHCI && + pdev->vendor == PCI_VENDOR_ID_INTEL && + pdev->device == PCI_DEVICE_ID_INTEL_LYNX_POINT_XHCI; +} + +bool usb_is_intel_switchable_xhci(struct pci_dev *pdev) +{ + return usb_is_intel_ppt_switchable_xhci(pdev) || + usb_is_intel_lpt_switchable_xhci(pdev); +} EXPORT_SYMBOL_GPL(usb_is_intel_switchable_xhci); /* @@ -742,6 +759,19 @@ void usb_enable_xhci_ports(struct pci_dev *xhci_pdev) { u32 ports_available; + /* Don't switchover the ports if the user hasn't compiled the xHCI + * driver. Otherwise they will see "dead" USB ports that don't power + * the devices. + */ + if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) { + dev_warn(&xhci_pdev->dev, + "CONFIG_USB_XHCI_HCD is turned off, " + "defaulting to EHCI.\n"); + dev_warn(&xhci_pdev->dev, + "USB 3.0 devices will work at USB 2.0 speeds.\n"); + return; + } + ports_available = 0xffffffff; /* Write USB3_PSSEN, the USB 3.0 Port SuperSpeed Enable * Register, to turn on SuperSpeed terminations for all diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c index 2bf1320dc9c3..c868be65e763 100644 --- a/drivers/usb/host/r8a66597-hcd.c +++ b/drivers/usb/host/r8a66597-hcd.c @@ -401,7 +401,7 @@ static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb) if (r8a66597->address_map & (1 << addr)) continue; - dbg("alloc_address: r8a66597_addr=%d", addr); + dev_dbg(&urb->dev->dev, "alloc_address: r8a66597_addr=%d\n", addr); r8a66597->address_map |= 1 << addr; if (make_r8a66597_device(r8a66597, urb, addr) < 0) @@ -426,7 +426,7 @@ static void free_usb_address(struct r8a66597 *r8a66597, if (!dev) return; - dbg("free_addr: addr=%d", dev->address); + dev_dbg(&dev->udev->dev, "free_addr: addr=%d\n", dev->address); dev->state = USB_STATE_DEFAULT; r8a66597->address_map &= ~(1 << dev->address); @@ -819,7 +819,7 @@ static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb, struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb); struct r8a66597_pipe *pipe = hep->hcpriv; - dbg("enable_pipe:"); + dev_dbg(&dev->udev->dev, "enable_pipe:\n"); pipe->info = *info; set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA); @@ -898,7 +898,7 @@ static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597, force_dequeue(r8a66597, pipenum, dev->address); } - dbg("disable_pipe"); + dev_dbg(&dev->udev->dev, "disable_pipe\n"); r8a66597->dma_map &= ~(dev->dma_map); dev->dma_map = 0; @@ -2264,7 +2264,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd) struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); int port; - dbg("%s", __func__); + dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__); for (port = 0; port < r8a66597->max_root_hub; port++) { struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; @@ -2273,7 +2273,7 @@ static int r8a66597_bus_suspend(struct usb_hcd *hcd) if (!(rh->port & USB_PORT_STAT_ENABLE)) continue; - dbg("suspend port = %d", port); + dev_dbg(&rh->dev->udev->dev, "suspend port = %d\n", port); r8a66597_bclr(r8a66597, UACT, dvstctr_reg); /* suspend */ rh->port |= USB_PORT_STAT_SUSPEND; @@ -2295,7 +2295,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd) struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd); int port; - dbg("%s", __func__); + dev_dbg(&r8a66597->device0.udev->dev, "%s\n", __func__); for (port = 0; port < r8a66597->max_root_hub; port++) { struct r8a66597_root_hub *rh = &r8a66597->root_hub[port]; @@ -2304,7 +2304,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd) if (!(rh->port & USB_PORT_STAT_SUSPEND)) continue; - dbg("resume port = %d", port); + dev_dbg(&rh->dev->udev->dev, "resume port = %d\n", port); rh->port &= ~USB_PORT_STAT_SUSPEND; rh->port |= USB_PORT_STAT_C_SUSPEND << 16; r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg); @@ -2360,7 +2360,7 @@ static int r8a66597_suspend(struct device *dev) struct r8a66597 *r8a66597 = dev_get_drvdata(dev); int port; - dbg("%s", __func__); + dev_dbg(dev, "%s\n", __func__); disable_controller(r8a66597); @@ -2378,7 +2378,7 @@ static int r8a66597_resume(struct device *dev) struct r8a66597 *r8a66597 = dev_get_drvdata(dev); struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597); - dbg("%s", __func__); + dev_dbg(dev, "%s\n", __func__); enable_controller(r8a66597); usb_root_hub_lost_power(hcd->self.root_hub); diff --git a/drivers/usb/host/ssb-hcd.c b/drivers/usb/host/ssb-hcd.c new file mode 100644 index 000000000000..c2a29faba076 --- /dev/null +++ b/drivers/usb/host/ssb-hcd.c @@ -0,0 +1,280 @@ +/* + * Sonics Silicon Backplane + * Broadcom USB-core driver (SSB bus glue) + * + * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de> + * + * Based on ssb-ohci driver + * Copyright 2007 Michael Buesch <m@bues.ch> + * + * Derived from the OHCI-PCI driver + * Copyright 1999 Roman Weissgaerber + * Copyright 2000-2002 David Brownell + * Copyright 1999 Linus Torvalds + * Copyright 1999 Gregory P. Smith + * + * Derived from the USBcore related parts of Broadcom-SB + * Copyright 2005-2011 Broadcom Corporation + * + * Licensed under the GNU/GPL. See COPYING for details. + */ +#include <linux/ssb/ssb.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb/ehci_pdriver.h> +#include <linux/usb/ohci_pdriver.h> + +MODULE_AUTHOR("Hauke Mehrtens"); +MODULE_DESCRIPTION("Common USB driver for SSB Bus"); +MODULE_LICENSE("GPL"); + +#define SSB_HCD_TMSLOW_HOSTMODE (1 << 29) + +struct ssb_hcd_device { + struct platform_device *ehci_dev; + struct platform_device *ohci_dev; + + u32 enable_flags; +}; + +static void __devinit ssb_hcd_5354wa(struct ssb_device *dev) +{ +#ifdef CONFIG_SSB_DRIVER_MIPS + /* Work around for 5354 failures */ + if (dev->id.revision == 2 && dev->bus->chip_id == 0x5354) { + /* Change syn01 reg */ + ssb_write32(dev, 0x894, 0x00fe00fe); + + /* Change syn03 reg */ + ssb_write32(dev, 0x89c, ssb_read32(dev, 0x89c) | 0x1); + } +#endif +} + +static void __devinit ssb_hcd_usb20wa(struct ssb_device *dev) +{ + if (dev->id.coreid == SSB_DEV_USB20_HOST) { + /* + * USB 2.0 special considerations: + * + * In addition to the standard SSB reset sequence, the Host + * Control Register must be programmed to bring the USB core + * and various phy components out of reset. + */ + ssb_write32(dev, 0x200, 0x7ff); + + /* Change Flush control reg */ + ssb_write32(dev, 0x400, ssb_read32(dev, 0x400) & ~8); + ssb_read32(dev, 0x400); + + /* Change Shim control reg */ + ssb_write32(dev, 0x304, ssb_read32(dev, 0x304) & ~0x100); + ssb_read32(dev, 0x304); + + udelay(1); + + ssb_hcd_5354wa(dev); + } +} + +/* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */ +static u32 __devinit ssb_hcd_init_chip(struct ssb_device *dev) +{ + u32 flags = 0; + + if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV) + /* Put the device into host-mode. */ + flags |= SSB_HCD_TMSLOW_HOSTMODE; + + ssb_device_enable(dev, flags); + + ssb_hcd_usb20wa(dev); + + return flags; +} + +static const struct usb_ehci_pdata ehci_pdata = { +}; + +static const struct usb_ohci_pdata ohci_pdata = { +}; + +static struct platform_device * __devinit +ssb_hcd_create_pdev(struct ssb_device *dev, bool ohci, u32 addr, u32 len) +{ + struct platform_device *hci_dev; + struct resource hci_res[2]; + int ret = -ENOMEM; + + memset(hci_res, 0, sizeof(hci_res)); + + hci_res[0].start = addr; + hci_res[0].end = hci_res[0].start + len - 1; + hci_res[0].flags = IORESOURCE_MEM; + + hci_res[1].start = dev->irq; + hci_res[1].flags = IORESOURCE_IRQ; + + hci_dev = platform_device_alloc(ohci ? "ohci-platform" : + "ehci-platform" , 0); + if (!hci_dev) + return NULL; + + hci_dev->dev.parent = dev->dev; + hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask; + + ret = platform_device_add_resources(hci_dev, hci_res, + ARRAY_SIZE(hci_res)); + if (ret) + goto err_alloc; + if (ohci) + ret = platform_device_add_data(hci_dev, &ohci_pdata, + sizeof(ohci_pdata)); + else + ret = platform_device_add_data(hci_dev, &ehci_pdata, + sizeof(ehci_pdata)); + if (ret) + goto err_alloc; + ret = platform_device_add(hci_dev); + if (ret) + goto err_alloc; + + return hci_dev; + +err_alloc: + platform_device_put(hci_dev); + return ERR_PTR(ret); +} + +static int __devinit ssb_hcd_probe(struct ssb_device *dev, + const struct ssb_device_id *id) +{ + int err, tmp; + int start, len; + u16 chipid_top; + u16 coreid = dev->id.coreid; + struct ssb_hcd_device *usb_dev; + + /* USBcores are only connected on embedded devices. */ + chipid_top = (dev->bus->chip_id & 0xFF00); + if (chipid_top != 0x4700 && chipid_top != 0x5300) + return -ENODEV; + + /* TODO: Probably need checks here; is the core connected? */ + + if (dma_set_mask(dev->dma_dev, DMA_BIT_MASK(32)) || + dma_set_coherent_mask(dev->dma_dev, DMA_BIT_MASK(32))) + return -EOPNOTSUPP; + + usb_dev = kzalloc(sizeof(struct ssb_hcd_device), GFP_KERNEL); + if (!usb_dev) + return -ENOMEM; + + /* We currently always attach SSB_DEV_USB11_HOSTDEV + * as HOST OHCI. If we want to attach it as Client device, + * we must branch here and call into the (yet to + * be written) Client mode driver. Same for remove(). */ + usb_dev->enable_flags = ssb_hcd_init_chip(dev); + + tmp = ssb_read32(dev, SSB_ADMATCH0); + + start = ssb_admatch_base(tmp); + len = (coreid == SSB_DEV_USB20_HOST) ? 0x800 : ssb_admatch_size(tmp); + usb_dev->ohci_dev = ssb_hcd_create_pdev(dev, true, start, len); + if (IS_ERR(usb_dev->ohci_dev)) { + err = PTR_ERR(usb_dev->ohci_dev); + goto err_free_usb_dev; + } + + if (coreid == SSB_DEV_USB20_HOST) { + start = ssb_admatch_base(tmp) + 0x800; /* ehci core offset */ + usb_dev->ehci_dev = ssb_hcd_create_pdev(dev, false, start, len); + if (IS_ERR(usb_dev->ehci_dev)) { + err = PTR_ERR(usb_dev->ehci_dev); + goto err_unregister_ohci_dev; + } + } + + ssb_set_drvdata(dev, usb_dev); + return 0; + +err_unregister_ohci_dev: + platform_device_unregister(usb_dev->ohci_dev); +err_free_usb_dev: + kfree(usb_dev); + return err; +} + +static void __devexit ssb_hcd_remove(struct ssb_device *dev) +{ + struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev); + struct platform_device *ohci_dev = usb_dev->ohci_dev; + struct platform_device *ehci_dev = usb_dev->ehci_dev; + + if (ohci_dev) + platform_device_unregister(ohci_dev); + if (ehci_dev) + platform_device_unregister(ehci_dev); + + ssb_device_disable(dev, 0); +} + +static void __devexit ssb_hcd_shutdown(struct ssb_device *dev) +{ + ssb_device_disable(dev, 0); +} + +#ifdef CONFIG_PM + +static int ssb_hcd_suspend(struct ssb_device *dev, pm_message_t state) +{ + ssb_device_disable(dev, 0); + + return 0; +} + +static int ssb_hcd_resume(struct ssb_device *dev) +{ + struct ssb_hcd_device *usb_dev = ssb_get_drvdata(dev); + + ssb_device_enable(dev, usb_dev->enable_flags); + + return 0; +} + +#else /* !CONFIG_PM */ +#define ssb_hcd_suspend NULL +#define ssb_hcd_resume NULL +#endif /* CONFIG_PM */ + +static const struct ssb_device_id ssb_hcd_table[] __devinitconst = { + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV), + SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV), + SSB_DEVTABLE_END +}; +MODULE_DEVICE_TABLE(ssb, ssb_hcd_table); + +static struct ssb_driver ssb_hcd_driver = { + .name = KBUILD_MODNAME, + .id_table = ssb_hcd_table, + .probe = ssb_hcd_probe, + .remove = __devexit_p(ssb_hcd_remove), + .shutdown = ssb_hcd_shutdown, + .suspend = ssb_hcd_suspend, + .resume = ssb_hcd_resume, +}; + +static int __init ssb_hcd_init(void) +{ + return ssb_driver_register(&ssb_hcd_driver); +} +module_init(ssb_hcd_init); + +static void __exit ssb_hcd_exit(void) +{ + ssb_driver_unregister(&ssb_hcd_driver); +} +module_exit(ssb_hcd_exit); diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 673ad120c43e..2732ef660c5c 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -475,6 +475,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, struct xhci_bus_state *bus_state; u16 link_state = 0; u16 wake_mask = 0; + u16 timeout = 0; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; @@ -558,6 +559,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, xhci_dbg(xhci, "Resume USB2 port %d\n", wIndex + 1); bus_state->resume_done[wIndex] = 0; + clear_bit(wIndex, &bus_state->resuming_ports); xhci_set_link_state(xhci, port_array, wIndex, XDEV_U0); xhci_dbg(xhci, "set port %d resume\n", @@ -622,6 +624,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, link_state = (wIndex & 0xff00) >> 3; if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) wake_mask = wIndex & 0xff00; + /* The MSB of wIndex is the U1/U2 timeout */ + timeout = (wIndex & 0xff00) >> 8; wIndex &= 0xff; if (!wIndex || wIndex > max_ports) goto error; @@ -746,6 +750,22 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, temp = xhci_readl(xhci, port_array[wIndex]); break; + case USB_PORT_FEAT_U1_TIMEOUT: + if (hcd->speed != HCD_USB3) + goto error; + temp = xhci_readl(xhci, port_array[wIndex] + 1); + temp &= ~PORT_U1_TIMEOUT_MASK; + temp |= PORT_U1_TIMEOUT(timeout); + xhci_writel(xhci, temp, port_array[wIndex] + 1); + break; + case USB_PORT_FEAT_U2_TIMEOUT: + if (hcd->speed != HCD_USB3) + goto error; + temp = xhci_readl(xhci, port_array[wIndex] + 1); + temp &= ~PORT_U2_TIMEOUT_MASK; + temp |= PORT_U2_TIMEOUT(timeout); + xhci_writel(xhci, temp, port_array[wIndex] + 1); + break; default: goto error; } @@ -845,7 +865,12 @@ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) /* Initial status is no changes */ retval = (max_ports + 8) / 8; memset(buf, 0, retval); - status = 0; + + /* + * Inform the usbcore about resume-in-progress by returning + * a non-zero value even if there are no status changes. + */ + status = bus_state->resuming_ports; mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC; @@ -885,15 +910,11 @@ int xhci_bus_suspend(struct usb_hcd *hcd) spin_lock_irqsave(&xhci->lock, flags); if (hcd->self.root_hub->do_remote_wakeup) { - port_index = max_ports; - while (port_index--) { - if (bus_state->resume_done[port_index] != 0) { - spin_unlock_irqrestore(&xhci->lock, flags); - xhci_dbg(xhci, "suspend failed because " - "port %d is resuming\n", - port_index + 1); - return -EBUSY; - } + if (bus_state->resuming_ports) { + spin_unlock_irqrestore(&xhci->lock, flags); + xhci_dbg(xhci, "suspend failed because " + "a port is resuming\n"); + return -EBUSY; } } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 68eaa908ac8e..ec4338eec826 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1791,6 +1791,14 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); struct dev_info *dev_info, *next; + struct list_head *tt_list_head; + struct list_head *tt; + struct list_head *endpoints; + struct list_head *ep, *q; + struct xhci_tt_bw_info *tt_info; + struct xhci_interval_bw_table *bwt; + struct xhci_virt_ep *virt_ep; + unsigned long flags; int size; int i; @@ -1807,6 +1815,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci->event_ring = NULL; xhci_dbg(xhci, "Freed event ring\n"); + if (xhci->lpm_command) + xhci_free_command(xhci, xhci->lpm_command); + xhci->cmd_ring_reserved_trbs = 0; if (xhci->cmd_ring) xhci_ring_free(xhci, xhci->cmd_ring); xhci->cmd_ring = NULL; @@ -1849,8 +1860,26 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } spin_unlock_irqrestore(&xhci->lock, flags); + bwt = &xhci->rh_bw->bw_table; + for (i = 0; i < XHCI_MAX_INTERVAL; i++) { + endpoints = &bwt->interval_bw[i].endpoints; + list_for_each_safe(ep, q, endpoints) { + virt_ep = list_entry(ep, struct xhci_virt_ep, bw_endpoint_list); + list_del(&virt_ep->bw_endpoint_list); + kfree(virt_ep); + } + } + + tt_list_head = &xhci->rh_bw->tts; + list_for_each_safe(tt, q, tt_list_head) { + tt_info = list_entry(tt, struct xhci_tt_bw_info, tt_list); + list_del(tt); + kfree(tt_info); + } + xhci->num_usb2_ports = 0; xhci->num_usb3_ports = 0; + xhci->num_active_eps = 0; kfree(xhci->usb2_ports); kfree(xhci->usb3_ports); kfree(xhci->port_array); @@ -2350,6 +2379,16 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) xhci_write_64(xhci, val_64, &xhci->op_regs->cmd_ring); xhci_dbg_cmd_ptrs(xhci); + xhci->lpm_command = xhci_alloc_command(xhci, true, true, flags); + if (!xhci->lpm_command) + goto fail; + + /* Reserve one command ring TRB for disabling LPM. + * Since the USB core grabs the shared usb_bus bandwidth mutex before + * disabling LPM, we only need to reserve one TRB for all devices. + */ + xhci->cmd_ring_reserved_trbs++; + val = xhci_readl(xhci, &xhci->cap_regs->db_off); val &= DBOFF_MASK; xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x" diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 7a856a767e77..18b231b0c5d3 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -72,6 +72,7 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) xhci_dbg(xhci, "QUIRK: Fresco Logic revision %u " "has broken MSI implementation\n", pdev->revision); + xhci->quirks |= XHCI_TRUST_TX_LENGTH; } if (pdev->vendor == PCI_VENDOR_ID_NEC) @@ -83,6 +84,10 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) /* AMD PLL quirk */ if (pdev->vendor == PCI_VENDOR_ID_AMD && usb_amd_find_chipset_info()) xhci->quirks |= XHCI_AMD_PLL_FIX; + if (pdev->vendor == PCI_VENDOR_ID_INTEL) { + xhci->quirks |= XHCI_LPM_SUPPORT; + xhci->quirks |= XHCI_INTEL_HOST; + } if (pdev->vendor == PCI_VENDOR_ID_INTEL && pdev->device == PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI) { xhci->quirks |= XHCI_SPURIOUS_SUCCESS; @@ -169,6 +174,13 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) if (retval) goto put_usb3_hcd; /* Roothub already marked as USB 3.0 speed */ + + /* We know the LPM timeout algorithms for this host, let the USB core + * enable and disable LPM for devices under the USB 3.0 roothub. + */ + if (xhci->quirks & XHCI_LPM_SUPPORT) + hcd_to_bus(xhci->shared_hcd)->root_hub->lpm_capable = 1; + return 0; put_usb3_hcd: @@ -292,6 +304,8 @@ static const struct hc_driver xhci_pci_hc_driver = { */ .update_device = xhci_update_device, .set_usb2_hw_lpm = xhci_set_usb2_hardware_lpm, + .enable_usb3_lpm_timeout = xhci_enable_usb3_lpm_timeout, + .disable_usb3_lpm_timeout = xhci_disable_usb3_lpm_timeout, }; /*-------------------------------------------------------------------------*/ diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 3d9422f16a20..23b4aefd1036 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1377,6 +1377,7 @@ static void handle_port_status(struct xhci_hcd *xhci, xhci_dbg(xhci, "resume HS port %d\n", port_id); bus_state->resume_done[faked_port_index] = jiffies + msecs_to_jiffies(20); + set_bit(faked_port_index, &bus_state->resuming_ports); mod_timer(&hcd->rh_timer, bus_state->resume_done[faked_port_index]); /* Do the rest in GetPortStatus */ @@ -1786,8 +1787,12 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, /* handle completion code */ switch (trb_comp_code) { case COMP_SUCCESS: - frame->status = 0; - break; + if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) { + frame->status = 0; + break; + } + if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) + trb_comp_code = COMP_SHORT_TX; case COMP_SHORT_TX: frame->status = td->urb->transfer_flags & URB_SHORT_NOT_OK ? -EREMOTEIO : 0; @@ -1803,6 +1808,7 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td, break; case COMP_DEV_ERR: case COMP_STALL: + case COMP_TX_ERR: frame->status = -EPROTO; skip_td = true; break; @@ -1883,13 +1889,16 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td, switch (trb_comp_code) { case COMP_SUCCESS: /* Double check that the HW transferred everything. */ - if (event_trb != td->last_trb) { + if (event_trb != td->last_trb || + TRB_LEN(le32_to_cpu(event->transfer_len)) != 0) { xhci_warn(xhci, "WARN Successful completion " "on short TX\n"); if (td->urb->transfer_flags & URB_SHORT_NOT_OK) *status = -EREMOTEIO; else *status = 0; + if ((xhci->quirks & XHCI_TRUST_TX_LENGTH)) + trb_comp_code = COMP_SHORT_TX; } else { *status = 0; } @@ -2048,6 +2057,13 @@ static int handle_tx_event(struct xhci_hcd *xhci, * transfer type */ case COMP_SUCCESS: + if (TRB_LEN(le32_to_cpu(event->transfer_len)) == 0) + break; + if (xhci->quirks & XHCI_TRUST_TX_LENGTH) + trb_comp_code = COMP_SHORT_TX; + else + xhci_warn(xhci, "WARN Successful completion on short TX: " + "needs XHCI_TRUST_TX_LENGTH quirk?\n"); case COMP_SHORT_TX: break; case COMP_STOP: @@ -2270,7 +2286,7 @@ cleanup: (status != 0 && !usb_endpoint_xfer_isoc(&urb->ep->desc))) xhci_dbg(xhci, "Giveback URB %p, len = %d, " - "expected = %x, status = %d\n", + "expected = %d, status = %d\n", urb, urb->actual_length, urb->transfer_buffer_length, status); @@ -3593,12 +3609,12 @@ int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, /* Queue an evaluate context command TRB */ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id) + u32 slot_id, bool command_must_succeed) { return queue_command(xhci, lower_32_bits(in_ctx_ptr), upper_32_bits(in_ctx_ptr), 0, TRB_TYPE(TRB_EVAL_CONTEXT) | SLOT_ID_FOR_TRB(slot_id), - false); + command_must_succeed); } /* diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 36641a7f2371..afdc73ee84a6 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -152,7 +152,7 @@ int xhci_reset(struct xhci_hcd *xhci) { u32 command; u32 state; - int ret; + int ret, i; state = xhci_readl(xhci, &xhci->op_regs->status); if ((state & STS_HALT) == 0) { @@ -175,7 +175,15 @@ int xhci_reset(struct xhci_hcd *xhci) * xHCI cannot write to any doorbells or operational registers other * than status until the "Controller Not Ready" flag is cleared. */ - return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); + ret = handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); + + for (i = 0; i < 2; ++i) { + xhci->bus_state[i].port_c_suspend = 0; + xhci->bus_state[i].suspended_ports = 0; + xhci->bus_state[i].resuming_ports = 0; + } + + return ret; } #ifdef CONFIG_PCI @@ -2438,7 +2446,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci, udev->slot_id, must_succeed); else ret = xhci_queue_evaluate_context(xhci, in_ctx->dma, - udev->slot_id); + udev->slot_id, must_succeed); if (ret < 0) { if (command) list_del(&command->cmd_list); @@ -3863,6 +3871,474 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev) #endif /* CONFIG_USB_SUSPEND */ +/*---------------------- USB 3.0 Link PM functions ------------------------*/ + +#ifdef CONFIG_PM +/* Service interval in nanoseconds = 2^(bInterval - 1) * 125us * 1000ns / 1us */ +static unsigned long long xhci_service_interval_to_ns( + struct usb_endpoint_descriptor *desc) +{ + return (1 << (desc->bInterval - 1)) * 125 * 1000; +} + +static u16 xhci_get_timeout_no_hub_lpm(struct usb_device *udev, + enum usb3_link_state state) +{ + unsigned long long sel; + unsigned long long pel; + unsigned int max_sel_pel; + char *state_name; + + switch (state) { + case USB3_LPM_U1: + /* Convert SEL and PEL stored in nanoseconds to microseconds */ + sel = DIV_ROUND_UP(udev->u1_params.sel, 1000); + pel = DIV_ROUND_UP(udev->u1_params.pel, 1000); + max_sel_pel = USB3_LPM_MAX_U1_SEL_PEL; + state_name = "U1"; + break; + case USB3_LPM_U2: + sel = DIV_ROUND_UP(udev->u2_params.sel, 1000); + pel = DIV_ROUND_UP(udev->u2_params.pel, 1000); + max_sel_pel = USB3_LPM_MAX_U2_SEL_PEL; + state_name = "U2"; + break; + default: + dev_warn(&udev->dev, "%s: Can't get timeout for non-U1 or U2 state.\n", + __func__); + return -EINVAL; + } + + if (sel <= max_sel_pel && pel <= max_sel_pel) + return USB3_LPM_DEVICE_INITIATED; + + if (sel > max_sel_pel) + dev_dbg(&udev->dev, "Device-initiated %s disabled " + "due to long SEL %llu ms\n", + state_name, sel); + else + dev_dbg(&udev->dev, "Device-initiated %s disabled " + "due to long PEL %llu\n ms", + state_name, pel); + return USB3_LPM_DISABLED; +} + +/* Returns the hub-encoded U1 timeout value. + * The U1 timeout should be the maximum of the following values: + * - For control endpoints, U1 system exit latency (SEL) * 3 + * - For bulk endpoints, U1 SEL * 5 + * - For interrupt endpoints: + * - Notification EPs, U1 SEL * 3 + * - Periodic EPs, max(105% of bInterval, U1 SEL * 2) + * - For isochronous endpoints, max(105% of bInterval, U1 SEL * 2) + */ +static u16 xhci_calculate_intel_u1_timeout(struct usb_device *udev, + struct usb_endpoint_descriptor *desc) +{ + unsigned long long timeout_ns; + int ep_type; + int intr_type; + + ep_type = usb_endpoint_type(desc); + switch (ep_type) { + case USB_ENDPOINT_XFER_CONTROL: + timeout_ns = udev->u1_params.sel * 3; + break; + case USB_ENDPOINT_XFER_BULK: + timeout_ns = udev->u1_params.sel * 5; + break; + case USB_ENDPOINT_XFER_INT: + intr_type = usb_endpoint_interrupt_type(desc); + if (intr_type == USB_ENDPOINT_INTR_NOTIFICATION) { + timeout_ns = udev->u1_params.sel * 3; + break; + } + /* Otherwise the calculation is the same as isoc eps */ + case USB_ENDPOINT_XFER_ISOC: + timeout_ns = xhci_service_interval_to_ns(desc); + timeout_ns = DIV_ROUND_UP_ULL(timeout_ns * 105, 100); + if (timeout_ns < udev->u1_params.sel * 2) + timeout_ns = udev->u1_params.sel * 2; + break; + default: + return 0; + } + + /* The U1 timeout is encoded in 1us intervals. */ + timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 1000); + /* Don't return a timeout of zero, because that's USB3_LPM_DISABLED. */ + if (timeout_ns == USB3_LPM_DISABLED) + timeout_ns++; + + /* If the necessary timeout value is bigger than what we can set in the + * USB 3.0 hub, we have to disable hub-initiated U1. + */ + if (timeout_ns <= USB3_LPM_U1_MAX_TIMEOUT) + return timeout_ns; + dev_dbg(&udev->dev, "Hub-initiated U1 disabled " + "due to long timeout %llu ms\n", timeout_ns); + return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U1); +} + +/* Returns the hub-encoded U2 timeout value. + * The U2 timeout should be the maximum of: + * - 10 ms (to avoid the bandwidth impact on the scheduler) + * - largest bInterval of any active periodic endpoint (to avoid going + * into lower power link states between intervals). + * - the U2 Exit Latency of the device + */ +static u16 xhci_calculate_intel_u2_timeout(struct usb_device *udev, + struct usb_endpoint_descriptor *desc) +{ + unsigned long long timeout_ns; + unsigned long long u2_del_ns; + + timeout_ns = 10 * 1000 * 1000; + + if ((usb_endpoint_xfer_int(desc) || usb_endpoint_xfer_isoc(desc)) && + (xhci_service_interval_to_ns(desc) > timeout_ns)) + timeout_ns = xhci_service_interval_to_ns(desc); + + u2_del_ns = udev->bos->ss_cap->bU2DevExitLat * 1000; + if (u2_del_ns > timeout_ns) + timeout_ns = u2_del_ns; + + /* The U2 timeout is encoded in 256us intervals */ + timeout_ns = DIV_ROUND_UP_ULL(timeout_ns, 256 * 1000); + /* If the necessary timeout value is bigger than what we can set in the + * USB 3.0 hub, we have to disable hub-initiated U2. + */ + if (timeout_ns <= USB3_LPM_U2_MAX_TIMEOUT) + return timeout_ns; + dev_dbg(&udev->dev, "Hub-initiated U2 disabled " + "due to long timeout %llu ms\n", timeout_ns); + return xhci_get_timeout_no_hub_lpm(udev, USB3_LPM_U2); +} + +static u16 xhci_call_host_update_timeout_for_endpoint(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_endpoint_descriptor *desc, + enum usb3_link_state state, + u16 *timeout) +{ + if (state == USB3_LPM_U1) { + if (xhci->quirks & XHCI_INTEL_HOST) + return xhci_calculate_intel_u1_timeout(udev, desc); + } else { + if (xhci->quirks & XHCI_INTEL_HOST) + return xhci_calculate_intel_u2_timeout(udev, desc); + } + + return USB3_LPM_DISABLED; +} + +static int xhci_update_timeout_for_endpoint(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_endpoint_descriptor *desc, + enum usb3_link_state state, + u16 *timeout) +{ + u16 alt_timeout; + + alt_timeout = xhci_call_host_update_timeout_for_endpoint(xhci, udev, + desc, state, timeout); + + /* If we found we can't enable hub-initiated LPM, or + * the U1 or U2 exit latency was too high to allow + * device-initiated LPM as well, just stop searching. + */ + if (alt_timeout == USB3_LPM_DISABLED || + alt_timeout == USB3_LPM_DEVICE_INITIATED) { + *timeout = alt_timeout; + return -E2BIG; + } + if (alt_timeout > *timeout) + *timeout = alt_timeout; + return 0; +} + +static int xhci_update_timeout_for_interface(struct xhci_hcd *xhci, + struct usb_device *udev, + struct usb_host_interface *alt, + enum usb3_link_state state, + u16 *timeout) +{ + int j; + + for (j = 0; j < alt->desc.bNumEndpoints; j++) { + if (xhci_update_timeout_for_endpoint(xhci, udev, + &alt->endpoint[j].desc, state, timeout)) + return -E2BIG; + continue; + } + return 0; +} + +static int xhci_check_intel_tier_policy(struct usb_device *udev, + enum usb3_link_state state) +{ + struct usb_device *parent; + unsigned int num_hubs; + + if (state == USB3_LPM_U2) + return 0; + + /* Don't enable U1 if the device is on a 2nd tier hub or lower. */ + for (parent = udev->parent, num_hubs = 0; parent->parent; + parent = parent->parent) + num_hubs++; + + if (num_hubs < 2) + return 0; + + dev_dbg(&udev->dev, "Disabling U1 link state for device" + " below second-tier hub.\n"); + dev_dbg(&udev->dev, "Plug device into first-tier hub " + "to decrease power consumption.\n"); + return -E2BIG; +} + +static int xhci_check_tier_policy(struct xhci_hcd *xhci, + struct usb_device *udev, + enum usb3_link_state state) +{ + if (xhci->quirks & XHCI_INTEL_HOST) + return xhci_check_intel_tier_policy(udev, state); + return -EINVAL; +} + +/* Returns the U1 or U2 timeout that should be enabled. + * If the tier check or timeout setting functions return with a non-zero exit + * code, that means the timeout value has been finalized and we shouldn't look + * at any more endpoints. + */ +static u16 xhci_calculate_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct usb_host_config *config; + char *state_name; + int i; + u16 timeout = USB3_LPM_DISABLED; + + if (state == USB3_LPM_U1) + state_name = "U1"; + else if (state == USB3_LPM_U2) + state_name = "U2"; + else { + dev_warn(&udev->dev, "Can't enable unknown link state %i\n", + state); + return timeout; + } + + if (xhci_check_tier_policy(xhci, udev, state) < 0) + return timeout; + + /* Gather some information about the currently installed configuration + * and alternate interface settings. + */ + if (xhci_update_timeout_for_endpoint(xhci, udev, &udev->ep0.desc, + state, &timeout)) + return timeout; + + config = udev->actconfig; + if (!config) + return timeout; + + for (i = 0; i < USB_MAXINTERFACES; i++) { + struct usb_driver *driver; + struct usb_interface *intf = config->interface[i]; + + if (!intf) + continue; + + /* Check if any currently bound drivers want hub-initiated LPM + * disabled. + */ + if (intf->dev.driver) { + driver = to_usb_driver(intf->dev.driver); + if (driver && driver->disable_hub_initiated_lpm) { + dev_dbg(&udev->dev, "Hub-initiated %s disabled " + "at request of driver %s\n", + state_name, driver->name); + return xhci_get_timeout_no_hub_lpm(udev, state); + } + } + + /* Not sure how this could happen... */ + if (!intf->cur_altsetting) + continue; + + if (xhci_update_timeout_for_interface(xhci, udev, + intf->cur_altsetting, + state, &timeout)) + return timeout; + } + return timeout; +} + +/* + * Issue an Evaluate Context command to change the Maximum Exit Latency in the + * slot context. If that succeeds, store the new MEL in the xhci_virt_device. + */ +static int xhci_change_max_exit_latency(struct xhci_hcd *xhci, + struct usb_device *udev, u16 max_exit_latency) +{ + struct xhci_virt_device *virt_dev; + struct xhci_command *command; + struct xhci_input_control_ctx *ctrl_ctx; + struct xhci_slot_ctx *slot_ctx; + unsigned long flags; + int ret; + + spin_lock_irqsave(&xhci->lock, flags); + if (max_exit_latency == xhci->devs[udev->slot_id]->current_mel) { + spin_unlock_irqrestore(&xhci->lock, flags); + return 0; + } + + /* Attempt to issue an Evaluate Context command to change the MEL. */ + virt_dev = xhci->devs[udev->slot_id]; + command = xhci->lpm_command; + xhci_slot_copy(xhci, command->in_ctx, virt_dev->out_ctx); + spin_unlock_irqrestore(&xhci->lock, flags); + + ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx); + ctrl_ctx->add_flags |= cpu_to_le32(SLOT_FLAG); + slot_ctx = xhci_get_slot_ctx(xhci, command->in_ctx); + slot_ctx->dev_info2 &= cpu_to_le32(~((u32) MAX_EXIT)); + slot_ctx->dev_info2 |= cpu_to_le32(max_exit_latency); + + xhci_dbg(xhci, "Set up evaluate context for LPM MEL change.\n"); + xhci_dbg(xhci, "Slot %u Input Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, command->in_ctx, 0); + + /* Issue and wait for the evaluate context command. */ + ret = xhci_configure_endpoint(xhci, udev, command, + true, true); + xhci_dbg(xhci, "Slot %u Output Context:\n", udev->slot_id); + xhci_dbg_ctx(xhci, virt_dev->out_ctx, 0); + + if (!ret) { + spin_lock_irqsave(&xhci->lock, flags); + virt_dev->current_mel = max_exit_latency; + spin_unlock_irqrestore(&xhci->lock, flags); + } + return ret; +} + +static int calculate_max_exit_latency(struct usb_device *udev, + enum usb3_link_state state_changed, + u16 hub_encoded_timeout) +{ + unsigned long long u1_mel_us = 0; + unsigned long long u2_mel_us = 0; + unsigned long long mel_us = 0; + bool disabling_u1; + bool disabling_u2; + bool enabling_u1; + bool enabling_u2; + + disabling_u1 = (state_changed == USB3_LPM_U1 && + hub_encoded_timeout == USB3_LPM_DISABLED); + disabling_u2 = (state_changed == USB3_LPM_U2 && + hub_encoded_timeout == USB3_LPM_DISABLED); + + enabling_u1 = (state_changed == USB3_LPM_U1 && + hub_encoded_timeout != USB3_LPM_DISABLED); + enabling_u2 = (state_changed == USB3_LPM_U2 && + hub_encoded_timeout != USB3_LPM_DISABLED); + + /* If U1 was already enabled and we're not disabling it, + * or we're going to enable U1, account for the U1 max exit latency. + */ + if ((udev->u1_params.timeout != USB3_LPM_DISABLED && !disabling_u1) || + enabling_u1) + u1_mel_us = DIV_ROUND_UP(udev->u1_params.mel, 1000); + if ((udev->u2_params.timeout != USB3_LPM_DISABLED && !disabling_u2) || + enabling_u2) + u2_mel_us = DIV_ROUND_UP(udev->u2_params.mel, 1000); + + if (u1_mel_us > u2_mel_us) + mel_us = u1_mel_us; + else + mel_us = u2_mel_us; + /* xHCI host controller max exit latency field is only 16 bits wide. */ + if (mel_us > MAX_EXIT) { + dev_warn(&udev->dev, "Link PM max exit latency of %lluus " + "is too big.\n", mel_us); + return -E2BIG; + } + return mel_us; +} + +/* Returns the USB3 hub-encoded value for the U1/U2 timeout. */ +int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + struct xhci_hcd *xhci; + u16 hub_encoded_timeout; + int mel; + int ret; + + xhci = hcd_to_xhci(hcd); + /* The LPM timeout values are pretty host-controller specific, so don't + * enable hub-initiated timeouts unless the vendor has provided + * information about their timeout algorithm. + */ + if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) || + !xhci->devs[udev->slot_id]) + return USB3_LPM_DISABLED; + + hub_encoded_timeout = xhci_calculate_lpm_timeout(hcd, udev, state); + mel = calculate_max_exit_latency(udev, state, hub_encoded_timeout); + if (mel < 0) { + /* Max Exit Latency is too big, disable LPM. */ + hub_encoded_timeout = USB3_LPM_DISABLED; + mel = 0; + } + + ret = xhci_change_max_exit_latency(xhci, udev, mel); + if (ret) + return ret; + return hub_encoded_timeout; +} + +int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + struct xhci_hcd *xhci; + u16 mel; + int ret; + + xhci = hcd_to_xhci(hcd); + if (!xhci || !(xhci->quirks & XHCI_LPM_SUPPORT) || + !xhci->devs[udev->slot_id]) + return 0; + + mel = calculate_max_exit_latency(udev, state, USB3_LPM_DISABLED); + ret = xhci_change_max_exit_latency(xhci, udev, mel); + if (ret) + return ret; + return 0; +} +#else /* CONFIG_PM */ + +int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + return USB3_LPM_DISABLED; +} + +int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state) +{ + return 0; +} +#endif /* CONFIG_PM */ + +/*-------------------------------------------------------------------------*/ + /* Once a hub descriptor is fetched for a device, we need to update the xHC's * internal data structures for the device. */ @@ -4090,7 +4566,6 @@ static int __init xhci_hcd_init(void) BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8); /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); - BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8); return 0; unreg_pci: xhci_unregister_pci(); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 3d69c4b2b542..de3d6e3e57be 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -362,8 +362,10 @@ struct xhci_op_regs { * Timeout can be up to 127us. 0xFF means an infinite timeout. */ #define PORT_U1_TIMEOUT(p) ((p) & 0xff) +#define PORT_U1_TIMEOUT_MASK 0xff /* Inactivity timer value for transitions into U2 */ #define PORT_U2_TIMEOUT(p) (((p) & 0xff) << 8) +#define PORT_U2_TIMEOUT_MASK (0xff << 8) /* Bits 24:31 for port testing */ /* USB2 Protocol PORTSPMSC */ @@ -914,6 +916,8 @@ struct xhci_virt_device { u8 real_port; struct xhci_interval_bw_table *bw_table; struct xhci_tt_bw_info *tt_info; + /* The current max exit latency for the enabled USB3 link states. */ + u16 current_mel; }; /* @@ -1362,6 +1366,8 @@ struct xhci_bus_state { u32 suspended_ports; u32 port_remote_wakeup; unsigned long resume_done[USB_MAXCHILDREN]; + /* which ports have started to resume */ + unsigned long resuming_ports; }; static inline unsigned int hcd_index(struct usb_hcd *hcd) @@ -1422,6 +1428,8 @@ struct xhci_hcd { /* slot enabling and address device helpers */ struct completion addr_dev; int slot_id; + /* For USB 3.0 LPM enable/disable. */ + struct xhci_command *lpm_command; /* Internal mirror of the HW's dcbaa */ struct xhci_virt_device *devs[MAX_HC_SLOTS]; /* For keeping track of bandwidth domains per roothub. */ @@ -1479,6 +1487,9 @@ struct xhci_hcd { #define XHCI_RESET_ON_RESUME (1 << 7) #define XHCI_SW_BW_CHECKING (1 << 8) #define XHCI_AMD_0x96_HOST (1 << 9) +#define XHCI_TRUST_TX_LENGTH (1 << 10) +#define XHCI_LPM_SUPPORT (1 << 11) +#define XHCI_INTEL_HOST (1 << 12) unsigned int num_active_eps; unsigned int limit_active_eps; /* There are two roothubs to keep track of bus suspend info for */ @@ -1752,7 +1763,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags, int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, u32 slot_id, bool command_must_succeed); int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr, - u32 slot_id); + u32 slot_id, bool command_must_succeed); int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index); int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id); @@ -1776,6 +1787,10 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, unsigned int slot_id, /* xHCI roothub code */ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, int port_id, u32 link_state); +int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state); +int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd, + struct usb_device *udev, enum usb3_link_state state); void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, int port_id, u32 port_bit); int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c index 575b56c79e97..7121b50098d3 100644 --- a/drivers/usb/image/mdc800.c +++ b/drivers/usb/image/mdc800.c @@ -284,18 +284,16 @@ static void mdc800_usb_irq (struct urb *urb) int data_received=0, wake_up; unsigned char* b=urb->transfer_buffer; struct mdc800_data* mdc800=urb->context; + struct device *dev = &mdc800->dev->dev; int status = urb->status; if (status >= 0) { - - //dbg ("%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); - if (mdc800_isBusy (b)) { if (!mdc800->camera_busy) { mdc800->camera_busy=1; - dbg ("gets busy"); + dev_dbg(dev, "gets busy\n"); } } else @@ -303,13 +301,13 @@ static void mdc800_usb_irq (struct urb *urb) if (mdc800->camera_busy && mdc800_isReady (b)) { mdc800->camera_busy=0; - dbg ("gets ready"); + dev_dbg(dev, "gets ready\n"); } } if (!(mdc800_isBusy (b) || mdc800_isReady (b))) { /* Store Data in camera_answer field */ - dbg ("%i %i %i %i %i %i %i %i ",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); + dev_dbg(dev, "%i %i %i %i %i %i %i %i \n",b[0],b[1],b[2],b[3],b[4],b[5],b[6],b[7]); memcpy (mdc800->camera_response,b,8); data_received=1; @@ -441,7 +439,7 @@ static int mdc800_usb_probe (struct usb_interface *intf, int irq_interval=0; int retval; - dbg ("(mdc800_usb_probe) called."); + dev_dbg(&intf->dev, "(%s) called.\n", __func__); if (mdc800->dev != NULL) @@ -554,7 +552,7 @@ static void mdc800_usb_disconnect (struct usb_interface *intf) { struct mdc800_data* mdc800 = usb_get_intfdata(intf); - dbg ("(mdc800_usb_disconnect) called"); + dev_dbg(&intf->dev, "(%s) called\n", __func__); if (mdc800) { if (mdc800->state == NOT_CONNECTED) @@ -656,7 +654,7 @@ static int mdc800_device_open (struct inode* inode, struct file *file) } mdc800->open=1; - dbg ("Mustek MDC800 device opened."); + dev_dbg(&mdc800->dev->dev, "Mustek MDC800 device opened.\n"); error_out: mutex_unlock(&mdc800->io_lock); @@ -670,7 +668,6 @@ error_out: static int mdc800_device_release (struct inode* inode, struct file *file) { int retval=0; - dbg ("Mustek MDC800 device closed."); mutex_lock(&mdc800->io_lock); if (mdc800->open && (mdc800->state != NOT_CONNECTED)) @@ -927,7 +924,7 @@ static ssize_t mdc800_device_write (struct file *file, const char __user *buf, s { mdc800->pic_len=(int) 65536*(unsigned char) mdc800->camera_response[0]+256*(unsigned char) mdc800->camera_response[1]+(unsigned char) mdc800->camera_response[2]; - dbg ("cached imagesize = %i",mdc800->pic_len); + dev_dbg(&mdc800->dev->dev, "cached imagesize = %i\n", mdc800->pic_len); } } diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index ac0d75a9005a..0fc6e5fc745f 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -88,6 +88,7 @@ static struct workqueue_struct *wq; static void appledisplay_complete(struct urb *urb) { struct appledisplay *pdata = urb->context; + struct device *dev = &pdata->udev->dev; unsigned long flags; int status = urb->status; int retval; @@ -97,18 +98,18 @@ static void appledisplay_complete(struct urb *urb) /* success */ break; case -EOVERFLOW: - printk(KERN_ERR "appletouch: OVERFLOW with data " - "length %d, actual length is %d\n", + dev_err(dev, + "OVERFLOW with data length %d, actual length is %d\n", ACD_URB_BUFFER_LEN, pdata->urb->actual_length); case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* This urb is terminated, clean up */ - dbg("%s - urb shuttingdown with status: %d", + dev_dbg(dev, "%s - urb shuttingdown with status: %d\n", __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", + dev_dbg(dev, "%s - nonzero urb status received: %d/n", __func__, status); goto exit; } @@ -132,8 +133,7 @@ static void appledisplay_complete(struct urb *urb) exit: retval = usb_submit_urb(pdata->urb, GFP_ATOMIC); if (retval) { - dev_err(&pdata->udev->dev, - "%s - usb_submit_urb failed with result %d\n", + dev_err(dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval); } } diff --git a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c index da97dcec1f32..d65984dee751 100644 --- a/drivers/usb/misc/emi26.c +++ b/drivers/usb/misc/emi26.c @@ -78,18 +78,14 @@ static int emi26_load_firmware (struct usb_device *dev) const struct firmware *bitstream_fw = NULL; const struct firmware *firmware_fw = NULL; const struct ihex_binrec *rec; - int err; + int err = -ENOMEM; int i; __u32 addr; /* Address to write */ __u8 *buf; buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL); - if (!buf) { - dev_err(&dev->dev, "%s - error loading firmware: error = %d\n", - __func__, -ENOMEM); - err = -ENOMEM; + if (!buf) goto wraperr; - } err = request_ihex_firmware(&loader_fw, "emi26/loader.fw", &dev->dev); if (err) @@ -111,11 +107,8 @@ static int emi26_load_firmware (struct usb_device *dev) /* Assert reset (stop the CPU in the EMI) */ err = emi26_set_reset(dev,1); - if (err < 0) { - dev_err(&dev->dev,"%s - error loading firmware: error = %d\n", - __func__, err); + if (err < 0) goto wraperr; - } rec = (const struct ihex_binrec *)loader_fw->data; /* 1. We need to put the loader for the FPGA into the EZ-USB */ @@ -123,19 +116,15 @@ static int emi26_load_firmware (struct usb_device *dev) err = emi26_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } rec = ihex_next_binrec(rec); } /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ /* 2. We upload the FPGA firmware into the EMI @@ -153,18 +142,14 @@ static int emi26_load_firmware (struct usb_device *dev) rec = ihex_next_binrec(rec); } err = emi26_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } while (rec); /* Assert reset (stop the CPU in the EMI) */ err = emi26_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } /* 3. We need to put the loader for the firmware into the EZ-USB (again...) */ for (rec = (const struct ihex_binrec *)loader_fw->data; @@ -172,19 +157,15 @@ static int emi26_load_firmware (struct usb_device *dev) err = emi26_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } msleep(250); /* let device settle */ /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ @@ -194,19 +175,15 @@ static int emi26_load_firmware (struct usb_device *dev) err = emi26_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_EXTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } } - + /* Assert reset (stop the CPU in the EMI) */ err = emi26_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } for (rec = (const struct ihex_binrec *)firmware_fw->data; rec; rec = ihex_next_binrec(rec)) { @@ -214,19 +191,15 @@ static int emi26_load_firmware (struct usb_device *dev) err = emi26_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } } /* De-assert reset (let the CPU run) */ err = emi26_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ /* return 1 to fail the driver inialization @@ -234,6 +207,10 @@ static int emi26_load_firmware (struct usb_device *dev) err = 1; wraperr: + if (err < 0) + dev_err(&dev->dev,"%s - error loading firmware: error = %d\n", + __func__, err); + release_firmware(loader_fw); release_firmware(bitstream_fw); release_firmware(firmware_fw); diff --git a/drivers/usb/misc/emi62.c b/drivers/usb/misc/emi62.c index 4e0f167a6c4e..ff08015b230c 100644 --- a/drivers/usb/misc/emi62.c +++ b/drivers/usb/misc/emi62.c @@ -56,7 +56,7 @@ static int emi62_writememory(struct usb_device *dev, int address, unsigned char *buffer = kmemdup(data, length, GFP_KERNEL); if (!buffer) { - err("emi62: kmalloc(%d) failed.", length); + dev_err(&dev->dev, "kmalloc(%d) failed.\n", length); return -ENOMEM; } /* Note: usb_control_msg returns negative value on error or length of the @@ -73,9 +73,8 @@ static int emi62_set_reset (struct usb_device *dev, unsigned char reset_bit) dev_info(&dev->dev, "%s - %d\n", __func__, reset_bit); response = emi62_writememory (dev, CPUCS_REG, &reset_bit, 1, 0xa0); - if (response < 0) { - err("emi62: set_reset (%d) failed", reset_bit); - } + if (response < 0) + dev_err(&dev->dev, "set_reset (%d) failed\n", reset_bit); return response; } @@ -87,18 +86,15 @@ static int emi62_load_firmware (struct usb_device *dev) const struct firmware *bitstream_fw = NULL; const struct firmware *firmware_fw = NULL; const struct ihex_binrec *rec; - int err; + int err = -ENOMEM; int i; __u32 addr; /* Address to write */ __u8 *buf; dev_dbg(&dev->dev, "load_firmware\n"); buf = kmalloc(FW_LOAD_SIZE, GFP_KERNEL); - if (!buf) { - err( "%s - error loading firmware: error = %d", __func__, -ENOMEM); - err = -ENOMEM; + if (!buf) goto wraperr; - } err = request_ihex_firmware(&loader_fw, "emi62/loader.fw", &dev->dev); if (err) @@ -112,16 +108,13 @@ static int emi62_load_firmware (struct usb_device *dev) err = request_ihex_firmware(&firmware_fw, FIRMWARE_FW, &dev->dev); if (err) { nofw: - err( "%s - request_firmware() failed", __func__); goto wraperr; } /* Assert reset (stop the CPU in the EMI) */ err = emi62_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } rec = (const struct ihex_binrec *)loader_fw->data; @@ -130,19 +123,15 @@ static int emi62_load_firmware (struct usb_device *dev) err = emi62_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } rec = ihex_next_binrec(rec); } /* De-assert reset (let the CPU run) */ err = emi62_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ /* 2. We upload the FPGA firmware into the EMI @@ -160,18 +149,14 @@ static int emi62_load_firmware (struct usb_device *dev) rec = ihex_next_binrec(rec); } err = emi62_writememory(dev, addr, buf, i, ANCHOR_LOAD_FPGA); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } while (rec); /* Assert reset (stop the CPU in the EMI) */ err = emi62_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } /* 3. We need to put the loader for the firmware into the EZ-USB (again...) */ for (rec = (const struct ihex_binrec *)loader_fw->data; @@ -179,18 +164,14 @@ static int emi62_load_firmware (struct usb_device *dev) err = emi62_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_INTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } /* De-assert reset (let the CPU run) */ err = emi62_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ /* 4. We put the part of the firmware that lies in the external RAM into the EZ-USB */ @@ -201,19 +182,15 @@ static int emi62_load_firmware (struct usb_device *dev) err = emi62_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_EXTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } } /* Assert reset (stop the CPU in the EMI) */ err = emi62_set_reset(dev,1); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } for (rec = (const struct ihex_binrec *)firmware_fw->data; rec; rec = ihex_next_binrec(rec)) { @@ -221,19 +198,15 @@ static int emi62_load_firmware (struct usb_device *dev) err = emi62_writememory(dev, be32_to_cpu(rec->addr), rec->data, be16_to_cpu(rec->len), ANCHOR_LOAD_EXTERNAL); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } } } /* De-assert reset (let the CPU run) */ err = emi62_set_reset(dev,0); - if (err < 0) { - err("%s - error loading firmware: error = %d", __func__, err); + if (err < 0) goto wraperr; - } msleep(250); /* let device settle */ release_firmware(loader_fw); @@ -247,6 +220,9 @@ static int emi62_load_firmware (struct usb_device *dev) return 1; wraperr: + if (err < 0) + dev_err(&dev->dev,"%s - error loading firmware: error = %d\n", + __func__, err); release_firmware(loader_fw); release_firmware(bitstream_fw); release_firmware(firmware_fw); diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 0dee24698504..ce978384fda1 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -200,7 +200,8 @@ reset: return -EAGAIN; /* should be IMGSIZE == 65040 */ - dbg("read %d bytes fingerprint data", bytes_read); + dev_dbg(&dev->interface->dev, "read %d bytes fingerprint data\n", + bytes_read); return result; } @@ -366,14 +367,14 @@ static int idmouse_probe(struct usb_interface *interface, kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - err("Unable to allocate input buffer."); + dev_err(&interface->dev, "Unable to allocate input buffer.\n"); idmouse_delete(dev); return -ENOMEM; } } if (!(dev->bulk_in_endpointAddr)) { - err("Unable to find bulk-in endpoint."); + dev_err(&interface->dev, "Unable to find bulk-in endpoint.\n"); idmouse_delete(dev); return -ENODEV; } @@ -385,7 +386,7 @@ static int idmouse_probe(struct usb_interface *interface, result = usb_register_dev(interface, &idmouse_class); if (result) { /* something prevented us from registering this device */ - err("Unble to allocate minor number."); + dev_err(&interface->dev, "Unble to allocate minor number.\n"); usb_set_intfdata(interface, NULL); idmouse_delete(dev); return result; diff --git a/drivers/usb/misc/iowarrior.c b/drivers/usb/misc/iowarrior.c index 4fd0dc835ae5..db46143c67a6 100644 --- a/drivers/usb/misc/iowarrior.c +++ b/drivers/usb/misc/iowarrior.c @@ -610,8 +610,8 @@ static int iowarrior_open(struct inode *inode, struct file *file) interface = usb_find_interface(&iowarrior_driver, subminor); if (!interface) { mutex_unlock(&iowarrior_mutex); - err("%s - error, can't find device for minor %d", __func__, - subminor); + printk(KERN_ERR "%s - error, can't find device for minor %d\n", + __func__, subminor); return -ENODEV; } diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 5db4ab52061e..ac762299eaa8 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -334,8 +334,8 @@ static int ld_usb_open(struct inode *inode, struct file *file) interface = usb_find_interface(&ld_usb_driver, subminor); if (!interface) { - err("%s - error, can't find device for minor %d\n", - __func__, subminor); + printk(KERN_ERR "%s - error, can't find device for minor %d\n", + __func__, subminor); return -ENODEV; } @@ -485,7 +485,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { retval = -ENODEV; - err("No device or device unplugged %d\n", retval); + printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -565,7 +565,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, /* verify that the device wasn't unplugged */ if (dev->intf == NULL) { retval = -ENODEV; - err("No device or device unplugged %d\n", retval); + printk(KERN_ERR "ldusb: No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -603,7 +603,9 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, bytes_to_write, USB_CTRL_SET_TIMEOUT * HZ); if (retval < 0) - err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval); + dev_err(&dev->intf->dev, + "Couldn't submit HID_REQ_SET_REPORT %d\n", + retval); goto unlock_exit; } @@ -624,7 +626,8 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); if (retval) { dev->interrupt_out_busy = 0; - err("Couldn't submit interrupt_out_urb %d\n", retval); + dev_err(&dev->intf->dev, + "Couldn't submit interrupt_out_urb %d\n", retval); goto unlock_exit; } retval = bytes_to_write; diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 575222042767..a2702cbfe804 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -354,8 +354,8 @@ static int tower_open (struct inode *inode, struct file *file) interface = usb_find_interface (&tower_driver, subminor); if (!interface) { - err ("%s - error, can't find device for minor %d", - __func__, subminor); + printk(KERN_ERR "%s - error, can't find device for minor %d\n", + __func__, subminor); retval = -ENODEV; goto exit; } @@ -397,7 +397,8 @@ static int tower_open (struct inode *inode, struct file *file) sizeof(reset_reply), 1000); if (result < 0) { - err("LEGO USB Tower reset control request failed"); + dev_err(&dev->udev->dev, + "LEGO USB Tower reset control request failed\n"); retval = result; goto unlock_exit; } @@ -420,7 +421,8 @@ static int tower_open (struct inode *inode, struct file *file) retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL); if (retval) { - err("Couldn't submit interrupt_in_urb %d", retval); + dev_err(&dev->udev->dev, + "Couldn't submit interrupt_in_urb %d\n", retval); dev->interrupt_in_running = 0; dev->open_count = 0; goto unlock_exit; @@ -608,7 +610,7 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - err("No device or device unplugged %d", retval); + printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -697,7 +699,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t /* verify that the device wasn't unplugged */ if (dev->udev == NULL) { retval = -ENODEV; - err("No device or device unplugged %d", retval); + printk(KERN_ERR "legousbtower: No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -744,7 +746,8 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL); if (retval) { dev->interrupt_out_busy = 0; - err("Couldn't submit interrupt_out_urb %d", retval); + dev_err(&dev->udev->dev, + "Couldn't submit interrupt_out_urb %d\n", retval); goto unlock_exit; } retval = bytes_to_write; @@ -803,9 +806,10 @@ resubmit: /* resubmit if we're still running */ if (dev->interrupt_in_running && dev->udev) { retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC); - if (retval) { - err("%s: usb_submit_urb failed (%d)", __func__, retval); - } + if (retval) + dev_err(&dev->udev->dev, + "%s: usb_submit_urb failed (%d)\n", + __func__, retval); } exit: @@ -852,6 +856,7 @@ static void tower_interrupt_out_callback (struct urb *urb) */ static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id) { + struct device *idev = &interface->dev; struct usb_device *udev = interface_to_usbdev(interface); struct lego_usb_tower *dev = NULL; struct usb_host_interface *iface_desc; @@ -871,7 +876,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL); if (dev == NULL) { - err ("Out of memory"); + dev_err(idev, "Out of memory\n"); goto exit; } @@ -915,37 +920,37 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device } } if(dev->interrupt_in_endpoint == NULL) { - err("interrupt in endpoint not found"); + dev_err(idev, "interrupt in endpoint not found\n"); goto error; } if (dev->interrupt_out_endpoint == NULL) { - err("interrupt out endpoint not found"); + dev_err(idev, "interrupt out endpoint not found\n"); goto error; } dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL); if (!dev->read_buffer) { - err("Couldn't allocate read_buffer"); + dev_err(idev, "Couldn't allocate read_buffer\n"); goto error; } dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL); if (!dev->interrupt_in_buffer) { - err("Couldn't allocate interrupt_in_buffer"); + dev_err(idev, "Couldn't allocate interrupt_in_buffer\n"); goto error; } dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_in_urb) { - err("Couldn't allocate interrupt_in_urb"); + dev_err(idev, "Couldn't allocate interrupt_in_urb\n"); goto error; } dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) { - err("Couldn't allocate interrupt_out_buffer"); + dev_err(idev, "Couldn't allocate interrupt_out_buffer\n"); goto error; } dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_out_urb) { - err("Couldn't allocate interrupt_out_urb"); + dev_err(idev, "Couldn't allocate interrupt_out_urb\n"); goto error; } dev->interrupt_in_interval = interrupt_in_interval ? interrupt_in_interval : dev->interrupt_in_endpoint->bInterval; @@ -958,7 +963,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device if (retval) { /* something prevented us from registering this driver */ - err ("Not able to get a minor for this device."); + dev_err(idev, "Not able to get a minor for this device.\n"); usb_set_intfdata (interface, NULL); goto error; } @@ -980,7 +985,7 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device sizeof(get_version_reply), 1000); if (result < 0) { - err("LEGO USB Tower get version control request failed"); + dev_err(idev, "LEGO USB Tower get version control request failed\n"); retval = result; goto error; } diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c index 487a8ce0775e..1084124c4a44 100644 --- a/drivers/usb/misc/rio500.c +++ b/drivers/usb/misc/rio500.c @@ -153,10 +153,10 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) requesttype = rio_cmd.requesttype | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - dbg - ("sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x", - requesttype, rio_cmd.request, rio_cmd.value, - rio_cmd.index, rio_cmd.length); + dev_dbg(&rio->rio_dev->dev, + "sending command:reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", + requesttype, rio_cmd.request, rio_cmd.value, + rio_cmd.index, rio_cmd.length); /* Send rio control message */ retries = 3; while (retries) { @@ -171,11 +171,14 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) if (result == -ETIMEDOUT) retries--; else if (result < 0) { - err("Error executing ioctrl. code = %d", result); + dev_err(&rio->rio_dev->dev, + "Error executing ioctrl. code = %d\n", + result); retries = 0; } else { - dbg("Executed ioctl. Result = %d (data=%02x)", - result, buffer[0]); + dev_dbg(&rio->rio_dev->dev, + "Executed ioctl. Result = %d (data=%02x)\n", + result, buffer[0]); if (copy_to_user(rio_cmd.buffer, buffer, rio_cmd.length)) { free_page((unsigned long) buffer); @@ -221,9 +224,10 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) requesttype = rio_cmd.requesttype | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE; - dbg("sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x", - requesttype, rio_cmd.request, rio_cmd.value, - rio_cmd.index, rio_cmd.length); + dev_dbg(&rio->rio_dev->dev, + "sending command: reqtype=%0x req=%0x value=%0x index=%0x len=%0x\n", + requesttype, rio_cmd.request, rio_cmd.value, + rio_cmd.index, rio_cmd.length); /* Send rio control message */ retries = 3; while (retries) { @@ -238,10 +242,13 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg) if (result == -ETIMEDOUT) retries--; else if (result < 0) { - err("Error executing ioctrl. code = %d", result); + dev_err(&rio->rio_dev->dev, + "Error executing ioctrl. code = %d\n", + result); retries = 0; } else { - dbg("Executed ioctl. Result = %d", result); + dev_dbg(&rio->rio_dev->dev, + "Executed ioctl. Result = %d\n", result); retries = 0; } @@ -313,8 +320,9 @@ write_rio(struct file *file, const char __user *buffer, usb_sndbulkpipe(rio->rio_dev, 2), obuf, thistime, &partial, 5000); - dbg("write stats: result:%d thistime:%lu partial:%u", - result, thistime, partial); + dev_dbg(&rio->rio_dev->dev, + "write stats: result:%d thistime:%lu partial:%u\n", + result, thistime, partial); if (result == -ETIMEDOUT) { /* NAK - so hold for a while */ if (!maxretry--) { @@ -332,7 +340,8 @@ write_rio(struct file *file, const char __user *buffer, break; }; if (result) { - err("Write Whoops - %x", result); + dev_err(&rio->rio_dev->dev, "Write Whoops - %x\n", + result); errn = -EIO; goto error; } @@ -393,15 +402,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) ibuf, this_read, &partial, 8000); - dbg("read stats: result:%d this_read:%u partial:%u", - result, this_read, partial); + dev_dbg(&rio->rio_dev->dev, + "read stats: result:%d this_read:%u partial:%u\n", + result, this_read, partial); if (partial) { count = this_read = partial; } else if (result == -ETIMEDOUT || result == 15) { /* FIXME: 15 ??? */ if (!maxretry--) { mutex_unlock(&(rio->lock)); - err("read_rio: maxretry timeout"); + dev_err(&rio->rio_dev->dev, + "read_rio: maxretry timeout\n"); return -ETIME; } prepare_to_wait(&rio->wait_q, &wait, TASK_INTERRUPTIBLE); @@ -410,8 +421,9 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos) continue; } else if (result != -EREMOTEIO) { mutex_unlock(&(rio->lock)); - err("Read Whoops - result:%u partial:%u this_read:%u", - result, partial, this_read); + dev_err(&rio->rio_dev->dev, + "Read Whoops - result:%u partial:%u this_read:%u\n", + result, partial, this_read); return -EIO; } else { mutex_unlock(&(rio->lock)); @@ -459,26 +471,29 @@ static int probe_rio(struct usb_interface *intf, retval = usb_register_dev(intf, &usb_rio_class); if (retval) { - err("Not able to get a minor for this device."); + dev_err(&dev->dev, + "Not able to get a minor for this device.\n"); return -ENOMEM; } rio->rio_dev = dev; if (!(rio->obuf = kmalloc(OBUF_SIZE, GFP_KERNEL))) { - err("probe_rio: Not enough memory for the output buffer"); + dev_err(&dev->dev, + "probe_rio: Not enough memory for the output buffer\n"); usb_deregister_dev(intf, &usb_rio_class); return -ENOMEM; } - dbg("probe_rio: obuf address:%p", rio->obuf); + dev_dbg(&intf->dev, "obuf address:%p\n", rio->obuf); if (!(rio->ibuf = kmalloc(IBUF_SIZE, GFP_KERNEL))) { - err("probe_rio: Not enough memory for the input buffer"); + dev_err(&dev->dev, + "probe_rio: Not enough memory for the input buffer\n"); usb_deregister_dev(intf, &usb_rio_class); kfree(rio->obuf); return -ENOMEM; } - dbg("probe_rio: ibuf address:%p", rio->ibuf); + dev_dbg(&intf->dev, "ibuf address:%p\n", rio->ibuf); mutex_init(&(rio->lock)); diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c index e2b4bd31c2b6..89927bcff974 100644 --- a/drivers/usb/misc/usblcd.c +++ b/drivers/usb/misc/usblcd.c @@ -87,8 +87,8 @@ static int lcd_open(struct inode *inode, struct file *file) interface = usb_find_interface(&lcd_driver, subminor); if (!interface) { mutex_unlock(&lcd_mutex); - err("USBLCD: %s - error, can't find device for minor %d", - __func__, subminor); + printk(KERN_ERR "USBLCD: %s - error, can't find device for minor %d\n", + __func__, subminor); return -ENODEV; } @@ -209,8 +209,8 @@ static void lcd_write_bulk_callback(struct urb *urb) !(status == -ENOENT || status == -ECONNRESET || status == -ESHUTDOWN)) { - dbg("USBLCD: %s - nonzero write bulk status received: %d", - __func__, status); + dev_dbg(&dev->interface->dev, + "nonzero write bulk status received: %d\n", status); } /* free up our allocated buffer */ @@ -268,8 +268,9 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, /* send the data out the bulk port */ retval = usb_submit_urb(urb, GFP_KERNEL); if (retval) { - err("USBLCD: %s - failed submitting write urb, error %d", - __func__, retval); + dev_err(&dev->udev->dev, + "%s - failed submitting write urb, error %d\n", + __func__, retval); goto error_unanchor; } @@ -322,7 +323,7 @@ static int lcd_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - err("Out of memory"); + dev_err(&interface->dev, "Out of memory\n"); goto error; } kref_init(&dev->kref); @@ -352,7 +353,8 @@ static int lcd_probe(struct usb_interface *interface, dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - err("Could not allocate bulk_in_buffer"); + dev_err(&interface->dev, + "Could not allocate bulk_in_buffer\n"); goto error; } } @@ -364,7 +366,8 @@ static int lcd_probe(struct usb_interface *interface, } } if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { - err("Could not find both bulk-in and bulk-out endpoints"); + dev_err(&interface->dev, + "Could not find both bulk-in and bulk-out endpoints\n"); goto error; } @@ -375,7 +378,8 @@ static int lcd_probe(struct usb_interface *interface, retval = usb_register_dev(interface, &lcd_class); if (retval) { /* something prevented us from registering this driver */ - err("Not able to get a minor for this device."); + dev_err(&interface->dev, + "Not able to get a minor for this device.\n"); usb_set_intfdata(interface, NULL); goto error; } diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c index 9dcb68f04f03..055b84adedac 100644 --- a/drivers/usb/misc/usbtest.c +++ b/drivers/usb/misc/usbtest.c @@ -1028,7 +1028,10 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param) case 13: /* short read, resembling case 10 */ req.wValue = cpu_to_le16((USB_DT_CONFIG << 8) | 0); /* last data packet "should" be DATA1, not DATA0 */ - len = 1024 - udev->descriptor.bMaxPacketSize0; + if (udev->speed == USB_SPEED_SUPER) + len = 1024 - 512; + else + len = 1024 - udev->descriptor.bMaxPacketSize0; expected = -EREMOTEIO; break; case 14: /* short read; try to fill the last packet */ @@ -1387,11 +1390,15 @@ static int test_halt(struct usbtest_dev *tdev, int ep, struct urb *urb) static int halt_simple(struct usbtest_dev *dev) { - int ep; - int retval = 0; - struct urb *urb; + int ep; + int retval = 0; + struct urb *urb; + struct usb_device *udev = testdev_to_usbdev(dev); - urb = simple_alloc_urb(testdev_to_usbdev(dev), 0, 512); + if (udev->speed == USB_SPEED_SUPER) + urb = simple_alloc_urb(udev, 0, 1024); + else + urb = simple_alloc_urb(udev, 0, 512); if (urb == NULL) return -ENOMEM; diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c index 8b1d94a76914..29cad9e0a7a9 100644 --- a/drivers/usb/misc/uss720.c +++ b/drivers/usb/misc/uss720.c @@ -85,9 +85,9 @@ static void destroy_priv(struct kref *kref) { struct parport_uss720_private *priv = container_of(kref, struct parport_uss720_private, ref_count); + dev_dbg(&priv->usbdev->dev, "destroying priv datastructure\n"); usb_put_dev(priv->usbdev); kfree(priv); - dbg("destroying priv datastructure"); } static void destroy_async(struct kref *kref) @@ -118,14 +118,17 @@ static void async_complete(struct urb *urb) priv = rq->priv; pp = priv->pp; if (status) { - err("async_complete: urb error %d", status); + dev_err(&urb->dev->dev, "async_complete: urb error %d\n", + status); } else if (rq->dr.bRequest == 3) { memcpy(priv->reg, rq->reg, sizeof(priv->reg)); #if 0 - dbg("async_complete regs %02x %02x %02x %02x %02x %02x %02x", - (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], (unsigned int)priv->reg[2], - (unsigned int)priv->reg[3], (unsigned int)priv->reg[4], (unsigned int)priv->reg[5], - (unsigned int)priv->reg[6]); + dev_dbg(&priv->usbdev->dev, + "async_complete regs %02x %02x %02x %02x %02x %02x %02x\n", + (unsigned int)priv->reg[0], (unsigned int)priv->reg[1], + (unsigned int)priv->reg[2], (unsigned int)priv->reg[3], + (unsigned int)priv->reg[4], (unsigned int)priv->reg[5], + (unsigned int)priv->reg[6]); #endif /* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */ if (rq->reg[2] & rq->reg[1] & 0x10 && pp) @@ -151,7 +154,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p return NULL; rq = kmalloc(sizeof(struct uss720_async_request), mem_flags); if (!rq) { - err("submit_async_request out of memory"); + dev_err(&usbdev->dev, "submit_async_request out of memory\n"); return NULL; } kref_init(&rq->ref_count); @@ -162,7 +165,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p rq->urb = usb_alloc_urb(0, mem_flags); if (!rq->urb) { kref_put(&rq->ref_count, destroy_async); - err("submit_async_request out of memory"); + dev_err(&usbdev->dev, "submit_async_request out of memory\n"); return NULL; } rq->dr.bRequestType = requesttype; @@ -182,7 +185,7 @@ static struct uss720_async_request *submit_async_request(struct parport_uss720_p if (!ret) return rq; destroy_async(&rq->ref_count); - err("submit_async_request submit_urb failed with %d", ret); + dev_err(&usbdev->dev, "submit_async_request submit_urb failed with %d\n", ret); return NULL; } @@ -217,7 +220,8 @@ static int get_1284_register(struct parport *pp, unsigned char reg, unsigned cha priv = pp->private_data; rq = submit_async_request(priv, 3, 0xc0, ((unsigned int)reg) << 8, 0, mem_flags); if (!rq) { - err("get_1284_register(%u) failed", (unsigned int)reg); + dev_err(&priv->usbdev->dev, "get_1284_register(%u) failed", + (unsigned int)reg); return -EIO; } if (!val) { @@ -248,7 +252,8 @@ static int set_1284_register(struct parport *pp, unsigned char reg, unsigned cha priv = pp->private_data; rq = submit_async_request(priv, 4, 0x40, (((unsigned int)reg) << 8) | val, 0, mem_flags); if (!rq) { - err("set_1284_register(%u,%u) failed", (unsigned int)reg, (unsigned int)val); + dev_err(&priv->usbdev->dev, "set_1284_register(%u,%u) failed", + (unsigned int)reg, (unsigned int)val); return -EIO; } kref_put(&rq->ref_count, destroy_async); @@ -690,9 +695,9 @@ static int uss720_probe(struct usb_interface *intf, unsigned char reg; int i; - dbg("probe: vendor id 0x%x, device id 0x%x\n", - le16_to_cpu(usbdev->descriptor.idVendor), - le16_to_cpu(usbdev->descriptor.idProduct)); + dev_dbg(&intf->dev, "probe: vendor id 0x%x, device id 0x%x\n", + le16_to_cpu(usbdev->descriptor.idVendor), + le16_to_cpu(usbdev->descriptor.idProduct)); /* our known interfaces have 3 alternate settings */ if (intf->num_altsetting != 3) { @@ -700,7 +705,7 @@ static int uss720_probe(struct usb_interface *intf, return -ENODEV; } i = usb_set_interface(usbdev, intf->altsetting->desc.bInterfaceNumber, 2); - dbg("set inteface result %d", i); + dev_dbg(&intf->dev, "set inteface result %d\n", i); interface = intf->cur_altsetting; @@ -731,11 +736,13 @@ static int uss720_probe(struct usb_interface *intf, set_1284_register(pp, 2, 0x0c, GFP_KERNEL); /* debugging */ get_1284_register(pp, 0, ®, GFP_KERNEL); - dbg("reg: %02x %02x %02x %02x %02x %02x %02x", - priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], priv->reg[4], priv->reg[5], priv->reg[6]); + dev_dbg(&intf->dev, "reg: %02x %02x %02x %02x %02x %02x %02x\n", + priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3], + priv->reg[4], priv->reg[5], priv->reg[6]); endpoint = &interface->endpoint[2]; - dbg("epaddr %d interval %d", endpoint->desc.bEndpointAddress, endpoint->desc.bInterval); + dev_dbg(&intf->dev, "epaddr %d interval %d\n", + endpoint->desc.bEndpointAddress, endpoint->desc.bInterval); parport_announce_port(pp); usb_set_intfdata(intf, pp); @@ -753,20 +760,20 @@ static void uss720_disconnect(struct usb_interface *intf) struct parport_uss720_private *priv; struct usb_device *usbdev; - dbg("disconnect"); + dev_dbg(&intf->dev, "disconnect\n"); usb_set_intfdata(intf, NULL); if (pp) { priv = pp->private_data; usbdev = priv->usbdev; priv->usbdev = NULL; priv->pp = NULL; - dbg("parport_remove_port"); + dev_dbg(&intf->dev, "parport_remove_port\n"); parport_remove_port(pp); parport_put_port(pp); kill_all_async_requests_priv(priv); kref_put(&priv->ref_count, destroy_priv); } - dbg("disconnect done"); + dev_dbg(&intf->dev, "disconnect done\n"); } /* table of cables that work through this driver */ diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c index 70201462e19c..42ad2e6d86c4 100644 --- a/drivers/usb/misc/yurex.c +++ b/drivers/usb/misc/yurex.c @@ -83,7 +83,8 @@ static void yurex_control_callback(struct urb *urb) int status = urb->status; if (status) { - err("%s - control failed: %d\n", __func__, status); + dev_err(&urb->dev->dev, "%s - control failed: %d\n", + __func__, status); wake_up_interruptible(&dev->waitq); return; } @@ -94,7 +95,7 @@ static void yurex_delete(struct kref *kref) { struct usb_yurex *dev = to_yurex_dev(kref); - dbg("yurex_delete"); + dev_dbg(&dev->interface->dev, "%s\n", __func__); usb_put_dev(dev->udev); if (dev->cntl_urb) { @@ -137,8 +138,9 @@ static void yurex_interrupt(struct urb *urb) case 0: /*success*/ break; case -EOVERFLOW: - err("%s - overflow with length %d, actual length is %d", - __func__, YUREX_BUF_SIZE, dev->urb->actual_length); + dev_err(&dev->interface->dev, + "%s - overflow with length %d, actual length is %d\n", + __func__, YUREX_BUF_SIZE, dev->urb->actual_length); case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: @@ -146,7 +148,8 @@ static void yurex_interrupt(struct urb *urb) /* The device is terminated, clean up */ return; default: - err("%s - unknown status received: %d", __func__, status); + dev_err(&dev->interface->dev, + "%s - unknown status received: %d\n", __func__, status); goto exit; } @@ -162,16 +165,19 @@ static void yurex_interrupt(struct urb *urb) if (i != 5) dev->bbu <<= 8; } - dbg("%s count: %lld", __func__, dev->bbu); + dev_dbg(&dev->interface->dev, "%s count: %lld\n", + __func__, dev->bbu); spin_unlock_irqrestore(&dev->lock, flags); kill_fasync(&dev->async_queue, SIGIO, POLL_IN); } else - dbg("data format error - no EOF"); + dev_dbg(&dev->interface->dev, + "data format error - no EOF\n"); break; case CMD_ACK: - dbg("%s ack: %c", __func__, buf[1]); + dev_dbg(&dev->interface->dev, "%s ack: %c\n", + __func__, buf[1]); wake_up_interruptible(&dev->waitq); break; } @@ -179,7 +185,7 @@ static void yurex_interrupt(struct urb *urb) exit: retval = usb_submit_urb(dev->urb, GFP_ATOMIC); if (retval) { - err("%s - usb_submit_urb failed: %d", + dev_err(&dev->interface->dev, "%s - usb_submit_urb failed: %d\n", __func__, retval); } } @@ -196,7 +202,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { - err("Out of memory"); + dev_err(&interface->dev, "Out of memory\n"); goto error; } kref_init(&dev->kref); @@ -219,7 +225,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ } if (!dev->int_in_endpointAddr) { retval = -ENODEV; - err("Could not find endpoints"); + dev_err(&interface->dev, "Could not find endpoints\n"); goto error; } @@ -227,14 +233,14 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate control URB */ dev->cntl_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->cntl_urb) { - err("Could not allocate control URB"); + dev_err(&interface->dev, "Could not allocate control URB\n"); goto error; } /* allocate buffer for control req */ dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL); if (!dev->cntl_req) { - err("Could not allocate cntl_req"); + dev_err(&interface->dev, "Could not allocate cntl_req\n"); goto error; } @@ -243,7 +249,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ GFP_KERNEL, &dev->cntl_urb->transfer_dma); if (!dev->cntl_buffer) { - err("Could not allocate cntl_buffer"); + dev_err(&interface->dev, "Could not allocate cntl_buffer\n"); goto error; } @@ -265,7 +271,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* allocate interrupt URB */ dev->urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->urb) { - err("Could not allocate URB"); + dev_err(&interface->dev, "Could not allocate URB\n"); goto error; } @@ -273,7 +279,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ dev->int_buffer = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE, GFP_KERNEL, &dev->urb->transfer_dma); if (!dev->int_buffer) { - err("Could not allocate int_buffer"); + dev_err(&interface->dev, "Could not allocate int_buffer\n"); goto error; } @@ -285,7 +291,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; if (usb_submit_urb(dev->urb, GFP_KERNEL)) { retval = -EIO; - err("Could not submitting URB"); + dev_err(&interface->dev, "Could not submitting URB\n"); goto error; } @@ -295,7 +301,8 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_ /* we can register the device now, as it is ready */ retval = usb_register_dev(interface, &yurex_class); if (retval) { - err("Not able to get a minor for this device."); + dev_err(&interface->dev, + "Not able to get a minor for this device.\n"); usb_set_intfdata(interface, NULL); goto error; } @@ -368,8 +375,8 @@ static int yurex_open(struct inode *inode, struct file *file) interface = usb_find_interface(&yurex_driver, subminor); if (!interface) { - err("%s - error, can't find device for minor %d", - __func__, subminor); + printk(KERN_ERR "%s - error, can't find device for minor %d", + __func__, subminor); retval = -ENODEV; goto exit; } @@ -505,7 +512,8 @@ static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t co /* send the data as the control msg */ prepare_to_wait(&dev->waitq, &wait, TASK_INTERRUPTIBLE); - dbg("%s - submit %c", __func__, dev->cntl_buffer[0]); + dev_dbg(&dev->interface->dev, "%s - submit %c\n", __func__, + dev->cntl_buffer[0]); retval = usb_submit_urb(dev->cntl_urb, GFP_KERNEL); if (retval >= 0) timeout = schedule_timeout(YUREX_WRITE_TIMEOUT); @@ -514,7 +522,9 @@ static ssize_t yurex_write(struct file *file, const char *user_buffer, size_t co mutex_unlock(&dev->io_mutex); if (retval < 0) { - err("%s - failed to send bulk msg, error %d", __func__, retval); + dev_err(&dev->interface->dev, + "%s - failed to send bulk msg, error %d\n", + __func__, retval); goto error; } if (set && timeout) diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index f70cab3beeec..ef0c3f9f0947 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -8,6 +8,7 @@ config USB_MUSB_HDRC tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)' depends on USB && USB_GADGET select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN) + select NOP_USB_XCEIV if (SOC_OMAPTI81XX || SOC_OMAPAM33XX) select TWL4030_USB if MACH_OMAP_3430SDP select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA select USB_OTG_UTILS @@ -54,6 +55,10 @@ config USB_MUSB_AM35X tristate "AM35x" depends on ARCH_OMAP +config USB_MUSB_DSPS + tristate "TI DSPS platforms" + depends on SOC_OMAPTI81XX || SOC_OMAPAM33XX + config USB_MUSB_BLACKFIN tristate "Blackfin" depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523) @@ -70,7 +75,8 @@ choice default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010 - default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X + default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X \ + || USB_MUSB_DSPS help Unfortunately, only one option can be enabled here. Ideally one should be able to build all these drivers into one kernel to diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile index 88bfb9dee4bf..3b858715b5ea 100644 --- a/drivers/usb/musb/Makefile +++ b/drivers/usb/musb/Makefile @@ -13,6 +13,7 @@ musb_hdrc-$(CONFIG_DEBUG_FS) += musb_debugfs.o # Hardware Glue Layer obj-$(CONFIG_USB_MUSB_OMAP2PLUS) += omap2430.o obj-$(CONFIG_USB_MUSB_AM35X) += am35x.o +obj-$(CONFIG_USB_MUSB_DSPS) += musb_dsps.o obj-$(CONFIG_USB_MUSB_TUSB6010) += tusb6010.o obj-$(CONFIG_USB_MUSB_DAVINCI) += davinci.o obj-$(CONFIG_USB_MUSB_DA8XX) += da8xx.o diff --git a/drivers/usb/musb/cppi_dma.c b/drivers/usb/musb/cppi_dma.c index 66bc376005d2..8637c1f69fc3 100644 --- a/drivers/usb/musb/cppi_dma.c +++ b/drivers/usb/musb/cppi_dma.c @@ -6,6 +6,7 @@ * The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci. */ +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/usb.h> diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 66aaccf04490..db3dff854b71 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1034,7 +1034,9 @@ static void musb_shutdown(struct platform_device *pdev) || defined(CONFIG_USB_MUSB_OMAP2PLUS) \ || defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \ || defined(CONFIG_USB_MUSB_AM35X) \ - || defined(CONFIG_USB_MUSB_AM35X_MODULE) + || defined(CONFIG_USB_MUSB_AM35X_MODULE) \ + || defined(CONFIG_USB_MUSB_DSPS) \ + || defined(CONFIG_USB_MUSB_DSPS_MODULE) static ushort __devinitdata fifo_mode = 4; #elif defined(CONFIG_USB_MUSB_UX500) \ || defined(CONFIG_USB_MUSB_UX500_MODULE) diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c new file mode 100644 index 000000000000..23db42db761a --- /dev/null +++ b/drivers/usb/musb/musb_dsps.c @@ -0,0 +1,711 @@ +/* + * Texas Instruments DSPS platforms "glue layer" + * + * Copyright (C) 2012, by Texas Instruments + * + * Based on the am35x "glue layer" code. + * + * This file is part of the Inventra Controller Driver for Linux. + * + * The Inventra Controller Driver for Linux 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. + * + * The Inventra Controller Driver for Linux is distributed in + * the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + * License for more details. + * + * You should have received a copy of the GNU General Public License + * along with The Inventra Controller Driver for Linux ; if not, + * write to the Free Software Foundation, Inc., 59 Temple Place, + * Suite 330, Boston, MA 02111-1307 USA + * + * musb_dsps.c will be a common file for all the TI DSPS platforms + * such as dm64x, dm36x, dm35x, da8x, am35x and ti81x. + * For now only ti81x is using this and in future davinci.c, am35x.c + * da8xx.c would be merged to this file after testing. + */ + +#include <linux/init.h> +#include <linux/io.h> +#include <linux/platform_device.h> +#include <linux/dma-mapping.h> +#include <linux/pm_runtime.h> +#include <linux/module.h> + +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/of_address.h> + +#include <plat/usb.h> + +#include "musb_core.h" + +/** + * avoid using musb_readx()/musb_writex() as glue layer should not be + * dependent on musb core layer symbols. + */ +static inline u8 dsps_readb(const void __iomem *addr, unsigned offset) + { return __raw_readb(addr + offset); } + +static inline u32 dsps_readl(const void __iomem *addr, unsigned offset) + { return __raw_readl(addr + offset); } + +static inline void dsps_writeb(void __iomem *addr, unsigned offset, u8 data) + { __raw_writeb(data, addr + offset); } + +static inline void dsps_writel(void __iomem *addr, unsigned offset, u32 data) + { __raw_writel(data, addr + offset); } + +/** + * DSPS musb wrapper register offset. + * FIXME: This should be expanded to have all the wrapper registers from TI DSPS + * musb ips. + */ +struct dsps_musb_wrapper { + u16 revision; + u16 control; + u16 status; + u16 eoi; + u16 epintr_set; + u16 epintr_clear; + u16 epintr_status; + u16 coreintr_set; + u16 coreintr_clear; + u16 coreintr_status; + u16 phy_utmi; + u16 mode; + + /* bit positions for control */ + unsigned reset:5; + + /* bit positions for interrupt */ + unsigned usb_shift:5; + u32 usb_mask; + u32 usb_bitmap; + unsigned drvvbus:5; + + unsigned txep_shift:5; + u32 txep_mask; + u32 txep_bitmap; + + unsigned rxep_shift:5; + u32 rxep_mask; + u32 rxep_bitmap; + + /* bit positions for phy_utmi */ + unsigned otg_disable:5; + + /* bit positions for mode */ + unsigned iddig:5; + /* miscellaneous stuff */ + u32 musb_core_offset; + u8 poll_seconds; +}; + +/** + * DSPS glue structure. + */ +struct dsps_glue { + struct device *dev; + struct platform_device *musb; /* child musb pdev */ + const struct dsps_musb_wrapper *wrp; /* wrapper register offsets */ + struct timer_list timer; /* otg_workaround timer */ +}; + +/** + * dsps_musb_enable - enable interrupts + */ +static void dsps_musb_enable(struct musb *musb) +{ + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + void __iomem *reg_base = musb->ctrl_base; + u32 epmask, coremask; + + /* Workaround: setup IRQs through both register sets. */ + epmask = ((musb->epmask & wrp->txep_mask) << wrp->txep_shift) | + ((musb->epmask & wrp->rxep_mask) << wrp->rxep_shift); + coremask = (wrp->usb_bitmap & ~MUSB_INTR_SOF); + + dsps_writel(reg_base, wrp->epintr_set, epmask); + dsps_writel(reg_base, wrp->coreintr_set, coremask); + /* Force the DRVVBUS IRQ so we can start polling for ID change. */ + if (is_otg_enabled(musb)) + dsps_writel(reg_base, wrp->coreintr_set, + (1 << wrp->drvvbus) << wrp->usb_shift); +} + +/** + * dsps_musb_disable - disable HDRC and flush interrupts + */ +static void dsps_musb_disable(struct musb *musb) +{ + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + void __iomem *reg_base = musb->ctrl_base; + + dsps_writel(reg_base, wrp->coreintr_clear, wrp->usb_bitmap); + dsps_writel(reg_base, wrp->epintr_clear, + wrp->txep_bitmap | wrp->rxep_bitmap); + dsps_writeb(musb->mregs, MUSB_DEVCTL, 0); + dsps_writel(reg_base, wrp->eoi, 0); +} + +static void otg_timer(unsigned long _musb) +{ + struct musb *musb = (void *)_musb; + void __iomem *mregs = musb->mregs; + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + u8 devctl; + unsigned long flags; + + /* + * We poll because DSPS IP's won't expose several OTG-critical + * status change events (from the transceiver) otherwise. + */ + devctl = dsps_readb(mregs, MUSB_DEVCTL); + dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, + otg_state_string(musb->xceiv->state)); + + spin_lock_irqsave(&musb->lock, flags); + switch (musb->xceiv->state) { + case OTG_STATE_A_WAIT_BCON: + devctl &= ~MUSB_DEVCTL_SESSION; + dsps_writeb(musb->mregs, MUSB_DEVCTL, devctl); + + devctl = dsps_readb(musb->mregs, MUSB_DEVCTL); + if (devctl & MUSB_DEVCTL_BDEVICE) { + musb->xceiv->state = OTG_STATE_B_IDLE; + MUSB_DEV_MODE(musb); + } else { + musb->xceiv->state = OTG_STATE_A_IDLE; + MUSB_HST_MODE(musb); + } + break; + case OTG_STATE_A_WAIT_VFALL: + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + dsps_writel(musb->ctrl_base, wrp->coreintr_set, + MUSB_INTR_VBUSERROR << wrp->usb_shift); + break; + case OTG_STATE_B_IDLE: + if (!is_peripheral_enabled(musb)) + break; + + devctl = dsps_readb(mregs, MUSB_DEVCTL); + if (devctl & MUSB_DEVCTL_BDEVICE) + mod_timer(&glue->timer, + jiffies + wrp->poll_seconds * HZ); + else + musb->xceiv->state = OTG_STATE_A_IDLE; + break; + default: + break; + } + spin_unlock_irqrestore(&musb->lock, flags); +} + +static void dsps_musb_try_idle(struct musb *musb, unsigned long timeout) +{ + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + static unsigned long last_timer; + + if (!is_otg_enabled(musb)) + return; + + if (timeout == 0) + timeout = jiffies + msecs_to_jiffies(3); + + /* Never idle if active, or when VBUS timeout is not set as host */ + if (musb->is_active || (musb->a_wait_bcon == 0 && + musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) { + dev_dbg(musb->controller, "%s active, deleting timer\n", + otg_state_string(musb->xceiv->state)); + del_timer(&glue->timer); + last_timer = jiffies; + return; + } + + if (time_after(last_timer, timeout) && timer_pending(&glue->timer)) { + dev_dbg(musb->controller, + "Longer idle timer already pending, ignoring...\n"); + return; + } + last_timer = timeout; + + dev_dbg(musb->controller, "%s inactive, starting idle timer for %u ms\n", + otg_state_string(musb->xceiv->state), + jiffies_to_msecs(timeout - jiffies)); + mod_timer(&glue->timer, timeout); +} + +static irqreturn_t dsps_interrupt(int irq, void *hci) +{ + struct musb *musb = hci; + void __iomem *reg_base = musb->ctrl_base; + struct device *dev = musb->controller; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + u32 epintr, usbintr; + + spin_lock_irqsave(&musb->lock, flags); + + /* Get endpoint interrupts */ + epintr = dsps_readl(reg_base, wrp->epintr_status); + musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift; + musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift; + + if (epintr) + dsps_writel(reg_base, wrp->epintr_status, epintr); + + /* Get usb core interrupts */ + usbintr = dsps_readl(reg_base, wrp->coreintr_status); + if (!usbintr && !epintr) + goto eoi; + + musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift; + if (usbintr) + dsps_writel(reg_base, wrp->coreintr_status, usbintr); + + dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", + usbintr, epintr); + /* + * DRVVBUS IRQs are the only proxy we have (a very poor one!) for + * DSPS IP's missing ID change IRQ. We need an ID change IRQ to + * switch appropriately between halves of the OTG state machine. + * Managing DEVCTL.SESSION per Mentor docs requires that we know its + * value but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. + * Also, DRVVBUS pulses for SRP (but not at 5V) ... + */ + if ((usbintr & MUSB_INTR_BABBLE) && is_host_enabled(musb)) + pr_info("CAUTION: musb: Babble Interrupt Occured\n"); + + if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { + int drvvbus = dsps_readl(reg_base, wrp->status); + void __iomem *mregs = musb->mregs; + u8 devctl = dsps_readb(mregs, MUSB_DEVCTL); + int err; + + err = is_host_enabled(musb) && (musb->int_usb & + MUSB_INTR_VBUSERROR); + if (err) { + /* + * The Mentor core doesn't debounce VBUS as needed + * to cope with device connect current spikes. This + * means it's not uncommon for bus-powered devices + * to get VBUS errors during enumeration. + * + * This is a workaround, but newer RTL from Mentor + * seems to allow a better one: "re"-starting sessions + * without waiting for VBUS to stop registering in + * devctl. + */ + musb->int_usb &= ~MUSB_INTR_VBUSERROR; + musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; + mod_timer(&glue->timer, + jiffies + wrp->poll_seconds * HZ); + WARNING("VBUS error workaround (delay coming)\n"); + } else if (is_host_enabled(musb) && drvvbus) { + musb->is_active = 1; + MUSB_HST_MODE(musb); + musb->xceiv->otg->default_a = 1; + musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; + del_timer(&glue->timer); + } else { + musb->is_active = 0; + MUSB_DEV_MODE(musb); + musb->xceiv->otg->default_a = 0; + musb->xceiv->state = OTG_STATE_B_IDLE; + } + + /* NOTE: this must complete power-on within 100 ms. */ + dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", + drvvbus ? "on" : "off", + otg_state_string(musb->xceiv->state), + err ? " ERROR" : "", + devctl); + ret = IRQ_HANDLED; + } + + if (musb->int_tx || musb->int_rx || musb->int_usb) + ret |= musb_interrupt(musb); + + eoi: + /* EOI needs to be written for the IRQ to be re-asserted. */ + if (ret == IRQ_HANDLED || epintr || usbintr) + dsps_writel(reg_base, wrp->eoi, 1); + + /* Poll for ID change */ + if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) + mod_timer(&glue->timer, jiffies + wrp->poll_seconds * HZ); + + spin_unlock_irqrestore(&musb->lock, flags); + + return ret; +} + +static int dsps_musb_init(struct musb *musb) +{ + struct device *dev = musb->controller; + struct musb_hdrc_platform_data *plat = dev->platform_data; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + const struct dsps_musb_wrapper *wrp = glue->wrp; + struct omap_musb_board_data *data = plat->board_data; + void __iomem *reg_base = musb->ctrl_base; + u32 rev, val; + int status; + + /* mentor core register starts at offset of 0x400 from musb base */ + musb->mregs += wrp->musb_core_offset; + + /* NOP driver needs change if supporting dual instance */ + usb_nop_xceiv_register(); + musb->xceiv = usb_get_transceiver(); + if (!musb->xceiv) + return -ENODEV; + + /* Returns zero if e.g. not clocked */ + rev = dsps_readl(reg_base, wrp->revision); + if (!rev) { + status = -ENODEV; + goto err0; + } + + if (is_host_enabled(musb)) + setup_timer(&glue->timer, otg_timer, (unsigned long) musb); + + /* Reset the musb */ + dsps_writel(reg_base, wrp->control, (1 << wrp->reset)); + + /* Start the on-chip PHY and its PLL. */ + if (data->set_phy_power) + data->set_phy_power(1); + + musb->isr = dsps_interrupt; + + /* reset the otgdisable bit, needed for host mode to work */ + val = dsps_readl(reg_base, wrp->phy_utmi); + val &= ~(1 << wrp->otg_disable); + dsps_writel(musb->ctrl_base, wrp->phy_utmi, val); + + /* clear level interrupt */ + dsps_writel(reg_base, wrp->eoi, 0); + + return 0; +err0: + usb_put_transceiver(musb->xceiv); + usb_nop_xceiv_unregister(); + return status; +} + +static int dsps_musb_exit(struct musb *musb) +{ + struct device *dev = musb->controller; + struct musb_hdrc_platform_data *plat = dev->platform_data; + struct omap_musb_board_data *data = plat->board_data; + struct platform_device *pdev = to_platform_device(dev->parent); + struct dsps_glue *glue = platform_get_drvdata(pdev); + + if (is_host_enabled(musb)) + del_timer_sync(&glue->timer); + + /* Shutdown the on-chip PHY and its PLL. */ + if (data->set_phy_power) + data->set_phy_power(0); + + /* NOP driver needs change if supporting dual instance */ + usb_put_transceiver(musb->xceiv); + usb_nop_xceiv_unregister(); + + return 0; +} + +static struct musb_platform_ops dsps_ops = { + .init = dsps_musb_init, + .exit = dsps_musb_exit, + + .enable = dsps_musb_enable, + .disable = dsps_musb_disable, + + .try_idle = dsps_musb_try_idle, +}; + +static u64 musb_dmamask = DMA_BIT_MASK(32); + +static int __devinit dsps_create_musb_pdev(struct dsps_glue *glue, u8 id) +{ + struct device *dev = glue->dev; + struct platform_device *pdev = to_platform_device(dev); + struct musb_hdrc_platform_data *pdata = dev->platform_data; + struct platform_device *musb; + struct resource *res; + struct resource resources[2]; + char res_name[10]; + int ret; + + /* get memory resource */ + sprintf(res_name, "musb%d", id); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); + if (!res) { + dev_err(dev, "%s get mem resource failed\n", res_name); + ret = -ENODEV; + goto err0; + } + res->parent = NULL; + resources[0] = *res; + + /* get irq resource */ + sprintf(res_name, "musb%d-irq", id); + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name); + if (!res) { + dev_err(dev, "%s get irq resource failed\n", res_name); + ret = -ENODEV; + goto err0; + } + strcpy((u8 *)res->name, "mc"); + res->parent = NULL; + resources[1] = *res; + + /* allocate the child platform device */ + musb = platform_device_alloc("musb-hdrc", -1); + if (!musb) { + dev_err(dev, "failed to allocate musb device\n"); + ret = -ENOMEM; + goto err0; + } + + musb->dev.parent = dev; + musb->dev.dma_mask = &musb_dmamask; + musb->dev.coherent_dma_mask = musb_dmamask; + + glue->musb = musb; + + pdata->platform_ops = &dsps_ops; + + ret = platform_device_add_resources(musb, resources, 2); + if (ret) { + dev_err(dev, "failed to add resources\n"); + goto err1; + } + + ret = platform_device_add_data(musb, pdata, sizeof(*pdata)); + if (ret) { + dev_err(dev, "failed to add platform_data\n"); + goto err1; + } + + ret = platform_device_add(musb); + if (ret) { + dev_err(dev, "failed to register musb device\n"); + goto err1; + } + + return 0; + +err1: + platform_device_put(musb); +err0: + return ret; +} + +static void __devexit dsps_delete_musb_pdev(struct dsps_glue *glue) +{ + platform_device_del(glue->musb); + platform_device_put(glue->musb); +} + +static int __devinit dsps_probe(struct platform_device *pdev) +{ + const struct platform_device_id *id = platform_get_device_id(pdev); + const struct dsps_musb_wrapper *wrp = + (struct dsps_musb_wrapper *)id->driver_data; + struct dsps_glue *glue; + struct resource *iomem; + int ret; + + /* allocate glue */ + glue = kzalloc(sizeof(*glue), GFP_KERNEL); + if (!glue) { + dev_err(&pdev->dev, "unable to allocate glue memory\n"); + ret = -ENOMEM; + goto err0; + } + + /* get memory resource */ + iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!iomem) { + dev_err(&pdev->dev, "failed to get usbss mem resourse\n"); + ret = -ENODEV; + goto err1; + } + + glue->dev = &pdev->dev; + + glue->wrp = kmemdup(wrp, sizeof(*wrp), GFP_KERNEL); + if (!glue->wrp) { + dev_err(&pdev->dev, "failed to duplicate wrapper struct memory\n"); + ret = -ENOMEM; + goto err1; + } + platform_set_drvdata(pdev, glue); + + /* create the child platform device for first instances of musb */ + ret = dsps_create_musb_pdev(glue, 0); + if (ret != 0) { + dev_err(&pdev->dev, "failed to create child pdev\n"); + goto err2; + } + + /* enable the usbss clocks */ + pm_runtime_enable(&pdev->dev); + + ret = pm_runtime_get_sync(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "pm_runtime_get_sync FAILED"); + goto err3; + } + + return 0; + +err3: + pm_runtime_disable(&pdev->dev); +err2: + kfree(glue->wrp); +err1: + kfree(glue); +err0: + return ret; +} +static int __devexit dsps_remove(struct platform_device *pdev) +{ + struct dsps_glue *glue = platform_get_drvdata(pdev); + + /* delete the child platform device */ + dsps_delete_musb_pdev(glue); + + /* disable usbss clocks */ + pm_runtime_put(&pdev->dev); + pm_runtime_disable(&pdev->dev); + kfree(glue->wrp); + kfree(glue); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int dsps_suspend(struct device *dev) +{ + struct musb_hdrc_platform_data *plat = dev->platform_data; + struct omap_musb_board_data *data = plat->board_data; + + /* Shutdown the on-chip PHY and its PLL. */ + if (data->set_phy_power) + data->set_phy_power(0); + + return 0; +} + +static int dsps_resume(struct device *dev) +{ + struct musb_hdrc_platform_data *plat = dev->platform_data; + struct omap_musb_board_data *data = plat->board_data; + + /* Start the on-chip PHY and its PLL. */ + if (data->set_phy_power) + data->set_phy_power(1); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); + +static const struct dsps_musb_wrapper ti81xx_driver_data __devinitconst = { + .revision = 0x00, + .control = 0x14, + .status = 0x18, + .eoi = 0x24, + .epintr_set = 0x38, + .epintr_clear = 0x40, + .epintr_status = 0x30, + .coreintr_set = 0x3c, + .coreintr_clear = 0x44, + .coreintr_status = 0x34, + .phy_utmi = 0xe0, + .mode = 0xe8, + .reset = 0, + .otg_disable = 21, + .iddig = 8, + .usb_shift = 0, + .usb_mask = 0x1ff, + .usb_bitmap = (0x1ff << 0), + .drvvbus = 8, + .txep_shift = 0, + .txep_mask = 0xffff, + .txep_bitmap = (0xffff << 0), + .rxep_shift = 16, + .rxep_mask = 0xfffe, + .rxep_bitmap = (0xfffe << 16), + .musb_core_offset = 0x400, + .poll_seconds = 2, +}; + +static const struct platform_device_id musb_dsps_id_table[] __devinitconst = { + { + .name = "musb-ti81xx", + .driver_data = (kernel_ulong_t) &ti81xx_driver_data, + }, + { }, /* Terminating Entry */ +}; +MODULE_DEVICE_TABLE(platform, musb_dsps_id_table); + +static const struct of_device_id musb_dsps_of_match[] __devinitconst = { + { .compatible = "musb-ti81xx", }, + { .compatible = "ti,ti81xx-musb", }, + { .compatible = "ti,am335x-musb", }, + { }, +}; +MODULE_DEVICE_TABLE(of, musb_dsps_of_match); + +static struct platform_driver dsps_usbss_driver = { + .probe = dsps_probe, + .remove = __devexit_p(dsps_remove), + .driver = { + .name = "musb-dsps", + .pm = &dsps_pm_ops, + .of_match_table = musb_dsps_of_match, + }, + .id_table = musb_dsps_id_table, +}; + +MODULE_DESCRIPTION("TI DSPS MUSB Glue Layer"); +MODULE_AUTHOR("Ravi B <ravibabu@ti.com>"); +MODULE_AUTHOR("Ajay Kumar Gupta <ajay.gupta@ti.com>"); +MODULE_LICENSE("GPL v2"); + +static int __init dsps_init(void) +{ + return platform_driver_register(&dsps_usbss_driver); +} +subsys_initcall(dsps_init); + +static void __exit dsps_exit(void) +{ + platform_driver_unregister(&dsps_usbss_driver); +} +module_exit(dsps_exit); diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h index 1d5eda26fbd1..f7c1c8e2dc3f 100644 --- a/drivers/usb/musb/musb_io.h +++ b/drivers/usb/musb/musb_io.h @@ -40,7 +40,7 @@ #if !defined(CONFIG_ARM) && !defined(CONFIG_SUPERH) \ && !defined(CONFIG_AVR32) && !defined(CONFIG_PPC32) \ && !defined(CONFIG_PPC64) && !defined(CONFIG_BLACKFIN) \ - && !defined(CONFIG_MIPS) + && !defined(CONFIG_MIPS) && !defined(CONFIG_M68K) static inline void readsl(const void __iomem *addr, void *buf, int len) { insl((unsigned long)addr, buf, len); } static inline void readsw(const void __iomem *addr, void *buf, int len) diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c index a0a2178974fe..bde6298a9693 100644 --- a/drivers/usb/otg/gpio_vbus.c +++ b/drivers/usb/otg/gpio_vbus.c @@ -37,7 +37,9 @@ struct gpio_vbus_data { struct regulator *vbus_draw; int vbus_draw_enabled; unsigned mA; - struct work_struct work; + struct delayed_work work; + int vbus; + int irq; }; @@ -51,8 +53,7 @@ struct gpio_vbus_data { * edges might be workable. */ #define VBUS_IRQ_FLAGS \ - ( IRQF_SAMPLE_RANDOM | IRQF_SHARED \ - | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING ) + (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) /* interface to regulator framework */ @@ -94,20 +95,26 @@ static int is_vbus_powered(struct gpio_vbus_mach_info *pdata) static void gpio_vbus_work(struct work_struct *work) { struct gpio_vbus_data *gpio_vbus = - container_of(work, struct gpio_vbus_data, work); + container_of(work, struct gpio_vbus_data, work.work); struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data; - int gpio, status; + int gpio, status, vbus; if (!gpio_vbus->phy.otg->gadget) return; + vbus = is_vbus_powered(pdata); + if ((vbus ^ gpio_vbus->vbus) == 0) + return; + gpio_vbus->vbus = vbus; + /* Peripheral controllers which manage the pullup themselves won't have * gpio_pullup configured here. If it's configured here, we'll do what * isp1301_omap::b_peripheral() does and enable the pullup here... although * that may complicate usb_gadget_{,dis}connect() support. */ gpio = pdata->gpio_pullup; - if (is_vbus_powered(pdata)) { + + if (vbus) { status = USB_EVENT_VBUS; gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL; gpio_vbus->phy.last_event = status; @@ -152,7 +159,7 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data) otg->gadget ? otg->gadget->name : "none"); if (otg->gadget) - schedule_work(&gpio_vbus->work); + schedule_delayed_work(&gpio_vbus->work, msecs_to_jiffies(100)); return IRQ_HANDLED; } @@ -166,12 +173,11 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg, struct gpio_vbus_data *gpio_vbus; struct gpio_vbus_mach_info *pdata; struct platform_device *pdev; - int gpio, irq; + int gpio; gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy); pdev = to_platform_device(gpio_vbus->dev); pdata = gpio_vbus->dev->platform_data; - irq = gpio_to_irq(pdata->gpio_vbus); gpio = pdata->gpio_pullup; if (!gadget) { @@ -195,7 +201,8 @@ static int gpio_vbus_set_peripheral(struct usb_otg *otg, dev_dbg(&pdev->dev, "registered gadget '%s'\n", gadget->name); /* initialize connection state */ - gpio_vbus_irq(irq, pdev); + gpio_vbus->vbus = 0; /* start with disconnected */ + gpio_vbus_irq(gpio_vbus->irq, pdev); return 0; } @@ -235,6 +242,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) struct gpio_vbus_data *gpio_vbus; struct resource *res; int err, gpio, irq; + unsigned long irqflags; if (!pdata || !gpio_is_valid(pdata->gpio_vbus)) return -EINVAL; @@ -271,10 +279,13 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (res) { irq = res->start; - res->flags &= IRQF_TRIGGER_MASK; - res->flags |= IRQF_SAMPLE_RANDOM | IRQF_SHARED; - } else + irqflags = (res->flags & IRQF_TRIGGER_MASK) | IRQF_SHARED; + } else { irq = gpio_to_irq(gpio); + irqflags = VBUS_IRQ_FLAGS; + } + + gpio_vbus->irq = irq; /* if data line pullup is in use, initialize it to "not pulling up" */ gpio = pdata->gpio_pullup; @@ -290,8 +301,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) gpio_direction_output(gpio, pdata->gpio_pullup_inverted); } - err = request_irq(irq, gpio_vbus_irq, VBUS_IRQ_FLAGS, - "vbus_detect", pdev); + err = request_irq(irq, gpio_vbus_irq, irqflags, "vbus_detect", pdev); if (err) { dev_err(&pdev->dev, "can't request irq %i, err: %d\n", irq, err); @@ -300,7 +310,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) ATOMIC_INIT_NOTIFIER_HEAD(&gpio_vbus->phy.notifier); - INIT_WORK(&gpio_vbus->work, gpio_vbus_work); + INIT_DELAYED_WORK(&gpio_vbus->work, gpio_vbus_work); gpio_vbus->vbus_draw = regulator_get(&pdev->dev, "vbus_draw"); if (IS_ERR(gpio_vbus->vbus_draw)) { @@ -317,9 +327,12 @@ static int __init gpio_vbus_probe(struct platform_device *pdev) goto err_otg; } + device_init_wakeup(&pdev->dev, pdata->wakeup); + return 0; err_otg: - free_irq(irq, &pdev->dev); + regulator_put(gpio_vbus->vbus_draw); + free_irq(irq, pdev); err_irq: if (gpio_is_valid(pdata->gpio_pullup)) gpio_free(pdata->gpio_pullup); @@ -337,11 +350,13 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev) struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data; int gpio = pdata->gpio_vbus; + device_init_wakeup(&pdev->dev, 0); + cancel_delayed_work_sync(&gpio_vbus->work); regulator_put(gpio_vbus->vbus_draw); usb_set_transceiver(NULL); - free_irq(gpio_to_irq(gpio), &pdev->dev); + free_irq(gpio_vbus->irq, pdev); if (gpio_is_valid(pdata->gpio_pullup)) gpio_free(pdata->gpio_pullup); gpio_free(gpio); @@ -352,6 +367,33 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int gpio_vbus_pm_suspend(struct device *dev) +{ + struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(gpio_vbus->irq); + + return 0; +} + +static int gpio_vbus_pm_resume(struct device *dev) +{ + struct gpio_vbus_data *gpio_vbus = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(gpio_vbus->irq); + + return 0; +} + +static const struct dev_pm_ops gpio_vbus_dev_pm_ops = { + .suspend = gpio_vbus_pm_suspend, + .resume = gpio_vbus_pm_resume, +}; +#endif + /* NOTE: the gpio-vbus device may *NOT* be hotplugged */ MODULE_ALIAS("platform:gpio-vbus"); @@ -360,6 +402,9 @@ static struct platform_driver gpio_vbus_driver = { .driver = { .name = "gpio-vbus", .owner = THIS_MODULE, +#ifdef CONFIG_PM + .pm = &gpio_vbus_dev_pm_ops, +#endif }, .remove = __exit_p(gpio_vbus_remove), }; diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c index e3fa387ca81e..d2a9a8e691b9 100644 --- a/drivers/usb/otg/twl6030-usb.c +++ b/drivers/usb/otg/twl6030-usb.c @@ -455,7 +455,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) twl->irq_enabled = true; status = request_threaded_irq(twl->irq1, NULL, twl6030_usbotg_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl6030_usb", twl); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", @@ -467,7 +467,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev) } status = request_threaded_irq(twl->irq2, NULL, twl6030_usb_irq, - IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT, "twl6030_usb", twl); if (status < 0) { dev_err(&pdev->dev, "can't get IRQ %d, err %d\n", diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig new file mode 100644 index 000000000000..3cfabcba7447 --- /dev/null +++ b/drivers/usb/phy/Kconfig @@ -0,0 +1,17 @@ +# +# Physical Layer USB driver configuration +# +comment "USB Physical Layer drivers" + depends on USB + +config USB_ISP1301 + tristate "NXP ISP1301 USB transceiver support" + depends on USB + depends on I2C + help + Say Y here to add support for the NXP ISP1301 USB transceiver driver. + This chip is typically used as USB transceiver for USB host, gadget + and OTG drivers (to be selected separately). + + To compile this driver as a module, choose M here: the + module will be called isp1301. diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile new file mode 100644 index 000000000000..eca095b1a890 --- /dev/null +++ b/drivers/usb/phy/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for physical layer USB drivers +# + +ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG + +obj-$(CONFIG_USB_ISP1301) += isp1301.o diff --git a/drivers/usb/phy/isp1301.c b/drivers/usb/phy/isp1301.c new file mode 100644 index 000000000000..b19f4932a037 --- /dev/null +++ b/drivers/usb/phy/isp1301.c @@ -0,0 +1,77 @@ +/* + * NXP ISP1301 USB transceiver driver + * + * Copyright (C) 2012 Roland Stigge + * + * Author: Roland Stigge <stigge@antcom.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/i2c.h> + +#define DRV_NAME "isp1301" + +#define ISP1301_I2C_ADDR 0x2C + +static const unsigned short normal_i2c[] = { + ISP1301_I2C_ADDR, ISP1301_I2C_ADDR + 1, I2C_CLIENT_END +}; + +static const struct i2c_device_id isp1301_id[] = { + { "isp1301", 0 }, + { } +}; + +static struct i2c_client *isp1301_i2c_client; + +static int isp1301_probe(struct i2c_client *client, + const struct i2c_device_id *i2c_id) +{ + isp1301_i2c_client = client; + return 0; +} + +static int isp1301_remove(struct i2c_client *client) +{ + return 0; +} + +static struct i2c_driver isp1301_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = isp1301_probe, + .remove = isp1301_remove, + .id_table = isp1301_id, +}; + +module_i2c_driver(isp1301_driver); + +static int match(struct device *dev, void *data) +{ + struct device_node *node = (struct device_node *)data; + return (dev->of_node == node) && + (dev->driver == &isp1301_driver.driver); +} + +struct i2c_client *isp1301_get_client(struct device_node *node) +{ + if (node) { /* reference of ISP1301 I2C node via DT */ + struct device *dev = bus_find_device(&i2c_bus_type, NULL, + node, match); + if (!dev) + return NULL; + return to_i2c_client(dev); + } else { /* non-DT: only one ISP1301 chip supported */ + return isp1301_i2c_client; + } +} +EXPORT_SYMBOL_GPL(isp1301_get_client); + +MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>"); +MODULE_DESCRIPTION("NXP ISP1301 USB transceiver driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index 00bd2a5e0362..28478ce26c34 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -55,6 +55,7 @@ struct usbhsg_gpriv { #define USBHSG_STATUS_STARTED (1 << 0) #define USBHSG_STATUS_REGISTERD (1 << 1) #define USBHSG_STATUS_WEDGE (1 << 2) +#define USBHSG_STATUS_SELF_POWERED (1 << 3) }; struct usbhsg_recip_handle { @@ -333,7 +334,10 @@ static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv, struct usb_ctrlrequest *ctrl) { struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep); - unsigned short status = 1 << USB_DEVICE_SELF_POWERED; + unsigned short status = 0; + + if (usbhsg_status_has(gpriv, USBHSG_STATUS_SELF_POWERED)) + status = 1 << USB_DEVICE_SELF_POWERED; __usbhsg_recip_send_status(gpriv, status); @@ -879,8 +883,21 @@ static int usbhsg_get_frame(struct usb_gadget *gadget) return usbhs_frame_get_num(priv); } +static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self) +{ + struct usbhsg_gpriv *gpriv = usbhsg_gadget_to_gpriv(gadget); + + if (is_self) + usbhsg_status_set(gpriv, USBHSG_STATUS_SELF_POWERED); + else + usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED); + + return 0; +} + static struct usb_gadget_ops usbhsg_gadget_ops = { .get_frame = usbhsg_get_frame, + .set_selfpowered = usbhsg_set_selfpowered, .udc_start = usbhsg_gadget_start, .udc_stop = usbhsg_gadget_stop, }; diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 7141d6599060..325d2910f9f9 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -669,6 +669,15 @@ config USB_SERIAL_SSU100 To compile this driver as a module, choose M here: the module will be called ssu100. +config USB_SERIAL_QT2 + tristate "USB Quatech Serial Driver for USB 2 devices" + help + Say Y here if you want to use the Quatech USB 2 + serial adapters. + + To compile this driver as a module, choose M here: the + module will be called quatech-serial. + config USB_SERIAL_DEBUG tristate "USB Debugging Device" help diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile index 07f198ee0486..1dc483a8bfc7 100644 --- a/drivers/usb/serial/Makefile +++ b/drivers/usb/serial/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_USB_SERIAL_OTI6858) += oti6858.o obj-$(CONFIG_USB_SERIAL_PL2303) += pl2303.o obj-$(CONFIG_USB_SERIAL_QCAUX) += qcaux.o obj-$(CONFIG_USB_SERIAL_QUALCOMM) += qcserial.o +obj-$(CONFIG_USB_SERIAL_QT2) += quatech2.o obj-$(CONFIG_USB_SERIAL_SAFE) += safe_serial.o obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI) += siemens_mpi.o obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS) += sierra.o diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c index eec4fb9a35c1..d634e6635632 100644 --- a/drivers/usb/serial/aircable.c +++ b/drivers/usb/serial/aircable.c @@ -111,13 +111,14 @@ static int aircable_probe(struct usb_serial *serial, for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) { endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_bulk_out(endpoint)) { - dbg("found bulk out on endpoint %d", i); + dev_dbg(&serial->dev->dev, + "found bulk out on endpoint %d\n", i); ++num_bulk_out; } } if (num_bulk_out == 0) { - dbg("Invalid interface, discarding"); + dev_dbg(&serial->dev->dev, "Invalid interface, discarding\n"); return -ENODEV; } @@ -133,7 +134,7 @@ static int aircable_process_packet(struct tty_struct *tty, packet += HCI_HEADER_LENGTH; } if (len <= 0) { - dbg("%s - malformed packet", __func__); + dev_dbg(&port->dev, "%s - malformed packet\n", __func__); return 0; } @@ -170,13 +171,6 @@ static void aircable_process_read_urb(struct urb *urb) tty_kref_put(tty); } -static struct usb_driver aircable_driver = { - .name = "aircable", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver aircable_device = { .driver = { .owner = THIS_MODULE, @@ -196,7 +190,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &aircable_device, NULL }; -module_usb_serial_driver(aircable_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c index f99f47100dd8..f8ce97d8b0ad 100644 --- a/drivers/usb/serial/ark3116.c +++ b/drivers/usb/serial/ark3116.c @@ -265,7 +265,7 @@ static void ark3116_set_termios(struct tty_struct *tty, hcr = (cflag & CRTSCTS) ? 0x03 : 0x00; /* calc baudrate */ - dbg("%s - setting bps to %d", __func__, bps); + dev_dbg(&port->dev, "%s - setting bps to %d\n", __func__, bps); eval = 0; switch (bps) { case 0: @@ -292,8 +292,8 @@ static void ark3116_set_termios(struct tty_struct *tty, /* keep old LCR_SBC bit */ lcr |= (priv->lcr & UART_LCR_SBC); - dbg("%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d", - __func__, hcr, lcr, quot); + dev_dbg(&port->dev, "%s - setting hcr:0x%02x,lcr:0x%02x,quot:%d\n", + __func__, hcr, lcr, quot); /* handshake control */ if (priv->hcr != hcr) { @@ -375,8 +375,9 @@ static int ark3116_open(struct tty_struct *tty, struct usb_serial_port *port) result = usb_serial_generic_open(tty, port); if (result) { - dbg("%s - usb_serial_generic_open failed: %d", - __func__, result); + dev_dbg(&port->dev, + "%s - usb_serial_generic_open failed: %d\n", + __func__, result); goto err_out; } @@ -622,24 +623,26 @@ static void ark3116_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); break; case 0: /* success */ /* discovered this by trail and error... */ if ((urb->actual_length == 4) && (data[0] == 0xe8)) { const __u8 id = data[1]&UART_IIR_ID; - dbg("%s: iir=%02x", __func__, data[1]); + dev_dbg(&port->dev, "%s: iir=%02x\n", __func__, data[1]); if (id == UART_IIR_MSI) { - dbg("%s: msr=%02x", __func__, data[3]); + dev_dbg(&port->dev, "%s: msr=%02x\n", + __func__, data[3]); ark3116_update_msr(port, data[3]); break; } else if (id == UART_IIR_RLSI) { - dbg("%s: lsr=%02x", __func__, data[2]); + dev_dbg(&port->dev, "%s: lsr=%02x\n", + __func__, data[2]); ark3116_update_lsr(port, data[2]); break; } @@ -714,13 +717,6 @@ static void ark3116_process_read_urb(struct urb *urb) tty_kref_put(tty); } -static struct usb_driver ark3116_driver = { - .name = "ark3116", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver ark3116_device = { .driver = { .owner = THIS_MODULE, @@ -747,7 +743,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &ark3116_device, NULL }; -module_usb_serial_driver(ark3116_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c index a52e0d2cec31..6b7365632951 100644 --- a/drivers/usb/serial/belkin_sa.c +++ b/drivers/usb/serial/belkin_sa.c @@ -2,17 +2,17 @@ * Belkin USB Serial Adapter Driver * * Copyright (C) 2000 William Greathouse (wgreathouse@smva.com) - * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 2000-2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com) * * This program is largely derived from work by the linux-usb group * and associated source files. Please see the usb/serial files for * individual credits and copyrights. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * * See Documentation/usb/usb-serial.txt for more information on using this * driver @@ -62,7 +62,7 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); -static const struct usb_device_id id_table_combined[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) }, { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) }, { USB_DEVICE(PERACOM_VID, PERACOM_PID) }, @@ -71,14 +71,7 @@ static const struct usb_device_id id_table_combined[] = { { USB_DEVICE(BELKIN_DOCKSTATION_VID, BELKIN_DOCKSTATION_PID) }, { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver belkin_driver = { - .name = "belkin", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; +MODULE_DEVICE_TABLE(usb, id_table); /* All of the device info needed for the serial converters */ static struct usb_serial_driver belkin_device = { @@ -87,7 +80,7 @@ static struct usb_serial_driver belkin_device = { .name = "belkin", }, .description = "Belkin / Peracom / GoHubs USB Serial Adapter", - .id_table = id_table_combined, + .id_table = id_table, .num_ports = 1, .open = belkin_sa_open, .close = belkin_sa_close, @@ -159,8 +152,6 @@ static void belkin_sa_release(struct usb_serial *serial) { int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); } @@ -170,8 +161,6 @@ static int belkin_sa_open(struct tty_struct *tty, { int retval; - dbg("%s port %d", __func__, port->number); - retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (retval) { dev_err(&port->dev, "usb_submit_urb(read int) failed\n"); @@ -187,8 +176,6 @@ static int belkin_sa_open(struct tty_struct *tty, static void belkin_sa_close(struct usb_serial_port *port) { - dbg("%s port %d", __func__, port->number); - usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } @@ -210,12 +197,12 @@ static void belkin_sa_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -403,7 +390,9 @@ static void belkin_sa_set_termios(struct tty_struct *tty, case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break; - default: dbg("CSIZE was not CS5-CS8, using default of 8"); + default: + dev_dbg(&port->dev, + "CSIZE was not CS5-CS8, using default of 8\n"); urb_value = BELKIN_SA_DATA_BITS(8); break; } @@ -463,8 +452,6 @@ static int belkin_sa_tiocmget(struct tty_struct *tty) unsigned long control_state; unsigned long flags; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; spin_unlock_irqrestore(&priv->lock, flags); @@ -484,8 +471,6 @@ static int belkin_sa_tiocmset(struct tty_struct *tty, int rts = 0; int dtr = 0; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; @@ -524,7 +509,7 @@ exit: return retval; } -module_usb_serial_driver(belkin_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c index ed8adb052ca7..f398d1e34474 100644 --- a/drivers/usb/serial/bus.c +++ b/drivers/usb/serial/bus.c @@ -124,8 +124,15 @@ static ssize_t store_new_id(struct device_driver *driver, return retval; } +static ssize_t show_dynids(struct device_driver *driver, char *buf) +{ + struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver); + + return usb_show_dynids(&usb_drv->dynids, buf); +} + static struct driver_attribute drv_attrs[] = { - __ATTR(new_id, S_IWUSR, NULL, store_new_id), + __ATTR(new_id, S_IRUGO | S_IWUSR, show_dynids, store_new_id), __ATTR_NULL, }; diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index aaab32db31d0..cabd1b15ddce 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -125,8 +125,6 @@ static int ch341_set_baudrate(struct usb_device *dev, unsigned long factor; short divisor; - dbg("ch341_set_baudrate(%d)", priv->baud_rate); - if (!priv->baud_rate) return -EINVAL; factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate); @@ -153,7 +151,6 @@ static int ch341_set_baudrate(struct usb_device *dev, static int ch341_set_handshake(struct usb_device *dev, u8 control) { - dbg("ch341_set_handshake(0x%02x)", control); return ch341_control_out(dev, 0xa4, ~control, 0); } @@ -164,8 +161,6 @@ static int ch341_get_status(struct usb_device *dev, struct ch341_private *priv) const unsigned size = 8; unsigned long flags; - dbg("ch341_get_status()"); - buffer = kmalloc(size, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -196,8 +191,6 @@ static int ch341_configure(struct usb_device *dev, struct ch341_private *priv) int r; const unsigned size = 8; - dbg("ch341_configure()"); - buffer = kmalloc(size, GFP_KERNEL); if (!buffer) return -ENOMEM; @@ -254,8 +247,6 @@ static int ch341_attach(struct usb_serial *serial) struct ch341_private *priv; int r; - dbg("ch341_attach()"); - /* private data */ priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL); if (!priv) @@ -290,7 +281,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) struct ch341_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); /* drop DTR and RTS */ spin_lock_irqsave(&priv->lock, flags); if (on) @@ -304,8 +294,6 @@ static void ch341_dtr_rts(struct usb_serial_port *port, int on) static void ch341_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } @@ -318,8 +306,6 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port) struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]); int r; - dbg("ch341_open()"); - priv->baud_rate = DEFAULT_BAUD_RATE; r = ch341_configure(serial->dev, priv); @@ -358,8 +344,6 @@ static void ch341_set_termios(struct tty_struct *tty, unsigned baud_rate; unsigned long flags; - dbg("ch341_set_termios()"); - baud_rate = tty_get_baud_rate(tty); priv->baud_rate = baud_rate; @@ -393,8 +377,6 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state) uint16_t reg_contents; uint8_t *break_reg; - dbg("%s()", __func__); - break_reg = kmalloc(2, GFP_KERNEL); if (!break_reg) { dev_err(&port->dev, "%s - kmalloc failed\n", __func__); @@ -461,8 +443,6 @@ static void ch341_read_int_callback(struct urb *urb) unsigned int actual_length = urb->actual_length; int status; - dbg("%s (%d)", __func__, port->number); - switch (urb->status) { case 0: /* success */ @@ -580,8 +560,6 @@ static int ch341_tiocmget(struct tty_struct *tty) u8 status; unsigned int result; - dbg("%s (%d)", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; status = priv->line_status; @@ -599,35 +577,18 @@ static int ch341_tiocmget(struct tty_struct *tty) return result; } - -static int ch341_reset_resume(struct usb_interface *intf) +static int ch341_reset_resume(struct usb_serial *serial) { - struct usb_device *dev = interface_to_usbdev(intf); - struct usb_serial *serial = NULL; struct ch341_private *priv; - serial = usb_get_intfdata(intf); priv = usb_get_serial_port_data(serial->port[0]); - /*reconfigure ch341 serial port after bus-reset*/ - ch341_configure(dev, priv); - - usb_serial_resume(intf); + /* reconfigure ch341 serial port after bus-reset */ + ch341_configure(serial->dev, priv); return 0; } -static struct usb_driver ch341_driver = { - .name = "ch341", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .reset_resume = ch341_reset_resume, - .id_table = id_table, - .supports_autosuspend = 1, -}; - static struct usb_serial_driver ch341_device = { .driver = { .owner = THIS_MODULE, @@ -646,13 +607,14 @@ static struct usb_serial_driver ch341_device = { .tiocmset = ch341_tiocmset, .read_int_callback = ch341_read_int_callback, .attach = ch341_attach, + .reset_resume = ch341_reset_resume, }; static struct usb_serial_driver * const serial_drivers[] = { &ch341_device, NULL }; -module_usb_serial_driver(ch341_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c index 1ee6b2ab0f89..b9cca6dcde07 100644 --- a/drivers/usb/serial/console.c +++ b/drivers/usb/serial/console.c @@ -113,7 +113,8 @@ static int usb_console_setup(struct console *co, char *options) serial = usb_serial_get_by_index(co->index); if (serial == NULL) { /* no device is connected yet, sorry :( */ - err("No USB device connected to ttyUSB%i", co->index); + printk(KERN_ERR "No USB device connected to ttyUSB%i\n", + co->index); return -ENODEV; } @@ -137,7 +138,7 @@ static int usb_console_setup(struct console *co, char *options) tty = kzalloc(sizeof(*tty), GFP_KERNEL); if (!tty) { retval = -ENOMEM; - err("no more memory"); + dev_err(&port->dev, "no more memory\n"); goto reset_open_count; } kref_init(&tty->kref); @@ -146,7 +147,7 @@ static int usb_console_setup(struct console *co, char *options) tty->index = co->index; if (tty_init_termios(tty)) { retval = -ENOMEM; - err("no more memory"); + dev_err(&port->dev, "no more memory\n"); goto free_tty; } } @@ -159,7 +160,7 @@ static int usb_console_setup(struct console *co, char *options) retval = usb_serial_generic_open(NULL, port); if (retval) { - err("could not open USB console port"); + dev_err(&port->dev, "could not open USB console port\n"); goto fail; } diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c index ec30f95ef399..1b1926200ba7 100644 --- a/drivers/usb/serial/cp210x.c +++ b/drivers/usb/serial/cp210x.c @@ -156,13 +156,6 @@ struct cp210x_port_private { __u8 bInterfaceNumber; }; -static struct usb_driver cp210x_driver = { - .name = "cp210x", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver cp210x_device = { .driver = { .owner = THIS_MODULE, @@ -188,8 +181,10 @@ static struct usb_serial_driver * const serial_drivers[] = { }; /* Config request types */ -#define REQTYPE_HOST_TO_DEVICE 0x41 -#define REQTYPE_DEVICE_TO_HOST 0xc1 +#define REQTYPE_HOST_TO_INTERFACE 0x41 +#define REQTYPE_INTERFACE_TO_HOST 0xc1 +#define REQTYPE_HOST_TO_DEVICE 0x40 +#define REQTYPE_DEVICE_TO_HOST 0xc0 /* Config request codes */ #define CP210X_IFC_ENABLE 0x00 @@ -286,7 +281,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request, /* Issue the request, attempting to read 'size' bytes */ result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - request, REQTYPE_DEVICE_TO_HOST, 0x0000, + request, REQTYPE_INTERFACE_TO_HOST, 0x0000, port_priv->bInterfaceNumber, buf, size, USB_CTRL_GET_TIMEOUT); @@ -340,13 +335,13 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request, if (size > 2) { result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - request, REQTYPE_HOST_TO_DEVICE, 0x0000, + request, REQTYPE_HOST_TO_INTERFACE, 0x0000, port_priv->bInterfaceNumber, buf, size, USB_CTRL_SET_TIMEOUT); } else { result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - request, REQTYPE_HOST_TO_DEVICE, data[0], + request, REQTYPE_HOST_TO_INTERFACE, data[0], port_priv->bInterfaceNumber, NULL, 0, USB_CTRL_SET_TIMEOUT); } @@ -422,8 +417,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) { int result; - dbg("%s - port %d", __func__, port->number); - result = cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE); if (result) { @@ -443,8 +436,6 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) static void cp210x_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_serial_generic_close(port); mutex_lock(&port->serial->disc_mutex); @@ -488,8 +479,6 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, unsigned int baud; unsigned int bits; - dbg("%s - port %d", __func__, port->number); - cp210x_get_config(port, CP210X_GET_BAUDRATE, &baud, 4); dbg("%s - baud rate = %d", __func__, baud); @@ -787,8 +776,6 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port, { unsigned int control = 0; - dbg("%s - port %d", __func__, port->number); - if (set & TIOCM_RTS) { control |= CONTROL_RTS; control |= CONTROL_WRITE_RTS; @@ -825,8 +812,6 @@ static int cp210x_tiocmget (struct tty_struct *tty) unsigned int control; int result; - dbg("%s - port %d", __func__, port->number); - cp210x_get_config(port, CP210X_GET_MDMSTS, &control, 1); result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) @@ -846,7 +831,6 @@ static void cp210x_break_ctl (struct tty_struct *tty, int break_state) struct usb_serial_port *port = tty->driver_data; unsigned int state; - dbg("%s - port %d", __func__, port->number); if (break_state == 0) state = BREAK_OFF; else @@ -891,7 +875,7 @@ static void cp210x_release(struct usb_serial *serial) } } -module_usb_serial_driver(cp210x_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index d39b9418f2fb..3aa0b530f68e 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -77,13 +77,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver cyberjack_driver = { - .name = "cyberjack", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver cyberjack_device = { .driver = { .owner = THIS_MODULE, @@ -122,8 +115,6 @@ static int cyberjack_startup(struct usb_serial *serial) struct cyberjack_private *priv; int i; - dbg("%s", __func__); - /* allocate the private data structure */ priv = kmalloc(sizeof(struct cyberjack_private), GFP_KERNEL); if (!priv) @@ -155,8 +146,6 @@ static void cyberjack_disconnect(struct usb_serial *serial) { int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) usb_kill_urb(serial->port[i]->interrupt_in_urb); } @@ -165,8 +154,6 @@ static void cyberjack_release(struct usb_serial *serial) { int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ kfree(usb_get_serial_port_data(serial->port[i])); @@ -180,8 +167,6 @@ static int cyberjack_open(struct tty_struct *tty, unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - dbg("%s - usb_clear_halt", __func__); usb_clear_halt(port->serial->dev, port->write_urb->pipe); @@ -197,8 +182,6 @@ static int cyberjack_open(struct tty_struct *tty, static void cyberjack_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - if (port->serial->dev) { /* shutdown any bulk reads that might be going on */ usb_kill_urb(port->write_urb); @@ -214,8 +197,6 @@ static int cyberjack_write(struct tty_struct *tty, int result; int wrexpected; - dbg("%s - port %d", __func__, port->number); - if (count == 0) { dbg("%s - write request of 0 bytes", __func__); return 0; @@ -307,8 +288,6 @@ static void cyberjack_read_int_callback(struct urb *urb) int status = urb->status; int result; - dbg("%s - port %d", __func__, port->number); - /* the urb might have been killed. */ if (status) return; @@ -367,8 +346,6 @@ static void cyberjack_read_bulk_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); if (status) { @@ -417,8 +394,6 @@ static void cyberjack_write_bulk_callback(struct urb *urb) struct cyberjack_private *priv = usb_get_serial_port_data(port); int status = urb->status; - dbg("%s - port %d", __func__, port->number); - set_bit(0, &port->write_urbs_free); if (status) { dbg("%s - nonzero write bulk status received: %d", @@ -475,7 +450,7 @@ exit: usb_serial_port_softint(port); } -module_usb_serial_driver(cyberjack_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c index afc886c75d2f..b78c34eb5d3f 100644 --- a/drivers/usb/serial/cypress_m8.c +++ b/drivers/usb/serial/cypress_m8.c @@ -89,13 +89,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver cypress_driver = { - .name = "cypress", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - enum packet_format { packet_format_1, /* b0:status, b1:payload count */ packet_format_2 /* b0[7:3]:status, b0[2:0]:payload count */ @@ -305,8 +298,6 @@ static int cypress_serial_control(struct tty_struct *tty, const unsigned int feature_len = 5; unsigned long flags; - dbg("%s", __func__); - priv = usb_get_serial_port_data(port); if (!priv->comm_is_ok) @@ -451,8 +442,6 @@ static int generic_startup(struct usb_serial *serial) struct cypress_private *priv; struct usb_serial_port *port = serial->port[0]; - dbg("%s - port %d", __func__, port->number); - priv = kzalloc(sizeof(struct cypress_private), GFP_KERNEL); if (!priv) return -ENOMEM; @@ -505,8 +494,6 @@ static int cypress_earthmate_startup(struct usb_serial *serial) struct cypress_private *priv; struct usb_serial_port *port = serial->port[0]; - dbg("%s", __func__); - if (generic_startup(serial)) { dbg("%s - Failed setting up port %d", __func__, port->number); @@ -537,8 +524,6 @@ static int cypress_hidcom_startup(struct usb_serial *serial) { struct cypress_private *priv; - dbg("%s", __func__); - if (generic_startup(serial)) { dbg("%s - Failed setting up port %d", __func__, serial->port[0]->number); @@ -556,8 +541,6 @@ static int cypress_ca42v2_startup(struct usb_serial *serial) { struct cypress_private *priv; - dbg("%s", __func__); - if (generic_startup(serial)) { dbg("%s - Failed setting up port %d", __func__, serial->port[0]->number); @@ -575,10 +558,7 @@ static void cypress_release(struct usb_serial *serial) { struct cypress_private *priv; - dbg("%s - port %d", __func__, serial->port[0]->number); - /* all open ports are closed at this point */ - priv = usb_get_serial_port_data(serial->port[0]); if (priv) { @@ -595,8 +575,6 @@ static int cypress_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - if (!priv->comm_is_ok) return -EIO; @@ -661,8 +639,6 @@ static void cypress_close(struct usb_serial_port *port) struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); - /* writing is potentially harmful, lock must be taken */ mutex_lock(&port->serial->disc_mutex); if (port->serial->disconnected) { @@ -720,7 +696,6 @@ static void cypress_send(struct usb_serial_port *port) if (!priv->comm_is_ok) return; - dbg("%s - port %d", __func__, port->number); dbg("%s - interrupt out size is %d", __func__, port->interrupt_out_size); @@ -828,8 +803,6 @@ static int cypress_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); room = kfifo_avail(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); @@ -847,8 +820,6 @@ static int cypress_tiocmget(struct tty_struct *tty) unsigned int result = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; status = priv->current_status; @@ -874,8 +845,6 @@ static int cypress_tiocmset(struct tty_struct *tty, struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) priv->line_control |= CONTROL_RTS; @@ -948,8 +917,6 @@ static void cypress_set_termios(struct tty_struct *tty, __u8 oldlines; int linechange = 0; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); /* We can't clean this one up as we don't know the device type early enough */ @@ -1096,8 +1063,6 @@ static int cypress_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); chars = kfifo_len(&priv->write_fifo); spin_unlock_irqrestore(&priv->lock, flags); @@ -1112,8 +1077,6 @@ static void cypress_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct cypress_private *priv = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); priv->rx_flags = THROTTLED; spin_unlock_irq(&priv->lock); @@ -1126,8 +1089,6 @@ static void cypress_unthrottle(struct tty_struct *tty) struct cypress_private *priv = usb_get_serial_port_data(port); int actually_throttled, result; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; priv->rx_flags = 0; @@ -1161,8 +1122,6 @@ static void cypress_read_int_callback(struct urb *urb) int i = 0; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ break; @@ -1303,8 +1262,6 @@ static void cypress_write_int_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ @@ -1346,7 +1303,7 @@ static void cypress_write_int_callback(struct urb *urb) cypress_send(port); } -module_usb_serial_driver(cypress_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c index 999f91bf70de..b5cd838093ef 100644 --- a/drivers/usb/serial/digi_acceleport.c +++ b/drivers/usb/serial/digi_acceleport.c @@ -271,14 +271,6 @@ static const struct usb_device_id id_table_4[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver digi_driver = { - .name = "digi_acceleport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - - /* device info needed for the Digi serial converter */ static struct usb_serial_driver digi_acceleport_2_device = { @@ -657,9 +649,6 @@ static void digi_rx_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); - - dbg("digi_rx_throttle: TOP: port=%d", priv->dp_port_num); - /* stop receiving characters by not resubmitting the read urb */ spin_lock_irqsave(&priv->dp_port_lock, flags); priv->dp_throttled = 1; @@ -675,8 +664,6 @@ static void digi_rx_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct digi_port *priv = usb_get_serial_port_data(port); - dbg("digi_rx_unthrottle: TOP: port=%d", priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); /* restart read chain */ @@ -904,8 +891,6 @@ static int digi_tiocmget(struct tty_struct *tty) unsigned int val; unsigned long flags; - dbg("%s: TOP: port=%d", __func__, priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); val = priv->dp_modem_signals; spin_unlock_irqrestore(&priv->dp_port_lock, flags); @@ -921,8 +906,6 @@ static int digi_tiocmset(struct tty_struct *tty, unsigned int val; unsigned long flags; - dbg("%s: TOP: port=%d", __func__, priv->dp_port_num); - spin_lock_irqsave(&priv->dp_port_lock, flags); val = (priv->dp_modem_signals & ~clear) | set; spin_unlock_irqrestore(&priv->dp_port_lock, flags); @@ -1013,8 +996,6 @@ static void digi_write_bulk_callback(struct urb *urb) int ret = 0; int status = urb->status; - dbg("digi_write_bulk_callback: TOP, status=%d", status); - /* port and serial sanity check */ if (port == NULL || (priv = usb_get_serial_port_data(port)) == NULL) { pr_err("%s: port or port->private is NULL, status=%d\n", @@ -1121,8 +1102,6 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port) struct digi_port *priv = usb_get_serial_port_data(port); struct ktermios not_termios; - dbg("digi_open: TOP: port=%d", priv->dp_port_num); - /* be sure the device is started up */ if (digi_startup_device(port->serial) != 0) return -ENXIO; @@ -1160,8 +1139,6 @@ static void digi_close(struct usb_serial_port *port) unsigned char buf[32]; struct digi_port *priv = usb_get_serial_port_data(port); - dbg("digi_close: TOP: port=%d", priv->dp_port_num); - mutex_lock(&port->serial->disc_mutex); /* if disconnected, just clear flags */ if (port->serial->disconnected) @@ -1220,7 +1197,6 @@ exit: wake_up_interruptible(&priv->dp_close_wait); spin_unlock_irq(&priv->dp_port_lock); mutex_unlock(&port->serial->disc_mutex); - dbg("digi_close: done"); } @@ -1269,8 +1245,6 @@ static int digi_startup(struct usb_serial *serial) struct digi_port *priv; struct digi_serial *serial_priv; - dbg("digi_startup: TOP"); - /* allocate the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ for (i = 0; i < serial->type->num_ports + 1; i++) { @@ -1325,7 +1299,6 @@ static int digi_startup(struct usb_serial *serial) static void digi_disconnect(struct usb_serial *serial) { int i; - dbg("digi_disconnect: TOP, in_interrupt()=%ld", in_interrupt()); /* stop reads and writes on all ports */ for (i = 0; i < serial->type->num_ports + 1; i++) { @@ -1338,7 +1311,6 @@ static void digi_disconnect(struct usb_serial *serial) static void digi_release(struct usb_serial *serial) { int i; - dbg("digi_release: TOP, in_interrupt()=%ld", in_interrupt()); /* free the private data structures for all ports */ /* number of regular ports + 1 for the out-of-band port */ @@ -1356,8 +1328,6 @@ static void digi_read_bulk_callback(struct urb *urb) int ret; int status = urb->status; - dbg("digi_read_bulk_callback: TOP"); - /* port sanity check, do not resubmit if port is not valid */ if (port == NULL) return; @@ -1507,9 +1477,6 @@ static int digi_read_oob_callback(struct urb *urb) int i; unsigned int rts; - dbg("digi_read_oob_callback: port=%d, len=%d", - priv->dp_port_num, urb->actual_length); - /* handle each oob command */ for (i = 0; i < urb->actual_length - 3;) { opcode = ((unsigned char *)urb->transfer_buffer)[i++]; @@ -1580,7 +1547,7 @@ static int digi_read_oob_callback(struct urb *urb) } -module_usb_serial_driver(digi_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c index 5b99fc09e327..cdf61dd07318 100644 --- a/drivers/usb/serial/empeg.c +++ b/drivers/usb/serial/empeg.c @@ -51,13 +51,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver empeg_driver = { - .name = "empeg", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver empeg_device = { .driver = { .owner = THIS_MODULE, @@ -80,14 +73,12 @@ static int empeg_startup(struct usb_serial *serial) { int r; - dbg("%s", __func__); - if (serial->dev->actconfig->desc.bConfigurationValue != 1) { dev_err(&serial->dev->dev, "active config #%d != 1 ??\n", serial->dev->actconfig->desc.bConfigurationValue); return -ENODEV; } - dbg("%s - reset config", __func__); + r = usb_reset_configuration(serial->dev); /* continue on with initialization */ @@ -138,7 +129,7 @@ static void empeg_init_termios(struct tty_struct *tty) tty_encode_baud_rate(tty, 115200, 115200); } -module_usb_serial_driver(empeg_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/ezusb.c b/drivers/usb/serial/ezusb.c index 3cfc762f5056..800e8eb60003 100644 --- a/drivers/usb/serial/ezusb.c +++ b/drivers/usb/serial/ezusb.c @@ -26,7 +26,6 @@ int ezusb_writememory(struct usb_serial *serial, int address, int result; unsigned char *transfer_buffer; - /* dbg("ezusb_writememory %x, %d", address, length); */ if (!serial->dev) { printk(KERN_ERR "ezusb: %s - no physical device present, " "failing.\n", __func__); @@ -50,7 +49,6 @@ int ezusb_set_reset(struct usb_serial *serial, unsigned char reset_bit) { int response; - /* dbg("%s - %d", __func__, reset_bit); */ response = ezusb_writememory(serial, CPUCS_REG, &reset_bit, 1, 0xa0); if (response < 0) dev_err(&serial->dev->dev, "%s- %d failed\n", diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c index 88c0b1963920..499b15fd82f1 100644 --- a/drivers/usb/serial/f81232.c +++ b/drivers/usb/serial/f81232.c @@ -68,8 +68,6 @@ static void f81232_read_int_callback(struct urb *urb) int status = urb->status; int retval; - dbg("%s (%d)", __func__, port->number); - switch (status) { case 0: /* success */ @@ -78,12 +76,12 @@ static void f81232_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -133,7 +131,7 @@ static void f81232_process_read_urb(struct urb *urb) tty_flag = TTY_PARITY; else if (line_status & UART_FRAME_ERROR) tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __func__, tty_flag); + dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag); /* overrun is special, not associated with a char */ if (line_status & UART_OVERRUN_ERROR) @@ -203,7 +201,6 @@ static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) f81232_set_termios(tty, port, &tmp_termios); - dbg("%s - submitting interrupt urb", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - failed submitting interrupt urb," @@ -293,7 +290,9 @@ static int f81232_ioctl(struct tty_struct *tty, { struct serial_struct ser; struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); + + dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, + port->number, cmd); switch (cmd) { case TIOCGSERIAL: @@ -309,10 +308,12 @@ static int f81232_ioctl(struct tty_struct *tty, return 0; case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, + port->number); return wait_modem_info(port, arg); default: - dbg("%s not supported = 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s not supported = 0x%04x\n", + __func__, cmd); break; } return -ENOIOCTLCMD; @@ -353,24 +354,12 @@ static void f81232_release(struct usb_serial *serial) } } -static struct usb_driver f81232_driver = { - .name = "f81232", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - static struct usb_serial_driver f81232_device = { .driver = { .owner = THIS_MODULE, .name = "f81232", }, .id_table = id_table, - .usb_driver = &f81232_driver, .num_ports = 1, .bulk_in_size = 256, .bulk_out_size = 256, @@ -394,7 +383,7 @@ static struct usb_serial_driver * const serial_drivers[] = { NULL, }; -module_usb_serial_driver(f81232_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver"); MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org"); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 02e7f2d32d52..8c084ea34e26 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -809,6 +809,7 @@ static struct usb_device_id id_table_combined [] = { .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, { USB_DEVICE(LARSENBRUSGAARD_VID, LB_ALTITRACK_PID) }, { USB_DEVICE(GN_OTOMETRICS_VID, AURICAL_USB_PID) }, + { USB_DEVICE(PI_VID, PI_E861_PID) }, { USB_DEVICE(BAYER_VID, BAYER_CONTOUR_CABLE_PID) }, { USB_DEVICE(FTDI_VID, MARVELL_OPENRD_PID), .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk }, @@ -861,13 +862,6 @@ static struct usb_device_id id_table_combined [] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver ftdi_driver = { - .name = "ftdi_sio", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - static const char *ftdi_chip_name[] = { [SIO] = "SIO", /* the serial part of FT8U100AX */ [FT8U232AM] = "FT8U232AM", @@ -1285,8 +1279,6 @@ static int read_latency_timer(struct usb_serial_port *port) unsigned char *buf; int rv; - dbg("%s", __func__); - buf = kmalloc(1, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -1593,8 +1585,6 @@ static int create_sysfs_attrs(struct usb_serial_port *port) struct ftdi_private *priv = usb_get_serial_port_data(port); int retval = 0; - dbg("%s", __func__); - /* XXX I've no idea if the original SIO supports the event_char * sysfs parameter, so I'm playing it safe. */ if (priv->chip_type != SIO) { @@ -1619,8 +1609,6 @@ static void remove_sysfs_attrs(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - dbg("%s", __func__); - /* XXX see create_sysfs_attrs */ if (priv->chip_type != SIO) { device_remove_file(&port->dev, &dev_attr_event_char); @@ -1667,8 +1655,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) struct ftdi_sio_quirk *quirk = usb_get_serial_data(port->serial); - dbg("%s", __func__); - priv = kzalloc(sizeof(struct ftdi_private), GFP_KERNEL); if (!priv) { dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, @@ -1704,8 +1690,6 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port) /* Called from usbserial:serial_probe */ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv) { - dbg("%s", __func__); - priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 77; priv->force_baud = 38400; @@ -1716,8 +1700,6 @@ static void ftdi_USB_UIRT_setup(struct ftdi_private *priv) static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv) { - dbg("%s", __func__); - priv->flags |= ASYNC_SPD_CUST; priv->custom_divisor = 240; priv->force_baud = 38400; @@ -1767,8 +1749,6 @@ static int ftdi_jtag_probe(struct usb_serial *serial) struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; - dbg("%s", __func__); - if (interface == udev->actconfig->interface[0]) { dev_info(&udev->dev, "Ignoring serial port reserved for JTAG\n"); @@ -1782,8 +1762,6 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial) { struct usb_device *udev = serial->dev; - dbg("%s", __func__); - if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) || (udev->product && !strcmp(udev->product, "BeagleBone/XDS100"))) return ftdi_jtag_probe(serial); @@ -1800,8 +1778,6 @@ static int ftdi_stmclite_probe(struct usb_serial *serial) struct usb_device *udev = serial->dev; struct usb_interface *interface = serial->interface; - dbg("%s", __func__); - if (interface == udev->actconfig->interface[2]) return 0; @@ -1839,8 +1815,6 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - dbg("%s", __func__); - priv->dev_gone = true; wake_up_interruptible_all(&priv->delta_msr_wait); @@ -1858,8 +1832,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port) struct ftdi_private *priv = usb_get_serial_port_data(port); int result; - dbg("%s", __func__); - /* No error checking for this (will get errors later anyway) */ /* See ftdi_sio.h for description of what is reset */ usb_control_msg(dev, usb_sndctrlpipe(dev, 0), @@ -1918,8 +1890,6 @@ static void ftdi_close(struct usb_serial_port *port) { struct ftdi_private *priv = usb_get_serial_port_data(port); - dbg("%s", __func__); - usb_serial_generic_close(port); kref_put(&priv->kref, ftdi_sio_priv_release); } @@ -1976,8 +1946,6 @@ static int ftdi_process_packet(struct tty_struct *tty, char flag; char *ch; - dbg("%s - port %d", __func__, port->number); - if (len < 2) { dbg("malformed packet"); return 0; @@ -2121,8 +2089,6 @@ static void ftdi_set_termios(struct tty_struct *tty, unsigned char vstop; unsigned char vstart; - dbg("%s", __func__); - /* Force baud rate if this device requires it, unless it is set to B0. */ if (priv->force_baud && ((termios->c_cflag & CBAUD) != B0)) { @@ -2295,8 +2261,6 @@ static int ftdi_tiocmget(struct tty_struct *tty) int len; int ret; - dbg("%s TIOCMGET", __func__); - buf = kmalloc(2, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -2346,7 +2310,7 @@ static int ftdi_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - dbg("%s TIOCMSET", __func__); + return update_mctrl(port, set, clear); } @@ -2435,7 +2399,6 @@ static int __init ftdi_init(void) { int retval; - dbg("%s", __func__); if (vendor > 0 && product > 0) { /* Add user specified VID/PID to reserved element of table. */ int i; @@ -2445,7 +2408,7 @@ static int __init ftdi_init(void) id_table_combined[i].idVendor = vendor; id_table_combined[i].idProduct = product; } - retval = usb_serial_register_drivers(&ftdi_driver, serial_drivers); + retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table_combined); if (retval == 0) printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); @@ -2454,9 +2417,7 @@ static int __init ftdi_init(void) static void __exit ftdi_exit(void) { - dbg("%s", __func__); - - usb_serial_deregister_drivers(&ftdi_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); } diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 0838baf892f3..f3c7c78ede33 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -785,6 +785,14 @@ #define RTSYSTEMS_SERIAL_VX7_PID 0x9e52 /* Serial converter for VX-7 Radios using FT232RL */ #define RTSYSTEMS_CT29B_PID 0x9e54 /* CT29B Radio Cable */ + +/* + * Physik Instrumente + * http://www.physikinstrumente.com/en/products/ + */ +#define PI_VID 0x1a72 /* Vendor ID */ +#define PI_E861_PID 0x1008 /* E-861 piezo controller USB connection */ + /* * Bayer Ascensia Contour blood glucose meter USB-converter cable. * http://winglucofacts.com/cables/ diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c index 4577b3607922..235707961ca3 100644 --- a/drivers/usb/serial/funsoft.c +++ b/drivers/usb/serial/funsoft.c @@ -24,13 +24,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver funsoft_driver = { - .name = "funsoft", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver funsoft_device = { .driver = { .owner = THIS_MODULE, @@ -44,7 +37,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &funsoft_device, NULL }; -module_usb_serial_driver(funsoft_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c index e8eb6347bf3a..346c15a51066 100644 --- a/drivers/usb/serial/garmin_gps.c +++ b/drivers/usb/serial/garmin_gps.c @@ -216,16 +216,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(GARMIN_VENDOR_ID, 3) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver garmin_driver = { - .name = "garmin_gps", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static inline int getLayerId(const __u8 *usbPacket) { @@ -345,8 +337,6 @@ static void pkt_clear(struct garmin_data *garmin_data_p) unsigned long flags; struct garmin_packet *result = NULL; - dbg("%s", __func__); - spin_lock_irqsave(&garmin_data_p->lock, flags); while (!list_empty(&garmin_data_p->pktlist)) { result = (struct garmin_packet *)garmin_data_p->pktlist.next; @@ -939,8 +929,6 @@ static int garmin_open(struct tty_struct *tty, struct usb_serial_port *port) int status = 0; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->mode = initial_mode; garmin_data_p->count = 0; @@ -996,8 +984,6 @@ static void garmin_write_bulk_callback(struct urb *urb) struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (GARMIN_LAYERID_APPL == getLayerId(urb->transfer_buffer)) { if (garmin_data_p->mode == MODE_GARMIN_SERIAL) { @@ -1027,9 +1013,6 @@ static int garmin_write_bulk(struct usb_serial_port *port, unsigned char *buffer; int status; - dbg("%s - port %d, state %d", __func__, port->number, - garmin_data_p->state); - spin_lock_irqsave(&garmin_data_p->lock, flags); garmin_data_p->flags &= ~FLAGS_DROP_DATA; spin_unlock_irqrestore(&garmin_data_p->lock, flags); @@ -1224,8 +1207,6 @@ static void garmin_read_bulk_callback(struct urb *urb) int status = urb->status; int retval; - dbg("%s - port %d", __func__, port->number); - if (!serial) { dbg("%s - bad serial pointer, exiting", __func__); return; @@ -1384,7 +1365,6 @@ static void garmin_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); /* set flag, data received will be put into a queue for later processing */ spin_lock_irq(&garmin_data_p->lock); @@ -1399,7 +1379,6 @@ static void garmin_unthrottle(struct tty_struct *tty) struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); spin_lock_irq(&garmin_data_p->lock); garmin_data_p->flags &= ~FLAGS_THROTTLED; spin_unlock_irq(&garmin_data_p->lock); @@ -1441,8 +1420,6 @@ static int garmin_attach(struct usb_serial *serial) struct usb_serial_port *port = serial->port[0]; struct garmin_data *garmin_data_p = NULL; - dbg("%s", __func__); - garmin_data_p = kzalloc(sizeof(struct garmin_data), GFP_KERNEL); if (garmin_data_p == NULL) { dev_err(&port->dev, "%s - Out of memory\n", __func__); @@ -1471,8 +1448,6 @@ static void garmin_disconnect(struct usb_serial *serial) struct usb_serial_port *port = serial->port[0]; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s", __func__); - usb_kill_urb(port->interrupt_in_urb); del_timer_sync(&garmin_data_p->timer); } @@ -1483,8 +1458,6 @@ static void garmin_release(struct usb_serial *serial) struct usb_serial_port *port = serial->port[0]; struct garmin_data *garmin_data_p = usb_get_serial_port_data(port); - dbg("%s", __func__); - kfree(garmin_data_p); } @@ -1516,7 +1489,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &garmin_device, NULL }; -module_usb_serial_driver(garmin_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 664deb63807c..105a6d898ca4 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -28,9 +28,6 @@ static int debug; #ifdef CONFIG_USB_SERIAL_GENERIC -static int generic_probe(struct usb_interface *interface, - const struct usb_device_id *id); - static __u16 vendor = 0x05f9; static __u16 product = 0xffff; @@ -49,13 +46,6 @@ static const struct usb_device_id generic_serial_ids[] = { {} }; -static struct usb_driver generic_driver = { - .name = "usbserial_generic", - .probe = generic_probe, - .disconnect = usb_serial_disconnect, - .id_table = generic_serial_ids, -}; - /* All of the device info needed for the Generic Serial Converter */ struct usb_serial_driver usb_serial_generic_device = { .driver = { @@ -75,16 +65,6 @@ static struct usb_serial_driver * const serial_drivers[] = { &usb_serial_generic_device, NULL }; -static int generic_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - const struct usb_device_id *id_pattern; - - id_pattern = usb_match_id(interface, generic_device_ids); - if (id_pattern != NULL) - return usb_serial_probe(interface, id); - return -ENODEV; -} #endif int usb_serial_generic_register(int _debug) @@ -99,7 +79,7 @@ int usb_serial_generic_register(int _debug) USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT; /* register our generic driver with ourselves */ - retval = usb_serial_register_drivers(&generic_driver, serial_drivers); + retval = usb_serial_register_drivers(serial_drivers, "usbserial_generic", generic_serial_ids); #endif return retval; } @@ -108,7 +88,7 @@ void usb_serial_generic_deregister(void) { #ifdef CONFIG_USB_SERIAL_GENERIC /* remove our generic driver */ - usb_serial_deregister_drivers(&generic_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); #endif } @@ -117,8 +97,6 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port int result = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - /* clear the throttle flags */ spin_lock_irqsave(&port->lock, flags); port->throttled = 0; @@ -139,12 +117,9 @@ static void generic_cleanup(struct usb_serial_port *port) unsigned long flags; int i; - dbg("%s - port %d", __func__, port->number); - if (serial->dev) { /* shutdown any bulk transfers that might be going on */ if (port->bulk_out_size) { - usb_kill_urb(port->write_urb); for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) usb_kill_urb(port->write_urbs[i]); @@ -161,7 +136,6 @@ static void generic_cleanup(struct usb_serial_port *port) void usb_serial_generic_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); generic_cleanup(port); } EXPORT_SYMBOL_GPL(usb_serial_generic_close); @@ -249,8 +223,6 @@ int usb_serial_generic_write(struct tty_struct *tty, { int result; - dbg("%s - port %d", __func__, port->number); - /* only do something if we have a bulk out endpoint */ if (!port->bulk_out_size) return -ENODEV; @@ -273,8 +245,6 @@ int usb_serial_generic_write_room(struct tty_struct *tty) unsigned long flags; int room; - dbg("%s - port %d", __func__, port->number); - if (!port->bulk_out_size) return 0; @@ -282,7 +252,7 @@ int usb_serial_generic_write_room(struct tty_struct *tty) room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); - dbg("%s - returns %d", __func__, room); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, room); return room; } @@ -292,8 +262,6 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) unsigned long flags; int chars; - dbg("%s - port %d", __func__, port->number); - if (!port->bulk_out_size) return 0; @@ -301,7 +269,7 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) chars = kfifo_len(&port->write_fifo) + port->tx_bytes; spin_unlock_irqrestore(&port->lock, flags); - dbg("%s - returns %d", __func__, chars); + dev_dbg(&port->dev, "%s - returns %d\n", __func__, chars); return chars; } @@ -313,7 +281,8 @@ static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, if (!test_and_clear_bit(index, &port->read_urbs_free)) return 0; - dbg("%s - port %d, urb %d\n", __func__, port->number, index); + dev_dbg(&port->dev, "%s - port %d, urb %d\n", __func__, + port->number, index); res = usb_submit_urb(port->read_urbs[index], mem_flags); if (res) { @@ -335,8 +304,6 @@ int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port, int res; int i; - dbg("%s - port %d", __func__, port->number); - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { res = usb_serial_generic_submit_read_urb(port, i, mem_flags); if (res) @@ -395,10 +362,12 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb) } set_bit(i, &port->read_urbs_free); - dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i, - urb->actual_length); + dev_dbg(&port->dev, "%s - port %d, urb %d, len %d\n", + __func__, port->number, i, urb->actual_length); + if (urb->status) { - dbg("%s - non-zero urb status: %d\n", __func__, urb->status); + dev_dbg(&port->dev, "%s - non-zero urb status: %d\n", + __func__, urb->status); return; } @@ -424,8 +393,6 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) int status = urb->status; int i; - dbg("%s - port %d", __func__, port->number); - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) if (port->write_urbs[i] == urb) break; @@ -436,7 +403,8 @@ void usb_serial_generic_write_bulk_callback(struct urb *urb) spin_unlock_irqrestore(&port->lock, flags); if (status) { - dbg("%s - non-zero urb status: %d", __func__, status); + dev_dbg(&port->dev, "%s - non-zero urb status: %d\n", + __func__, status); spin_lock_irqsave(&port->lock, flags); kfifo_reset_out(&port->write_fifo); @@ -454,8 +422,6 @@ void usb_serial_generic_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - /* Set the throttle request flag. It will be picked up * by usb_serial_generic_read_bulk_callback(). */ spin_lock_irqsave(&port->lock, flags); @@ -469,8 +435,6 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; int was_throttled; - dbg("%s - port %d", __func__, port->number); - /* Clear the throttle flags */ spin_lock_irq(&port->lock); was_throttled = port->throttled; @@ -525,7 +489,8 @@ void usb_serial_handle_dcd_change(struct usb_serial_port *usb_port, { struct tty_port *port = &usb_port->port; - dbg("%s - port %d, status %d", __func__, usb_port->number, status); + dev_dbg(&usb_port->dev, "%s - port %d, status %d\n", __func__, + usb_port->number, status); if (status) wake_up_interruptible(&port->open_wait); @@ -566,8 +531,6 @@ void usb_serial_generic_disconnect(struct usb_serial *serial) { int i; - dbg("%s", __func__); - /* stop reads and writes on all ports */ for (i = 0; i < serial->num_ports; ++i) generic_cleanup(serial->port[i]); @@ -576,5 +539,4 @@ EXPORT_SYMBOL_GPL(usb_serial_generic_disconnect); void usb_serial_generic_release(struct usb_serial *serial) { - dbg("%s", __func__); } diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c index 2563e788c9b3..0bbaf21a9d1e 100644 --- a/drivers/usb/serial/hp4x.c +++ b/drivers/usb/serial/hp4x.c @@ -36,13 +36,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver hp49gp_driver = { - .name = "hp4X", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver hp49gp_device = { .driver = { .owner = THIS_MODULE, @@ -56,7 +49,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &hp49gp_device, NULL }; -module_usb_serial_driver(hp49gp_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c index 323e87235711..e1f5ccd1e8f8 100644 --- a/drivers/usb/serial/io_edgeport.c +++ b/drivers/usb/serial/io_edgeport.c @@ -3181,7 +3181,7 @@ static void edge_release(struct usb_serial *serial) kfree(edge_serial); } -module_usb_serial_driver(io_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h index d0e7c9affb6f..350afddb55ba 100644 --- a/drivers/usb/serial/io_tables.h +++ b/drivers/usb/serial/io_tables.h @@ -95,13 +95,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver io_driver = { - .name = "io_edgeport", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - static struct usb_serial_driver edgeport_2port_device = { .driver = { .owner = THIS_MODULE, diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c index 40a95a7fe383..3936904c6419 100644 --- a/drivers/usb/serial/io_ti.c +++ b/drivers/usb/serial/io_ti.c @@ -197,14 +197,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver io_driver = { - .name = "io_ti", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - - static unsigned char OperationalMajorVersion; static unsigned char OperationalMinorVersion; static unsigned short OperationalBuildNumber; @@ -547,6 +539,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, { int baud_rate; struct tty_struct *tty = tty_port_tty_get(&port->port->port); + struct usb_serial *serial = port->port->serial; wait_queue_t wait; unsigned long flags; @@ -561,7 +554,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, set_current_state(TASK_INTERRUPTIBLE); if (kfifo_len(&port->write_fifo) == 0 || timeout == 0 || signal_pending(current) - || !usb_get_intfdata(port->port->serial->interface)) + || serial->disconnected) /* disconnect */ break; spin_unlock_irqrestore(&port->ep_lock, flags); @@ -578,7 +571,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, /* wait for data to drain from the device */ timeout += jiffies; while ((long)(jiffies - timeout) < 0 && !signal_pending(current) - && usb_get_intfdata(port->port->serial->interface)) { + && !serial->disconnected) { /* not disconnected */ if (!tx_active(port)) break; @@ -586,7 +579,7 @@ static void chase_port(struct edgeport_port *port, unsigned long timeout, } /* disconnected */ - if (!usb_get_intfdata(port->port->serial->interface)) + if (serial->disconnected) return; /* wait one more character time, based on baud rate */ @@ -2003,8 +1996,8 @@ static void edge_close(struct usb_serial_port *port) { struct edgeport_serial *edge_serial; struct edgeport_port *edge_port; + struct usb_serial *serial = port->serial; int port_number; - int status; dbg("%s - port %d", __func__, port->number); @@ -2028,12 +2021,18 @@ static void edge_close(struct usb_serial_port *port) * send a close port command to it */ dbg("%s - send umpc_close_port", __func__); port_number = port->number - port->serial->minor; - status = send_cmd(port->serial->dev, + + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) { + send_cmd(serial->dev, UMPC_CLOSE_PORT, (__u8)(UMPM_UART1_PORT + port_number), 0, NULL, 0); + } + mutex_unlock(&serial->disc_mutex); + mutex_lock(&edge_serial->es_lock); --edge_port->edge_serial->num_ports_open; if (edge_port->edge_serial->num_ports_open <= 0) { @@ -2783,7 +2782,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &edgeport_1port_device, &edgeport_2port_device, NULL }; -module_usb_serial_driver(io_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index 10c02b8b5664..c85a7eb87d4e 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -33,7 +33,6 @@ #define DRIVER_AUTHOR "Ganesh Varadarajan <ganesh@veritas.com>" #define DRIVER_DESC "USB PocketPC PDA driver" -static __u16 product, vendor; static bool debug; static int connect_retries = KP_RETRIES; static int initial_wait; @@ -45,8 +44,6 @@ static int ipaq_calc_num_ports(struct usb_serial *serial); static int ipaq_startup(struct usb_serial *serial); static struct usb_device_id ipaq_id_table [] = { - /* The first entry is a placeholder for the insmod-specified device */ - { USB_DEVICE(0x049F, 0x0003) }, { USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */ { USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */ { USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */ @@ -505,13 +502,6 @@ static struct usb_device_id ipaq_id_table [] = { MODULE_DEVICE_TABLE(usb, ipaq_id_table); -static struct usb_driver ipaq_driver = { - .name = "ipaq", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ipaq_id_table, -}; - /* All of the device info needed for the Compaq iPAQ */ static struct usb_serial_driver ipaq_device = { @@ -539,8 +529,6 @@ static int ipaq_open(struct tty_struct *tty, int result = 0; int retries = connect_retries; - dbg("%s - port %d", __func__, port->number); - msleep(1000*initial_wait); /* @@ -577,7 +565,7 @@ static int ipaq_calc_num_ports(struct usb_serial *serial) */ int ipaq_num_ports = 1; - dbg("%s - numberofendpoints: %d", __FUNCTION__, + dev_dbg(&serial->dev->dev, "%s - numberofendpoints: %d\n", __func__, (int)serial->interface->cur_altsetting->desc.bNumEndpoints); /* @@ -596,8 +584,6 @@ static int ipaq_calc_num_ports(struct usb_serial *serial) static int ipaq_startup(struct usb_serial *serial) { - dbg("%s", __func__); - /* Some of the devices in ipaq_id_table[] are composite, and we * shouldn't bind to all the interfaces. This test will rule out * some obviously invalid possibilities. @@ -617,36 +603,14 @@ static int ipaq_startup(struct usb_serial *serial) return -ENODEV; } - dbg("%s - iPAQ module configured for %d ports", - __FUNCTION__, serial->num_ports); + dev_dbg(&serial->dev->dev, + "%s - iPAQ module configured for %d ports\n", __func__, + serial->num_ports); return usb_reset_configuration(serial->dev); } -static int __init ipaq_init(void) -{ - int retval; - - if (vendor) { - ipaq_id_table[0].idVendor = vendor; - ipaq_id_table[0].idProduct = product; - } - - retval = usb_serial_register_drivers(&ipaq_driver, serial_drivers); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" - DRIVER_DESC "\n"); - return retval; -} - -static void __exit ipaq_exit(void) -{ - usb_serial_deregister_drivers(&ipaq_driver, serial_drivers); -} - - -module_init(ipaq_init); -module_exit(ipaq_exit); +module_usb_serial_driver(serial_drivers, ipaq_id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -655,12 +619,6 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified USB idVendor"); - -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified USB idProduct"); - module_param(connect_retries, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(connect_retries, "Maximum number of connect retries (one second each)"); diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 76a06406e26a..5811d34b6c6b 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -132,19 +132,11 @@ enum { #define IPW_WANTS_TO_SEND 0x30 -static const struct usb_device_id usb_ipw_ids[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(IPW_VID, IPW_PID) }, { }, }; - -MODULE_DEVICE_TABLE(usb, usb_ipw_ids); - -static struct usb_driver usb_ipw_driver = { - .name = "ipwtty", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = usb_ipw_ids, -}; +MODULE_DEVICE_TABLE(usb, id_table); static bool debug; @@ -155,8 +147,6 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port) u8 *buf_flow_init; int result; - dbg("%s", __func__); - buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL); if (!buf_flow_init) return -ENOMEM; @@ -317,7 +307,7 @@ static struct usb_serial_driver ipw_device = { .name = "ipw", }, .description = "IPWireless converter", - .id_table = usb_ipw_ids, + .id_table = id_table, .num_ports = 1, .disconnect = usb_wwan_disconnect, .open = ipw_open, @@ -333,7 +323,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &ipw_device, NULL }; -module_usb_serial_driver(usb_ipw_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); /* Module information */ MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 84965cd65c76..fc09414c960f 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -77,13 +77,6 @@ static const struct usb_device_id ir_id_table[] = { MODULE_DEVICE_TABLE(usb, ir_id_table); -static struct usb_driver ir_driver = { - .name = "ir-usb", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ir_id_table, -}; - static struct usb_serial_driver ir_device = { .driver = { .owner = THIS_MODULE, @@ -103,18 +96,21 @@ static struct usb_serial_driver * const serial_drivers[] = { &ir_device, NULL }; -static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc) +static inline void irda_usb_dump_class_desc(struct usb_serial *serial, + struct usb_irda_cs_descriptor *desc) { - dbg("bLength=%x", desc->bLength); - dbg("bDescriptorType=%x", desc->bDescriptorType); - dbg("bcdSpecRevision=%x", __le16_to_cpu(desc->bcdSpecRevision)); - dbg("bmDataSize=%x", desc->bmDataSize); - dbg("bmWindowSize=%x", desc->bmWindowSize); - dbg("bmMinTurnaroundTime=%d", desc->bmMinTurnaroundTime); - dbg("wBaudRate=%x", __le16_to_cpu(desc->wBaudRate)); - dbg("bmAdditionalBOFs=%x", desc->bmAdditionalBOFs); - dbg("bIrdaRateSniff=%x", desc->bIrdaRateSniff); - dbg("bMaxUnicastList=%x", desc->bMaxUnicastList); + struct device *dev = &serial->dev->dev; + + dev_dbg(dev, "bLength=%x\n", desc->bLength); + dev_dbg(dev, "bDescriptorType=%x\n", desc->bDescriptorType); + dev_dbg(dev, "bcdSpecRevision=%x\n", __le16_to_cpu(desc->bcdSpecRevision)); + dev_dbg(dev, "bmDataSize=%x\n", desc->bmDataSize); + dev_dbg(dev, "bmWindowSize=%x\n", desc->bmWindowSize); + dev_dbg(dev, "bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime); + dev_dbg(dev, "wBaudRate=%x\n", __le16_to_cpu(desc->wBaudRate)); + dev_dbg(dev, "bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs); + dev_dbg(dev, "bIrdaRateSniff=%x\n", desc->bIrdaRateSniff); + dev_dbg(dev, "bMaxUnicastList=%x\n", desc->bMaxUnicastList); } /*------------------------------------------------------------------*/ @@ -130,8 +126,9 @@ static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc) * Based on the same function in drivers/net/irda/irda-usb.c */ static struct usb_irda_cs_descriptor * -irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) +irda_usb_find_class_desc(struct usb_serial *serial, unsigned int ifnum) { + struct usb_device *dev = serial->dev; struct usb_irda_cs_descriptor *desc; int ret; @@ -144,20 +141,20 @@ irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum) USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, ifnum, desc, sizeof(*desc), 1000); - dbg("%s - ret=%d", __func__, ret); + dev_dbg(&serial->dev->dev, "%s - ret=%d\n", __func__, ret); if (ret < sizeof(*desc)) { - dbg("%s - class descriptor read %s (%d)", - __func__, - (ret < 0) ? "failed" : "too short", - ret); + dev_dbg(&serial->dev->dev, + "%s - class descriptor read %s (%d)\n", __func__, + (ret < 0) ? "failed" : "too short", ret); goto error; } if (desc->bDescriptorType != USB_DT_CS_IRDA) { - dbg("%s - bad class descriptor type", __func__); + dev_dbg(&serial->dev->dev, "%s - bad class descriptor type\n", + __func__); goto error; } - irda_usb_dump_class_desc(desc); + irda_usb_dump_class_desc(serial, desc); return desc; error: @@ -207,14 +204,15 @@ static int ir_startup(struct usb_serial *serial) { struct usb_irda_cs_descriptor *irda_desc; - irda_desc = irda_usb_find_class_desc(serial->dev, 0); + irda_desc = irda_usb_find_class_desc(serial, 0); if (!irda_desc) { dev_err(&serial->dev->dev, "IRDA class descriptor not found, device not bound\n"); return -ENODEV; } - dbg("%s - Baud rates supported:%s%s%s%s%s%s%s%s%s", + dev_dbg(&serial->dev->dev, + "%s - Baud rates supported:%s%s%s%s%s%s%s%s%s\n", __func__, (irda_desc->wBaudRate & USB_IRDA_BR_2400) ? " 2400" : "", (irda_desc->wBaudRate & USB_IRDA_BR_9600) ? " 9600" : "", @@ -264,8 +262,6 @@ static int ir_open(struct tty_struct *tty, struct usb_serial_port *port) { int i; - dbg("%s - port %d", __func__, port->number); - for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) port->write_urbs[i]->transfer_flags = URB_ZERO_PACKET; @@ -322,15 +318,11 @@ static void ir_process_read_urb(struct urb *urb) static void ir_set_termios_callback(struct urb *urb) { - struct usb_serial_port *port = urb->context; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - kfree(urb->transfer_buffer); - if (status) - dbg("%s - non-zero urb status: %d", __func__, status); + if (urb->status) + dev_dbg(&urb->dev->dev, "%s - non-zero urb status: %d\n", + __func__, urb->status); } static void ir_set_termios(struct tty_struct *tty, @@ -342,8 +334,6 @@ static void ir_set_termios(struct tty_struct *tty, speed_t baud; int ir_baud; - dbg("%s - port %d", __func__, port->number); - baud = tty_get_baud_rate(tty); /* @@ -447,7 +437,7 @@ static int __init ir_init(void) ir_device.bulk_out_size = buffer_size; } - retval = usb_serial_register_drivers(&ir_driver, serial_drivers); + retval = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ir_id_table); if (retval == 0) printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":" DRIVER_DESC "\n"); @@ -456,7 +446,7 @@ static int __init ir_init(void) static void __exit ir_exit(void) { - usb_serial_deregister_drivers(&ir_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); } diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c index f2192d527db0..22b1eb5040b7 100644 --- a/drivers/usb/serial/iuu_phoenix.c +++ b/drivers/usb/serial/iuu_phoenix.c @@ -51,13 +51,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver iuu_driver = { - .name = "iuu_phoenix", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - /* turbo parameter */ static int boost = 100; static int clockmode = 1; @@ -135,8 +128,6 @@ static void iuu_release(struct usb_serial *serial) if (!port) return; - dbg("%s", __func__); - if (priv) { iuu_free_buf(priv); dbg("%s - I will free all", __func__); @@ -198,8 +189,6 @@ static void iuu_rxcmd(struct urb *urb) int result; int status = urb->status; - dbg("%s - enter", __func__); - if (status) { dbg("%s - status = %d", __func__, status); /* error stop all */ @@ -221,7 +210,6 @@ static int iuu_reset(struct usb_serial_port *port, u8 wt) struct iuu_private *priv = usb_get_serial_port_data(port); int result; char *buf_ptr = port->write_urb->transfer_buffer; - dbg("%s - enter", __func__); /* Prepare the reset sequence */ @@ -255,8 +243,6 @@ static void iuu_update_status_callback(struct urb *urb) u8 *st; int status = urb->status; - dbg("%s - enter", __func__); - if (status) { dbg("%s - status = %d", __func__, status); /* error stop all */ @@ -299,8 +285,6 @@ static int iuu_status(struct usb_serial_port *port) { int result; - dbg("%s - enter", __func__); - memset(port->write_urb->transfer_buffer, IUU_GET_STATE_REGISTER, 1); usb_fill_bulk_urb(port->write_urb, port->serial->dev, usb_sndbulkpipe(port->serial->dev, @@ -318,8 +302,6 @@ static int bulk_immediate(struct usb_serial_port *port, u8 *buf, u8 count) struct usb_serial *serial = port->serial; int actual = 0; - dbg("%s - enter", __func__); - /* send the data out the bulk port */ status = @@ -341,10 +323,7 @@ static int read_immediate(struct usb_serial_port *port, u8 *buf, u8 count) struct usb_serial *serial = port->serial; int actual = 0; - dbg("%s - enter", __func__); - /* send the data out the bulk port */ - status = usb_bulk_msg(serial->dev, usb_rcvbulkpipe(serial->dev, @@ -367,8 +346,6 @@ static int iuu_led(struct usb_serial_port *port, unsigned int R, if (!buf) return -ENOMEM; - dbg("%s - enter", __func__); - buf[0] = IUU_SET_LED; buf[1] = R & 0xFF; buf[2] = (R >> 8) & 0xFF; @@ -460,8 +437,6 @@ static int iuu_clk(struct usb_serial_port *port, int dwFrq) unsigned int P2 = 0; int frq = (int)dwFrq; - dbg("%s - enter", __func__); - if (frq == 0) { priv->buf[Count++] = IUU_UART_WRITE_I2C; priv->buf[Count++] = FrqGenAdr << 1; @@ -590,8 +565,6 @@ static int iuu_uart_flush(struct usb_serial_port *port) u8 rxcmd = IUU_UART_RX; struct iuu_private *priv = usb_get_serial_port_data(port); - dbg("%s - enter", __func__); - if (iuu_led(port, 0xF000, 0, 0, 0xFF) < 0) return -EIO; @@ -630,8 +603,6 @@ static void read_buf_callback(struct urb *urb) struct tty_struct *tty; int status = urb->status; - dbg("%s - status = %d", __func__, status); - if (status) { if (status == -EPROTO) { /* reschedule needed */ @@ -659,7 +630,6 @@ static int iuu_bulk_write(struct usb_serial_port *port) int i; int buf_len; char *buf_ptr = port->write_urb->transfer_buffer; - dbg("%s - enter", __func__); spin_lock_irqsave(&priv->lock, flags); *buf_ptr++ = IUU_UART_ESC; @@ -691,7 +661,6 @@ static int iuu_bulk_write(struct usb_serial_port *port) static int iuu_read_buf(struct usb_serial_port *port, int len) { int result; - dbg("%s - enter", __func__); usb_fill_bulk_urb(port->read_urb, port->serial->dev, usb_rcvbulkpipe(port->serial->dev, @@ -713,8 +682,6 @@ static void iuu_uart_read_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; priv->poll++; - dbg("%s - enter", __func__); - if (status) { dbg("%s - status = %d", __func__, status); /* error stop all */ @@ -771,7 +738,6 @@ static int iuu_uart_write(struct tty_struct *tty, struct usb_serial_port *port, { struct iuu_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s - enter", __func__); if (count > 256) return -ENOMEM; @@ -792,8 +758,6 @@ static void read_rxcmd_callback(struct urb *urb) int result; int status = urb->status; - dbg("%s - status = %d", __func__, status); - if (status) { /* error stop all */ return; @@ -1015,8 +979,6 @@ static void iuu_close(struct usb_serial_port *port) if (!serial) return; - dbg("%s - port %d", __func__, port->number); - iuu_uart_off(port); if (serial->dev) { /* free writebuf */ @@ -1031,7 +993,6 @@ static void iuu_close(struct usb_serial_port *port) static void iuu_init_termios(struct tty_struct *tty) { - dbg("%s - enter", __func__); *(tty->termios) = tty_std_termios; tty->termios->c_cflag = CLOCAL | CREAD | CS8 | B9600 | TIOCM_CTS | CSTOPB | PARENB; @@ -1188,8 +1149,6 @@ static int iuu_vcc_set(struct usb_serial_port *port, unsigned int vcc) if (!buf) return -ENOMEM; - dbg("%s - enter", __func__); - buf[0] = IUU_SET_VCC; buf[1] = vcc & 0xFF; buf[2] = (vcc >> 8) & 0xFF; @@ -1250,15 +1209,11 @@ static DEVICE_ATTR(vcc_mode, S_IRUSR | S_IWUSR, show_vcc_mode, static int iuu_create_sysfs_attrs(struct usb_serial_port *port) { - dbg("%s", __func__); - return device_create_file(&port->dev, &dev_attr_vcc_mode); } static int iuu_remove_sysfs_attrs(struct usb_serial_port *port) { - dbg("%s", __func__); - device_remove_file(&port->dev, &dev_attr_vcc_mode); return 0; } @@ -1294,7 +1249,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &iuu_device, NULL }; -module_usb_serial_driver(iuu_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR("Alain Degreffe eczema@ecze.com"); diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c index a39ddd1b0dca..a1b99243dac9 100644 --- a/drivers/usb/serial/keyspan.c +++ b/drivers/usb/serial/keyspan.c @@ -130,15 +130,13 @@ struct keyspan_port_private { #include "keyspan_usa67msg.h" -module_usb_serial_driver(keyspan_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, keyspan_ids_combined); static void keyspan_break_ctl(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; struct keyspan_port_private *p_priv; - dbg("%s", __func__); - p_priv = usb_get_serial_port_data(port); if (break_state == -1) @@ -158,8 +156,6 @@ static void keyspan_set_termios(struct tty_struct *tty, const struct keyspan_device_details *d_details; unsigned int cflag; - dbg("%s", __func__); - p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; cflag = tty->termios->c_cflag; @@ -306,8 +302,6 @@ static void usa26_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - endpoint = usb_pipeendpoint(urb->pipe); if (status) { @@ -369,8 +363,6 @@ static void usa2x_outdat_callback(struct urb *urb) static void usa26_inack_callback(struct urb *urb) { - dbg("%s", __func__); - } static void usa26_outcont_callback(struct urb *urb) @@ -452,7 +444,6 @@ exit: ; static void usa26_glocont_callback(struct urb *urb) { - dbg("%s", __func__); } @@ -465,8 +456,6 @@ static void usa28_indat_callback(struct urb *urb) struct keyspan_port_private *p_priv; int status = urb->status; - dbg("%s", __func__); - port = urb->context; p_priv = usb_get_serial_port_data(port); data = urb->transfer_buffer; @@ -505,7 +494,6 @@ static void usa28_indat_callback(struct urb *urb) static void usa28_inack_callback(struct urb *urb) { - dbg("%s", __func__); } static void usa28_outcont_callback(struct urb *urb) @@ -585,7 +573,6 @@ exit: ; static void usa28_glocont_callback(struct urb *urb) { - dbg("%s", __func__); } @@ -596,8 +583,6 @@ static void usa49_glocont_callback(struct urb *urb) struct keyspan_port_private *p_priv; int i; - dbg("%s", __func__); - serial = urb->context; for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; @@ -625,8 +610,6 @@ static void usa49_instat_callback(struct urb *urb) int old_dcd_state; int status = urb->status; - dbg("%s", __func__); - serial = urb->context; if (status) { @@ -679,7 +662,6 @@ exit: ; static void usa49_inack_callback(struct urb *urb) { - dbg("%s", __func__); } static void usa49_indat_callback(struct urb *urb) @@ -691,8 +673,6 @@ static void usa49_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - endpoint = usb_pipeendpoint(urb->pipe); if (status) { @@ -742,8 +722,6 @@ static void usa49wg_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - serial = urb->context; if (status) { @@ -806,7 +784,6 @@ static void usa49wg_indat_callback(struct urb *urb) /* not used, usa-49 doesn't have per-port control endpoints */ static void usa49_outcont_callback(struct urb *urb) { - dbg("%s", __func__); } static void usa90_indat_callback(struct urb *urb) @@ -819,8 +796,6 @@ static void usa90_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s", __func__); - endpoint = usb_pipeendpoint(urb->pipe); if (status) { @@ -957,8 +932,6 @@ static void usa67_instat_callback(struct urb *urb) int old_dcd_state; int status = urb->status; - dbg("%s", __func__); - serial = urb->context; if (status) { @@ -1010,8 +983,6 @@ static void usa67_glocont_callback(struct urb *urb) struct keyspan_port_private *p_priv; int i; - dbg("%s", __func__); - serial = urb->context; for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; @@ -1035,7 +1006,6 @@ static int keyspan_write_room(struct tty_struct *tty) int data_len; struct urb *this_urb; - dbg("%s", __func__); p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; @@ -1078,8 +1048,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port) p_priv = usb_get_serial_port_data(port); d_details = p_priv->device_details; - dbg("%s - port%d.", __func__, port->number); - /* Set some sane defaults */ p_priv->rts_state = 1; p_priv->dtr_state = 1; @@ -1165,7 +1133,6 @@ static void keyspan_close(struct usb_serial_port *port) struct keyspan_serial_private *s_priv; struct keyspan_port_private *p_priv; - dbg("%s", __func__); s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); @@ -1438,8 +1405,6 @@ static void keyspan_setup_urbs(struct usb_serial *serial) struct callbacks *cback; int endp; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); d_details = s_priv->device_details; @@ -1853,8 +1818,6 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial, struct urb *this_urb; int device_port, err; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -1980,8 +1943,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial, struct urb *this_urb; int err, device_port; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -2168,8 +2129,6 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial, int err; u8 prescaler; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -2300,8 +2259,6 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial, struct urb *this_urb; int err, device_port; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); p_priv = usb_get_serial_port_data(port); d_details = s_priv->device_details; @@ -2442,8 +2399,6 @@ static void keyspan_send_setup(struct usb_serial_port *port, int reset_port) struct keyspan_serial_private *s_priv; const struct keyspan_device_details *d_details; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); d_details = s_priv->device_details; @@ -2477,8 +2432,6 @@ static int keyspan_startup(struct usb_serial *serial) struct keyspan_port_private *p_priv; const struct keyspan_device_details *d_details; - dbg("%s", __func__); - for (i = 0; (d_details = keyspan_devices[i]) != NULL; ++i) if (d_details->product_id == le16_to_cpu(serial->dev->descriptor.idProduct)) @@ -2538,8 +2491,6 @@ static void keyspan_disconnect(struct usb_serial *serial) struct keyspan_serial_private *s_priv; struct keyspan_port_private *p_priv; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); /* Stop reading/writing urbs */ @@ -2579,8 +2530,6 @@ static void keyspan_release(struct usb_serial *serial) struct usb_serial_port *port; struct keyspan_serial_private *s_priv; - dbg("%s", __func__); - s_priv = usb_get_serial_data(serial); /* dbg("Freeing serial->private."); */ diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h index 622853c9e384..fe1c5d91692c 100644 --- a/drivers/usb/serial/keyspan.h +++ b/drivers/usb/serial/keyspan.h @@ -487,13 +487,6 @@ static const struct usb_device_id keyspan_ids_combined[] = { MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); -static struct usb_driver keyspan_driver = { - .name = "keyspan", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = keyspan_ids_combined, -}; - /* usb_device_id table for the pre-firmware download keyspan devices */ static const struct usb_device_id keyspan_pre_ids[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) }, diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 693bcdfcb3d5..a4ac3cfeffc4 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -86,13 +86,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver keyspan_pda_driver = { - .name = "keyspan_pda", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - static const struct usb_device_id id_table_std[] = { { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) }, { } /* Terminating entry */ @@ -131,7 +124,6 @@ static void keyspan_pda_request_unthrottle(struct work_struct *work) struct usb_serial *serial = priv->serial; int result; - dbg(" request_unthrottle"); /* ask the device to tell us when the tx buffer becomes sufficiently empty */ result = usb_control_msg(serial->dev, @@ -226,7 +218,7 @@ static void keyspan_pda_rx_throttle(struct tty_struct *tty) send an XOFF, although it might make sense to foist that off upon the device too. */ struct usb_serial_port *port = tty->driver_data; - dbg("keyspan_pda_rx_throttle port %d", port->number); + usb_kill_urb(port->interrupt_in_urb); } @@ -235,7 +227,7 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; /* just restart the receive interrupt URB */ - dbg("keyspan_pda_rx_unthrottle port %d", port->number); + if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL)) dbg(" usb_submit_urb(read urb) failed"); } @@ -466,7 +458,6 @@ static int keyspan_pda_write(struct tty_struct *tty, select() or poll() too) until we receive that unthrottle interrupt. Block if we can't write anything at all, otherwise write as much as we can. */ - dbg("keyspan_pda_write(%d)", count); if (count == 0) { dbg(" write request of 0 bytes"); return 0; @@ -766,8 +757,6 @@ static int keyspan_pda_startup(struct usb_serial *serial) static void keyspan_pda_release(struct usb_serial *serial) { - dbg("%s", __func__); - kfree(usb_get_serial_port_data(serial->port[0])); } @@ -834,7 +823,7 @@ static struct usb_serial_driver * const serial_drivers[] = { NULL }; -module_usb_serial_driver(keyspan_pda_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c index 10f05407e535..5bed59cd5776 100644 --- a/drivers/usb/serial/kl5kusb105.c +++ b/drivers/usb/serial/kl5kusb105.c @@ -86,13 +86,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver kl5kusb105d_driver = { - .name = "kl5kusb105d", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver kl5kusb105d_device = { .driver = { .owner = THIS_MODULE, @@ -282,8 +275,6 @@ static void klsi_105_release(struct usb_serial *serial) { int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); } @@ -298,8 +289,6 @@ static int klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port) struct klsi_105_port_settings *cfg; unsigned long flags; - dbg("%s port %d", __func__, port->number); - /* Do a defined restart: * Set up sane default baud rate and send the 'READ_ON' * vendor command. @@ -376,8 +365,6 @@ static void klsi_105_close(struct usb_serial_port *port) { int rc; - dbg("%s port %d", __func__, port->number); - mutex_lock(&port->serial->disc_mutex); if (!port->serial->disconnected) { /* send READ_OFF */ @@ -646,7 +633,6 @@ static int klsi_105_tiocmget(struct tty_struct *tty) unsigned long flags; int rc; unsigned long line_state; - dbg("%s - request, just guessing", __func__); rc = klsi_105_get_line_state(port, &line_state); if (rc < 0) { @@ -668,8 +654,6 @@ static int klsi_105_tiocmset(struct tty_struct *tty, { int retval = -EINVAL; - dbg("%s", __func__); - /* if this ever gets implemented, it should be done something like this: struct usb_serial *serial = port->serial; struct klsi_105_private *priv = usb_get_serial_port_data(port); @@ -692,7 +676,7 @@ static int klsi_105_tiocmset(struct tty_struct *tty, return retval; } -module_usb_serial_driver(kl5kusb105d_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c index 4a9a75eb9b95..fafeabb64c55 100644 --- a/drivers/usb/serial/kobil_sct.c +++ b/drivers/usb/serial/kobil_sct.c @@ -81,18 +81,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) }, { } /* Terminating entry */ }; - - MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver kobil_driver = { - .name = "kobil", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - static struct usb_serial_driver kobil_device = { .driver = { .owner = THIS_MODULE, @@ -193,7 +183,6 @@ static int kobil_startup(struct usb_serial *serial) static void kobil_release(struct usb_serial *serial) { int i; - dbg("%s - port %d", __func__, serial->port[0]->number); for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); @@ -217,7 +206,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) int transfer_buffer_length = 8; int write_urb_transfer_buffer_length = 8; - dbg("%s - port %d", __func__, port->number); priv = usb_get_serial_port_data(port); /* allocate memory for transfer buffer */ @@ -327,8 +315,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port) static void kobil_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - /* FIXME: Add rts/dtr methods */ if (port->write_urb) { usb_poison_urb(port->write_urb); @@ -349,8 +335,6 @@ static void kobil_read_int_callback(struct urb *urb) int status = urb->status; /* char *dbg_data; */ - dbg("%s - port %d", __func__, port->number); - if (status) { dbg("%s - port %d Read int status not zero: %d", __func__, port->number, status); @@ -474,7 +458,6 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port, static int kobil_write_room(struct tty_struct *tty) { - /* dbg("%s - port %d", __func__, port->number); */ /* FIXME */ return 8; } @@ -683,7 +666,7 @@ static int kobil_ioctl(struct tty_struct *tty, } } -module_usb_serial_driver(kobil_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c index 6edd26130e25..d0ec1aa52719 100644 --- a/drivers/usb/serial/mct_u232.c +++ b/drivers/usb/serial/mct_u232.c @@ -73,22 +73,14 @@ static void mct_u232_unthrottle(struct tty_struct *tty); /* * All of the device info needed for the MCT USB-RS232 converter. */ -static const struct usb_device_id id_table_combined[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) }, { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) }, { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) }, { USB_DEVICE(MCT_U232_BELKIN_F5U109_VID, MCT_U232_BELKIN_F5U109_PID) }, { } /* Terminating entry */ }; - -MODULE_DEVICE_TABLE(usb, id_table_combined); - -static struct usb_driver mct_u232_driver = { - .name = "mct_u232", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; +MODULE_DEVICE_TABLE(usb, id_table); static struct usb_serial_driver mct_u232_device = { .driver = { @@ -96,7 +88,7 @@ static struct usb_serial_driver mct_u232_device = { .name = "mct_u232", }, .description = "MCT U232", - .id_table = id_table_combined, + .id_table = id_table, .num_ports = 1, .open = mct_u232_open, .close = mct_u232_close, @@ -427,8 +419,6 @@ static void mct_u232_release(struct usb_serial *serial) struct mct_u232_private *priv; int i; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { /* My special items, the standard routines free my urbs */ priv = usb_get_serial_port_data(serial->port[i]); @@ -446,8 +436,6 @@ static int mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned char last_lcr; unsigned char last_msr; - dbg("%s port %d", __func__, port->number); - /* Compensate for a hardware bug: although the Sitecom U232-P25 * device reports a maximum output packet size of 32 bytes, * it seems to be able to accept only 16 bytes (and that's what @@ -528,8 +516,6 @@ static void mct_u232_dtr_rts(struct usb_serial_port *port, int on) static void mct_u232_close(struct usb_serial_port *port) { - dbg("%s port %d", __func__, port->number); - if (port->serial->dev) { /* shutdown our urbs */ usb_kill_urb(port->write_urb); @@ -572,7 +558,6 @@ static void mct_u232_read_int_callback(struct urb *urb) return; } - dbg("%s - port %d", __func__, port->number); usb_serial_debug_data(debug, &port->dev, __func__, urb->actual_length, data); @@ -733,8 +718,6 @@ static void mct_u232_break_ctl(struct tty_struct *tty, int break_state) unsigned char lcr; unsigned long flags; - dbg("%sstate=%d", __func__, break_state); - spin_lock_irqsave(&priv->lock, flags); lcr = priv->last_lcr; @@ -753,8 +736,6 @@ static int mct_u232_tiocmget(struct tty_struct *tty) unsigned int control_state; unsigned long flags; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; spin_unlock_irqrestore(&priv->lock, flags); @@ -771,8 +752,6 @@ static int mct_u232_tiocmset(struct tty_struct *tty, unsigned int control_state; unsigned long flags; - dbg("%s", __func__); - spin_lock_irqsave(&priv->lock, flags); control_state = priv->control_state; @@ -796,8 +775,6 @@ static void mct_u232_throttle(struct tty_struct *tty) struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); priv->rx_flags |= THROTTLED; if (C_CRTSCTS(tty)) { @@ -816,8 +793,6 @@ static void mct_u232_unthrottle(struct tty_struct *tty) struct mct_u232_private *priv = usb_get_serial_port_data(port); unsigned int control_state; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); if ((priv->rx_flags & THROTTLED) && C_CRTSCTS(tty)) { priv->rx_flags &= ~THROTTLED; @@ -906,7 +881,7 @@ static int mct_u232_get_icount(struct tty_struct *tty, return 0; } -module_usb_serial_driver(mct_u232_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c index 08d16e8c002d..81423f7361db 100644 --- a/drivers/usb/serial/metro-usb.c +++ b/drivers/usb/serial/metro-usb.c @@ -17,7 +17,6 @@ #include <linux/tty_flip.h> #include <linux/moduleparam.h> #include <linux/spinlock.h> -#include <linux/errno.h> #include <linux/uaccess.h> #include <linux/usb/serial.h> @@ -56,6 +55,47 @@ MODULE_DEVICE_TABLE(usb, id_table); /* Input parameter constants. */ static bool debug; +/* UNI-Directional mode commands for device configure */ +#define UNI_CMD_OPEN 0x80 +#define UNI_CMD_CLOSE 0xFF + +inline int metrousb_is_unidirectional_mode(struct usb_serial_port *port) +{ + __u16 product_id = le16_to_cpu( + port->serial->dev->descriptor.idProduct); + + return product_id == FOCUS_PRODUCT_ID_UNI; +} + +static int metrousb_send_unidirectional_cmd(u8 cmd, struct usb_serial_port *port) +{ + int ret; + int actual_len; + u8 *buffer_cmd = NULL; + + if (!metrousb_is_unidirectional_mode(port)) + return 0; + + buffer_cmd = kzalloc(sizeof(cmd), GFP_KERNEL); + if (!buffer_cmd) + return -ENOMEM; + + *buffer_cmd = cmd; + + ret = usb_interrupt_msg(port->serial->dev, + usb_sndintpipe(port->serial->dev, port->interrupt_out_endpointAddress), + buffer_cmd, sizeof(cmd), + &actual_len, USB_CTRL_SET_TIMEOUT); + + kfree(buffer_cmd); + + if (ret < 0) + return ret; + else if (actual_len != sizeof(cmd)) + return -EIO; + return 0; +} + static void metrousb_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -78,12 +118,12 @@ static void metrousb_read_int_callback(struct urb *urb) /* urb has been terminated. */ dev_dbg(&port->dev, "%s - urb shutting down, error code=%d\n", - __func__, result); + __func__, urb->status); return; default: dev_dbg(&port->dev, "%s - non-zero urb received, error code=%d\n", - __func__, result); + __func__, urb->status); goto exit; } @@ -91,7 +131,7 @@ static void metrousb_read_int_callback(struct urb *urb) /* Set the data read from the usb port into the serial port buffer. */ tty = tty_port_tty_get(&port->port); if (!tty) { - dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n", + dev_err(&port->dev, "%s - bad tty pointer - exiting\n", __func__); return; } @@ -121,7 +161,7 @@ static void metrousb_read_int_callback(struct urb *urb) result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) - dev_dbg(&port->dev, + dev_err(&port->dev, "%s - failed submitting interrupt in urb, error code=%d\n", __func__, result); } @@ -131,11 +171,19 @@ exit: /* Try to resubmit the urb. */ result = usb_submit_urb(urb, GFP_ATOMIC); if (result) - dev_dbg(&port->dev, + dev_err(&port->dev, "%s - failed submitting interrupt in urb, error code=%d\n", __func__, result); } +static void metrousb_write_int_callback(struct urb *urb) +{ + struct usb_serial_port *port = urb->context; + + dev_warn(&port->dev, "%s not implemented yet.\n", + __func__); +} + static void metrousb_cleanup(struct usb_serial_port *port) { dev_dbg(&port->dev, "%s\n", __func__); @@ -146,6 +194,9 @@ static void metrousb_cleanup(struct usb_serial_port *port) usb_unlink_urb(port->interrupt_in_urb); usb_kill_urb(port->interrupt_in_urb); } + + /* Send deactivate cmd to device */ + metrousb_send_unidirectional_cmd(UNI_CMD_CLOSE, port); } } @@ -160,7 +211,7 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) /* Make sure the urb is initialized. */ if (!port->interrupt_in_urb) { - dev_dbg(&port->dev, "%s - interrupt urb not initialized\n", + dev_err(&port->dev, "%s - interrupt urb not initialized\n", __func__); return -ENODEV; } @@ -191,12 +242,21 @@ static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port) result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { - dev_dbg(&port->dev, + dev_err(&port->dev, "%s - failed submitting interrupt in urb, error code=%d\n", __func__, result); goto exit; } + /* Send activate cmd to device */ + result = metrousb_send_unidirectional_cmd(UNI_CMD_OPEN, port); + if (result) { + dev_err(&port->dev, + "%s - failed to configure device for port number=%d, error code=%d\n", + __func__, port->number, result); + goto exit; + } + dev_dbg(&port->dev, "%s - port open\n", __func__); exit: return result; @@ -221,7 +281,7 @@ static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int contr METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST, control_state, 0, NULL, 0, WDR_TIMEOUT); if (retval < 0) - dev_dbg(&serial->dev->dev, + dev_err(&serial->dev->dev, "%s - set modem ctrl=0x%x failed, error code=%d\n", __func__, mcr, retval); @@ -354,29 +414,23 @@ static void metrousb_unthrottle(struct tty_struct *tty) port->interrupt_in_urb->dev = port->serial->dev; result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) - dev_dbg(tty->dev, + dev_err(tty->dev, "failed submitting interrupt in urb error code=%d\n", result); } -static struct usb_driver metrousb_driver = { - .name = "metro-usb", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table -}; - static struct usb_serial_driver metrousb_device = { .driver = { .owner = THIS_MODULE, .name = "metro-usb", }, - .description = "Metrologic USB to serial converter.", + .description = "Metrologic USB to Serial", .id_table = id_table, .num_ports = 1, .open = metrousb_open, .close = metrousb_cleanup, .read_int_callback = metrousb_read_int_callback, + .write_int_callback = metrousb_write_int_callback, .attach = metrousb_startup, .release = metrousb_shutdown, .throttle = metrousb_throttle, @@ -390,7 +444,7 @@ static struct usb_serial_driver * const serial_drivers[] = { NULL, }; -module_usb_serial_driver(metrousb_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Philip Nicastro"); diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index bdce82034122..a07dd3c8cfef 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -79,12 +79,12 @@ static struct usb_serial_driver moschip7720_2port_driver; #define MOSCHIP_DEVICE_ID_7720 0x7720 #define MOSCHIP_DEVICE_ID_7715 0x7715 -static const struct usb_device_id moschip_port_id_table[] = { +static const struct usb_device_id id_table[] = { { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) }, { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) }, { } /* terminating entry */ }; -MODULE_DEVICE_TABLE(usb, moschip_port_id_table); +MODULE_DEVICE_TABLE(usb, id_table); #ifdef CONFIG_USB_SERIAL_MOS7715_PARPORT @@ -257,7 +257,6 @@ static void destroy_mos_parport(struct kref *kref) struct mos7715_parport *mos_parport = container_of(kref, struct mos7715_parport, ref_count); - dbg("%s called", __func__); kfree(mos_parport); } @@ -266,7 +265,7 @@ static void destroy_urbtracker(struct kref *kref) struct urbtracker *urbtrack = container_of(kref, struct urbtracker, ref_count); struct mos7715_parport *mos_parport = urbtrack->mos_parport; - dbg("%s called", __func__); + usb_free_urb(urbtrack->urb); kfree(urbtrack); kref_put(&mos_parport->ref_count, destroy_mos_parport); @@ -285,8 +284,6 @@ static void send_deferred_urbs(unsigned long _mos_parport) struct urbtracker *urbtrack; struct list_head *cursor, *next; - dbg("%s called", __func__); - /* if release function ran, game over */ if (unlikely(mos_parport->serial == NULL)) return; @@ -335,7 +332,7 @@ static void async_complete(struct urb *urb) { struct urbtracker *urbtrack = urb->context; int status = urb->status; - dbg("%s called", __func__); + if (unlikely(status)) dbg("%s - nonzero urb status received: %d", __func__, status); @@ -355,7 +352,6 @@ static int write_parport_reg_nonblock(struct mos7715_parport *mos_parport, struct usb_ctrlrequest setup; struct usb_serial *serial = mos_parport->serial; struct usb_device *usbdev = serial->dev; - dbg("%s called", __func__); /* create and initialize the control urb and containing urbtracker */ urbtrack = kmalloc(sizeof(struct urbtracker), GFP_ATOMIC); @@ -476,7 +472,7 @@ static inline void parport_epilogue(struct parport *pp) static void parport_mos7715_write_data(struct parport *pp, unsigned char d) { struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called: %2.2x", __func__, d); + if (parport_prologue(pp) < 0) return; mos7715_change_mode(mos_parport, SPP); @@ -488,7 +484,7 @@ static unsigned char parport_mos7715_read_data(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; unsigned char d; - dbg("%s called", __func__); + if (parport_prologue(pp) < 0) return 0; read_mos_reg(mos_parport->serial, dummy, DPR, &d); @@ -500,7 +496,7 @@ static void parport_mos7715_write_control(struct parport *pp, unsigned char d) { struct mos7715_parport *mos_parport = pp->private_data; __u8 data; - dbg("%s called: %2.2x", __func__, d); + if (parport_prologue(pp) < 0) return; data = ((__u8)d & 0x0f) | (mos_parport->shadowDCR & 0xf0); @@ -513,7 +509,7 @@ static unsigned char parport_mos7715_read_control(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; __u8 dcr; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { @@ -531,7 +527,7 @@ static unsigned char parport_mos7715_frob_control(struct parport *pp, { struct mos7715_parport *mos_parport = pp->private_data; __u8 dcr; - dbg("%s called", __func__); + mask &= 0x0f; val &= 0x0f; if (parport_prologue(pp) < 0) @@ -547,7 +543,7 @@ static unsigned char parport_mos7715_read_status(struct parport *pp) { unsigned char status; struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { /* release called */ @@ -561,17 +557,16 @@ static unsigned char parport_mos7715_read_status(struct parport *pp) static void parport_mos7715_enable_irq(struct parport *pp) { - dbg("%s called", __func__); } + static void parport_mos7715_disable_irq(struct parport *pp) { - dbg("%s called", __func__); } static void parport_mos7715_data_forward(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); + if (parport_prologue(pp) < 0) return; mos7715_change_mode(mos_parport, PS2); @@ -583,7 +578,7 @@ static void parport_mos7715_data_forward(struct parport *pp) static void parport_mos7715_data_reverse(struct parport *pp) { struct mos7715_parport *mos_parport = pp->private_data; - dbg("%s called", __func__); + if (parport_prologue(pp) < 0) return; mos7715_change_mode(mos_parport, PS2); @@ -595,7 +590,6 @@ static void parport_mos7715_data_reverse(struct parport *pp) static void parport_mos7715_init_state(struct pardevice *dev, struct parport_state *s) { - dbg("%s called", __func__); s->u.pc.ctr = DCR_INIT_VAL; s->u.pc.ecr = ECR_INIT_VAL; } @@ -605,7 +599,7 @@ static void parport_mos7715_save_state(struct parport *pp, struct parport_state *s) { struct mos7715_parport *mos_parport; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { /* release called */ @@ -622,7 +616,7 @@ static void parport_mos7715_restore_state(struct parport *pp, struct parport_state *s) { struct mos7715_parport *mos_parport; - dbg("%s called", __func__); + spin_lock(&release_lock); mos_parport = pp->private_data; if (unlikely(mos_parport == NULL)) { /* release called */ @@ -641,7 +635,7 @@ static size_t parport_mos7715_write_compat(struct parport *pp, int retval; struct mos7715_parport *mos_parport = pp->private_data; int actual_len; - dbg("%s called: %u chars", __func__, (unsigned int)len); + if (parport_prologue(pp) < 0) return 0; mos7715_change_mode(mos_parport, PPF); @@ -2164,20 +2158,13 @@ static void mos7720_release(struct usb_serial *serial) kfree(usb_get_serial_port_data(serial->port[i])); } -static struct usb_driver usb_driver = { - .name = "moschip7720", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_port_id_table, -}; - static struct usb_serial_driver moschip7720_2port_driver = { .driver = { .owner = THIS_MODULE, .name = "moschip7720", }, .description = "Moschip 2 port adapter", - .id_table = moschip_port_id_table, + .id_table = id_table, .calc_num_ports = mos77xx_calc_num_ports, .open = mos7720_open, .close = mos7720_close, @@ -2203,7 +2190,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &moschip7720_2port_driver, NULL }; -module_usb_serial_driver(usb_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index c526550694a0..29160f8b5101 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -114,10 +114,10 @@ #define USB_VENDOR_ID_MOSCHIP 0x9710 #define MOSCHIP_DEVICE_ID_7840 0x7840 #define MOSCHIP_DEVICE_ID_7820 0x7820 +#define MOSCHIP_DEVICE_ID_7810 0x7810 /* The native component can have its vendor/device id's overridden * in vendor-specific implementations. Such devices can be handled - * by making a change here, in moschip_port_id_table, and in - * moschip_id_table_combined + * by making a change here, in id_table. */ #define USB_VENDOR_ID_BANDB 0x0856 #define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 @@ -184,31 +184,16 @@ #define NUM_URBS 16 /* URB Count */ #define URB_TRANSFER_BUFFER_SIZE 32 /* URB Size */ +/* LED on/off milliseconds*/ +#define LED_ON_MS 500 +#define LED_OFF_MS 500 -static const struct usb_device_id moschip_port_id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, - {} /* terminating entry */ -}; +static int device_type; -static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { +static const struct usb_device_id id_table[] __devinitconst = { {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, + {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, @@ -226,8 +211,7 @@ static const struct usb_device_id moschip_id_table_combined[] __devinitconst = { {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, {} /* terminating entry */ }; - -MODULE_DEVICE_TABLE(usb, moschip_id_table_combined); +MODULE_DEVICE_TABLE(usb, id_table); /* This structure holds all of the local port information */ @@ -261,8 +245,13 @@ struct moschip_port { struct urb *write_urb_pool[NUM_URBS]; char busy[NUM_URBS]; bool read_urb_busy; -}; + /* For device(s) with LED indicator */ + bool has_led; + bool led_flag; + struct timer_list led_timer1; /* Timer for LED on */ + struct timer_list led_timer2; /* Timer for LED off */ +}; static bool debug; @@ -572,6 +561,69 @@ static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, return ret; } +static void mos7840_set_led_callback(struct urb *urb) +{ + switch (urb->status) { + case 0: + /* Success */ + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + /* This urb is terminated, clean up */ + dbg("%s - urb shutting down with status: %d", __func__, + urb->status); + break; + default: + dbg("%s - nonzero urb status received: %d", __func__, + urb->status); + } +} + +static void mos7840_set_led_async(struct moschip_port *mcs, __u16 wval, + __u16 reg) +{ + struct usb_device *dev = mcs->port->serial->dev; + struct usb_ctrlrequest *dr = mcs->dr; + + dr->bRequestType = MCS_WR_RTYPE; + dr->bRequest = MCS_WRREQ; + dr->wValue = cpu_to_le16(wval); + dr->wIndex = cpu_to_le16(reg); + dr->wLength = cpu_to_le16(0); + + usb_fill_control_urb(mcs->control_urb, dev, usb_sndctrlpipe(dev, 0), + (unsigned char *)dr, NULL, 0, mos7840_set_led_callback, NULL); + + usb_submit_urb(mcs->control_urb, GFP_ATOMIC); +} + +static void mos7840_set_led_sync(struct usb_serial_port *port, __u16 reg, + __u16 val) +{ + struct usb_device *dev = port->serial->dev; + + usb_control_msg(dev, usb_sndctrlpipe(dev, 0), MCS_WRREQ, MCS_WR_RTYPE, + val, reg, NULL, 0, MOS_WDR_TIMEOUT); +} + +static void mos7840_led_off(unsigned long arg) +{ + struct moschip_port *mcs = (struct moschip_port *) arg; + + /* Turn off LED */ + mos7840_set_led_async(mcs, 0x0300, MODEM_CONTROL_REGISTER); + mod_timer(&mcs->led_timer2, + jiffies + msecs_to_jiffies(LED_OFF_MS)); +} + +static void mos7840_led_flag_off(unsigned long arg) +{ + struct moschip_port *mcs = (struct moschip_port *) arg; + + mcs->led_flag = false; +} + /***************************************************************************** * mos7840_interrupt_callback * this is the callback function for when we have received data on the @@ -591,8 +643,6 @@ static void mos7840_interrupt_callback(struct urb *urb) __u16 wval, wreg = 0; int status = urb->status; - dbg("%s", " : Entering"); - switch (status) { case 0: /* success */ @@ -766,12 +816,8 @@ static void mos7840_bulk_in_callback(struct urb *urb) return; } - dbg("%s", "Entering... "); - data = urb->transfer_buffer; - dbg("%s", "Entering ..........."); - if (urb->actual_length) { tty = tty_port_tty_get(&mos7840_port->port->port); if (tty) { @@ -792,6 +838,14 @@ static void mos7840_bulk_in_callback(struct urb *urb) return; } + /* Turn on LED */ + if (mos7840_port->has_led && !mos7840_port->led_flag) { + mos7840_port->led_flag = true; + mos7840_set_led_async(mos7840_port, 0x0301, + MODEM_CONTROL_REGISTER); + mod_timer(&mos7840_port->led_timer1, + jiffies + msecs_to_jiffies(LED_ON_MS)); + } mos7840_port->read_urb_busy = true; retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC); @@ -835,8 +889,6 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) return; } - dbg("%s", "Entering ........."); - tty = tty_port_tty_get(&mos7840_port->port->port); if (tty && mos7840_port->open) tty_wakeup(tty); @@ -878,8 +930,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) struct moschip_port *mos7840_port; struct moschip_port *port0; - dbg ("%s enter", __func__); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Port Paranoia failed"); return -ENODEV; @@ -1151,10 +1201,7 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) dbg("usb_serial serial:%p mos7840_port:%p\n usb_serial_port port:%p", serial, mos7840_port, port); - dbg ("%s leave", __func__); - return 0; - } /***************************************************************************** @@ -1175,18 +1222,14 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " mos7840_chars_in_buffer:entering ..........."); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Invalid port"); return 0; } mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) { - dbg("%s", "mos7840_break:leaving ..........."); + if (mos7840_port == NULL) return 0; - } spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) @@ -1211,8 +1254,6 @@ static void mos7840_close(struct usb_serial_port *port) int j; __u16 Data; - dbg("%s", "mos7840_close:entering..."); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Port Paranoia failed"); return; @@ -1287,8 +1328,6 @@ static void mos7840_close(struct usb_serial_port *port) mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); mos7840_port->open = 0; - - dbg("%s", "Leaving ............"); } /************************************************************************ @@ -1343,9 +1382,6 @@ static void mos7840_break(struct tty_struct *tty, int break_state) struct usb_serial *serial; struct moschip_port *mos7840_port; - dbg("%s", "Entering ..........."); - dbg("mos7840_break: Start"); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Port Paranoia failed"); return; @@ -1395,8 +1431,6 @@ static int mos7840_write_room(struct tty_struct *tty) unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " mos7840_write_room:entering ..........."); - if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Invalid port"); dbg("%s", " mos7840_write_room:leaving ..........."); @@ -1445,9 +1479,6 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, /* __u16 Data; */ const unsigned char *current_position = data; unsigned char *data1; - dbg("%s", "entering ..........."); - /* dbg("mos7840_write: mos7840_port->shadowLCR is %x", - mos7840_port->shadowLCR); */ #ifdef NOTMOS7840 Data = 0x00; @@ -1554,6 +1585,14 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, data1 = urb->transfer_buffer; dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress); + /* Turn on LED */ + if (mos7840_port->has_led && !mos7840_port->led_flag) { + mos7840_port->led_flag = true; + mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0301); + mod_timer(&mos7840_port->led_timer1, + jiffies + msecs_to_jiffies(LED_ON_MS)); + } + /* send it down the pipe */ status = usb_submit_urb(urb, GFP_ATOMIC); @@ -1602,8 +1641,6 @@ static void mos7840_throttle(struct tty_struct *tty) return; } - dbg("%s", "Entering .........."); - /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); @@ -1646,8 +1683,6 @@ static void mos7840_unthrottle(struct tty_struct *tty) return; } - dbg("%s", "Entering .........."); - /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { unsigned char start_char = START_CHAR(tty); @@ -1676,8 +1711,6 @@ static int mos7840_tiocmget(struct tty_struct *tty) int status; mos7840_port = mos7840_get_port_private(port); - dbg("%s - port %d", __func__, port->number); - if (mos7840_port == NULL) return -ENODEV; @@ -1704,8 +1737,6 @@ static int mos7840_tiocmset(struct tty_struct *tty, unsigned int mcr; int status; - dbg("%s - port %d", __func__, port->number); - mos7840_port = mos7840_get_port_private(port); if (mos7840_port == NULL) @@ -1746,7 +1777,6 @@ static int mos7840_tiocmset(struct tty_struct *tty, static int mos7840_calc_baud_rate_divisor(int baudRate, int *divisor, __u16 *clk_sel_val) { - dbg("%s - %d", __func__, baudRate); if (baudRate <= 115200) { @@ -1839,8 +1869,6 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, return -1; } - dbg("%s", "Entering .........."); - number = mos7840_port->port->number - mos7840_port->port->serial->minor; dbg("%s - port = %d, baud = %d", __func__, @@ -1966,8 +1994,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty, return; } - dbg("%s", "Entering .........."); - lData = LCR_BITS_8; lStop = LCR_STOP_1; lParity = LCR_PAR_NONE; @@ -2108,7 +2134,7 @@ static void mos7840_set_termios(struct tty_struct *tty, unsigned int cflag; struct usb_serial *serial; struct moschip_port *mos7840_port; - dbg("mos7840_set_termios: START"); + if (mos7840_port_paranoia_check(port, __func__)) { dbg("%s", "Invalid port"); return; @@ -2327,28 +2353,74 @@ static int mos7840_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +static int mos7810_check(struct usb_serial *serial) +{ + int i, pass_count = 0; + __u16 data = 0, mcr_data = 0; + __u16 test_pattern = 0x55AA; + + /* Store MCR setting */ + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0x0300, MODEM_CONTROL_REGISTER, + &mcr_data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + + for (i = 0; i < 16; i++) { + /* Send the 1-bit test pattern out to MCS7810 test pin */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), + MCS_WRREQ, MCS_WR_RTYPE, + (0x0300 | (((test_pattern >> i) & 0x0001) << 1)), + MODEM_CONTROL_REGISTER, NULL, 0, MOS_WDR_TIMEOUT); + + /* Read the test pattern back */ + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data, + VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); + + /* If this is a MCS7810 device, both test patterns must match */ + if (((test_pattern >> i) ^ (~data >> 1)) & 0x0001) + break; + + pass_count++; + } + + /* Restore MCR setting */ + usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), MCS_WRREQ, + MCS_WR_RTYPE, 0x0300 | mcr_data, MODEM_CONTROL_REGISTER, NULL, + 0, MOS_WDR_TIMEOUT); + + if (pass_count == 16) + return 1; + + return 0; +} + static int mos7840_calc_num_ports(struct usb_serial *serial) { - __u16 Data = 0x00; - int ret = 0; + __u16 data = 0x00; int mos7840_num_ports; - ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data, + usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &data, VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT); - if ((Data & 0x01) == 0) { - mos7840_num_ports = 2; - serial->num_bulk_in = 2; - serial->num_bulk_out = 2; - serial->num_ports = 2; + if (serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7810 || + serial->dev->descriptor.idProduct == MOSCHIP_DEVICE_ID_7820) { + device_type = serial->dev->descriptor.idProduct; } else { - mos7840_num_ports = 4; - serial->num_bulk_in = 4; - serial->num_bulk_out = 4; - serial->num_ports = 4; + /* For a MCS7840 device GPIO0 must be set to 1 */ + if ((data & 0x01) == 1) + device_type = MOSCHIP_DEVICE_ID_7840; + else if (mos7810_check(serial)) + device_type = MOSCHIP_DEVICE_ID_7810; + else + device_type = MOSCHIP_DEVICE_ID_7820; } + mos7840_num_ports = (device_type >> 4) & 0x000F; + serial->num_bulk_in = mos7840_num_ports; + serial->num_bulk_out = mos7840_num_ports; + serial->num_ports = mos7840_num_ports; + return mos7840_num_ports; } @@ -2361,9 +2433,7 @@ static int mos7840_startup(struct usb_serial *serial) struct moschip_port *mos7840_port; struct usb_device *dev; int i, status; - __u16 Data; - dbg("%s", "mos7840_startup :Entering.........."); if (!serial) { dbg("%s", "Invalid Handler"); @@ -2372,9 +2442,6 @@ static int mos7840_startup(struct usb_serial *serial) dev = serial->dev; - dbg("%s", "Entering..."); - dbg ("mos7840_startup: serial = %p", serial); - /* we set up the pointers to the endpoints in the mos7840_open * * function, as the structures aren't created yet. */ @@ -2563,6 +2630,34 @@ static int mos7840_startup(struct usb_serial *serial) status = -ENOMEM; goto error; } + + mos7840_port->has_led = false; + + /* Initialize LED timers */ + if (device_type == MOSCHIP_DEVICE_ID_7810) { + mos7840_port->has_led = true; + + init_timer(&mos7840_port->led_timer1); + mos7840_port->led_timer1.function = mos7840_led_off; + mos7840_port->led_timer1.expires = + jiffies + msecs_to_jiffies(LED_ON_MS); + mos7840_port->led_timer1.data = + (unsigned long)mos7840_port; + + init_timer(&mos7840_port->led_timer2); + mos7840_port->led_timer2.function = + mos7840_led_flag_off; + mos7840_port->led_timer2.expires = + jiffies + msecs_to_jiffies(LED_OFF_MS); + mos7840_port->led_timer2.data = + (unsigned long)mos7840_port; + + mos7840_port->led_flag = false; + + /* Turn off LED */ + mos7840_set_led_sync(serial->port[i], + MODEM_CONTROL_REGISTER, 0x0300); + } } dbg ("mos7840_startup: all ports configured..........."); @@ -2602,7 +2697,6 @@ static void mos7840_disconnect(struct usb_serial *serial) int i; unsigned long flags; struct moschip_port *mos7840_port; - dbg("%s", " disconnect :entering.........."); if (!serial) { dbg("%s", "Invalid Handler"); @@ -2624,9 +2718,6 @@ static void mos7840_disconnect(struct usb_serial *serial) usb_kill_urb(mos7840_port->control_urb); } } - - dbg("%s", "Thank u :: "); - } /**************************************************************************** @@ -2638,7 +2729,6 @@ static void mos7840_release(struct usb_serial *serial) { int i; struct moschip_port *mos7840_port; - dbg("%s", " release :entering.........."); if (!serial) { dbg("%s", "Invalid Handler"); @@ -2654,30 +2744,28 @@ static void mos7840_release(struct usb_serial *serial) mos7840_port = mos7840_get_port_private(serial->port[i]); dbg("mos7840_port %d = %p", i, mos7840_port); if (mos7840_port) { + if (mos7840_port->has_led) { + /* Turn off LED */ + mos7840_set_led_sync(mos7840_port->port, + MODEM_CONTROL_REGISTER, 0x0300); + + del_timer_sync(&mos7840_port->led_timer1); + del_timer_sync(&mos7840_port->led_timer2); + } kfree(mos7840_port->ctrl_buf); kfree(mos7840_port->dr); kfree(mos7840_port); } } - - dbg("%s", "Thank u :: "); - } -static struct usb_driver io_driver = { - .name = "mos7840", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = moschip_id_table_combined, -}; - static struct usb_serial_driver moschip7840_4port_device = { .driver = { .owner = THIS_MODULE, .name = "mos7840", }, .description = DRIVER_DESC, - .id_table = moschip_port_id_table, + .id_table = id_table, .num_ports = 4, .open = mos7840_open, .close = mos7840_close, @@ -2707,7 +2795,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &moschip7840_4port_device, NULL }; -module_usb_serial_driver(io_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c index 3ab6214b4bbf..c5ff6c7795a6 100644 --- a/drivers/usb/serial/moto_modem.c +++ b/drivers/usb/serial/moto_modem.c @@ -31,13 +31,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver moto_driver = { - .name = "moto-modem", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver moto_device = { .driver = { .owner = THIS_MODULE, @@ -51,5 +44,5 @@ static struct usb_serial_driver * const serial_drivers[] = { &moto_device, NULL }; -module_usb_serial_driver(moto_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c index 29ab6eb5b536..d95452cc076d 100644 --- a/drivers/usb/serial/navman.c +++ b/drivers/usb/serial/navman.c @@ -30,13 +30,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver navman_driver = { - .name = "navman", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static void navman_read_int_callback(struct urb *urb) { struct usb_serial_port *port = urb->context; @@ -53,12 +46,12 @@ static void navman_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -84,10 +77,9 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port) { int result = 0; - dbg("%s - port %d", __func__, port->number); - if (port->interrupt_in_urb) { - dbg("%s - adding interrupt input for treo", __func__); + dev_dbg(&port->dev, "%s - adding interrupt input for treo\n", + __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, @@ -99,16 +91,12 @@ static int navman_open(struct tty_struct *tty, struct usb_serial_port *port) static void navman_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_kill_urb(port->interrupt_in_urb); } static int navman_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - dbg("%s - port %d", __func__, port->number); - /* * This device can't write any data, only read from the device */ @@ -132,7 +120,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &navman_device, NULL }; -module_usb_serial_driver(navman_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index 88dc785bb298..6f3d7051c7f4 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -54,17 +54,8 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) }, { } /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver omninet_driver = { - .name = "omninet", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - static struct usb_serial_driver zyxel_omninet_device = { .driver = { .owner = THIS_MODULE, @@ -144,8 +135,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) struct usb_serial_port *wport; int result = 0; - dbg("%s - port %d", __func__, port->number); - wport = serial->port[1]; tty_port_tty_set(&wport->port, tty); @@ -160,7 +149,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port) static void omninet_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); usb_kill_urb(port->read_urb); } @@ -178,8 +166,6 @@ static void omninet_read_bulk_callback(struct urb *urb) int result; int i; - dbg("%s - port %d", __func__, port->number); - if (status) { dbg("%s - nonzero read bulk status received: %d", __func__, status); @@ -225,8 +211,6 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, int result; - dbg("%s - port %d", __func__, port->number); - if (count == 0) { dbg("%s - write request of 0 bytes", __func__); return 0; @@ -289,8 +273,6 @@ static void omninet_write_bulk_callback(struct urb *urb) struct usb_serial_port *port = urb->context; int status = urb->status; - dbg("%s - port %0x", __func__, port->number); - set_bit(0, &port->write_urbs_free); if (status) { dbg("%s - nonzero write bulk status received: %d", @@ -306,8 +288,6 @@ static void omninet_disconnect(struct usb_serial *serial) { struct usb_serial_port *wport = serial->port[1]; - dbg("%s", __func__); - usb_kill_urb(wport->write_urb); } @@ -316,12 +296,10 @@ static void omninet_release(struct usb_serial *serial) { struct usb_serial_port *port = serial->port[0]; - dbg("%s", __func__); - kfree(usb_get_serial_port_data(port)); } -module_usb_serial_driver(omninet_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c index 82cc9d202b83..02cb1b7f6559 100644 --- a/drivers/usb/serial/opticon.c +++ b/drivers/usb/serial/opticon.c @@ -70,8 +70,6 @@ static void opticon_read_bulk_callback(struct urb *urb) int data_length; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ @@ -179,8 +177,6 @@ static int opticon_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; priv->actually_throttled = false; @@ -216,8 +212,6 @@ static void opticon_close(struct usb_serial_port *port) { struct opticon_private *priv = usb_get_serial_data(port->serial); - dbg("%s - port %d", __func__, port->number); - /* shutdown our urbs */ usb_kill_urb(priv->bulk_read_urb); } @@ -256,8 +250,6 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port, int status; struct usb_ctrlrequest *dr; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); if (priv->outstanding_urbs > URB_UPPER_LIMIT) { spin_unlock_irqrestore(&priv->lock, flags); @@ -338,8 +330,6 @@ static int opticon_write_room(struct tty_struct *tty) struct opticon_private *priv = usb_get_serial_data(port->serial); unsigned long flags; - dbg("%s - port %d", __func__, port->number); - /* * We really can take almost anything the user throws at us * but let's pick a nice big number to tell the tty @@ -362,7 +352,6 @@ static void opticon_throttle(struct tty_struct *tty) struct opticon_private *priv = usb_get_serial_data(port->serial); unsigned long flags; - dbg("%s - port %d", __func__, port->number); spin_lock_irqsave(&priv->lock, flags); priv->throttled = true; spin_unlock_irqrestore(&priv->lock, flags); @@ -376,8 +365,6 @@ static void opticon_unthrottle(struct tty_struct *tty) unsigned long flags; int result, was_throttled; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; was_throttled = priv->actually_throttled; @@ -400,10 +387,6 @@ static int opticon_tiocmget(struct tty_struct *tty) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); if (priv->rts) result |= TIOCM_RTS; @@ -419,13 +402,13 @@ static int opticon_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; struct opticon_private *priv = usb_get_serial_data(port->serial); unsigned long flags; bool rts; bool changed = false; + int ret; - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; /* We only support RTS so we only handle that */ spin_lock_irqsave(&priv->lock, flags); @@ -441,7 +424,14 @@ static int opticon_tiocmset(struct tty_struct *tty, return 0; /* Send the new RTS state to the connected device */ - return send_control_msg(port, CONTROL_RTS, !rts); + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + ret = send_control_msg(port, CONTROL_RTS, !rts); + else + ret = -ENODEV; + mutex_unlock(&serial->disc_mutex); + + return ret; } static int get_serial_info(struct opticon_private *priv, @@ -555,8 +545,6 @@ static void opticon_disconnect(struct usb_serial *serial) { struct opticon_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - usb_kill_urb(priv->bulk_read_urb); usb_free_urb(priv->bulk_read_urb); } @@ -565,24 +553,20 @@ static void opticon_release(struct usb_serial *serial) { struct opticon_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - kfree(priv->bulk_in_buffer); kfree(priv); } -static int opticon_suspend(struct usb_interface *intf, pm_message_t message) +static int opticon_suspend(struct usb_serial *serial, pm_message_t message) { - struct usb_serial *serial = usb_get_intfdata(intf); struct opticon_private *priv = usb_get_serial_data(serial); usb_kill_urb(priv->bulk_read_urb); return 0; } -static int opticon_resume(struct usb_interface *intf) +static int opticon_resume(struct usb_serial *serial) { - struct usb_serial *serial = usb_get_intfdata(intf); struct opticon_private *priv = usb_get_serial_data(serial); struct usb_serial_port *port = serial->port[0]; int result; @@ -597,15 +581,6 @@ static int opticon_resume(struct usb_interface *intf) return result; } -static struct usb_driver opticon_driver = { - .name = "opticon", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = opticon_suspend, - .resume = opticon_resume, - .id_table = id_table, -}; - static struct usb_serial_driver opticon_device = { .driver = { .owner = THIS_MODULE, @@ -625,13 +600,15 @@ static struct usb_serial_driver opticon_device = { .ioctl = opticon_ioctl, .tiocmget = opticon_tiocmget, .tiocmset = opticon_tiocmset, + .suspend = opticon_suspend, + .resume = opticon_resume, }; static struct usb_serial_driver * const serial_drivers[] = { &opticon_device, NULL }; -module_usb_serial_driver(opticon_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index f4465ccddc35..1aae9028cd0b 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -1220,18 +1220,6 @@ static const struct usb_device_id option_ids[] = { }; MODULE_DEVICE_TABLE(usb, option_ids); -static struct usb_driver option_driver = { - .name = "option", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, -#ifdef CONFIG_PM - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -#endif - .id_table = option_ids, -}; - /* The card has three separate interfaces, which the serial driver * recognizes separately, thus num_port=1. */ @@ -1300,7 +1288,7 @@ struct option_port_private { unsigned long tx_start_time[N_OUT_URB]; }; -module_usb_serial_driver(option_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, option_ids); static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason, const struct option_blacklist_info *blacklist) @@ -1375,7 +1363,6 @@ static void option_instat_callback(struct urb *urb) struct usb_serial_port *port = urb->context; struct option_port_private *portdata = usb_get_serial_port_data(port); - dbg("%s", __func__); dbg("%s: urb %p port %p has data %p", __func__, urb, port, portdata); if (status == 0) { @@ -1413,7 +1400,7 @@ static void option_instat_callback(struct urb *urb) req_pkt->bRequestType, req_pkt->bRequest); } } else - err("%s: error %d", __func__, status); + dev_err(&port->dev, "%s: error %d\n", __func__, status); /* Resubmit urb so we continue receiving IRQ data */ if (status != -ESHUTDOWN && status != -ENOENT) { @@ -1437,7 +1424,6 @@ static int option_send_setup(struct usb_serial_port *port) struct option_port_private *portdata; int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber; int val = 0; - dbg("%s", __func__); if (is_blacklisted(ifNum, OPTION_BLACKLIST_SENDSETUP, (struct option_blacklist_info *) intfdata->private)) { diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index 5fdc33c6a3c0..5976b65ab6ee 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -66,13 +66,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver oti6858_driver = { - .name = "oti6858", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static bool debug; /* requests */ @@ -211,8 +204,6 @@ static void setup_line(struct work_struct *work) unsigned long flags; int result; - dbg("%s(port = %d)", __func__, port->number); - new_setup = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL); if (new_setup == NULL) { dev_err(&port->dev, "%s(): out of memory!\n", __func__); @@ -282,8 +273,6 @@ static void send_data(struct work_struct *work) unsigned long flags; u8 *allow; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); if (priv->flags.write_urb_in_use) { spin_unlock_irqrestore(&priv->lock, flags); @@ -379,8 +368,6 @@ static int oti6858_startup(struct usb_serial *serial) static int oti6858_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *buf, int count) { - dbg("%s(port = %d, count = %d)", __func__, port->number, count); - if (!count) return count; @@ -395,8 +382,6 @@ static int oti6858_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&port->lock, flags); room = kfifo_avail(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); @@ -410,8 +395,6 @@ static int oti6858_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&port->lock, flags); chars = kfifo_len(&port->write_fifo); spin_unlock_irqrestore(&port->lock, flags); @@ -437,8 +420,6 @@ static void oti6858_set_termios(struct tty_struct *tty, __le16 divisor; int br; - dbg("%s(port = %d)", __func__, port->number); - if (!tty) { dbg("%s(): no tty structures", __func__); return; @@ -545,8 +526,6 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result; - dbg("%s(port = %d)", __func__, port->number); - usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -602,8 +581,6 @@ static void oti6858_close(struct usb_serial_port *port) struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; - dbg("%s(port = %d)", __func__, port->number); - spin_lock_irqsave(&port->lock, flags); /* clear out any remaining data in the buffer */ kfifo_reset_out(&port->write_fifo); @@ -633,9 +610,6 @@ static int oti6858_tiocmset(struct tty_struct *tty, dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)", __func__, port->number, set, clear); - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - /* FIXME: check if this is correct (active high/low) */ spin_lock_irqsave(&priv->lock, flags); control = priv->pending_setup.control; @@ -663,11 +637,6 @@ static int oti6858_tiocmget(struct tty_struct *tty) unsigned pin_state; unsigned result = 0; - dbg("%s(port = %d)", __func__, port->number); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); pin_state = priv->status.pin_state & PIN_MASK; spin_unlock_irqrestore(&priv->lock, flags); @@ -750,8 +719,6 @@ static void oti6858_release(struct usb_serial *serial) { int i; - dbg("%s()", __func__); - for (i = 0; i < serial->num_ports; ++i) kfree(usb_get_serial_port_data(serial->port[i])); } @@ -763,9 +730,6 @@ static void oti6858_read_int_callback(struct urb *urb) int transient = 0, can_recv = 0, resubmit = 1; int status = urb->status; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - switch (status) { case 0: /* success */ @@ -882,9 +846,6 @@ static void oti6858_read_bulk_callback(struct urb *urb) int status = urb->status; int result; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - spin_lock_irqsave(&priv->lock, flags); priv->flags.read_urb_in_use = 0; spin_unlock_irqrestore(&priv->lock, flags); @@ -916,9 +877,6 @@ static void oti6858_write_bulk_callback(struct urb *urb) int status = urb->status; int result; - dbg("%s(port = %d, status = %d)", - __func__, port->number, status); - switch (status) { case 0: /* success */ @@ -958,7 +916,7 @@ static void oti6858_write_bulk_callback(struct urb *urb) } } -module_usb_serial_driver(oti6858_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(OTI6858_DESCRIPTION); MODULE_AUTHOR(OTI6858_AUTHOR); diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index a1a9062954c4..13b8dd6481f5 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -38,8 +38,6 @@ static bool debug; -#define PL2303_CLOSING_WAIT (30*HZ) - static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) }, @@ -97,16 +95,6 @@ static const struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver pl2303_driver = { - .name = "pl2303", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -}; - #define SET_LINE_REQUEST_TYPE 0x21 #define SET_LINE_REQUEST 0x20 @@ -161,8 +149,9 @@ static int pl2303_vendor_read(__u16 value, __u16 index, int res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, value, index, buf, 1, 100); - dbg("0x%x:0x%x:0x%x:0x%x %d - %x", VENDOR_READ_REQUEST_TYPE, - VENDOR_READ_REQUEST, value, index, res, buf[0]); + dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d - %x\n", + VENDOR_READ_REQUEST_TYPE, VENDOR_READ_REQUEST, value, index, + res, buf[0]); return res; } @@ -172,8 +161,9 @@ static int pl2303_vendor_write(__u16 value, __u16 index, int res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, 100); - dbg("0x%x:0x%x:0x%x:0x%x %d", VENDOR_WRITE_REQUEST_TYPE, - VENDOR_WRITE_REQUEST, value, index, res); + dev_dbg(&serial->dev->dev, "0x%x:0x%x:0x%x:0x%x %d\n", + VENDOR_WRITE_REQUEST_TYPE, VENDOR_WRITE_REQUEST, value, index, + res); return res; } @@ -196,7 +186,7 @@ static int pl2303_startup(struct usb_serial *serial) type = type_1; else if (serial->dev->descriptor.bDeviceClass == 0xFF) type = type_1; - dbg("device type: %d", type); + dev_dbg(&serial->interface->dev, "device type: %d\n", type); for (i = 0; i < serial->num_ports; ++i) { priv = kzalloc(sizeof(struct pl2303_private), GFP_KERNEL); @@ -243,7 +233,8 @@ static int set_control_lines(struct usb_device *dev, u8 value) retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), SET_CONTROL_REQUEST, SET_CONTROL_REQUEST_TYPE, value, 0, NULL, 0, 100); - dbg("%s - value = %d, retval = %d", __func__, value, retval); + dev_dbg(&dev->dev, "%s - value = %d, retval = %d\n", __func__, + value, retval); return retval; } @@ -265,8 +256,6 @@ static void pl2303_set_termios(struct tty_struct *tty, int baud_floor, baud_ceil; int k; - dbg("%s - port %d", __func__, port->number); - /* The PL2303 is reported to lose bytes if you change serial settings even to the same values as before. Thus we actually need to filter in this specific case */ @@ -287,7 +276,7 @@ static void pl2303_set_termios(struct tty_struct *tty, i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); - dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, + dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CSIZE) { @@ -306,7 +295,7 @@ static void pl2303_set_termios(struct tty_struct *tty, buf[6] = 8; break; } - dbg("%s - data bits = %d", __func__, buf[6]); + dev_dbg(&port->dev, "data bits = %d\n", buf[6]); } /* For reference buf[0]:buf[3] baud rate value */ @@ -315,7 +304,7 @@ static void pl2303_set_termios(struct tty_struct *tty, * 9600 baud (at least my PL2303X always does) */ baud = tty_get_baud_rate(tty); - dbg("%s - baud requested = %d", __func__, baud); + dev_dbg(&port->dev, "baud requested = %d\n", baud); if (baud) { /* Set baudrate to nearest supported value */ for (k=0; k<ARRAY_SIZE(baud_sup); k++) { @@ -341,7 +330,7 @@ static void pl2303_set_termios(struct tty_struct *tty, else if (baud > 6000000) baud = 6000000; } - dbg("%s - baud set = %d", __func__, baud); + dev_dbg(&port->dev, "baud set = %d\n", baud); if (baud <= 115200) { buf[0] = baud & 0xff; buf[1] = (baud >> 8) & 0xff; @@ -372,14 +361,14 @@ static void pl2303_set_termios(struct tty_struct *tty, */ if ((cflag & CSIZE) == CS5) { buf[4] = 1; - dbg("%s - stop bits = 1.5", __func__); + dev_dbg(&port->dev, "stop bits = 1.5\n"); } else { buf[4] = 2; - dbg("%s - stop bits = 2", __func__); + dev_dbg(&port->dev, "stop bits = 2\n"); } } else { buf[4] = 0; - dbg("%s - stop bits = 1", __func__); + dev_dbg(&port->dev, "stop bits = 1\n"); } if (cflag & PARENB) { @@ -391,29 +380,29 @@ static void pl2303_set_termios(struct tty_struct *tty, if (cflag & PARODD) { if (cflag & CMSPAR) { buf[5] = 3; - dbg("%s - parity = mark", __func__); + dev_dbg(&port->dev, "parity = mark\n"); } else { buf[5] = 1; - dbg("%s - parity = odd", __func__); + dev_dbg(&port->dev, "parity = odd\n"); } } else { if (cflag & CMSPAR) { buf[5] = 4; - dbg("%s - parity = space", __func__); + dev_dbg(&port->dev, "parity = space\n"); } else { buf[5] = 2; - dbg("%s - parity = even", __func__); + dev_dbg(&port->dev, "parity = even\n"); } } } else { buf[5] = 0; - dbg("%s - parity = none", __func__); + dev_dbg(&port->dev, "parity = none\n"); } i = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), SET_LINE_REQUEST, SET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); - dbg("0x21:0x20:0:0 %d", i); + dev_dbg(&port->dev, "0x21:0x20:0:0 %d\n", i); /* change control lines if we are switching to or from B0 */ spin_lock_irqsave(&priv->lock, flags); @@ -435,7 +424,7 @@ static void pl2303_set_termios(struct tty_struct *tty, i = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), GET_LINE_REQUEST, GET_LINE_REQUEST_TYPE, 0, 0, buf, 7, 100); - dbg("0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x", i, + dev_dbg(&port->dev, "0xa1:0x21:0:0 %d - %x %x %x %x %x %x %x\n", i, buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); if (cflag & CRTSCTS) { @@ -473,8 +462,6 @@ static void pl2303_dtr_rts(struct usb_serial_port *port, int on) static void pl2303_close(struct usb_serial_port *port) { - dbg("%s - port %d", __func__, port->number); - usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); } @@ -486,8 +473,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) struct pl2303_private *priv = usb_get_serial_port_data(port); int result; - dbg("%s - port %d", __func__, port->number); - if (priv->type != HX) { usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -501,7 +486,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) if (tty) pl2303_set_termios(tty, port, &tmp_termios); - dbg("%s - submitting interrupt urb", __func__); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) { dev_err(&port->dev, "%s - failed submitting interrupt urb," @@ -523,12 +507,11 @@ static int pl2303_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; + struct usb_serial *serial = port->serial; struct pl2303_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 control; - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; + int ret; spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) @@ -542,7 +525,14 @@ static int pl2303_tiocmset(struct tty_struct *tty, control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); - return set_control_lines(port->serial->dev, control); + mutex_lock(&serial->disc_mutex); + if (!serial->disconnected) + ret = set_control_lines(serial->dev, control); + else + ret = -ENODEV; + mutex_unlock(&serial->disc_mutex); + + return ret; } static int pl2303_tiocmget(struct tty_struct *tty) @@ -554,11 +544,6 @@ static int pl2303_tiocmget(struct tty_struct *tty) unsigned int status; unsigned int result; - dbg("%s (%d)", __func__, port->number); - - if (!usb_get_intfdata(port->serial->interface)) - return -ENODEV; - spin_lock_irqsave(&priv->lock, flags); mcr = priv->line_control; status = priv->line_status; @@ -571,7 +556,7 @@ static int pl2303_tiocmget(struct tty_struct *tty) | ((status & UART_RING) ? TIOCM_RI : 0) | ((status & UART_DCD) ? TIOCM_CD : 0); - dbg("%s - result = %x", __func__, result); + dev_dbg(&port->dev, "%s - result = %x\n", __func__, result); return result; } @@ -625,7 +610,8 @@ static int pl2303_ioctl(struct tty_struct *tty, { struct serial_struct ser; struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); + + dev_dbg(&port->dev, "%s cmd = 0x%04x\n", __func__, cmd); switch (cmd) { case TIOCGSERIAL: @@ -641,10 +627,10 @@ static int pl2303_ioctl(struct tty_struct *tty, return 0; case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s TIOCMIWAIT\n", __func__); return wait_modem_info(port, arg); default: - dbg("%s not supported = 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s not supported = 0x%04x\n", __func__, cmd); break; } return -ENOIOCTLCMD; @@ -657,20 +643,18 @@ static void pl2303_break_ctl(struct tty_struct *tty, int break_state) u16 state; int result; - dbg("%s - port %d", __func__, port->number); - if (break_state == 0) state = BREAK_OFF; else state = BREAK_ON; - dbg("%s - turning break %s", __func__, + dev_dbg(&port->dev, "%s - turning break %s\n", __func__, state == BREAK_OFF ? "off" : "on"); result = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 0, NULL, 0, 100); if (result) - dbg("%s - error sending break = %d", __func__, result); + dev_err(&port->dev, "error sending break = %d\n", result); } static void pl2303_release(struct usb_serial *serial) @@ -678,8 +662,6 @@ static void pl2303_release(struct usb_serial *serial) int i; struct pl2303_private *priv; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { priv = usb_get_serial_port_data(serial->port[i]); kfree(priv); @@ -742,8 +724,6 @@ static void pl2303_read_int_callback(struct urb *urb) int status = urb->status; int retval; - dbg("%s (%d)", __func__, port->number); - switch (status) { case 0: /* success */ @@ -752,12 +732,12 @@ static void pl2303_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", __func__, - status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", __func__, - status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -769,7 +749,7 @@ static void pl2303_read_int_callback(struct urb *urb) exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval) - dev_err(&urb->dev->dev, + dev_err(&port->dev, "%s - usb_submit_urb failed with result %d\n", __func__, retval); } @@ -807,7 +787,7 @@ static void pl2303_process_read_urb(struct urb *urb) tty_flag = TTY_PARITY; else if (line_status & UART_FRAME_ERROR) tty_flag = TTY_FRAME; - dbg("%s - tty_flag = %d", __func__, tty_flag); + dev_dbg(&port->dev, "%s - tty_flag = %d\n", __func__, tty_flag); /* overrun is special, not associated with a char */ if (line_status & UART_OVERRUN_ERROR) @@ -855,7 +835,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &pl2303_device, NULL }; -module_usb_serial_driver(pl2303_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c index 966245680f55..a4edc7ee9c8a 100644 --- a/drivers/usb/serial/qcaux.c +++ b/drivers/usb/serial/qcaux.c @@ -77,13 +77,6 @@ static struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver qcaux_driver = { - .name = "qcaux", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver qcaux_device = { .driver = { .owner = THIS_MODULE, @@ -97,5 +90,5 @@ static struct usb_serial_driver * const serial_drivers[] = { &qcaux_device, NULL }; -module_usb_serial_driver(qcaux_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c index 0206b10c9e6e..0d5fe59ebb9e 100644 --- a/drivers/usb/serial/qcserial.c +++ b/drivers/usb/serial/qcserial.c @@ -112,32 +112,22 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver qcdriver = { - .name = "qcserial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = true, -}; - static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) { struct usb_wwan_intf_private *data; struct usb_host_interface *intf = serial->interface->cur_altsetting; + struct device *dev = &serial->dev->dev; int retval = -ENODEV; __u8 nintf; __u8 ifnum; bool is_gobi1k = id->driver_info ? true : false; - dbg("%s", __func__); - dbg("Is Gobi 1000 = %d", is_gobi1k); + dev_dbg(dev, "Is Gobi 1000 = %d\n", is_gobi1k); nintf = serial->dev->actconfig->desc.bNumInterfaces; - dbg("Num Interfaces = %d", nintf); + dev_dbg(dev, "Num Interfaces = %d\n", nintf); ifnum = intf->desc.bInterfaceNumber; - dbg("This Interface = %d", ifnum); + dev_dbg(dev, "This Interface = %d\n", ifnum); data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL); @@ -158,7 +148,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) if (intf->desc.bNumEndpoints == 2 && usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { - dbg("QDL port found"); + dev_dbg(dev, "QDL port found\n"); if (serial->interface->num_altsetting == 1) { retval = 0; /* Success */ @@ -167,7 +157,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) retval = usb_set_interface(serial->dev, ifnum, 1); if (retval < 0) { - dev_err(&serial->dev->dev, + dev_err(dev, "Could not set interface, error %d\n", retval); retval = -ENODEV; @@ -196,20 +186,20 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) */ if (ifnum == 1 && !is_gobi1k) { - dbg("Gobi 2K+ DM/DIAG interface found"); + dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n"); retval = usb_set_interface(serial->dev, ifnum, 0); if (retval < 0) { - dev_err(&serial->dev->dev, + dev_err(dev, "Could not set interface, error %d\n", retval); retval = -ENODEV; kfree(data); } } else if (ifnum == 2) { - dbg("Modem port found"); + dev_dbg(dev, "Modem port found\n"); retval = usb_set_interface(serial->dev, ifnum, 0); if (retval < 0) { - dev_err(&serial->dev->dev, + dev_err(dev, "Could not set interface, error %d\n", retval); retval = -ENODEV; @@ -221,10 +211,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) * # echo "\$GPS_START" > /dev/ttyUSBx * # echo "\$GPS_STOP" > /dev/ttyUSBx */ - dbg("Gobi 2K+ NMEA GPS interface found"); + dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n"); retval = usb_set_interface(serial->dev, ifnum, 0); if (retval < 0) { - dev_err(&serial->dev->dev, + dev_err(dev, "Could not set interface, error %d\n", retval); retval = -ENODEV; @@ -234,8 +224,7 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) break; default: - dev_err(&serial->dev->dev, - "unknown number of interfaces: %d\n", nintf); + dev_err(dev, "unknown number of interfaces: %d\n", nintf); kfree(data); retval = -ENODEV; } @@ -250,8 +239,6 @@ static void qc_release(struct usb_serial *serial) { struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - /* Call usb_wwan release & free the private data allocated in qcprobe */ usb_wwan_release(serial); usb_set_serial_data(serial, NULL); @@ -285,7 +272,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &qcdevice, NULL }; -module_usb_serial_driver(qcdriver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c new file mode 100644 index 000000000000..8dd88ebe9863 --- /dev/null +++ b/drivers/usb/serial/quatech2.c @@ -0,0 +1,1155 @@ +/* + * usb-serial driver for Quatech USB 2 devices + * + * Copyright (C) 2012 Bill Pemberton (wfp5p@virginia.edu) + * + * 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. + * + * + * These devices all have only 1 bulk in and 1 bulk out that is shared + * for all serial ports. + * + */ + +#include <asm/unaligned.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/module.h> +#include <linux/serial.h> +#include <linux/usb.h> +#include <linux/usb/serial.h> +#include <linux/serial_reg.h> +#include <linux/uaccess.h> + +static bool debug; + +/* default urb timeout for usb operations */ +#define QT2_USB_TIMEOUT USB_CTRL_SET_TIMEOUT + +#define QT_OPEN_CLOSE_CHANNEL 0xca +#define QT_SET_GET_DEVICE 0xc2 +#define QT_SET_GET_REGISTER 0xc0 +#define QT_GET_SET_PREBUF_TRIG_LVL 0xcc +#define QT_SET_ATF 0xcd +#define QT_TRANSFER_IN 0xc0 +#define QT_HW_FLOW_CONTROL_MASK 0xc5 +#define QT_SW_FLOW_CONTROL_MASK 0xc6 +#define QT2_BREAK_CONTROL 0xc8 +#define QT2_GET_SET_UART 0xc1 +#define QT2_FLUSH_DEVICE 0xc4 +#define QT2_GET_SET_QMCR 0xe1 +#define QT2_QMCR_RS232 0x40 +#define QT2_QMCR_RS422 0x10 + +#define SERIAL_CRTSCTS ((UART_MCR_RTS << 8) | UART_MSR_CTS) + +#define SERIAL_EVEN_PARITY (UART_LCR_PARITY | UART_LCR_EPAR) + +/* status bytes for the device */ +#define QT2_CONTROL_BYTE 0x1b +#define QT2_LINE_STATUS 0x00 /* following 1 byte is line status */ +#define QT2_MODEM_STATUS 0x01 /* following 1 byte is modem status */ +#define QT2_XMIT_HOLD 0x02 /* following 2 bytes are ?? */ +#define QT2_CHANGE_PORT 0x03 /* following 1 byte is port to change to */ +#define QT2_REC_FLUSH 0x04 /* no following info */ +#define QT2_XMIT_FLUSH 0x05 /* no following info */ +#define QT2_CONTROL_ESCAPE 0xff /* pass through previous 2 control bytes */ + +#define MAX_BAUD_RATE 921600 +#define DEFAULT_BAUD_RATE 9600 + +#define QT2_WRITE_BUFFER_SIZE 512 /* size of write buffer */ +#define QT2_WRITE_CONTROL_SIZE 5 /* control bytes used for a write */ + +/* Version Information */ +#define DRIVER_VERSION "v0.1" +#define DRIVER_DESC "Quatech 2nd gen USB to Serial Driver" + +#define USB_VENDOR_ID_QUATECH 0x061d +#define QUATECH_SSU2_100 0xC120 /* RS232 single port */ +#define QUATECH_DSU2_100 0xC140 /* RS232 dual port */ +#define QUATECH_DSU2_400 0xC150 /* RS232/422/485 dual port */ +#define QUATECH_QSU2_100 0xC160 /* RS232 four port */ +#define QUATECH_QSU2_400 0xC170 /* RS232/422/485 four port */ +#define QUATECH_ESU2_100 0xC1A0 /* RS232 eight port */ +#define QUATECH_ESU2_400 0xC180 /* RS232/422/485 eight port */ + +struct qt2_device_detail { + int product_id; + int num_ports; +}; + +#define QT_DETAILS(prod, ports) \ + .product_id = (prod), \ + .num_ports = (ports) + +static const struct qt2_device_detail qt2_device_details[] = { + {QT_DETAILS(QUATECH_SSU2_100, 1)}, + {QT_DETAILS(QUATECH_DSU2_400, 2)}, + {QT_DETAILS(QUATECH_DSU2_100, 2)}, + {QT_DETAILS(QUATECH_QSU2_400, 4)}, + {QT_DETAILS(QUATECH_QSU2_100, 4)}, + {QT_DETAILS(QUATECH_ESU2_400, 8)}, + {QT_DETAILS(QUATECH_ESU2_100, 8)}, + {QT_DETAILS(0, 0)} /* Terminating entry */ +}; + +static const struct usb_device_id id_table[] = { + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_DSU2_400)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_QSU2_400)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_100)}, + {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_ESU2_400)}, + {} /* Terminating entry */ +}; +MODULE_DEVICE_TABLE(usb, id_table); + +struct qt2_serial_private { + unsigned char current_port; /* current port for incoming data */ + + struct urb *read_urb; /* shared among all ports */ + char read_buffer[512]; +}; + +struct qt2_port_private { + bool is_open; + u8 device_port; + + spinlock_t urb_lock; + bool urb_in_use; + struct urb *write_urb; + char write_buffer[QT2_WRITE_BUFFER_SIZE]; + + spinlock_t lock; + u8 shadowLSR; + u8 shadowMSR; + + wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */ + struct async_icount icount; + + struct usb_serial_port *port; +}; + +static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch); +static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch); +static void qt2_write_bulk_callback(struct urb *urb); +static void qt2_read_bulk_callback(struct urb *urb); + +static void qt2_release(struct usb_serial *serial) +{ + int i; + + kfree(usb_get_serial_data(serial)); + + for (i = 0; i < serial->num_ports; i++) + kfree(usb_get_serial_port_data(serial->port[i])); +} + +static inline int calc_baud_divisor(int baudrate) +{ + int divisor, rem; + + divisor = MAX_BAUD_RATE / baudrate; + rem = MAX_BAUD_RATE % baudrate; + /* Round to nearest divisor */ + if (((rem * 2) >= baudrate) && (baudrate != 110)) + divisor++; + + return divisor; +} + +static inline int qt2_set_port_config(struct usb_device *dev, + unsigned char port_number, + u16 baudrate, u16 lcr) +{ + int divisor = calc_baud_divisor(baudrate); + u16 index = ((u16) (lcr << 8) | (u16) (port_number)); + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + QT2_GET_SET_UART, 0x40, + divisor, index, NULL, 0, QT2_USB_TIMEOUT); +} + +static inline int qt2_control_msg(struct usb_device *dev, + u8 request, u16 data, u16 index) +{ + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + request, 0x40, data, index, + NULL, 0, QT2_USB_TIMEOUT); +} + +static inline int qt2_setdevice(struct usb_device *dev, u8 *data) +{ + u16 x = ((u16) (data[1] << 8) | (u16) (data[0])); + + return qt2_control_msg(dev, QT_SET_GET_DEVICE, x, 0); +} + + +static inline int qt2_getdevice(struct usb_device *dev, u8 *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_DEVICE, 0xc0, 0, 0, + data, 3, QT2_USB_TIMEOUT); +} + +static inline int qt2_getregister(struct usb_device *dev, + u8 uart, + u8 reg, + u8 *data) +{ + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0xc0, reg, + uart, data, sizeof(*data), QT2_USB_TIMEOUT); + +} + +static inline int qt2_setregister(struct usb_device *dev, + u8 uart, u8 reg, u16 data) +{ + u16 value = (data << 8) | reg; + + return usb_control_msg(dev, usb_sndctrlpipe(dev, 0), + QT_SET_GET_REGISTER, 0x40, value, uart, + NULL, 0, QT2_USB_TIMEOUT); +} + +static inline int update_mctrl(struct qt2_port_private *port_priv, + unsigned int set, unsigned int clear) +{ + struct usb_serial_port *port = port_priv->port; + struct usb_device *dev = port->serial->dev; + unsigned urb_value; + int status; + + if (((set | clear) & (TIOCM_DTR | TIOCM_RTS)) == 0) { + dev_dbg(&port->dev, + "update_mctrl - DTR|RTS not being set|cleared\n"); + return 0; /* no change */ + } + + clear &= ~set; /* 'set' takes precedence over 'clear' */ + urb_value = 0; + if (set & TIOCM_DTR) + urb_value |= UART_MCR_DTR; + if (set & TIOCM_RTS) + urb_value |= UART_MCR_RTS; + + status = qt2_setregister(dev, port_priv->device_port, UART_MCR, + urb_value); + if (status < 0) + dev_err(&port->dev, + "update_mctrl - Error from MODEM_CTRL urb: %i\n", + status); + return status; +} + +static int qt2_calc_num_ports(struct usb_serial *serial) +{ + struct qt2_device_detail d; + int i; + + for (i = 0; d = qt2_device_details[i], d.product_id != 0; i++) { + if (d.product_id == le16_to_cpu(serial->dev->descriptor.idProduct)) + return d.num_ports; + } + + /* we didn't recognize the device */ + dev_err(&serial->dev->dev, + "don't know the number of ports, assuming 1\n"); + + return 1; +} + +static void qt2_set_termios(struct tty_struct *tty, + struct usb_serial_port *port, + struct ktermios *old_termios) +{ + struct usb_device *dev = port->serial->dev; + struct qt2_port_private *port_priv; + struct ktermios *termios = tty->termios; + u16 baud; + unsigned int cflag = termios->c_cflag; + u16 new_lcr = 0; + int status; + + port_priv = usb_get_serial_port_data(port); + + if (cflag & PARENB) { + if (cflag & PARODD) + new_lcr |= UART_LCR_PARITY; + else + new_lcr |= SERIAL_EVEN_PARITY; + } + + switch (cflag & CSIZE) { + case CS5: + new_lcr |= UART_LCR_WLEN5; + break; + case CS6: + new_lcr |= UART_LCR_WLEN6; + break; + case CS7: + new_lcr |= UART_LCR_WLEN7; + break; + default: + case CS8: + new_lcr |= UART_LCR_WLEN8; + break; + } + + baud = tty_get_baud_rate(tty); + if (!baud) + baud = 9600; + + status = qt2_set_port_config(dev, port_priv->device_port, baud, + new_lcr); + if (status < 0) + dev_err(&port->dev, "%s - qt2_set_port_config failed: %i\n", + __func__, status); + + if (cflag & CRTSCTS) + status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, + SERIAL_CRTSCTS, + port_priv->device_port); + else + status = qt2_control_msg(dev, QT_HW_FLOW_CONTROL_MASK, + 0, port_priv->device_port); + if (status < 0) + dev_err(&port->dev, "%s - set HW flow control failed: %i\n", + __func__, status); + + if (I_IXOFF(tty) || I_IXON(tty)) { + u16 x = ((u16) (START_CHAR(tty) << 8) | (u16) (STOP_CHAR(tty))); + + status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, + x, port_priv->device_port); + } else + status = qt2_control_msg(dev, QT_SW_FLOW_CONTROL_MASK, + 0, port_priv->device_port); + + if (status < 0) + dev_err(&port->dev, "%s - set SW flow control failed: %i\n", + __func__, status); + +} + +static int qt2_open(struct tty_struct *tty, struct usb_serial_port *port) +{ + struct usb_serial *serial; + struct qt2_serial_private *serial_priv; + struct qt2_port_private *port_priv; + u8 *data; + u16 device_port; + int status; + unsigned long flags; + + device_port = (u16) (port->number - port->serial->minor); + + serial = port->serial; + + port_priv = usb_get_serial_port_data(port); + serial_priv = usb_get_serial_data(serial); + + /* set the port to RS232 mode */ + status = qt2_control_msg(serial->dev, QT2_GET_SET_QMCR, + QT2_QMCR_RS232, device_port); + if (status < 0) { + dev_err(&port->dev, + "%s failed to set RS232 mode for port %i error %i\n", + __func__, device_port, status); + return status; + } + + data = kzalloc(2, GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* open the port */ + status = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + QT_OPEN_CLOSE_CHANNEL, + 0xc0, 0, + device_port, data, 2, QT2_USB_TIMEOUT); + + if (status < 0) { + dev_err(&port->dev, "%s - open port failed %i", __func__, + status); + kfree(data); + return status; + } + + spin_lock_irqsave(&port_priv->lock, flags); + port_priv->shadowLSR = data[0]; + port_priv->shadowMSR = data[1]; + spin_unlock_irqrestore(&port_priv->lock, flags); + + kfree(data); + + /* set to default speed and 8bit word size */ + status = qt2_set_port_config(serial->dev, device_port, + DEFAULT_BAUD_RATE, UART_LCR_WLEN8); + if (status < 0) { + dev_err(&port->dev, + "%s - initial setup failed for port %i (%i)\n", + __func__, port->number, device_port); + return status; + } + + port_priv->is_open = true; + port_priv->device_port = (u8) device_port; + + if (tty) + qt2_set_termios(tty, port, tty->termios); + + return 0; + +} + +static void qt2_close(struct usb_serial_port *port) +{ + struct usb_serial *serial; + struct qt2_serial_private *serial_priv; + struct qt2_port_private *port_priv; + unsigned long flags; + int i; + + serial = port->serial; + serial_priv = usb_get_serial_data(serial); + port_priv = usb_get_serial_port_data(port); + + port_priv->is_open = false; + + spin_lock_irqsave(&port_priv->urb_lock, flags); + if (port_priv->write_urb->status == -EINPROGRESS) + usb_kill_urb(port_priv->write_urb); + port_priv->urb_in_use = false; + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + + /* flush the port transmit buffer */ + i = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + QT2_FLUSH_DEVICE, 0x40, 1, + port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); + + if (i < 0) + dev_err(&port->dev, "%s - transmit buffer flush failed: %i\n", + __func__, i); + + /* flush the port receive buffer */ + i = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + QT2_FLUSH_DEVICE, 0x40, 0, + port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); + + if (i < 0) + dev_err(&port->dev, "%s - receive buffer flush failed: %i\n", + __func__, i); + + /* close the port */ + i = usb_control_msg(serial->dev, + usb_sndctrlpipe(serial->dev, 0), + QT_OPEN_CLOSE_CHANNEL, + 0x40, 0, + port_priv->device_port, NULL, 0, QT2_USB_TIMEOUT); + + if (i < 0) + dev_err(&port->dev, "%s - close port failed %i\n", + __func__, i); + +} + +static void qt2_disconnect(struct usb_serial *serial) +{ + struct qt2_serial_private *serial_priv = usb_get_serial_data(serial); + struct qt2_port_private *port_priv; + int i; + + if (serial_priv->read_urb->status == -EINPROGRESS) + usb_kill_urb(serial_priv->read_urb); + + usb_free_urb(serial_priv->read_urb); + + for (i = 0; i < serial->num_ports; i++) { + port_priv = usb_get_serial_port_data(serial->port[i]); + + if (port_priv->write_urb->status == -EINPROGRESS) + usb_kill_urb(port_priv->write_urb); + usb_free_urb(port_priv->write_urb); + } +} + +static int get_serial_info(struct usb_serial_port *port, + struct serial_struct __user *retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + + memset(&tmp, 0, sizeof(tmp)); + tmp.line = port->serial->minor; + tmp.port = 0; + tmp.irq = 0; + tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; + tmp.xmit_fifo_size = port->bulk_out_size; + tmp.baud_base = 9600; + tmp.close_delay = 5*HZ; + tmp.closing_wait = 30*HZ; + + if (copy_to_user(retinfo, &tmp, sizeof(*retinfo))) + return -EFAULT; + return 0; +} + +static int wait_modem_info(struct usb_serial_port *port, unsigned int arg) +{ + struct qt2_port_private *priv = usb_get_serial_port_data(port); + struct async_icount prev, cur; + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + prev = priv->icount; + spin_unlock_irqrestore(&priv->lock, flags); + + while (1) { + wait_event_interruptible(priv->delta_msr_wait, + ((priv->icount.rng != prev.rng) || + (priv->icount.dsr != prev.dsr) || + (priv->icount.dcd != prev.dcd) || + (priv->icount.cts != prev.cts))); + + if (signal_pending(current)) + return -ERESTARTSYS; + + spin_lock_irqsave(&priv->lock, flags); + cur = priv->icount; + spin_unlock_irqrestore(&priv->lock, flags); + + if ((prev.rng == cur.rng) && + (prev.dsr == cur.dsr) && + (prev.dcd == cur.dcd) && + (prev.cts == cur.cts)) + return -EIO; + + if ((arg & TIOCM_RNG && (prev.rng != cur.rng)) || + (arg & TIOCM_DSR && (prev.dsr != cur.dsr)) || + (arg & TIOCM_CD && (prev.dcd != cur.dcd)) || + (arg & TIOCM_CTS && (prev.cts != cur.cts))) + return 0; + } + return 0; +} + +static int qt2_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + struct qt2_port_private *priv = usb_get_serial_port_data(port); + struct async_icount cnow = priv->icount; + + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + icount->rx = cnow.rx; + icount->tx = cnow.tx; + icount->frame = cnow.frame; + icount->overrun = cnow.overrun; + icount->parity = cnow.parity; + icount->brk = cnow.brk; + icount->buf_overrun = cnow.buf_overrun; + + return 0; +} + +static int qt2_ioctl(struct tty_struct *tty, + unsigned int cmd, unsigned long arg) +{ + struct usb_serial_port *port = tty->driver_data; + + switch (cmd) { + case TIOCGSERIAL: + return get_serial_info(port, + (struct serial_struct __user *)arg); + + case TIOCMIWAIT: + return wait_modem_info(port, arg); + + default: + break; + } + + return -ENOIOCTLCMD; +} + +static void qt2_process_status(struct usb_serial_port *port, unsigned char *ch) +{ + switch (*ch) { + case QT2_LINE_STATUS: + qt2_update_lsr(port, ch + 1); + break; + case QT2_MODEM_STATUS: + qt2_update_msr(port, ch + 1); + break; + } +} + +/* not needed, kept to document functionality */ +static void qt2_process_xmit_empty(struct usb_serial_port *port, + unsigned char *ch) +{ + int bytes_written; + + bytes_written = (int)(*ch) + (int)(*(ch + 1) << 4); +} + +/* not needed, kept to document functionality */ +static void qt2_process_flush(struct usb_serial_port *port, unsigned char *ch) +{ + return; +} + +void qt2_process_read_urb(struct urb *urb) +{ + struct usb_serial *serial; + struct qt2_serial_private *serial_priv; + struct usb_serial_port *port; + struct qt2_port_private *port_priv; + struct tty_struct *tty; + bool escapeflag; + unsigned char *ch; + int i; + unsigned char newport; + int len = urb->actual_length; + + if (!len) + return; + + ch = urb->transfer_buffer; + tty = NULL; + serial = urb->context; + serial_priv = usb_get_serial_data(serial); + port = serial->port[serial_priv->current_port]; + port_priv = usb_get_serial_port_data(port); + + if (port_priv->is_open) + tty = tty_port_tty_get(&port->port); + + for (i = 0; i < urb->actual_length; i++) { + ch = (unsigned char *)urb->transfer_buffer + i; + if ((i <= (len - 3)) && + (*ch == QT2_CONTROL_BYTE) && + (*(ch + 1) == QT2_CONTROL_BYTE)) { + escapeflag = false; + switch (*(ch + 2)) { + case QT2_LINE_STATUS: + case QT2_MODEM_STATUS: + if (i > (len - 4)) { + dev_warn(&port->dev, + "%s - status message too short\n", + __func__); + break; + } + qt2_process_status(port, ch + 2); + i += 3; + escapeflag = true; + break; + case QT2_XMIT_HOLD: + if (i > (len - 5)) { + dev_warn(&port->dev, + "%s - xmit_empty message too short\n", + __func__); + break; + } + qt2_process_xmit_empty(port, ch + 3); + i += 4; + escapeflag = true; + break; + case QT2_CHANGE_PORT: + if (i > (len - 4)) { + dev_warn(&port->dev, + "%s - change_port message too short\n", + __func__); + break; + } + if (tty) { + tty_flip_buffer_push(tty); + tty_kref_put(tty); + } + + newport = *(ch + 3); + + if (newport > serial->num_ports) { + dev_err(&port->dev, + "%s - port change to invalid port: %i\n", + __func__, newport); + break; + } + + serial_priv->current_port = newport; + port = serial->port[serial_priv->current_port]; + port_priv = usb_get_serial_port_data(port); + if (port_priv->is_open) + tty = tty_port_tty_get(&port->port); + else + tty = NULL; + i += 3; + escapeflag = true; + break; + case QT2_REC_FLUSH: + case QT2_XMIT_FLUSH: + qt2_process_flush(port, ch + 2); + i += 2; + escapeflag = true; + break; + case QT2_CONTROL_ESCAPE: + tty_buffer_request_room(tty, 2); + tty_insert_flip_string(tty, ch, 2); + i += 2; + escapeflag = true; + break; + default: + dev_warn(&port->dev, + "%s - unsupported command %i\n", + __func__, *(ch + 2)); + break; + } + if (escapeflag) + continue; + } + + if (tty) { + tty_buffer_request_room(tty, 1); + tty_insert_flip_string(tty, ch, 1); + } + } + + if (tty) { + tty_flip_buffer_push(tty); + tty_kref_put(tty); + } +} + +static void qt2_write_bulk_callback(struct urb *urb) +{ + struct usb_serial_port *port; + struct qt2_port_private *port_priv; + + port = urb->context; + port_priv = usb_get_serial_port_data(port); + + spin_lock(&port_priv->urb_lock); + + port_priv->urb_in_use = false; + usb_serial_port_softint(port); + + spin_unlock(&port_priv->urb_lock); + +} + +static void qt2_read_bulk_callback(struct urb *urb) +{ + struct usb_serial *serial = urb->context; + int status; + + if (urb->status) { + dev_warn(&serial->dev->dev, + "%s - non-zero urb status: %i\n", __func__, + urb->status); + return; + } + + qt2_process_read_urb(urb); + + status = usb_submit_urb(urb, GFP_ATOMIC); + if (status != 0) + dev_err(&serial->dev->dev, + "%s - resubmit read urb failed: %i\n", + __func__, status); +} + +static int qt2_setup_urbs(struct usb_serial *serial) +{ + struct usb_serial_port *port; + struct usb_serial_port *port0; + struct qt2_serial_private *serial_priv; + struct qt2_port_private *port_priv; + int pcount, status; + + port0 = serial->port[0]; + + serial_priv = usb_get_serial_data(serial); + serial_priv->read_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!serial_priv->read_urb) { + dev_err(&serial->dev->dev, "No free urbs available\n"); + return -ENOMEM; + } + + usb_fill_bulk_urb(serial_priv->read_urb, serial->dev, + usb_rcvbulkpipe(serial->dev, + port0->bulk_in_endpointAddress), + serial_priv->read_buffer, + sizeof(serial_priv->read_buffer), + qt2_read_bulk_callback, serial); + + /* setup write_urb for each port */ + for (pcount = 0; pcount < serial->num_ports; pcount++) { + + port = serial->port[pcount]; + port_priv = usb_get_serial_port_data(port); + + port_priv->write_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!port_priv->write_urb) { + dev_err(&serial->dev->dev, + "failed to alloc write_urb for port %i\n", + pcount); + return -ENOMEM; + } + + usb_fill_bulk_urb(port_priv->write_urb, + serial->dev, + usb_sndbulkpipe(serial->dev, + port0-> + bulk_out_endpointAddress), + port_priv->write_buffer, + sizeof(port_priv->write_buffer), + qt2_write_bulk_callback, port); + } + + status = usb_submit_urb(serial_priv->read_urb, GFP_KERNEL); + if (status != 0) { + dev_err(&serial->dev->dev, + "%s - submit read urb failed %i\n", __func__, status); + return status; + } + + return 0; + +} + +static int qt2_attach(struct usb_serial *serial) +{ + struct qt2_serial_private *serial_priv; + struct qt2_port_private *port_priv; + int status, pcount; + + /* power on unit */ + status = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), + 0xc2, 0x40, 0x8000, 0, NULL, 0, + QT2_USB_TIMEOUT); + if (status < 0) { + dev_err(&serial->dev->dev, + "%s - failed to power on unit: %i\n", __func__, status); + return status; + } + + serial_priv = kzalloc(sizeof(*serial_priv), GFP_KERNEL); + if (!serial_priv) { + dev_err(&serial->dev->dev, "%s - Out of memory\n", __func__); + return -ENOMEM; + } + + usb_set_serial_data(serial, serial_priv); + + for (pcount = 0; pcount < serial->num_ports; pcount++) { + port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL); + if (!port_priv) { + dev_err(&serial->dev->dev, + "%s- kmalloc(%Zd) failed.\n", __func__, + sizeof(*port_priv)); + pcount--; + status = -ENOMEM; + goto attach_failed; + } + + spin_lock_init(&port_priv->lock); + spin_lock_init(&port_priv->urb_lock); + init_waitqueue_head(&port_priv->delta_msr_wait); + + port_priv->port = serial->port[pcount]; + + usb_set_serial_port_data(serial->port[pcount], port_priv); + } + + status = qt2_setup_urbs(serial); + if (status != 0) + goto attach_failed; + + return 0; + +attach_failed: + for (/* empty */; pcount >= 0; pcount--) { + port_priv = usb_get_serial_port_data(serial->port[pcount]); + kfree(port_priv); + } + kfree(serial_priv); + return status; +} + +static int qt2_tiocmget(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct usb_device *dev = port->serial->dev; + struct qt2_port_private *port_priv = usb_get_serial_port_data(port); + u8 *d; + int r; + + d = kzalloc(2, GFP_KERNEL); + if (!d) + return -ENOMEM; + + r = qt2_getregister(dev, port_priv->device_port, UART_MCR, d); + if (r < 0) + goto mget_out; + + r = qt2_getregister(dev, port_priv->device_port, UART_MSR, d + 1); + if (r < 0) + goto mget_out; + + r = (d[0] & UART_MCR_DTR ? TIOCM_DTR : 0) | + (d[0] & UART_MCR_RTS ? TIOCM_RTS : 0) | + (d[1] & UART_MSR_CTS ? TIOCM_CTS : 0) | + (d[1] & UART_MSR_DCD ? TIOCM_CAR : 0) | + (d[1] & UART_MSR_RI ? TIOCM_RI : 0) | + (d[1] & UART_MSR_DSR ? TIOCM_DSR : 0); + +mget_out: + kfree(d); + return r; +} + +static int qt2_tiocmset(struct tty_struct *tty, + unsigned int set, unsigned int clear) +{ + struct qt2_port_private *port_priv; + + port_priv = usb_get_serial_port_data(tty->driver_data); + return update_mctrl(port_priv, set, clear); +} + +static void qt2_break_ctl(struct tty_struct *tty, int break_state) +{ + struct usb_serial_port *port = tty->driver_data; + struct qt2_port_private *port_priv; + int status; + u16 val; + + port_priv = usb_get_serial_port_data(port); + + if (!port_priv->is_open) { + dev_err(&port->dev, + "%s - port is not open\n", __func__); + return; + } + + val = (break_state == -1) ? 1 : 0; + + status = qt2_control_msg(port->serial->dev, QT2_BREAK_CONTROL, + val, port_priv->device_port); + if (status < 0) + dev_warn(&port->dev, + "%s - failed to send control message: %i\n", __func__, + status); +} + + + +static void qt2_dtr_rts(struct usb_serial_port *port, int on) +{ + struct usb_device *dev = port->serial->dev; + struct qt2_port_private *port_priv = usb_get_serial_port_data(port); + + mutex_lock(&port->serial->disc_mutex); + if (!port->serial->disconnected) { + /* Disable flow control */ + if (!on && qt2_setregister(dev, port_priv->device_port, + UART_MCR, 0) < 0) + dev_warn(&port->dev, "error from flowcontrol urb\n"); + /* drop RTS and DTR */ + if (on) + update_mctrl(port_priv, TIOCM_DTR | TIOCM_RTS, 0); + else + update_mctrl(port_priv, 0, TIOCM_DTR | TIOCM_RTS); + } + mutex_unlock(&port->serial->disc_mutex); +} + +static void qt2_update_msr(struct usb_serial_port *port, unsigned char *ch) +{ + struct qt2_port_private *port_priv; + u8 newMSR = (u8) *ch; + unsigned long flags; + + port_priv = usb_get_serial_port_data(port); + + spin_lock_irqsave(&port_priv->lock, flags); + port_priv->shadowMSR = newMSR; + spin_unlock_irqrestore(&port_priv->lock, flags); + + if (newMSR & UART_MSR_ANY_DELTA) { + /* update input line counters */ + if (newMSR & UART_MSR_DCTS) + port_priv->icount.cts++; + + if (newMSR & UART_MSR_DDSR) + port_priv->icount.dsr++; + + if (newMSR & UART_MSR_DDCD) + port_priv->icount.dcd++; + + if (newMSR & UART_MSR_TERI) + port_priv->icount.rng++; + + wake_up_interruptible(&port_priv->delta_msr_wait); + } +} + +static void qt2_update_lsr(struct usb_serial_port *port, unsigned char *ch) +{ + struct qt2_port_private *port_priv; + struct async_icount *icount; + unsigned long flags; + u8 newLSR = (u8) *ch; + + port_priv = usb_get_serial_port_data(port); + + if (newLSR & UART_LSR_BI) + newLSR &= (u8) (UART_LSR_OE | UART_LSR_BI); + + spin_lock_irqsave(&port_priv->lock, flags); + port_priv->shadowLSR = newLSR; + spin_unlock_irqrestore(&port_priv->lock, flags); + + icount = &port_priv->icount; + + if (newLSR & UART_LSR_BRK_ERROR_BITS) { + + if (newLSR & UART_LSR_BI) + icount->brk++; + + if (newLSR & UART_LSR_OE) + icount->overrun++; + + if (newLSR & UART_LSR_PE) + icount->parity++; + + if (newLSR & UART_LSR_FE) + icount->frame++; + } + +} + +static int qt2_write_room(struct tty_struct *tty) +{ + struct usb_serial_port *port = tty->driver_data; + struct qt2_port_private *port_priv; + unsigned long flags = 0; + int r; + + port_priv = usb_get_serial_port_data(port); + + spin_lock_irqsave(&port_priv->urb_lock, flags); + + if (port_priv->urb_in_use) + r = 0; + else + r = QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE; + + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + + return r; +} + +static int qt2_write(struct tty_struct *tty, + struct usb_serial_port *port, + const unsigned char *buf, int count) +{ + struct qt2_port_private *port_priv; + struct urb *write_urb; + unsigned char *data; + unsigned long flags; + int status; + int bytes_out = 0; + + port_priv = usb_get_serial_port_data(port); + + if (port_priv->write_urb == NULL) { + dev_err(&port->dev, "%s - no output urb\n", __func__); + return 0; + } + write_urb = port_priv->write_urb; + + count = min(count, QT2_WRITE_BUFFER_SIZE - QT2_WRITE_CONTROL_SIZE); + + data = write_urb->transfer_buffer; + spin_lock_irqsave(&port_priv->urb_lock, flags); + if (port_priv->urb_in_use == true) { + printk(KERN_INFO "qt2_write - urb is in use\n"); + goto write_out; + } + + *data++ = QT2_CONTROL_BYTE; + *data++ = QT2_CONTROL_BYTE; + *data++ = port_priv->device_port; + put_unaligned_le16(count, data); + data += 2; + memcpy(data, buf, count); + + write_urb->transfer_buffer_length = count + QT2_WRITE_CONTROL_SIZE; + + status = usb_submit_urb(write_urb, GFP_ATOMIC); + if (status == 0) { + port_priv->urb_in_use = true; + bytes_out += count; + } + +write_out: + spin_unlock_irqrestore(&port_priv->urb_lock, flags); + return bytes_out; +} + + +static struct usb_serial_driver qt2_device = { + .driver = { + .owner = THIS_MODULE, + .name = "quatech-serial", + }, + .description = DRIVER_DESC, + .id_table = id_table, + .open = qt2_open, + .close = qt2_close, + .write = qt2_write, + .write_room = qt2_write_room, + .calc_num_ports = qt2_calc_num_ports, + .attach = qt2_attach, + .release = qt2_release, + .disconnect = qt2_disconnect, + .dtr_rts = qt2_dtr_rts, + .break_ctl = qt2_break_ctl, + .tiocmget = qt2_tiocmget, + .tiocmset = qt2_tiocmset, + .get_icount = qt2_get_icount, + .ioctl = qt2_ioctl, + .set_termios = qt2_set_termios, +}; + +static struct usb_serial_driver *const serial_drivers[] = { + &qt2_device, NULL +}; + +module_usb_serial_driver(serial_drivers, id_table); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +module_param(debug, bool, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index ae4ee30c7411..36e9d9fc0618 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -151,13 +151,6 @@ static struct usb_device_id id_table[] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver safe_driver = { - .name = "safe_serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static const __u16 crc10_table[256] = { 0x000, 0x233, 0x255, 0x066, 0x299, 0x0aa, 0x0cc, 0x2ff, 0x301, 0x132, 0x154, 0x367, 0x198, 0x3ab, 0x3cd, 0x1fe, @@ -339,12 +332,12 @@ static int __init safe_init(void) } } - return usb_serial_register_drivers(&safe_driver, serial_drivers); + return usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, id_table); } static void __exit safe_exit(void) { - usb_serial_deregister_drivers(&safe_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); } module_init(safe_init); diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c index 46c0430fd38b..e4a1787cdbac 100644 --- a/drivers/usb/serial/siemens_mpi.c +++ b/drivers/usb/serial/siemens_mpi.c @@ -29,13 +29,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver siemens_usb_mpi_driver = { - .name = "siemens_mpi", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver siemens_usb_mpi_device = { .driver = { .owner = THIS_MODULE, @@ -49,7 +42,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &siemens_usb_mpi_device, NULL }; -module_usb_serial_driver(siemens_usb_mpi_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c index 8c8bf806f6fa..ba54a0a8235c 100644 --- a/drivers/usb/serial/sierra.c +++ b/drivers/usb/serial/sierra.c @@ -63,9 +63,7 @@ struct sierra_intf_private { static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) { - int result; - dev_dbg(&udev->dev, "%s\n", __func__); - result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetPower, /* __u8 request */ USB_TYPE_VENDOR, /* __u8 request type */ swiState, /* __u16 value */ @@ -73,14 +71,11 @@ static int sierra_set_power_state(struct usb_device *udev, __u16 swiState) NULL, /* void *data */ 0, /* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ - return result; } static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) { - int result; - dev_dbg(&udev->dev, "%s\n", __func__); - result = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SWIMS_USB_REQUEST_SetNmea, /* __u8 request */ USB_TYPE_VENDOR, /* __u8 request type */ enable, /* __u16 value */ @@ -88,7 +83,6 @@ static int sierra_vsc_set_nmea(struct usb_device *udev, __u16 enable) NULL, /* void *data */ 0, /* __u16 size */ USB_CTRL_SET_TIMEOUT); /* int timeout */ - return result; } static int sierra_calc_num_ports(struct usb_serial *serial) @@ -96,8 +90,6 @@ static int sierra_calc_num_ports(struct usb_serial *serial) int num_ports = 0; u8 ifnum, numendpoints; - dev_dbg(&serial->dev->dev, "%s\n", __func__); - ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber; numendpoints = serial->interface->cur_altsetting->desc.bNumEndpoints; @@ -150,7 +142,6 @@ static int sierra_calc_interface(struct usb_serial *serial) int interface; struct usb_interface *p_interface; struct usb_host_interface *p_host_interface; - dev_dbg(&serial->dev->dev, "%s\n", __func__); /* Get the interface structure pointer from the serial struct */ p_interface = serial->interface; @@ -175,9 +166,8 @@ static int sierra_probe(struct usb_serial *serial, u8 ifnum; udev = serial->dev; - dev_dbg(&udev->dev, "%s\n", __func__); - ifnum = sierra_calc_interface(serial); + /* * If this interface supports more than 1 alternate * select the 2nd one @@ -344,8 +334,6 @@ static int sierra_send_setup(struct usb_serial_port *port) int do_send = 0; int retval; - dev_dbg(&port->dev, "%s\n", __func__); - portdata = usb_get_serial_port_data(port); if (portdata->dtr_state) @@ -393,7 +381,6 @@ static int sierra_send_setup(struct usb_serial_port *port) static void sierra_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { - dev_dbg(&port->dev, "%s\n", __func__); tty_termios_copy_hw(tty->termios, old_termios); sierra_send_setup(port); } @@ -404,7 +391,6 @@ static int sierra_tiocmget(struct tty_struct *tty) unsigned int value; struct sierra_port_private *portdata; - dev_dbg(&port->dev, "%s\n", __func__); portdata = usb_get_serial_port_data(port); value = ((portdata->rts_state) ? TIOCM_RTS : 0) | @@ -441,8 +427,7 @@ static void sierra_release_urb(struct urb *urb) { struct usb_serial_port *port; if (urb) { - port = urb->context; - dev_dbg(&port->dev, "%s: %p\n", __func__, urb); + port = urb->context; kfree(urb->transfer_buffer); usb_free_urb(urb); } @@ -455,7 +440,6 @@ static void sierra_outdat_callback(struct urb *urb) struct sierra_intf_private *intfdata; int status = urb->status; - dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); intfdata = port->serial->private; /* free up the transfer buffer, as usb_free_urb() does not do this */ @@ -598,8 +582,6 @@ static void sierra_indat_callback(struct urb *urb) endpoint = usb_pipeendpoint(urb->pipe); port = urb->context; - dev_dbg(&port->dev, "%s: %p\n", __func__, urb); - if (status) { dev_dbg(&port->dev, "%s: nonzero status: %d on" " endpoint %02x\n", __func__, status, endpoint); @@ -697,8 +679,6 @@ static int sierra_write_room(struct tty_struct *tty) struct sierra_port_private *portdata = usb_get_serial_port_data(port); unsigned long flags; - dev_dbg(&port->dev, "%s - port %d\n", __func__, port->number); - /* try to give a good number back based on if we have any free urbs at * this point in time */ spin_lock_irqsave(&portdata->lock, flags); @@ -805,8 +785,6 @@ static void sierra_close(struct usb_serial_port *port) struct sierra_port_private *portdata; struct sierra_intf_private *intfdata = port->serial->private; - - dev_dbg(&port->dev, "%s\n", __func__); portdata = usb_get_serial_port_data(port); portdata->rts_state = 0; @@ -851,8 +829,6 @@ static int sierra_open(struct tty_struct *tty, struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); - dev_dbg(&port->dev, "%s\n", __func__); - /* Set some sane defaults */ portdata->rts_state = 1; portdata->dtr_state = 1; @@ -915,8 +891,6 @@ static int sierra_startup(struct usb_serial *serial) int i; u8 ifnum; - dev_dbg(&serial->dev->dev, "%s\n", __func__); - /* Set Device mode to D0 */ sierra_set_power_state(serial->dev, 0x0000); @@ -977,8 +951,6 @@ static void sierra_release(struct usb_serial *serial) struct usb_serial_port *port; struct sierra_port_private *portdata; - dev_dbg(&serial->dev->dev, "%s\n", __func__); - for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; if (!port) @@ -1067,29 +1039,11 @@ static int sierra_resume(struct usb_serial *serial) return ec ? -EIO : 0; } -static int sierra_reset_resume(struct usb_interface *intf) -{ - struct usb_serial *serial = usb_get_intfdata(intf); - dev_err(&serial->dev->dev, "%s\n", __func__); - return usb_serial_resume(intf); -} #else #define sierra_suspend NULL #define sierra_resume NULL -#define sierra_reset_resume NULL #endif -static struct usb_driver sierra_driver = { - .name = "sierra", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .reset_resume = sierra_reset_resume, - .id_table = id_table, - .supports_autosuspend = 1, -}; - static struct usb_serial_driver sierra_device = { .driver = { .owner = THIS_MODULE, @@ -1118,7 +1072,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &sierra_device, NULL }; -module_usb_serial_driver(sierra_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c index f06c9a8f3d37..cad608984710 100644 --- a/drivers/usb/serial/spcp8x5.c +++ b/drivers/usb/serial/spcp8x5.c @@ -151,14 +151,6 @@ enum spcp8x5_type { SPCP835_TYPE, }; -static struct usb_driver spcp8x5_driver = { - .name = "spcp8x5", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - - struct spcp8x5_private { spinlock_t lock; enum spcp8x5_type type; @@ -433,7 +425,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty, if (i < 0) dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n", uartdata, i); - dbg("0x21:0x40:0:0 %d", i); + dev_dbg(&port->dev, "0x21:0x40:0:0 %d\n", i); if (cflag & CRTSCTS) { /* enable hardware flow control */ @@ -454,8 +446,6 @@ static int spcp8x5_open(struct tty_struct *tty, struct usb_serial_port *port) u8 status = 0x30; /* status 0x30 means DSR and CTS = 1 other CDC RI and delta = 0 */ - dbg("%s - port %d", __func__, port->number); - usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); @@ -579,15 +569,19 @@ static int spcp8x5_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) { struct usb_serial_port *port = tty->driver_data; - dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd); + + dev_dbg(&port->dev, "%s (%d) cmd = 0x%04x\n", __func__, + port->number, cmd); switch (cmd) { case TIOCMIWAIT: - dbg("%s (%d) TIOCMIWAIT", __func__, port->number); + dev_dbg(&port->dev, "%s (%d) TIOCMIWAIT\n", __func__, + port->number); return spcp8x5_wait_modem_info(port, arg); default: - dbg("%s not supported = 0x%04x", __func__, cmd); + dev_dbg(&port->dev, "%s not supported = 0x%04x", __func__, + cmd); break; } @@ -666,7 +660,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &spcp8x5_device, NULL }; -module_usb_serial_driver(spcp8x5_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_VERSION(DRIVER_VERSION); diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c index 3cdc8a52de44..3fee23bf0c14 100644 --- a/drivers/usb/serial/ssu100.c +++ b/drivers/usb/serial/ssu100.c @@ -59,20 +59,8 @@ static const struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_QUATECH, QUATECH_SSU100)}, {} /* Terminating entry */ }; - MODULE_DEVICE_TABLE(usb, id_table); - -static struct usb_driver ssu100_driver = { - .name = "ssu100", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .supports_autosuspend = 1, -}; - struct ssu100_port_private { spinlock_t status_lock; u8 shadowLSR; @@ -85,7 +73,6 @@ static void ssu100_release(struct usb_serial *serial) { struct ssu100_port_private *priv = usb_get_serial_port_data(*serial->port); - dbg("%s", __func__); kfree(priv); } @@ -171,8 +158,6 @@ static int ssu100_initdevice(struct usb_device *dev) u8 *data; int result = 0; - dbg("%s", __func__); - data = kzalloc(3, GFP_KERNEL); if (!data) return -ENOMEM; @@ -237,8 +222,6 @@ static void ssu100_set_termios(struct tty_struct *tty, u16 urb_value = 0; /* will hold the new flags */ int result; - dbg("%s", __func__); - if (cflag & PARENB) { if (cflag & PARODD) urb_value |= UART_LCR_PARITY; @@ -312,8 +295,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) int result; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - data = kzalloc(2, GFP_KERNEL); if (!data) return -ENOMEM; @@ -348,7 +329,6 @@ static int ssu100_open(struct tty_struct *tty, struct usb_serial_port *port) static void ssu100_close(struct usb_serial_port *port) { - dbg("%s", __func__); usb_serial_generic_close(port); } @@ -467,8 +447,6 @@ static int ssu100_attach(struct usb_serial *serial) struct ssu100_port_private *priv; struct usb_serial_port *port = *serial->port; - dbg("%s", __func__); - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { dev_err(&port->dev, "%s- kmalloc(%Zd) failed.\n", __func__, @@ -490,8 +468,6 @@ static int ssu100_tiocmget(struct tty_struct *tty) u8 *d; int r; - dbg("%s\n", __func__); - d = kzalloc(2, GFP_KERNEL); if (!d) return -ENOMEM; @@ -522,7 +498,6 @@ static int ssu100_tiocmset(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct usb_device *dev = port->serial->dev; - dbg("%s\n", __func__); return update_mctrl(dev, set, clear); } @@ -530,8 +505,6 @@ static void ssu100_dtr_rts(struct usb_serial_port *port, int on) { struct usb_device *dev = port->serial->dev; - dbg("%s\n", __func__); - mutex_lock(&port->serial->disc_mutex); if (!port->serial->disconnected) { /* Disable flow control */ @@ -618,8 +591,6 @@ static int ssu100_process_packet(struct urb *urb, int i; char *ch; - dbg("%s - port %d", __func__, port->number); - if ((len >= 4) && (packet[0] == 0x1b) && (packet[1] == 0x1b) && ((packet[2] == 0x00) || (packet[2] == 0x01))) { @@ -656,8 +627,6 @@ static void ssu100_process_read_urb(struct urb *urb) struct tty_struct *tty; int count; - dbg("%s", __func__); - tty = tty_port_tty_get(&port->port); if (!tty) return; @@ -695,7 +664,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &ssu100_device, NULL }; -module_usb_serial_driver(ssu100_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c index 1a5be136e6cf..e53d2aac35c5 100644 --- a/drivers/usb/serial/symbolserial.c +++ b/drivers/usb/serial/symbolserial.c @@ -54,8 +54,6 @@ static void symbol_int_callback(struct urb *urb) int result; int data_length; - dbg("%s - port %d", __func__, port->number); - switch (status) { case 0: /* success */ @@ -64,12 +62,12 @@ static void symbol_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -125,8 +123,6 @@ static int symbol_open(struct tty_struct *tty, struct usb_serial_port *port) unsigned long flags; int result = 0; - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&priv->lock, flags); priv->throttled = false; priv->actually_throttled = false; @@ -150,8 +146,6 @@ static void symbol_close(struct usb_serial_port *port) { struct symbol_private *priv = usb_get_serial_data(port->serial); - dbg("%s - port %d", __func__, port->number); - /* shutdown our urbs */ usb_kill_urb(priv->int_urb); } @@ -161,7 +155,6 @@ static void symbol_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct symbol_private *priv = usb_get_serial_data(port->serial); - dbg("%s - port %d", __func__, port->number); spin_lock_irq(&priv->lock); priv->throttled = true; spin_unlock_irq(&priv->lock); @@ -174,8 +167,6 @@ static void symbol_unthrottle(struct tty_struct *tty) int result; bool was_throttled; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&priv->lock); priv->throttled = false; was_throttled = priv->actually_throttled; @@ -266,8 +257,6 @@ static void symbol_disconnect(struct usb_serial *serial) { struct symbol_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - usb_kill_urb(priv->int_urb); usb_free_urb(priv->int_urb); } @@ -276,19 +265,10 @@ static void symbol_release(struct usb_serial *serial) { struct symbol_private *priv = usb_get_serial_data(serial); - dbg("%s", __func__); - kfree(priv->int_buffer); kfree(priv); } -static struct usb_driver symbol_driver = { - .name = "symbol", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver symbol_device = { .driver = { .owner = THIS_MODULE, @@ -309,7 +289,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &symbol_device, NULL }; -module_usb_serial_driver(symbol_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index ab74123d658e..a4404f5ad68e 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -165,7 +165,7 @@ static unsigned int product_5052_count; /* the array dimension is the number of default entries plus */ /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */ /* null entry */ -static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -180,6 +180,7 @@ static struct usb_device_id ti_id_table_3410[14+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, }; static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { @@ -189,7 +190,7 @@ static struct usb_device_id ti_id_table_5052[5+TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) }, }; -static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] = { +static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = { { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) }, { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) }, { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) }, @@ -208,16 +209,10 @@ static struct usb_device_id ti_id_table_combined[18+2*TI_EXTRA_VID_PID_COUNT+1] { USB_DEVICE(IBM_VENDOR_ID, IBM_454B_PRODUCT_ID) }, { USB_DEVICE(IBM_VENDOR_ID, IBM_454C_PRODUCT_ID) }, { USB_DEVICE(ABBOTT_VENDOR_ID, ABBOTT_PRODUCT_ID) }, + { USB_DEVICE(TI_VENDOR_ID, FRI2_PRODUCT_ID) }, { } }; -static struct usb_driver ti_usb_driver = { - .name = "ti_usb_3410_5052", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = ti_id_table_combined, -}; - static struct usb_serial_driver ti_1port_device = { .driver = { .owner = THIS_MODULE, @@ -344,20 +339,18 @@ static int __init ti_init(void) ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE; } - ret = usb_serial_register_drivers(&ti_usb_driver, serial_drivers); + ret = usb_serial_register_drivers(serial_drivers, KBUILD_MODNAME, ti_id_table_combined); if (ret == 0) printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":" TI_DRIVER_DESC "\n"); return ret; } - static void __exit ti_exit(void) { - usb_serial_deregister_drivers(&ti_usb_driver, serial_drivers); + usb_serial_deregister_drivers(serial_drivers); } - module_init(ti_init); module_exit(ti_exit); @@ -394,7 +387,9 @@ static int ti_startup(struct usb_serial *serial) /* if we have only 1 configuration, download firmware */ if (dev->descriptor.bNumConfigurations == 1) { - if ((status = ti_download_firmware(tdev)) != 0) + status = ti_download_firmware(tdev); + + if (status != 0) goto free_tdev; /* 3410 must be reset, 5052 resets itself */ @@ -463,8 +458,6 @@ static void ti_release(struct usb_serial *serial) struct ti_device *tdev = usb_get_serial_data(serial); struct ti_port *tport; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; ++i) { tport = usb_get_serial_port_data(serial->port[i]); if (tport) { @@ -489,8 +482,6 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port) TI_PIPE_TIMEOUT_ENABLE | (TI_TRANSFER_TIMEOUT << 2)); - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return -ENODEV; @@ -631,8 +622,6 @@ static void ti_close(struct usb_serial_port *port) int status; int do_unlock; - dbg("%s - port %d", __func__, port->number); - tdev = usb_get_serial_data(port->serial); tport = usb_get_serial_port_data(port); if (tdev == NULL || tport == NULL) @@ -666,8 +655,6 @@ static void ti_close(struct usb_serial_port *port) } if (do_unlock) mutex_unlock(&tdev->td_open_close_lock); - - dbg("%s - exit", __func__); } @@ -676,8 +663,6 @@ static int ti_write(struct tty_struct *tty, struct usb_serial_port *port, { struct ti_port *tport = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (count == 0) { dbg("%s - write request of 0 bytes", __func__); return 0; @@ -701,8 +686,6 @@ static int ti_write_room(struct tty_struct *tty) int room = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return 0; @@ -722,8 +705,6 @@ static int ti_chars_in_buffer(struct tty_struct *tty) int chars = 0; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return 0; @@ -741,8 +722,6 @@ static void ti_throttle(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct ti_port *tport = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return; @@ -758,8 +737,6 @@ static void ti_unthrottle(struct tty_struct *tty) struct ti_port *tport = usb_get_serial_port_data(port); int status; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return; @@ -854,8 +831,6 @@ static void ti_set_termios(struct tty_struct *tty, int port_number = port->number - port->serial->minor; unsigned int mcr; - dbg("%s - port %d", __func__, port->number); - cflag = tty->termios->c_cflag; iflag = tty->termios->c_iflag; @@ -988,8 +963,6 @@ static int ti_tiocmget(struct tty_struct *tty) unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return -ENODEV; @@ -1020,8 +993,6 @@ static int ti_tiocmset(struct tty_struct *tty, unsigned int mcr; unsigned long flags; - dbg("%s - port %d", __func__, port->number); - if (tport == NULL) return -ENODEV; @@ -1084,8 +1055,6 @@ static void ti_interrupt_callback(struct urb *urb) int retval; __u8 msr; - dbg("%s", __func__); - switch (status) { case 0: break; @@ -1165,8 +1134,6 @@ static void ti_bulk_in_callback(struct urb *urb) int retval = 0; struct tty_struct *tty; - dbg("%s", __func__); - switch (status) { case 0: break; @@ -1233,8 +1200,6 @@ static void ti_bulk_out_callback(struct urb *urb) struct usb_serial_port *port = tport->tp_port; int status = urb->status; - dbg("%s - port %d", __func__, port->number); - tport->tp_write_urb_in_use = 0; switch (status) { @@ -1287,9 +1252,6 @@ static void ti_send(struct ti_port *tport) struct tty_struct *tty = tty_port_tty_get(&port->port); /* FIXME */ unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - spin_lock_irqsave(&tport->tp_lock, flags); if (tport->tp_write_urb_in_use) @@ -1366,8 +1328,6 @@ static int ti_get_lsr(struct ti_port *tport) int port_number = port->number - port->serial->minor; struct ti_port_status *data; - dbg("%s - port %d", __func__, port->number); - size = sizeof(struct ti_port_status); data = kmalloc(size, GFP_KERNEL); if (!data) { @@ -1480,8 +1440,6 @@ static void ti_drain(struct ti_port *tport, unsigned long timeout, int flush) struct usb_serial_port *port = tport->tp_port; wait_queue_t wait; - dbg("%s - port %d", __func__, port->number); - spin_lock_irq(&tport->tp_lock); /* wait for data to drain from the buffer */ @@ -1679,11 +1637,12 @@ static int ti_download_firmware(struct ti_device *tdev) const struct firmware *fw_p; char buf[32]; - dbg("%s\n", __func__); /* try ID specific firmware first, then try generic firmware */ sprintf(buf, "ti_usb-v%04x-p%04x.fw", dev->descriptor.idVendor, dev->descriptor.idProduct); - if ((status = request_firmware(&fw_p, buf, &dev->dev)) != 0) { + status = request_firmware(&fw_p, buf, &dev->dev); + + if (status != 0) { buf[0] = '\0'; if (dev->descriptor.idVendor == MTS_VENDOR_ID) { switch (dev->descriptor.idProduct) { diff --git a/drivers/usb/serial/ti_usb_3410_5052.h b/drivers/usb/serial/ti_usb_3410_5052.h index f140f1b9d5c0..b353e7e3d480 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.h +++ b/drivers/usb/serial/ti_usb_3410_5052.h @@ -37,6 +37,7 @@ #define TI_5152_BOOT_PRODUCT_ID 0x5152 /* no EEPROM, no firmware */ #define TI_5052_EEPROM_PRODUCT_ID 0x505A /* EEPROM, no firmware */ #define TI_5052_FIRMWARE_PRODUCT_ID 0x505F /* firmware is running */ +#define FRI2_PRODUCT_ID 0x5053 /* Fish River Island II */ /* Multi-Tech vendor and product ids */ #define MTS_VENDOR_ID 0x06E0 diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 97355a15bbea..6a1b609a0d94 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -1,7 +1,7 @@ /* * USB Serial Converter driver * - * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (C) 1999 - 2012 Greg Kroah-Hartman (greg@kroah.com) * Copyright (C) 2000 Peter Berger (pberger@brimson.com) * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com) * @@ -43,17 +43,6 @@ #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/" #define DRIVER_DESC "USB Serial Driver core" -/* Driver structure we register with the USB core */ -static struct usb_driver usb_serial_driver = { - .name = "usbserial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .suspend = usb_serial_suspend, - .resume = usb_serial_resume, - .no_dynamic_id = 1, - .supports_autosuspend = 1, -}; - /* There is no MODULE_DEVICE_TABLE for usbserial.c. Instead the MODULE_DEVICE_TABLE declarations in each serial driver cause the "hotplug" program to pull in whatever module is necessary @@ -710,7 +699,7 @@ static const struct tty_port_operations serial_port_ops = { .shutdown = serial_down, }; -int usb_serial_probe(struct usb_interface *interface, +static int usb_serial_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct usb_device *dev = interface_to_usbdev(interface); @@ -856,6 +845,8 @@ int usb_serial_probe(struct usb_interface *interface, module_put(type->driver.owner); return -EIO; } + dev_info(&interface->dev, "The \"generic\" usb-serial driver is only for testing and one-off prototypes.\n"); + dev_info(&interface->dev, "Tell linux-usb@vger.kernel.org to add your device to a proper driver.\n"); } #endif if (!num_ports) { @@ -1043,6 +1034,8 @@ int usb_serial_probe(struct usb_interface *interface, dbg("the device claims to support interrupt out transfers, but write_int_callback is not defined"); } + usb_set_intfdata(interface, serial); + /* if this device type has an attach function, call it */ if (type->attach) { retval = type->attach(serial); @@ -1087,10 +1080,7 @@ int usb_serial_probe(struct usb_interface *interface, serial->disconnected = 0; usb_serial_console_init(debug, minor); - exit: - /* success */ - usb_set_intfdata(interface, serial); module_put(type->driver.owner); return 0; @@ -1099,9 +1089,8 @@ probe_error: module_put(type->driver.owner); return -EIO; } -EXPORT_SYMBOL_GPL(usb_serial_probe); -void usb_serial_disconnect(struct usb_interface *interface) +static void usb_serial_disconnect(struct usb_interface *interface) { int i; struct usb_serial *serial = usb_get_intfdata(interface); @@ -1112,7 +1101,6 @@ void usb_serial_disconnect(struct usb_interface *interface) dbg("%s", __func__); mutex_lock(&serial->disc_mutex); - usb_set_intfdata(interface, NULL); /* must set a flag, to signal subdrivers */ serial->disconnected = 1; mutex_unlock(&serial->disc_mutex); @@ -1137,7 +1125,6 @@ void usb_serial_disconnect(struct usb_interface *interface) usb_serial_put(serial); dev_info(dev, "device disconnected\n"); } -EXPORT_SYMBOL_GPL(usb_serial_disconnect); int usb_serial_suspend(struct usb_interface *intf, pm_message_t message) { @@ -1181,6 +1168,22 @@ int usb_serial_resume(struct usb_interface *intf) } EXPORT_SYMBOL(usb_serial_resume); +static int usb_serial_reset_resume(struct usb_interface *intf) +{ + struct usb_serial *serial = usb_get_intfdata(intf); + int rv; + + serial->suspending = 0; + if (serial->type->reset_resume) + rv = serial->type->reset_resume(serial); + else { + rv = -EOPNOTSUPP; + intf->needs_binding = 1; + } + + return rv; +} + static const struct tty_operations serial_ops = { .open = serial_open, .close = serial_close, @@ -1204,6 +1207,17 @@ static const struct tty_operations serial_ops = { struct tty_driver *usb_serial_tty_driver; +/* Driver structure we register with the USB core */ +static struct usb_driver usb_serial_driver = { + .name = "usbserial", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .suspend = usb_serial_suspend, + .resume = usb_serial_resume, + .no_dynamic_id = 1, + .supports_autosuspend = 1, +}; + static int __init usb_serial_init(void) { int i; @@ -1338,7 +1352,6 @@ static int usb_serial_register(struct usb_serial_driver *driver) driver->description); return -EINVAL; } - driver->usb_driver->supports_autosuspend = 1; /* Add this device to our list of devices */ mutex_lock(&table_lock); @@ -1369,18 +1382,19 @@ static void usb_serial_deregister(struct usb_serial_driver *device) /** * usb_serial_register_drivers - register drivers for a usb-serial module - * @udriver: usb_driver used for matching devices/interfaces * @serial_drivers: NULL-terminated array of pointers to drivers to be registered + * @name: name of the usb_driver for this set of @serial_drivers + * @id_table: list of all devices this @serial_drivers set binds to * - * Registers @udriver and all the drivers in the @serial_drivers array. - * Automatically fills in the .no_dynamic_id field in @udriver and - * the .usb_driver field in each serial driver. + * Registers all the drivers in the @serial_drivers array, and dynamically + * creates a struct usb_driver with the name @name and id_table of @id_table. */ -int usb_serial_register_drivers(struct usb_driver *udriver, - struct usb_serial_driver * const serial_drivers[]) +int usb_serial_register_drivers(struct usb_serial_driver *const serial_drivers[], + const char *name, + const struct usb_device_id *id_table) { int rc; - const struct usb_device_id *saved_id_table; + struct usb_driver *udriver; struct usb_serial_driver * const *sd; /* @@ -1391,12 +1405,30 @@ int usb_serial_register_drivers(struct usb_driver *udriver, * Performance hack: We don't want udriver to be probed until * the serial drivers are registered, because the probe would * simply fail for lack of a matching serial driver. - * Therefore save off udriver's id_table until we are all set. + * So we leave udriver's id_table set to NULL until we are all set. + * + * Suspend/resume support is implemented in the usb-serial core, + * so fill in the PM-related fields in udriver. */ - saved_id_table = udriver->id_table; - udriver->id_table = NULL; + udriver = kzalloc(sizeof(*udriver), GFP_KERNEL); + if (!udriver) + return -ENOMEM; + udriver->name = name; udriver->no_dynamic_id = 1; + udriver->supports_autosuspend = 1; + udriver->suspend = usb_serial_suspend; + udriver->resume = usb_serial_resume; + udriver->probe = usb_serial_probe; + udriver->disconnect = usb_serial_disconnect; + + /* we only set the reset_resume field if the serial_driver has one */ + for (sd = serial_drivers; *sd; ++sd) { + if ((*sd)->reset_resume) + udriver->reset_resume = usb_serial_reset_resume; + break; + } + rc = usb_register(udriver); if (rc) return rc; @@ -1408,8 +1440,8 @@ int usb_serial_register_drivers(struct usb_driver *udriver, goto failed; } - /* Now restore udriver's id_table and look for matches */ - udriver->id_table = saved_id_table; + /* Now set udriver's id_table and look for matches */ + udriver->id_table = id_table; rc = driver_attach(&udriver->drvwrap.driver); return 0; @@ -1423,17 +1455,20 @@ EXPORT_SYMBOL_GPL(usb_serial_register_drivers); /** * usb_serial_deregister_drivers - deregister drivers for a usb-serial module - * @udriver: usb_driver to unregister * @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered * - * Deregisters @udriver and all the drivers in the @serial_drivers array. + * Deregisters all the drivers in the @serial_drivers array and deregisters and + * frees the struct usb_driver that was created by the call to + * usb_serial_register_drivers(). */ -void usb_serial_deregister_drivers(struct usb_driver *udriver, - struct usb_serial_driver * const serial_drivers[]) +void usb_serial_deregister_drivers(struct usb_serial_driver *const serial_drivers[]) { + struct usb_driver *udriver = (*serial_drivers)->usb_driver; + for (; *serial_drivers; ++serial_drivers) usb_serial_deregister(*serial_drivers); usb_deregister(udriver); + kfree(udriver); } EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers); diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c index e3e8995a4739..5760f97ee508 100644 --- a/drivers/usb/serial/usb_debug.c +++ b/drivers/usb/serial/usb_debug.c @@ -35,13 +35,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver debug_driver = { - .name = "debug", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - /* This HW really does not support a serial break, so one will be * emulated when ever the break state is set to true. */ @@ -83,5 +76,5 @@ static struct usb_serial_driver * const serial_drivers[] = { &debug_device, NULL }; -module_usb_serial_driver(debug_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index c88657dd31c8..f35971dff4a5 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -43,11 +43,8 @@ void usb_wwan_dtr_rts(struct usb_serial_port *port, int on) { struct usb_serial *serial = port->serial; struct usb_wwan_port_private *portdata; - struct usb_wwan_intf_private *intfdata; - dbg("%s", __func__); - intfdata = port->serial->private; if (!intfdata->send_setup) @@ -69,8 +66,6 @@ void usb_wwan_set_termios(struct tty_struct *tty, { struct usb_wwan_intf_private *intfdata = port->serial->private; - dbg("%s", __func__); - /* Doesn't support option setting */ tty_termios_copy_hw(tty->termios, old_termios); @@ -286,8 +281,6 @@ static void usb_wwan_indat_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int status = urb->status; - dbg("%s: %p", __func__, urb); - endpoint = usb_pipeendpoint(urb->pipe); port = urb->context; @@ -307,20 +300,17 @@ static void usb_wwan_indat_callback(struct urb *urb) } /* Resubmit urb so we continue receiving */ - if (status != -ESHUTDOWN) { - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - if (err != -EPERM) { - printk(KERN_ERR "%s: resubmit read urb failed. " - "(%d)", __func__, err); - /* busy also in error unless we are killed */ - usb_mark_last_busy(port->serial->dev); - } - } else { + err = usb_submit_urb(urb, GFP_ATOMIC); + if (err) { + if (err != -EPERM) { + printk(KERN_ERR "%s: resubmit read urb failed. " + "(%d)", __func__, err); + /* busy also in error unless we are killed */ usb_mark_last_busy(port->serial->dev); } + } else { + usb_mark_last_busy(port->serial->dev); } - } } @@ -331,8 +321,6 @@ static void usb_wwan_outdat_callback(struct urb *urb) struct usb_wwan_intf_private *intfdata; int i; - dbg("%s", __func__); - port = urb->context; intfdata = port->serial->private; @@ -406,8 +394,6 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); intfdata = serial->private; - dbg("%s", __func__); - /* Start reading from the IN endpoint */ for (i = 0; i < N_IN_URB; i++) { urb = portdata->in_urbs[i]; @@ -441,7 +427,6 @@ void usb_wwan_close(struct usb_serial_port *port) struct usb_wwan_port_private *portdata; struct usb_wwan_intf_private *intfdata = port->serial->private; - dbg("%s", __func__); portdata = usb_get_serial_port_data(port); if (serial->dev) { @@ -492,8 +477,6 @@ static void usb_wwan_setup_urbs(struct usb_serial *serial) struct usb_serial_port *port; struct usb_wwan_port_private *portdata; - dbg("%s", __func__); - for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; portdata = usb_get_serial_port_data(port); @@ -534,8 +517,6 @@ int usb_wwan_startup(struct usb_serial *serial) struct usb_wwan_port_private *portdata; u8 *buffer; - dbg("%s", __func__); - /* Now setup per port private data */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; @@ -603,8 +584,6 @@ static void stop_read_write_urbs(struct usb_serial *serial) void usb_wwan_disconnect(struct usb_serial *serial) { - dbg("%s", __func__); - stop_read_write_urbs(serial); } EXPORT_SYMBOL(usb_wwan_disconnect); @@ -615,8 +594,6 @@ void usb_wwan_release(struct usb_serial *serial) struct usb_serial_port *port; struct usb_wwan_port_private *portdata; - dbg("%s", __func__); - /* Now free them */ for (i = 0; i < serial->num_ports; ++i) { port = serial->port[i]; @@ -649,8 +626,6 @@ int usb_wwan_suspend(struct usb_serial *serial, pm_message_t message) struct usb_wwan_intf_private *intfdata = serial->private; int b; - dbg("%s entered", __func__); - if (PMSG_IS_AUTO(message)) { spin_lock_irq(&intfdata->susp_lock); b = intfdata->in_flight; @@ -714,7 +689,6 @@ int usb_wwan_resume(struct usb_serial *serial) struct urb *urb; int err = 0; - dbg("%s entered", __func__); /* get the interrupt URBs resubmitted unconditionally */ for (i = 0; i < serial->num_ports; i++) { port = serial->port[i]; @@ -725,8 +699,8 @@ int usb_wwan_resume(struct usb_serial *serial) err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO); dbg("Submitted interrupt URB for port %d (result %d)", i, err); if (err < 0) { - err("%s: Error %d for interrupt URB of port%d", - __func__, err, i); + dev_err(&port->dev, "%s: Error %d for interrupt URB\n", + __func__, err); goto err_out; } } @@ -747,8 +721,8 @@ int usb_wwan_resume(struct usb_serial *serial) urb = portdata->in_urbs[j]; err = usb_submit_urb(urb, GFP_ATOMIC); if (err < 0) { - err("%s: Error %d for bulk URB %d", - __func__, err, i); + dev_err(&port->dev, "%s: Error %d for bulk URB %d\n", + __func__, err, i); spin_unlock_irq(&intfdata->susp_lock); goto err_out; } diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c index 71d696474f24..f253c91383da 100644 --- a/drivers/usb/serial/visor.c +++ b/drivers/usb/serial/visor.c @@ -53,8 +53,6 @@ static int palm_os_4_probe(struct usb_serial *serial, /* Parameters that may be passed into the module. */ static bool debug; -static __u16 vendor; -static __u16 product; static struct usb_device_id id_table [] = { { USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID), @@ -115,14 +113,12 @@ static struct usb_device_id id_table [] = { .driver_info = (kernel_ulong_t)&palm_os_4_probe }, { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { }, /* optional parameter entry */ { } /* Terminating entry */ }; static struct usb_device_id clie_id_5_table [] = { { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_UX50_ID), .driver_info = (kernel_ulong_t)&palm_os_4_probe }, - { }, /* optional parameter entry */ { } /* Terminating entry */ }; @@ -162,19 +158,11 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, { USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) }, { USB_DEVICE(FOSSIL_VENDOR_ID, FOSSIL_ABACUS_ID) }, - { }, /* optional parameter entry */ { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver visor_driver = { - .name = "visor", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; - /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */ static struct usb_serial_driver handspring_device = { @@ -244,8 +232,6 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) { int result = 0; - dbg("%s - port %d", __func__, port->number); - if (!port->read_urb) { /* this is needed for some brain dead Sony devices */ dev_err(&port->dev, "Device lied about number of ports, please use a lower one.\n"); @@ -258,7 +244,7 @@ static int visor_open(struct tty_struct *tty, struct usb_serial_port *port) goto exit; if (port->interrupt_in_urb) { - dbg("%s - adding interrupt input for treo", __func__); + dev_dbg(&port->dev, "adding interrupt input for treo\n"); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result) dev_err(&port->dev, @@ -274,8 +260,6 @@ static void visor_close(struct usb_serial_port *port) { unsigned char *transfer_buffer; - dbg("%s - port %d", __func__, port->number); - /* shutdown our urbs */ usb_serial_generic_close(port); usb_kill_urb(port->interrupt_in_urb); @@ -310,12 +294,12 @@ static void visor_read_int_callback(struct urb *urb) case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ - dbg("%s - urb shutting down with status: %d", - __func__, status); + dev_dbg(&port->dev, "%s - urb shutting down with status: %d\n", + __func__, status); return; default: - dbg("%s - nonzero urb status received: %d", - __func__, status); + dev_dbg(&port->dev, "%s - nonzero urb status received: %d\n", + __func__, status); goto exit; } @@ -348,8 +332,6 @@ static int palm_os_3_probe(struct usb_serial *serial, int i; int num_ports = 0; - dbg("%s", __func__); - transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL); if (!transfer_buffer) { dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, @@ -445,8 +427,6 @@ static int palm_os_4_probe(struct usb_serial *serial, unsigned char *transfer_buffer; int retval; - dbg("%s", __func__); - transfer_buffer = kmalloc(sizeof(*connection_info), GFP_KERNEL); if (!transfer_buffer) { dev_err(dev, "%s - kmalloc(%Zd) failed.\n", __func__, @@ -478,8 +458,6 @@ static int visor_probe(struct usb_serial *serial, int (*startup)(struct usb_serial *serial, const struct usb_device_id *id); - dbg("%s", __func__); - /* * some Samsung Android phones in modem mode have the same ID * as SPH-I500, but they are ACM devices, so dont bind to them @@ -521,8 +499,6 @@ static int clie_3_5_startup(struct usb_serial *serial) int result; u8 *data; - dbg("%s", __func__); - data = kmalloc(1, GFP_KERNEL); if (!data) return -ENOMEM; @@ -585,8 +561,6 @@ static int treo_attach(struct usb_serial *serial) (serial->num_interrupt_in == 0)) return 0; - dbg("%s", __func__); - /* * It appears that Treos and Kyoceras want to use the * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint, @@ -622,8 +596,6 @@ static int clie_5_attach(struct usb_serial *serial) unsigned int pipe; int j; - dbg("%s", __func__); - /* TH55 registers 2 ports. Communication in from the UX50/TH55 uses bulk_in_endpointAddress from port 0. Communication out to the UX50/TH55 uses @@ -648,59 +620,7 @@ static int clie_5_attach(struct usb_serial *serial) return 0; } -static int __init visor_init(void) -{ - int i, retval; - /* Only if parameters were passed to us */ - if (vendor > 0 && product > 0) { - struct usb_device_id usb_dev_temp[] = { - { - USB_DEVICE(vendor, product), - .driver_info = - (kernel_ulong_t) &palm_os_4_probe - } - }; - - /* Find the last entry in id_table */ - for (i = 0;; i++) { - if (id_table[i].idVendor == 0) { - id_table[i] = usb_dev_temp[0]; - break; - } - } - /* Find the last entry in id_table_combined */ - for (i = 0;; i++) { - if (id_table_combined[i].idVendor == 0) { - id_table_combined[i] = usb_dev_temp[0]; - break; - } - } - printk(KERN_INFO KBUILD_MODNAME - ": Untested USB device specified at time of module insertion\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Warning: This is not guaranteed to work\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Using a newer kernel is preferred to this method\n"); - printk(KERN_INFO KBUILD_MODNAME - ": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n", - vendor, product); - } - - retval = usb_serial_register_drivers(&visor_driver, serial_drivers); - if (retval == 0) - printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n"); - return retval; -} - - -static void __exit visor_exit (void) -{ - usb_serial_deregister_drivers(&visor_driver, serial_drivers); -} - - -module_init(visor_init); -module_exit(visor_exit); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -708,9 +628,3 @@ MODULE_LICENSE("GPL"); module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); - -module_param(vendor, ushort, 0); -MODULE_PARM_DESC(vendor, "User specified vendor ID"); -module_param(product, ushort, 0); -MODULE_PARM_DESC(product, "User specified product ID"); - diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c index 078f338b5feb..0c0aa876c209 100644 --- a/drivers/usb/serial/vivopay-serial.c +++ b/drivers/usb/serial/vivopay-serial.c @@ -25,13 +25,6 @@ static struct usb_device_id id_table [] = { MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver vivopay_serial_driver = { - .name = "vivopay-serial", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver vivopay_serial_device = { .driver = { .owner = THIS_MODULE, @@ -45,7 +38,7 @@ static struct usb_serial_driver * const serial_drivers[] = { &vivopay_serial_device, NULL }; -module_usb_serial_driver(vivopay_serial_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>"); MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 407e23c87946..473635e7f5db 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -45,7 +45,6 @@ static bool debug; /* * Version Information */ -#define DRIVER_VERSION "v2.0" #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Stuart MacDonald <stuartm@connecttech.com>" #define DRIVER_DESC "USB ConnectTech WhiteHEAT driver" @@ -78,12 +77,6 @@ static const struct usb_device_id id_table_combined[] = { MODULE_DEVICE_TABLE(usb, id_table_combined); -static struct usb_driver whiteheat_driver = { - .name = "whiteheat", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table_combined, -}; /* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */ static int whiteheat_firmware_download(struct usb_serial *serial, @@ -96,10 +89,6 @@ static void whiteheat_release(struct usb_serial *serial); static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port); static void whiteheat_close(struct usb_serial_port *port); -static int whiteheat_write(struct tty_struct *tty, - struct usb_serial_port *port, - const unsigned char *buf, int count); -static int whiteheat_write_room(struct tty_struct *tty); static int whiteheat_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg); static void whiteheat_set_termios(struct tty_struct *tty, @@ -108,11 +97,6 @@ static int whiteheat_tiocmget(struct tty_struct *tty); static int whiteheat_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear); static void whiteheat_break_ctl(struct tty_struct *tty, int break_state); -static int whiteheat_chars_in_buffer(struct tty_struct *tty); -static void whiteheat_throttle(struct tty_struct *tty); -static void whiteheat_unthrottle(struct tty_struct *tty); -static void whiteheat_read_callback(struct urb *urb); -static void whiteheat_write_callback(struct urb *urb); static struct usb_serial_driver whiteheat_fake_device = { .driver = { @@ -138,18 +122,13 @@ static struct usb_serial_driver whiteheat_device = { .release = whiteheat_release, .open = whiteheat_open, .close = whiteheat_close, - .write = whiteheat_write, - .write_room = whiteheat_write_room, .ioctl = whiteheat_ioctl, .set_termios = whiteheat_set_termios, .break_ctl = whiteheat_break_ctl, .tiocmget = whiteheat_tiocmget, .tiocmset = whiteheat_tiocmset, - .chars_in_buffer = whiteheat_chars_in_buffer, - .throttle = whiteheat_throttle, - .unthrottle = whiteheat_unthrottle, - .read_bulk_callback = whiteheat_read_callback, - .write_bulk_callback = whiteheat_write_callback, + .throttle = usb_serial_generic_throttle, + .unthrottle = usb_serial_generic_unthrottle, }; static struct usb_serial_driver * const serial_drivers[] = { @@ -166,29 +145,8 @@ struct whiteheat_command_private { __u8 result_buffer[64]; }; - -#define THROTTLED 0x01 -#define ACTUALLY_THROTTLED 0x02 - -static int urb_pool_size = 8; - -struct whiteheat_urb_wrap { - struct list_head list; - struct urb *urb; -}; - struct whiteheat_private { - spinlock_t lock; - __u8 flags; __u8 mcr; /* FIXME: no locking on mcr */ - struct list_head rx_urbs_free; - struct list_head rx_urbs_submitted; - struct list_head rx_urb_q; - struct work_struct rx_work; - struct usb_serial_port *port; - struct list_head tx_urbs_free; - struct list_head tx_urbs_submitted; - struct mutex deathwarrant; }; @@ -198,12 +156,6 @@ static void stop_command_port(struct usb_serial *serial); static void command_port_write_callback(struct urb *urb); static void command_port_read_callback(struct urb *urb); -static int start_port_read(struct usb_serial_port *port); -static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, - struct list_head *head); -static struct list_head *list_first(struct list_head *head); -static void rx_data_softint(struct work_struct *work); - static int firm_send_command(struct usb_serial_port *port, __u8 command, __u8 *data, __u8 datasize); static int firm_open(struct usb_serial_port *port); @@ -247,8 +199,6 @@ static int whiteheat_firmware_download(struct usb_serial *serial, const struct firmware *loader_fw = NULL, *firmware_fw = NULL; const struct ihex_binrec *record; - dbg("%s", __func__); - if (request_ihex_firmware(&firmware_fw, "whiteheat.fw", &serial->dev->dev)) { dev_err(&serial->dev->dev, @@ -349,11 +299,6 @@ static int whiteheat_attach(struct usb_serial *serial) __u8 *command; __u8 *result; int i; - int j; - struct urb *urb; - int buf_size; - struct whiteheat_urb_wrap *wrap; - struct list_head *tmp; command_port = serial->port[COMMAND_PORT]; @@ -408,8 +353,8 @@ static int whiteheat_attach(struct usb_serial *serial) hw_info = (struct whiteheat_hw_info *)&result[1]; - dev_info(&serial->dev->dev, "%s: Driver %s: Firmware v%d.%02d\n", - serial->type->description, DRIVER_VERSION, + dev_info(&serial->dev->dev, "%s: Firmware v%d.%02d\n", + serial->type->description, hw_info->sw_major_rev, hw_info->sw_minor_rev); for (i = 0; i < serial->num_ports; i++) { @@ -423,72 +368,7 @@ static int whiteheat_attach(struct usb_serial *serial) goto no_private; } - spin_lock_init(&info->lock); - mutex_init(&info->deathwarrant); - info->flags = 0; info->mcr = 0; - INIT_WORK(&info->rx_work, rx_data_softint); - info->port = port; - - INIT_LIST_HEAD(&info->rx_urbs_free); - INIT_LIST_HEAD(&info->rx_urbs_submitted); - INIT_LIST_HEAD(&info->rx_urb_q); - INIT_LIST_HEAD(&info->tx_urbs_free); - INIT_LIST_HEAD(&info->tx_urbs_submitted); - - for (j = 0; j < urb_pool_size; j++) { - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "No free urbs available\n"); - goto no_rx_urb; - } - buf_size = port->read_urb->transfer_buffer_length; - urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&port->dev, - "Couldn't allocate urb buffer\n"); - goto no_rx_buf; - } - wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); - if (!wrap) { - dev_err(&port->dev, - "Couldn't allocate urb wrapper\n"); - goto no_rx_wrap; - } - usb_fill_bulk_urb(urb, serial->dev, - usb_rcvbulkpipe(serial->dev, - port->bulk_in_endpointAddress), - urb->transfer_buffer, buf_size, - whiteheat_read_callback, port); - wrap->urb = urb; - list_add(&wrap->list, &info->rx_urbs_free); - - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - dev_err(&port->dev, "No free urbs available\n"); - goto no_tx_urb; - } - buf_size = port->write_urb->transfer_buffer_length; - urb->transfer_buffer = kmalloc(buf_size, GFP_KERNEL); - if (!urb->transfer_buffer) { - dev_err(&port->dev, - "Couldn't allocate urb buffer\n"); - goto no_tx_buf; - } - wrap = kmalloc(sizeof(*wrap), GFP_KERNEL); - if (!wrap) { - dev_err(&port->dev, - "Couldn't allocate urb wrapper\n"); - goto no_tx_wrap; - } - usb_fill_bulk_urb(urb, serial->dev, - usb_sndbulkpipe(serial->dev, - port->bulk_out_endpointAddress), - urb->transfer_buffer, buf_size, - whiteheat_write_callback, port); - wrap->urb = urb; - list_add(&wrap->list, &info->tx_urbs_free); - } usb_set_serial_port_data(port, info); } @@ -531,29 +411,6 @@ no_command_private: for (i = serial->num_ports - 1; i >= 0; i--) { port = serial->port[i]; info = usb_get_serial_port_data(port); - for (j = urb_pool_size - 1; j >= 0; j--) { - tmp = list_first(&info->tx_urbs_free); - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); -no_tx_wrap: - kfree(urb->transfer_buffer); -no_tx_buf: - usb_free_urb(urb); -no_tx_urb: - tmp = list_first(&info->rx_urbs_free); - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); -no_rx_wrap: - kfree(urb->transfer_buffer); -no_rx_buf: - usb_free_urb(urb); -no_rx_urb: - ; - } kfree(info); no_private: ; @@ -569,56 +426,27 @@ no_command_buffer: static void whiteheat_release(struct usb_serial *serial) { struct usb_serial_port *command_port; - struct usb_serial_port *port; struct whiteheat_private *info; - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - struct list_head *tmp; - struct list_head *tmp2; int i; - dbg("%s", __func__); - /* free up our private data for our command port */ command_port = serial->port[COMMAND_PORT]; kfree(usb_get_serial_port_data(command_port)); for (i = 0; i < serial->num_ports; i++) { - port = serial->port[i]; - info = usb_get_serial_port_data(port); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } - list_for_each_safe(tmp, tmp2, &info->tx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - kfree(wrap); - kfree(urb->transfer_buffer); - usb_free_urb(urb); - } + info = usb_get_serial_port_data(serial->port[i]); kfree(info); } } static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) { - int retval = 0; - - dbg("%s - port %d", __func__, port->number); + int retval; retval = start_command_port(port->serial); if (retval) goto exit; - if (tty) - tty->low_latency = 1; - /* send an open port command */ retval = firm_open(port); if (retval) { @@ -640,144 +468,25 @@ static int whiteheat_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(port->serial->dev, port->read_urb->pipe); usb_clear_halt(port->serial->dev, port->write_urb->pipe); - /* Start reading from the device */ - retval = start_port_read(port); + retval = usb_serial_generic_open(tty, port); if (retval) { - dev_err(&port->dev, - "%s - failed submitting read urb, error %d\n", - __func__, retval); firm_close(port); stop_command_port(port->serial); goto exit; } - exit: - dbg("%s - exit, retval = %d", __func__, retval); return retval; } static void whiteheat_close(struct usb_serial_port *port) { - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - struct list_head *tmp; - struct list_head *tmp2; - - dbg("%s - port %d", __func__, port->number); - firm_report_tx_done(port); firm_close(port); - /* shutdown our bulk reads and writes */ - mutex_lock(&info->deathwarrant); - spin_lock_irq(&info->lock); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irq(&info->lock); - usb_kill_urb(urb); - spin_lock_irq(&info->lock); - list_add(tmp, &info->rx_urbs_free); - } - list_for_each_safe(tmp, tmp2, &info->rx_urb_q) - list_move(tmp, &info->rx_urbs_free); - list_for_each_safe(tmp, tmp2, &info->tx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irq(&info->lock); - usb_kill_urb(urb); - spin_lock_irq(&info->lock); - list_add(tmp, &info->tx_urbs_free); - } - spin_unlock_irq(&info->lock); - mutex_unlock(&info->deathwarrant); - stop_command_port(port->serial); -} - - -static int whiteheat_write(struct tty_struct *tty, - struct usb_serial_port *port, const unsigned char *buf, int count) -{ - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - int result; - int bytes; - int sent = 0; - unsigned long flags; - struct list_head *tmp; - - dbg("%s - port %d", __func__, port->number); - - if (count == 0) { - dbg("%s - write request of 0 bytes", __func__); - return (0); - } - - while (count) { - spin_lock_irqsave(&info->lock, flags); - if (list_empty(&info->tx_urbs_free)) { - spin_unlock_irqrestore(&info->lock, flags); - break; - } - tmp = list_first(&info->tx_urbs_free); - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - bytes = (count > port->bulk_out_size) ? - port->bulk_out_size : count; - memcpy(urb->transfer_buffer, buf + sent, bytes); - - usb_serial_debug_data(debug, &port->dev, - __func__, bytes, urb->transfer_buffer); - - urb->transfer_buffer_length = bytes; - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err_console(port, - "%s - failed submitting write urb, error %d\n", - __func__, result); - sent = result; - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->tx_urbs_free); - spin_unlock_irqrestore(&info->lock, flags); - break; - } else { - sent += bytes; - count -= bytes; - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->tx_urbs_submitted); - spin_unlock_irqrestore(&info->lock, flags); - } - } - - return sent; -} - -static int whiteheat_write_room(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct list_head *tmp; - int room = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); + usb_serial_generic_close(port); - spin_lock_irqsave(&info->lock, flags); - list_for_each(tmp, &info->tx_urbs_free) - room++; - spin_unlock_irqrestore(&info->lock, flags); - room *= port->bulk_out_size; - - dbg("%s - returns %d", __func__, room); - return (room); + stop_command_port(port->serial); } static int whiteheat_tiocmget(struct tty_struct *tty) @@ -786,8 +495,6 @@ static int whiteheat_tiocmget(struct tty_struct *tty) struct whiteheat_private *info = usb_get_serial_port_data(port); unsigned int modem_signals = 0; - dbg("%s - port %d", __func__, port->number); - firm_get_dtr_rts(port); if (info->mcr & UART_MCR_DTR) modem_signals |= TIOCM_DTR; @@ -803,8 +510,6 @@ static int whiteheat_tiocmset(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct whiteheat_private *info = usb_get_serial_port_data(port); - dbg("%s - port %d", __func__, port->number); - if (set & TIOCM_RTS) info->mcr |= UART_MCR_RTS; if (set & TIOCM_DTR) @@ -837,7 +542,7 @@ static int whiteheat_ioctl(struct tty_struct *tty, serstruct.line = port->serial->minor; serstruct.port = port->number; serstruct.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ; - serstruct.xmit_fifo_size = port->bulk_out_size; + serstruct.xmit_fifo_size = kfifo_size(&port->write_fifo); serstruct.custom_divisor = 0; serstruct.baud_base = 460800; serstruct.close_delay = CLOSING_DELAY; @@ -867,60 +572,6 @@ static void whiteheat_break_ctl(struct tty_struct *tty, int break_state) } -static int whiteheat_chars_in_buffer(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct list_head *tmp; - struct whiteheat_urb_wrap *wrap; - int chars = 0; - unsigned long flags; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irqsave(&info->lock, flags); - list_for_each(tmp, &info->tx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - chars += wrap->urb->transfer_buffer_length; - } - spin_unlock_irqrestore(&info->lock, flags); - - dbg("%s - returns %d", __func__, chars); - return chars; -} - - -static void whiteheat_throttle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&info->lock); - info->flags |= THROTTLED; - spin_unlock_irq(&info->lock); -} - - -static void whiteheat_unthrottle(struct tty_struct *tty) -{ - struct usb_serial_port *port = tty->driver_data; - struct whiteheat_private *info = usb_get_serial_port_data(port); - int actually_throttled; - - dbg("%s - port %d", __func__, port->number); - - spin_lock_irq(&info->lock); - actually_throttled = info->flags & ACTUALLY_THROTTLED; - info->flags &= ~(THROTTLED | ACTUALLY_THROTTLED); - spin_unlock_irq(&info->lock); - - if (actually_throttled) - rx_data_softint(&info->rx_work); -} - - /***************************************************************************** * Connect Tech's White Heat callback routines *****************************************************************************/ @@ -928,8 +579,6 @@ static void command_port_write_callback(struct urb *urb) { int status = urb->status; - dbg("%s", __func__); - if (status) { dbg("nonzero urb status: %d", status); return; @@ -945,8 +594,6 @@ static void command_port_read_callback(struct urb *urb) unsigned char *data = urb->transfer_buffer; int result; - dbg("%s", __func__); - command_info = usb_get_serial_port_data(command_port); if (!command_info) { dbg("%s - command_info is NULL, exiting.", __func__); @@ -989,80 +636,6 @@ static void command_port_read_callback(struct urb *urb) } -static void whiteheat_read_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct whiteheat_urb_wrap *wrap; - unsigned char *data = urb->transfer_buffer; - struct whiteheat_private *info = usb_get_serial_port_data(port); - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - spin_lock(&info->lock); - wrap = urb_to_wrap(urb, &info->rx_urbs_submitted); - if (!wrap) { - spin_unlock(&info->lock); - dev_err(&port->dev, "%s - Not my urb!\n", __func__); - return; - } - list_del(&wrap->list); - spin_unlock(&info->lock); - - if (status) { - dbg("%s - nonzero read bulk status received: %d", - __func__, status); - spin_lock(&info->lock); - list_add(&wrap->list, &info->rx_urbs_free); - spin_unlock(&info->lock); - return; - } - - usb_serial_debug_data(debug, &port->dev, - __func__, urb->actual_length, data); - - spin_lock(&info->lock); - list_add_tail(&wrap->list, &info->rx_urb_q); - if (info->flags & THROTTLED) { - info->flags |= ACTUALLY_THROTTLED; - spin_unlock(&info->lock); - return; - } - spin_unlock(&info->lock); - - schedule_work(&info->rx_work); -} - - -static void whiteheat_write_callback(struct urb *urb) -{ - struct usb_serial_port *port = urb->context; - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - int status = urb->status; - - dbg("%s - port %d", __func__, port->number); - - spin_lock(&info->lock); - wrap = urb_to_wrap(urb, &info->tx_urbs_submitted); - if (!wrap) { - spin_unlock(&info->lock); - dev_err(&port->dev, "%s - Not my urb!\n", __func__); - return; - } - list_move(&wrap->list, &info->tx_urbs_free); - spin_unlock(&info->lock); - - if (status) { - dbg("%s - nonzero write bulk status received: %d", - __func__, status); - return; - } - - usb_serial_port_softint(port); -} - - /***************************************************************************** * Connect Tech's White Heat firmware interface *****************************************************************************/ @@ -1337,124 +910,7 @@ static void stop_command_port(struct usb_serial *serial) mutex_unlock(&command_info->mutex); } - -static int start_port_read(struct usb_serial_port *port) -{ - struct whiteheat_private *info = usb_get_serial_port_data(port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - int retval = 0; - unsigned long flags; - struct list_head *tmp; - struct list_head *tmp2; - - spin_lock_irqsave(&info->lock, flags); - - list_for_each_safe(tmp, tmp2, &info->rx_urbs_free) { - list_del(tmp); - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - spin_unlock_irqrestore(&info->lock, flags); - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - list_for_each_safe(tmp, tmp2, &info->rx_urbs_submitted) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - usb_kill_urb(urb); - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - } - break; - } - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_submitted); - } - - spin_unlock_irqrestore(&info->lock, flags); - - return retval; -} - - -static struct whiteheat_urb_wrap *urb_to_wrap(struct urb *urb, - struct list_head *head) -{ - struct whiteheat_urb_wrap *wrap; - struct list_head *tmp; - - list_for_each(tmp, head) { - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - if (wrap->urb == urb) - return wrap; - } - - return NULL; -} - - -static struct list_head *list_first(struct list_head *head) -{ - return head->next; -} - - -static void rx_data_softint(struct work_struct *work) -{ - struct whiteheat_private *info = - container_of(work, struct whiteheat_private, rx_work); - struct usb_serial_port *port = info->port; - struct tty_struct *tty = tty_port_tty_get(&port->port); - struct whiteheat_urb_wrap *wrap; - struct urb *urb; - unsigned long flags; - struct list_head *tmp; - struct list_head *tmp2; - int result; - int sent = 0; - - spin_lock_irqsave(&info->lock, flags); - if (info->flags & THROTTLED) { - spin_unlock_irqrestore(&info->lock, flags); - goto out; - } - - list_for_each_safe(tmp, tmp2, &info->rx_urb_q) { - list_del(tmp); - spin_unlock_irqrestore(&info->lock, flags); - - wrap = list_entry(tmp, struct whiteheat_urb_wrap, list); - urb = wrap->urb; - - if (tty && urb->actual_length) - sent += tty_insert_flip_string(tty, - urb->transfer_buffer, urb->actual_length); - - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&port->dev, - "%s - failed resubmitting read urb, error %d\n", - __func__, result); - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_free); - continue; - } - - spin_lock_irqsave(&info->lock, flags); - list_add(tmp, &info->rx_urbs_submitted); - } - spin_unlock_irqrestore(&info->lock, flags); - - if (sent) - tty_flip_buffer_push(tty); -out: - tty_kref_put(tty); -} - -module_usb_serial_driver(whiteheat_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table_combined); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -1463,8 +919,5 @@ MODULE_LICENSE("GPL"); MODULE_FIRMWARE("whiteheat.fw"); MODULE_FIRMWARE("whiteheat_loader.fw"); -module_param(urb_pool_size, int, 0); -MODULE_PARM_DESC(urb_pool_size, "Number of urbs to use for buffering"); - module_param(debug, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(debug, "Debug enabled or not"); diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c index 9d0bb3752cd4..c043aa84a0ba 100644 --- a/drivers/usb/serial/zio.c +++ b/drivers/usb/serial/zio.c @@ -22,13 +22,6 @@ static const struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static struct usb_driver zio_driver = { - .name = "zio", - .probe = usb_serial_probe, - .disconnect = usb_serial_disconnect, - .id_table = id_table, -}; - static struct usb_serial_driver zio_device = { .driver = { .owner = THIS_MODULE, @@ -42,5 +35,5 @@ static struct usb_serial_driver * const serial_drivers[] = { &zio_device, NULL }; -module_usb_serial_driver(zio_driver, serial_drivers); +module_usb_serial_driver(serial_drivers, id_table); MODULE_LICENSE("GPL"); diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index e7e678109500..b28f2ad127d4 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -1933,11 +1933,7 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag) kfree(buf); nofw: - if (sd_fw != NULL) { - release_firmware(sd_fw); - sd_fw = NULL; - } - + release_firmware(sd_fw); return result; } diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 856ad92c40de..8f3cbb8dc81b 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -1885,6 +1885,13 @@ UNUSUAL_DEV( 0x1652, 0x6600, 0x0201, 0x0201, USB_SC_DEVICE, USB_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE ), +/* Reported by Jesse Feddema <jdfeddema@gmail.com> */ +UNUSUAL_DEV( 0x177f, 0x0400, 0x0000, 0x0000, + "Yarvik", + "PMP400", + USB_SC_DEVICE, USB_PR_DEVICE, NULL, + US_FL_BULK_IGNORE_TAG | US_FL_MAX_SECTORS_64 ), + /* Reported by Hans de Goede <hdegoede@redhat.com> * These Appotech controllers are found in Picture Frames, they provide a * (buggy) emulation of a cdrom drive which contains the windows software diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c index 2653e73db623..e23c30ab66da 100644 --- a/drivers/usb/storage/usb.c +++ b/drivers/usb/storage/usb.c @@ -121,7 +121,7 @@ MODULE_PARM_DESC(quirks, "supplemental list of device IDs and their quirks"); } static struct us_unusual_dev us_unusual_dev_list[] = { -# include "unusual_devs.h" +# include "unusual_devs.h" { } /* Terminating entry */ }; @@ -261,17 +261,17 @@ EXPORT_SYMBOL_GPL(usb_stor_post_reset); void fill_inquiry_response(struct us_data *us, unsigned char *data, unsigned int data_len) { - if (data_len<36) // You lose. + if (data_len < 36) /* You lose. */ return; memset(data+8, ' ', 28); - if(data[0]&0x20) { /* USB device currently not connected. Return + if (data[0]&0x20) { /* USB device currently not connected. Return peripheral qualifier 001b ("...however, the physical device is not currently connected to this logical unit") and leave vendor and product identification empty. ("If the target does store some of the INQUIRY data on the - device, it may return zeros or ASCII spaces + device, it may return zeros or ASCII spaces (20h) in those fields until the data is available from the device."). */ } else { @@ -298,7 +298,7 @@ static int usb_stor_control_thread(void * __us) struct us_data *us = (struct us_data *)__us; struct Scsi_Host *host = us_to_host(us); - for(;;) { + for (;;) { US_DEBUGP("*** thread sleeping.\n"); if (wait_for_completion_interruptible(&us->cmnd_ready)) break; @@ -327,7 +327,7 @@ static int usb_stor_control_thread(void * __us) scsi_unlock(host); - /* reject the command if the direction indicator + /* reject the command if the direction indicator * is UNKNOWN */ if (us->srb->sc_data_direction == DMA_BIDIRECTIONAL) { @@ -338,7 +338,7 @@ static int usb_stor_control_thread(void * __us) /* reject if target != 0 or if LUN is higher than * the maximum known LUN */ - else if (us->srb->device->id && + else if (us->srb->device->id && !(us->fflags & US_FL_SCM_MULT_TARG)) { US_DEBUGP("Bad target number (%d:%d)\n", us->srb->device->id, us->srb->device->lun); @@ -351,7 +351,7 @@ static int usb_stor_control_thread(void * __us) us->srb->result = DID_BAD_TARGET << 16; } - /* Handle those devices which need us to fake + /* Handle those devices which need us to fake * their inquiry data */ else if ((us->srb->cmnd[0] == INQUIRY) && (us->fflags & US_FL_FIX_INQUIRY)) { @@ -376,7 +376,7 @@ static int usb_stor_control_thread(void * __us) /* indicate that the command is done */ if (us->srb->result != DID_ABORT << 16) { - US_DEBUGP("scsi cmd done, result=0x%x\n", + US_DEBUGP("scsi cmd done, result=0x%x\n", us->srb->result); us->srb->scsi_done(us->srb); } else { @@ -414,7 +414,7 @@ SkipForAbort: } __set_current_state(TASK_RUNNING); return 0; -} +} /*********************************************************************** * Device probing and disconnecting @@ -732,7 +732,7 @@ static int get_pipes(struct us_data *us) us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0); us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev, usb_endpoint_num(ep_out)); - us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, + us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, usb_endpoint_num(ep_in)); if (ep_int) { us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev, diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c index b4a71679c933..0616f235bd6b 100644 --- a/drivers/usb/usb-skeleton.c +++ b/drivers/usb/usb-skeleton.c @@ -93,8 +93,8 @@ static int skel_open(struct inode *inode, struct file *file) interface = usb_find_interface(&skel_driver, subminor); if (!interface) { - err("%s - error, can't find device for minor %d", - __func__, subminor); + pr_err("%s - error, can't find device for minor %d\n", + __func__, subminor); retval = -ENODEV; goto exit; } @@ -179,8 +179,9 @@ static void skel_read_bulk_callback(struct urb *urb) if (!(urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) - err("%s - nonzero write bulk status received: %d", - __func__, urb->status); + dev_err(&dev->interface->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, urb->status); dev->errors = urb->status; } else { @@ -213,7 +214,8 @@ static int skel_do_read_io(struct usb_skel *dev, size_t count) /* do it */ rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL); if (rv < 0) { - err("%s - failed submitting read urb, error %d", + dev_err(&dev->interface->dev, + "%s - failed submitting read urb, error %d\n", __func__, rv); dev->bulk_in_filled = 0; rv = (rv == -ENOMEM) ? rv : -EIO; @@ -364,8 +366,9 @@ static void skel_write_bulk_callback(struct urb *urb) if (!(urb->status == -ENOENT || urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) - err("%s - nonzero write bulk status received: %d", - __func__, urb->status); + dev_err(&dev->interface->dev, + "%s - nonzero write bulk status received: %d\n", + __func__, urb->status); spin_lock(&dev->err_lock); dev->errors = urb->status; @@ -459,8 +462,9 @@ static ssize_t skel_write(struct file *file, const char *user_buffer, retval = usb_submit_urb(urb, GFP_KERNEL); mutex_unlock(&dev->io_mutex); if (retval) { - err("%s - failed submitting write urb, error %d", __func__, - retval); + dev_err(&dev->interface->dev, + "%s - failed submitting write urb, error %d\n", + __func__, retval); goto error_unanchor; } @@ -519,7 +523,7 @@ static int skel_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) { - err("Out of memory"); + dev_err(&interface->dev, "Out of memory\n"); goto error; } kref_init(&dev->kref); @@ -546,12 +550,14 @@ static int skel_probe(struct usb_interface *interface, dev->bulk_in_endpointAddr = endpoint->bEndpointAddress; dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); if (!dev->bulk_in_buffer) { - err("Could not allocate bulk_in_buffer"); + dev_err(&interface->dev, + "Could not allocate bulk_in_buffer\n"); goto error; } dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->bulk_in_urb) { - err("Could not allocate bulk_in_urb"); + dev_err(&interface->dev, + "Could not allocate bulk_in_urb\n"); goto error; } } @@ -563,7 +569,8 @@ static int skel_probe(struct usb_interface *interface, } } if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) { - err("Could not find both bulk-in and bulk-out endpoints"); + dev_err(&interface->dev, + "Could not find both bulk-in and bulk-out endpoints\n"); goto error; } @@ -574,7 +581,8 @@ static int skel_probe(struct usb_interface *interface, retval = usb_register_dev(interface, &skel_class); if (retval) { /* something prevented us from registering this driver */ - err("Not able to get a minor for this device."); + dev_err(&interface->dev, + "Not able to get a minor for this device.\n"); usb_set_intfdata(interface, NULL); goto error; } |