diff options
Diffstat (limited to 'drivers')
101 files changed, 1679 insertions, 6990 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig index a871a988829d..7f33bcc315f2 100644 --- a/drivers/usb/Kconfig +++ b/drivers/usb/Kconfig @@ -133,35 +133,6 @@ comment "USB port drivers" if USB -config USB_USS720 - tristate "USS720 parport driver" - depends on PARPORT - select PARPORT_NOT_PC - help - This driver is for USB parallel port adapters that use the Lucent - Technologies USS-720 chip. These cables are plugged into your USB - port and provide USB compatibility to peripherals designed with - parallel port interfaces. - - The chip has two modes: automatic mode and manual mode. In automatic - mode, it looks to the computer like a standard USB printer. Only - printers may be connected to the USS-720 in this mode. The generic - USB printer driver ("USB Printer support", above) may be used in - that mode, and you can say N here if you want to use the chip only - in this mode. - - Manual mode is not limited to printers, any parallel port - device should work. This driver utilizes manual mode. - Note however that some operations are three orders of magnitude - slower than on a PCI/ISA Parallel Port, so timing critical - applications might not work. - - Say Y here if you own an USS-720 USB->Parport cable and intend to - connect anything other than a printer to it. - - To compile this driver as a module, choose M here: the - module will be called uss720. - source "drivers/usb/serial/Kconfig" source "drivers/usb/misc/Kconfig" diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile index a81e6ef293af..3a9a0dd4be70 100644 --- a/drivers/usb/Makefile +++ b/drivers/usb/Makefile @@ -31,7 +31,6 @@ obj-$(CONFIG_USB_FHCI_HCD) += host/ obj-$(CONFIG_USB_XHCI_HCD) += host/ obj-$(CONFIG_USB_SL811_HCD) += host/ obj-$(CONFIG_USB_ISP1362_HCD) += host/ -obj-$(CONFIG_USB_U132_HCD) += host/ obj-$(CONFIG_USB_R8A66597_HCD) += host/ obj-$(CONFIG_USB_FSL_USB2) += host/ obj-$(CONFIG_USB_FOTG210_HCD) += host/ diff --git a/drivers/usb/cdns3/cdns3-debug.h b/drivers/usb/cdns3/cdns3-debug.h index a5c6a29e1340..4618cfe85a4f 100644 --- a/drivers/usb/cdns3/cdns3-debug.h +++ b/drivers/usb/cdns3/cdns3-debug.h @@ -107,8 +107,7 @@ static inline char *cdns3_decode_ep0_irq(char *str, * Prints out all TRBs in the endpoint ring, even those after the Link TRB. *. */ -static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, - struct cdns3_trb *ring, char *str) +static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, char *str) { dma_addr_t addr = priv_ep->trb_pool_dma; struct cdns3_trb *trb; @@ -136,9 +135,6 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, "\t\tfree trbs: %d, CCS=%d, PCS=%d\n", priv_ep->free_trbs, priv_ep->ccs, priv_ep->pcs); - if (trb_per_sector > TRBS_PER_SEGMENT) - trb_per_sector = TRBS_PER_SEGMENT; - if (trb_per_sector > TRBS_PER_SEGMENT) { sprintf(str + ret, "\t\tTransfer ring %d too big\n", trb_per_sector); @@ -146,7 +142,7 @@ static inline char *cdns3_dbg_ring(struct cdns3_endpoint *priv_ep, } for (i = 0; i < trb_per_sector; ++i) { - trb = &ring[i]; + trb = &priv_ep->trb_pool[i]; ret += sprintf(str + ret, "\t\t@%pad %08x %08x %08x\n", &addr, le32_to_cpu(trb->buffer), diff --git a/drivers/usb/cdns3/cdns3-trace.h b/drivers/usb/cdns3/cdns3-trace.h index 7574b4a62813..40db89e3333c 100644 --- a/drivers/usb/cdns3/cdns3-trace.h +++ b/drivers/usb/cdns3/cdns3-trace.h @@ -100,13 +100,12 @@ DECLARE_EVENT_CLASS(cdns3_log_usb_irq, TP_STRUCT__entry( __field(enum usb_device_speed, speed) __field(u32, usb_ists) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __entry->speed = cdns3_get_speed(priv_dev); __entry->usb_ists = usb_ists; ), - TP_printk("%s", cdns3_decode_usb_irq(__get_str(str), __entry->speed, + TP_printk("%s", cdns3_decode_usb_irq(__get_buf(CDNS3_MSG_MAX), __entry->speed, __entry->usb_ists)) ); @@ -124,7 +123,6 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq, __field(u32, ep_traddr) __field(u32, ep_last_sid) __field(u32, use_streams) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __assign_str(ep_name, priv_ep->name); @@ -134,7 +132,7 @@ DECLARE_EVENT_CLASS(cdns3_log_epx_irq, __entry->use_streams = priv_ep->use_streams; ), TP_printk("%s, ep_traddr: %08x ep_last_sid: %08x use_streams: %d", - cdns3_decode_epx_irq(__get_str(str), + cdns3_decode_epx_irq(__get_buf(CDNS3_MSG_MAX), __get_str(ep_name), __entry->ep_sts), __entry->ep_traddr, @@ -153,13 +151,12 @@ DECLARE_EVENT_CLASS(cdns3_log_ep0_irq, TP_STRUCT__entry( __field(int, ep_dir) __field(u32, ep_sts) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __entry->ep_dir = priv_dev->selected_ep; __entry->ep_sts = ep_sts; ), - TP_printk("%s", cdns3_decode_ep0_irq(__get_str(str), + TP_printk("%s", cdns3_decode_ep0_irq(__get_buf(CDNS3_MSG_MAX), __entry->ep_dir, __entry->ep_sts)) ); @@ -178,7 +175,6 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl, __field(u16, wValue) __field(u16, wIndex) __field(u16, wLength) - __dynamic_array(char, str, CDNS3_MSG_MAX) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; @@ -187,7 +183,7 @@ DECLARE_EVENT_CLASS(cdns3_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNS3_MSG_MAX, + TP_printk("%s", usb_decode_ctrl(__get_buf(CDNS3_MSG_MAX), CDNS3_MSG_MAX, __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) @@ -438,22 +434,16 @@ DECLARE_EVENT_CLASS(cdns3_log_ring, TP_PROTO(struct cdns3_endpoint *priv_ep), TP_ARGS(priv_ep), TP_STRUCT__entry( - __dynamic_array(u8, ring, TRB_RING_SIZE) - __dynamic_array(u8, priv_ep, sizeof(struct cdns3_endpoint)) __dynamic_array(char, buffer, - (TRBS_PER_SEGMENT * 65) + CDNS3_MSG_MAX) + GET_TRBS_PER_SEGMENT(priv_ep->type) > TRBS_PER_SEGMENT ? + CDNS3_MSG_MAX : + (GET_TRBS_PER_SEGMENT(priv_ep->type) * 65) + CDNS3_MSG_MAX) ), TP_fast_assign( - memcpy(__get_dynamic_array(priv_ep), priv_ep, - sizeof(struct cdns3_endpoint)); - memcpy(__get_dynamic_array(ring), priv_ep->trb_pool, - TRB_RING_SIZE); + cdns3_dbg_ring(priv_ep, __get_str(buffer)); ), - TP_printk("%s", - cdns3_dbg_ring((struct cdns3_endpoint *)__get_str(priv_ep), - (struct cdns3_trb *)__get_str(ring), - __get_str(buffer))) + TP_printk("%s", __get_str(buffer)) ); DEFINE_EVENT(cdns3_log_ring, cdns3_ring, diff --git a/drivers/usb/cdns3/cdnsp-trace.h b/drivers/usb/cdns3/cdnsp-trace.h index 5983dfb99653..4b51011eb00b 100644 --- a/drivers/usb/cdns3/cdnsp-trace.h +++ b/drivers/usb/cdns3/cdnsp-trace.h @@ -271,7 +271,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl, __field(u16, wValue) __field(u16, wIndex) __field(u16, wLength) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; @@ -280,7 +279,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", usb_decode_ctrl(__get_str(str), CDNSP_MSG_MAX, + TP_printk("%s", usb_decode_ctrl(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) @@ -345,7 +344,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb, __field(u32, field3) __field(union cdnsp_trb *, trb) __field(dma_addr_t, trb_dma) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->type = ring->type; @@ -359,7 +357,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_trb, ), TP_printk("%s: %s trb: %p(%pad)", cdnsp_ring_type_string(__entry->type), - cdnsp_decode_trb(__get_str(str), CDNSP_MSG_MAX, + cdnsp_decode_trb(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->field0, __entry->field1, __entry->field2, __entry->field3), __entry->trb, &__entry->trb_dma @@ -544,7 +542,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx, __field(u32, info2) __field(u64, deq) __field(u32, tx_info) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->ep_info); @@ -552,7 +549,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_ep_ctx, __entry->deq = le64_to_cpu(ctx->deq); __entry->tx_info = le32_to_cpu(ctx->tx_info); ), - TP_printk("%s", cdnsp_decode_ep_context(__get_str(str), CDNSP_MSG_MAX, + TP_printk("%s", cdnsp_decode_ep_context(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->info, __entry->info2, __entry->deq, __entry->tx_info) ) @@ -777,7 +774,6 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc, TP_STRUCT__entry( __field(u32, portnum) __field(u32, portsc) - __dynamic_array(char, str, CDNSP_MSG_MAX) ), TP_fast_assign( __entry->portnum = portnum; @@ -785,7 +781,7 @@ DECLARE_EVENT_CLASS(cdnsp_log_portsc, ), TP_printk("port-%d: %s", __entry->portnum, - cdnsp_decode_portsc(__get_str(str), CDNSP_MSG_MAX, + cdnsp_decode_portsc(__get_buf(CDNSP_MSG_MAX), CDNSP_MSG_MAX, __entry->portsc) ) ); diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile index 6f4a3deced35..71afeab97e83 100644 --- a/drivers/usb/chipidea/Makefile +++ b/drivers/usb/chipidea/Makefile @@ -14,5 +14,5 @@ ci_hdrc-$(CONFIG_USB_OTG_FSM) += otg_fsm.o obj-$(CONFIG_USB_CHIPIDEA_GENERIC) += ci_hdrc_usb2.o obj-$(CONFIG_USB_CHIPIDEA_MSM) += ci_hdrc_msm.o obj-$(CONFIG_USB_CHIPIDEA_PCI) += ci_hdrc_pci.o -obj-$(CONFIG_USB_CHIPIDEA_IMX) += ci_hdrc_imx.o usbmisc_imx.o +obj-$(CONFIG_USB_CHIPIDEA_IMX) += usbmisc_imx.o ci_hdrc_imx.o obj-$(CONFIG_USB_CHIPIDEA_TEGRA) += ci_hdrc_tegra.o diff --git a/drivers/usb/chipidea/ci_hdrc_imx.c b/drivers/usb/chipidea/ci_hdrc_imx.c index 2eeccf4ec9d6..2855ac303001 100644 --- a/drivers/usb/chipidea/ci_hdrc_imx.c +++ b/drivers/usb/chipidea/ci_hdrc_imx.c @@ -152,12 +152,12 @@ static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev) * Check the various over current related properties. If over current * detection is disabled we're not interested in the polarity. */ - if (of_find_property(np, "disable-over-current", NULL)) { + if (of_property_read_bool(np, "disable-over-current")) { data->disable_oc = 1; - } else if (of_find_property(np, "over-current-active-high", NULL)) { + } else if (of_property_read_bool(np, "over-current-active-high")) { data->oc_pol_active_low = 0; data->oc_pol_configured = 1; - } else if (of_find_property(np, "over-current-active-low", NULL)) { + } else if (of_property_read_bool(np, "over-current-active-low")) { data->oc_pol_active_low = 1; data->oc_pol_configured = 1; } else { diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index 281fc51720ce..d1d252c87e4f 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -753,7 +753,7 @@ static int ci_get_platdata(struct device *dev, return ret; } - if (of_find_property(dev->of_node, "non-zero-ttctrl-ttha", NULL)) + if (of_property_read_bool(dev->of_node, "non-zero-ttctrl-ttha")) platdata->flags |= CI_HDRC_SET_NON_ZERO_TTHA; ext_id = ERR_PTR(-ENODEV); diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index bbc610e5bd69..e72c43615d77 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -247,60 +247,6 @@ static int ci_otg_show(struct seq_file *s, void *unused) } DEFINE_SHOW_ATTRIBUTE(ci_otg); -static int ci_role_show(struct seq_file *s, void *data) -{ - struct ci_hdrc *ci = s->private; - - if (ci->role != CI_ROLE_END) - seq_printf(s, "%s\n", ci_role(ci)->name); - - return 0; -} - -static ssize_t ci_role_write(struct file *file, const char __user *ubuf, - size_t count, loff_t *ppos) -{ - struct seq_file *s = file->private_data; - struct ci_hdrc *ci = s->private; - enum ci_role role; - char buf[8]; - int ret; - - if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count))) - return -EFAULT; - - for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++) - if (ci->roles[role] && - !strncmp(buf, ci->roles[role]->name, - strlen(ci->roles[role]->name))) - break; - - if (role == CI_ROLE_END || role == ci->role) - return -EINVAL; - - pm_runtime_get_sync(ci->dev); - disable_irq(ci->irq); - ci_role_stop(ci); - ret = ci_role_start(ci, role); - enable_irq(ci->irq); - pm_runtime_put_sync(ci->dev); - - return ret ? ret : count; -} - -static int ci_role_open(struct inode *inode, struct file *file) -{ - return single_open(file, ci_role_show, inode->i_private); -} - -static const struct file_operations ci_role_fops = { - .open = ci_role_open, - .write = ci_role_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - static int ci_registers_show(struct seq_file *s, void *unused) { struct ci_hdrc *ci = s->private; @@ -354,7 +300,6 @@ void dbg_create_files(struct ci_hdrc *ci) if (ci_otg_is_fsm_mode(ci)) debugfs_create_file("otg", S_IRUGO, dir, ci, &ci_otg_fops); - debugfs_create_file("role", S_IRUGO | S_IWUSR, dir, ci, &ci_role_fops); debugfs_create_file("registers", S_IRUGO, dir, ci, &ci_registers_fops); } diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 533baa85083c..a34b22537d7c 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -81,15 +81,11 @@ int usb_acpi_port_lpm_incapable(struct usb_device *hdev, int index) return -ENODEV; } - obj = acpi_evaluate_dsm(port_handle, &guid, 0, - USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL); - - if (!obj) - return -ENODEV; - - if (obj->type != ACPI_TYPE_INTEGER) { + obj = acpi_evaluate_dsm_typed(port_handle, &guid, 0, + USB_DSM_DISABLE_U1_U2_FOR_PORT, NULL, + ACPI_TYPE_INTEGER); + if (!obj) { dev_dbg(&hdev->dev, "evaluate port-%d _DSM failed\n", port1); - ACPI_FREE(obj); return -EINVAL; } diff --git a/drivers/usb/dwc2/hcd_queue.c b/drivers/usb/dwc2/hcd_queue.c index 0a1145592fc7..0d4495c6b9f7 100644 --- a/drivers/usb/dwc2/hcd_queue.c +++ b/drivers/usb/dwc2/hcd_queue.c @@ -1078,7 +1078,7 @@ static void dwc2_pick_first_frame(struct dwc2_hsotg *hsotg, struct dwc2_qh *qh) earliest_frame = dwc2_frame_num_inc(frame_number, 1); next_active_frame = earliest_frame; - /* Get the "no microframe schduler" out of the way... */ + /* Get the "no microframe scheduler" out of the way... */ if (!hsotg->params.uframe_sched) { if (qh->do_split) /* Splits are active at microframe 0 minus 1 */ diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c index 9ed9fd956940..21d16533bd2f 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c @@ -508,8 +508,7 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) of_usb_update_otg_caps(hsotg->dev->of_node, &p->otg_caps); } - if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL)) - p->oc_disable = true; + p->oc_disable = of_property_read_bool(hsotg->dev->of_node, "disable-over-current"); } static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 476b63618511..ed0ab90d3fac 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -800,6 +800,16 @@ static int dwc3_phy_setup(struct dwc3 *dwc) if (dwc->dis_u2_freeclk_exists_quirk || dwc->gfladj_refclk_lpm_sel) reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS; + /* + * Some ULPI USB PHY does not support internal VBUS supply, to drive + * the CPEN pin requires the configuration of the ULPI DRVVBUSEXTERNAL + * bit of OTG_CTRL register. Controller configures the USB2 PHY + * ULPIEXTVBUSDRV bit[17] of the GUSB2PHYCFG register to drive vBus + * with an external supply. + */ + if (dwc->ulpi_ext_vbus_drv) + reg |= DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV; + dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg); return 0; @@ -1553,6 +1563,8 @@ static void dwc3_get_properties(struct dwc3 *dwc) "snps,dis-tx-ipgap-linecheck-quirk"); dwc->resume_hs_terminations = device_property_read_bool(dev, "snps,resume-hs-terminations"); + dwc->ulpi_ext_vbus_drv = device_property_read_bool(dev, + "snps,ulpi-ext-vbus-drv"); dwc->parkmode_disable_ss_quirk = device_property_read_bool(dev, "snps,parkmode-disable-ss-quirk"); dwc->gfladj_refclk_lpm_sel = device_property_read_bool(dev, diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 4743e918dcaf..26c8efefbff9 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -280,6 +280,7 @@ /* Global USB2 PHY Configuration Register */ #define DWC3_GUSB2PHYCFG_PHYSOFTRST BIT(31) #define DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS BIT(30) +#define DWC3_GUSB2PHYCFG_ULPIEXTVBUSDRV BIT(17) #define DWC3_GUSB2PHYCFG_SUSPHY BIT(6) #define DWC3_GUSB2PHYCFG_ULPI_UTMI BIT(4) #define DWC3_GUSB2PHYCFG_ENBLSLPM BIT(8) @@ -526,6 +527,7 @@ #define DWC3_DGCMD_SET_ENDPOINT_NRDY 0x0c #define DWC3_DGCMD_SET_ENDPOINT_PRIME 0x0d #define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK 0x10 +#define DWC3_DGCMD_DEV_NOTIFICATION 0x07 #define DWC3_DGCMD_STATUS(n) (((n) >> 12) & 0x0F) #define DWC3_DGCMD_CMDACT BIT(10) @@ -538,6 +540,8 @@ #define DWC3_DGCMDPAR_TX_FIFO BIT(5) #define DWC3_DGCMDPAR_LOOPBACK_DIS (0 << 0) #define DWC3_DGCMDPAR_LOOPBACK_ENA BIT(0) +#define DWC3_DGCMDPAR_DN_FUNC_WAKE BIT(0) +#define DWC3_DGCMDPAR_INTF_SEL(n) ((n) << 4) /* Device Endpoint Command Register */ #define DWC3_DEPCMD_PARAM_SHIFT 16 @@ -1100,6 +1104,8 @@ struct dwc3_scratchpad_array { * check during HS transmit. * @resume_hs_terminations: Set if we enable quirk for fixing improper crc * generation after resume from suspend. + * @ulpi_ext_vbus_drv: Set to confiure the upli chip to drives CPEN pin + * VBUS with an external supply. * @parkmode_disable_ss_quirk: set if we need to disable all SuperSpeed * instances in park mode. * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk @@ -1110,6 +1116,7 @@ struct dwc3_scratchpad_array { * 3 - Reserved * @dis_metastability_quirk: set to disable metastability quirk. * @dis_split_quirk: set to disable split boundary. + * @wakeup_configured: set if the device is configured for remote wakeup. * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @max_cfg_eps: current max number of IN eps used across all USB configs. @@ -1317,6 +1324,7 @@ struct dwc3 { unsigned dis_del_phy_power_chg_quirk:1; unsigned dis_tx_ipgap_linecheck_quirk:1; unsigned resume_hs_terminations:1; + unsigned ulpi_ext_vbus_drv:1; unsigned parkmode_disable_ss_quirk:1; unsigned gfladj_refclk_lpm_sel:1; @@ -1327,6 +1335,7 @@ struct dwc3 { unsigned dis_split_quirk:1; unsigned async_callbacks:1; + unsigned wakeup_configured:1; u16 imod_interval; diff --git a/drivers/usb/dwc3/debug.h b/drivers/usb/dwc3/debug.h index 8bb2c9e3b9ac..09d703852a92 100644 --- a/drivers/usb/dwc3/debug.h +++ b/drivers/usb/dwc3/debug.h @@ -72,6 +72,8 @@ dwc3_gadget_generic_cmd_string(u8 cmd) return "Set Endpoint Prime"; case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: return "Run SoC Bus Loopback Test"; + case DWC3_DGCMD_DEV_NOTIFICATION: + return "Device Notification"; default: return "UNKNOWN"; } diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 850df0e6bcab..e4a2560b9dc0 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -88,6 +88,9 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GPRTBIMAP_HS1), dump_register(GPRTBIMAP_FS0), dump_register(GPRTBIMAP_FS1), + dump_register(GUCTL2), + dump_register(VER_NUMBER), + dump_register(VER_TYPE), dump_register(GUSB2PHYCFG(0)), dump_register(GUSB2PHYCFG(1)), @@ -229,6 +232,8 @@ static const struct debugfs_reg32 dwc3_regs[] = { dump_register(GEVNTCOUNT(0)), dump_register(GHWPARAMS8), + dump_register(GUCTL3), + dump_register(GFLADJ), dump_register(DCFG), dump_register(DCTL), dump_register(DEVTEN), diff --git a/drivers/usb/dwc3/dwc3-am62.c b/drivers/usb/dwc3/dwc3-am62.c index 173cf3579c55..b22fb78bc8e7 100644 --- a/drivers/usb/dwc3/dwc3-am62.c +++ b/drivers/usb/dwc3/dwc3-am62.c @@ -17,6 +17,8 @@ #include <linux/regmap.h> #include <linux/pinctrl/consumer.h> +#include "core.h" + /* USB WRAPPER register offsets */ #define USBSS_PID 0x0 #define USBSS_OVERCURRENT_CTRL 0x4 @@ -45,6 +47,10 @@ #define USBSS_PHY_VBUS_SEL_SHIFT 1 #define USBSS_PHY_LANE_REVERSE BIT(0) +/* CORE STAT register bits */ +#define USBSS_CORE_OPERATIONAL_MODE_MASK GENMASK(13, 12) +#define USBSS_CORE_OPERATIONAL_MODE_SHIFT 12 + /* MODE CONTROL register bits */ #define USBSS_MODE_VALID BIT(0) @@ -54,6 +60,13 @@ #define USBSS_WAKEUP_CFG_SESSVALID_EN BIT(1) #define USBSS_WAKEUP_CFG_VBUSVALID_EN BIT(0) +#define USBSS_WAKEUP_CFG_ALL (USBSS_WAKEUP_CFG_VBUSVALID_EN | \ + USBSS_WAKEUP_CFG_SESSVALID_EN | \ + USBSS_WAKEUP_CFG_LINESTATE_EN | \ + USBSS_WAKEUP_CFG_OVERCURRENT_EN) + +#define USBSS_WAKEUP_CFG_NONE 0 + /* WAKEUP STAT register bits */ #define USBSS_WAKEUP_STAT_OVERCURRENT BIT(4) #define USBSS_WAKEUP_STAT_LINESTATE BIT(3) @@ -97,6 +110,7 @@ struct dwc3_data { struct regmap *syscon; unsigned int offset; unsigned int vbus_divider; + u32 wakeup_stat; }; static const int dwc3_ti_rate_table[] = { /* in KHZ */ @@ -233,6 +247,12 @@ static int dwc3_ti_probe(struct platform_device *pdev) reg |= USBSS_MODE_VALID; dwc3_ti_writel(data, USBSS_MODE_CONTROL, reg); + /* Device has capability to wakeup system from sleep */ + device_set_wakeup_capable(dev, true); + ret = device_wakeup_enable(dev); + if (ret) + dev_err(dev, "couldn't enable device as a wakeup source: %d\n", ret); + /* Setting up autosuspend */ pm_runtime_set_autosuspend_delay(dev, DWC3_AM62_AUTOSUSPEND_DELAY); pm_runtime_use_autosuspend(dev); @@ -281,6 +301,27 @@ static int dwc3_ti_remove(struct platform_device *pdev) static int dwc3_ti_suspend_common(struct device *dev) { struct dwc3_data *data = dev_get_drvdata(dev); + u32 reg, current_prtcap_dir; + + if (device_may_wakeup(dev)) { + reg = dwc3_ti_readl(data, USBSS_CORE_STAT); + current_prtcap_dir = (reg & USBSS_CORE_OPERATIONAL_MODE_MASK) + >> USBSS_CORE_OPERATIONAL_MODE_SHIFT; + /* Set wakeup config enable bits */ + reg = dwc3_ti_readl(data, USBSS_WAKEUP_CONFIG); + if (current_prtcap_dir == DWC3_GCTL_PRTCAP_HOST) { + reg = USBSS_WAKEUP_CFG_LINESTATE_EN | USBSS_WAKEUP_CFG_OVERCURRENT_EN; + } else { + reg = USBSS_WAKEUP_CFG_VBUSVALID_EN | USBSS_WAKEUP_CFG_SESSVALID_EN; + /* + * Enable LINESTATE wake up only if connected to bus + * and in U2/L3 state else it causes spurious wake-up. + */ + } + dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, reg); + /* clear wakeup status so we know what caused the wake up */ + dwc3_ti_writel(data, USBSS_WAKEUP_STAT, USBSS_WAKEUP_STAT_CLR); + } clk_disable_unprepare(data->usb2_refclk); @@ -290,9 +331,18 @@ static int dwc3_ti_suspend_common(struct device *dev) static int dwc3_ti_resume_common(struct device *dev) { struct dwc3_data *data = dev_get_drvdata(dev); + u32 reg; clk_prepare_enable(data->usb2_refclk); + if (device_may_wakeup(dev)) { + /* Clear wakeup config enable bits */ + dwc3_ti_writel(data, USBSS_WAKEUP_CONFIG, USBSS_WAKEUP_CFG_NONE); + } + + reg = dwc3_ti_readl(data, USBSS_WAKEUP_STAT); + data->wakeup_stat = reg; + return 0; } diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 560793545362..44a04c9b2073 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -388,107 +388,41 @@ static void dwc3_pci_remove(struct pci_dev *pci) } static const struct pci_device_id dwc3_pci_id_table[] = { - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BSW), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BYT), - (kernel_ulong_t) &dwc3_pci_intel_byt_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MRFLD), - (kernel_ulong_t) &dwc3_pci_intel_mrfld_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CMLH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SPTH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_BXT_M), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_APL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_KBP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_GLK), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CNPV), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ICLLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_EHL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGPH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_JSP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADL_PCH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLN_PCH), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_ADLS), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_RPLS), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLM), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLP), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTLS), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_MTL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_TGL), - (kernel_ulong_t) &dwc3_pci_intel_swnode, }, - - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_NL_USB), - (kernel_ulong_t) &dwc3_pci_amd_swnode, }, - - { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MR), - (kernel_ulong_t)&dwc3_pci_amd_mr_swnode, }, + { PCI_DEVICE_DATA(INTEL, BSW, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BYT, &dwc3_pci_intel_byt_swnode) }, + { PCI_DEVICE_DATA(INTEL, MRFLD, &dwc3_pci_intel_mrfld_swnode) }, + { PCI_DEVICE_DATA(INTEL, CMLLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CMLH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, SPTLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, SPTH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BXT, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BXT_M, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, APL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, KBP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, GLK, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, CNPV, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ICLLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, EHL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, TGPLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, TGPH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, JSP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADL_PCH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADLN, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADLN_PCH, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, ADLS, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, RPL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, RPLS, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTLM, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTLP, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, MTLS, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, TGL, &dwc3_pci_intel_swnode) }, + + { PCI_DEVICE_DATA(AMD, NL_USB, &dwc3_pci_amd_swnode) }, + { PCI_DEVICE_DATA(AMD, MR, &dwc3_pci_amd_mr_swnode) }, { } /* Terminating Entry */ }; diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 61de693461da..953b752a5052 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -30,6 +30,8 @@ static void __dwc3_ep0_do_control_status(struct dwc3 *dwc, struct dwc3_ep *dep); static void __dwc3_ep0_do_control_data(struct dwc3 *dwc, struct dwc3_ep *dep, struct dwc3_request *req); +static int dwc3_ep0_delegate_req(struct dwc3 *dwc, + struct usb_ctrlrequest *ctrl); static void dwc3_ep0_prepare_one_trb(struct dwc3_ep *dep, dma_addr_t buf_dma, u32 len, u32 type, bool chain) @@ -356,6 +358,9 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, usb_status |= 1 << USB_DEV_STAT_U1_ENABLED; if (reg & DWC3_DCTL_INITU2ENA) usb_status |= 1 << USB_DEV_STAT_U2_ENABLED; + } else { + usb_status |= dwc->gadget->wakeup_armed << + USB_DEVICE_REMOTE_WAKEUP; } break; @@ -365,7 +370,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, * Function Remote Wake Capable D0 * Function Remote Wakeup D1 */ - break; + return dwc3_ep0_delegate_req(dwc, ctrl); case USB_RECIP_ENDPOINT: dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); @@ -476,6 +481,10 @@ static int dwc3_ep0_handle_device(struct dwc3 *dwc, switch (wValue) { case USB_DEVICE_REMOTE_WAKEUP: + if (dwc->wakeup_configured) + dwc->gadget->wakeup_armed = set; + else + ret = -EINVAL; break; /* * 9.4.1 says only for SS, in AddressState only for @@ -510,13 +519,7 @@ static int dwc3_ep0_handle_intf(struct dwc3 *dwc, switch (wValue) { case USB_INTRF_FUNC_SUSPEND: - /* - * REVISIT: Ideally we would enable some low power mode here, - * however it's unclear what we should be doing here. - * - * For now, we're not doing anything, just making sure we return - * 0 so USB Command Verifier tests pass without any errors. - */ + ret = dwc3_ep0_delegate_req(dwc, ctrl); break; default: ret = -EINVAL; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index cf5b4f49c3ed..287ea6ee2463 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -258,7 +258,7 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned int cmd, return ret; } -static int __dwc3_gadget_wakeup(struct dwc3 *dwc); +static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async); /** * dwc3_send_gadget_ep_cmd - issue an endpoint command @@ -325,7 +325,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3_ep *dep, unsigned int cmd, fallthrough; case DWC3_LINK_STATE_U3: - ret = __dwc3_gadget_wakeup(dwc); + ret = __dwc3_gadget_wakeup(dwc, false); dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n", ret); break; @@ -2273,6 +2273,22 @@ static const struct usb_ep_ops dwc3_gadget_ep_ops = { /* -------------------------------------------------------------------------- */ +static void dwc3_gadget_enable_linksts_evts(struct dwc3 *dwc, bool set) +{ + u32 reg; + + if (DWC3_VER_IS_PRIOR(DWC3, 250A)) + return; + + reg = dwc3_readl(dwc->regs, DWC3_DEVTEN); + if (set) + reg |= DWC3_DEVTEN_ULSTCNGEN; + else + reg &= ~DWC3_DEVTEN_ULSTCNGEN; + + dwc3_writel(dwc->regs, DWC3_DEVTEN, reg); +} + static int dwc3_gadget_get_frame(struct usb_gadget *g) { struct dwc3 *dwc = gadget_to_dwc(g); @@ -2280,7 +2296,7 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g) return __dwc3_gadget_get_frame(dwc); } -static int __dwc3_gadget_wakeup(struct dwc3 *dwc) +static int __dwc3_gadget_wakeup(struct dwc3 *dwc, bool async) { int retries; @@ -2311,9 +2327,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) return -EINVAL; } + if (async) + dwc3_gadget_enable_linksts_evts(dwc, true); + ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV); if (ret < 0) { dev_err(dwc->dev, "failed to put link in Recovery\n"); + dwc3_gadget_enable_linksts_evts(dwc, false); return ret; } @@ -2325,6 +2345,13 @@ static int __dwc3_gadget_wakeup(struct dwc3 *dwc) dwc3_writel(dwc->regs, DWC3_DCTL, reg); } + /* + * Since link status change events are enabled we will receive + * an U0 event when wakeup is successful. So bail out. + */ + if (async) + return 0; + /* poll until Link State changes to ON */ retries = 20000; @@ -2350,13 +2377,77 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) unsigned long flags; int ret; + if (!dwc->wakeup_configured) { + dev_err(dwc->dev, "remote wakeup not configured\n"); + return -EINVAL; + } + + spin_lock_irqsave(&dwc->lock, flags); + if (!dwc->gadget->wakeup_armed) { + dev_err(dwc->dev, "not armed for remote wakeup\n"); + spin_unlock_irqrestore(&dwc->lock, flags); + return -EINVAL; + } + ret = __dwc3_gadget_wakeup(dwc, true); + + spin_unlock_irqrestore(&dwc->lock, flags); + + return ret; +} + +static void dwc3_resume_gadget(struct dwc3 *dwc); + +static int dwc3_gadget_func_wakeup(struct usb_gadget *g, int intf_id) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + int ret; + int link_state; + + if (!dwc->wakeup_configured) { + dev_err(dwc->dev, "remote wakeup not configured\n"); + return -EINVAL; + } + spin_lock_irqsave(&dwc->lock, flags); - ret = __dwc3_gadget_wakeup(dwc); + /* + * If the link is in U3, signal for remote wakeup and wait for the + * link to transition to U0 before sending device notification. + */ + link_state = dwc3_gadget_get_link_state(dwc); + if (link_state == DWC3_LINK_STATE_U3) { + ret = __dwc3_gadget_wakeup(dwc, false); + if (ret) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -EINVAL; + } + dwc3_resume_gadget(dwc); + dwc->link_state = DWC3_LINK_STATE_U0; + } + + ret = dwc3_send_gadget_generic_command(dwc, DWC3_DGCMD_DEV_NOTIFICATION, + DWC3_DGCMDPAR_DN_FUNC_WAKE | + DWC3_DGCMDPAR_INTF_SEL(intf_id)); + if (ret) + dev_err(dwc->dev, "function remote wakeup failed, ret:%d\n", ret); + spin_unlock_irqrestore(&dwc->lock, flags); return ret; } +static int dwc3_gadget_set_remote_wakeup(struct usb_gadget *g, int set) +{ + struct dwc3 *dwc = gadget_to_dwc(g); + unsigned long flags; + + spin_lock_irqsave(&dwc->lock, flags); + dwc->wakeup_configured = !!set; + spin_unlock_irqrestore(&dwc->lock, flags); + + return 0; +} + static int dwc3_gadget_set_selfpowered(struct usb_gadget *g, int is_selfpowered) { @@ -2982,6 +3073,8 @@ static void dwc3_gadget_async_callbacks(struct usb_gadget *g, bool enable) static const struct usb_gadget_ops dwc3_gadget_ops = { .get_frame = dwc3_gadget_get_frame, .wakeup = dwc3_gadget_wakeup, + .func_wakeup = dwc3_gadget_func_wakeup, + .set_remote_wakeup = dwc3_gadget_set_remote_wakeup, .set_selfpowered = dwc3_gadget_set_selfpowered, .pullup = dwc3_gadget_pullup, .udc_start = dwc3_gadget_start, @@ -3827,6 +3920,8 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc) dwc->gadget->speed = USB_SPEED_UNKNOWN; dwc->setup_packet_pending = false; + dwc->gadget->wakeup_armed = false; + dwc3_gadget_enable_linksts_evts(dwc, false); usb_gadget_set_state(dwc->gadget, USB_STATE_NOTATTACHED); if (dwc->ep0state != EP0_SETUP_PHASE) { @@ -3920,6 +4015,8 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc) reg &= ~DWC3_DCTL_TSTCTRL_MASK; dwc3_gadget_dctl_write_safe(dwc, reg); dwc->test_mode = false; + dwc->gadget->wakeup_armed = false; + dwc3_gadget_enable_linksts_evts(dwc, false); dwc3_clear_stall_all_ep(dwc); /* Reset device address to zero */ @@ -4072,7 +4169,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) */ } -static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) +static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc, unsigned int evtinfo) { /* * TODO take core out of low power mode when that's @@ -4084,6 +4181,8 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) dwc->gadget_driver->resume(dwc->gadget); spin_lock(&dwc->lock); } + + dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK; } static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, @@ -4165,6 +4264,12 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, } switch (next) { + case DWC3_LINK_STATE_U0: + if (dwc->gadget->wakeup_armed) { + dwc3_gadget_enable_linksts_evts(dwc, false); + dwc3_resume_gadget(dwc); + } + break; case DWC3_LINK_STATE_U1: if (dwc->speed == USB_SPEED_SUPER) dwc3_suspend_gadget(dwc); @@ -4233,7 +4338,7 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, dwc3_gadget_conndone_interrupt(dwc); break; case DWC3_DEVICE_EVENT_WAKEUP: - dwc3_gadget_wakeup_interrupt(dwc); + dwc3_gadget_wakeup_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_HIBER_REQ: if (dev_WARN_ONCE(dwc->dev, !dwc->has_hibernation, @@ -4247,15 +4352,8 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc, break; case DWC3_DEVICE_EVENT_SUSPEND: /* It changed to be suspend event for version 2.30a and above */ - if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) { - /* - * Ignore suspend event until the gadget enters into - * USB_STATE_CONFIGURED state. - */ - if (dwc->gadget->state >= USB_STATE_CONFIGURED) - dwc3_gadget_suspend_interrupt(dwc, - event->event_info); - } + if (!DWC3_VER_IS_PRIOR(DWC3, 230A)) + dwc3_gadget_suspend_interrupt(dwc, event->event_info); break; case DWC3_DEVICE_EVENT_SOF: case DWC3_DEVICE_EVENT_ERRATIC_ERROR: @@ -4417,11 +4515,6 @@ static int dwc3_gadget_get_irq(struct dwc3 *dwc) goto out; irq = platform_get_irq(dwc3_pdev, 0); - if (irq > 0) - goto out; - - if (!irq) - irq = -EINVAL; out: return irq; @@ -4493,6 +4586,7 @@ int dwc3_gadget_init(struct dwc3 *dwc) dwc->gadget->sg_supported = true; dwc->gadget->name = "dwc3-gadget"; dwc->gadget->lpm_capable = !dwc->usb2_gadget_lpm_disable; + dwc->gadget->wakeup_capable = true; /* * FIXME We might be setting max_speed to <SUPER, however versions diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c index f6f13e7f1ba1..61f57fe5bb78 100644 --- a/drivers/usb/dwc3/host.c +++ b/drivers/usb/dwc3/host.c @@ -52,13 +52,8 @@ static int dwc3_host_get_irq(struct dwc3 *dwc) goto out; irq = platform_get_irq(dwc3_pdev, 0); - if (irq > 0) { + if (irq > 0) dwc3_host_fill_xhci_irq_res(dwc, irq, NULL); - goto out; - } - - if (!irq) - irq = -EINVAL; out: return irq; diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h index 1975aec8d36d..d2997d17cfbe 100644 --- a/drivers/usb/dwc3/trace.h +++ b/drivers/usb/dwc3/trace.h @@ -54,14 +54,13 @@ DECLARE_EVENT_CLASS(dwc3_log_event, TP_STRUCT__entry( __field(u32, event) __field(u32, ep0state) - __dynamic_array(char, str, DWC3_MSG_MAX) ), TP_fast_assign( __entry->event = event; __entry->ep0state = dwc->ep0state; ), TP_printk("event (%08x): %s", __entry->event, - dwc3_decode_event(__get_str(str), DWC3_MSG_MAX, + dwc3_decode_event(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX, __entry->event, __entry->ep0state)) ); @@ -79,7 +78,6 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, __field(__u16, wValue) __field(__u16, wIndex) __field(__u16, wLength) - __dynamic_array(char, str, DWC3_MSG_MAX) ), TP_fast_assign( __entry->bRequestType = ctrl->bRequestType; @@ -88,7 +86,7 @@ DECLARE_EVENT_CLASS(dwc3_log_ctrl, __entry->wIndex = le16_to_cpu(ctrl->wIndex); __entry->wLength = le16_to_cpu(ctrl->wLength); ), - TP_printk("%s", usb_decode_ctrl(__get_str(str), DWC3_MSG_MAX, + TP_printk("%s", usb_decode_ctrl(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX, __entry->bRequestType, __entry->bRequest, __entry->wValue, __entry->wIndex, __entry->wLength) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 5377d873c08e..1b3489149e5e 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -492,6 +492,46 @@ int usb_interface_id(struct usb_configuration *config, } EXPORT_SYMBOL_GPL(usb_interface_id); +/** + * usb_func_wakeup - sends function wake notification to the host. + * @func: function that sends the remote wakeup notification. + * + * Applicable to devices operating at enhanced superspeed when usb + * functions are put in function suspend state and armed for function + * remote wakeup. On completion, function wake notification is sent. If + * the device is in low power state it tries to bring the device to active + * state before sending the wake notification. Since it is a synchronous + * call, caller must take care of not calling it in interrupt context. + * For devices operating at lower speeds returns negative errno. + * + * Returns zero on success, else negative errno. + */ +int usb_func_wakeup(struct usb_function *func) +{ + struct usb_gadget *gadget = func->config->cdev->gadget; + int id; + + if (!gadget->ops->func_wakeup) + return -EOPNOTSUPP; + + if (!func->func_wakeup_armed) { + ERROR(func->config->cdev, "not armed for func remote wakeup\n"); + return -EINVAL; + } + + for (id = 0; id < MAX_CONFIG_INTERFACES; id++) + if (func->config->interface[id] == func) + break; + + if (id == MAX_CONFIG_INTERFACES) { + ERROR(func->config->cdev, "Invalid function\n"); + return -EINVAL; + } + + return gadget->ops->func_wakeup(gadget, id); +} +EXPORT_SYMBOL_GPL(usb_func_wakeup); + static u8 encode_bMaxPower(enum usb_device_speed speed, struct usb_configuration *c) { @@ -513,6 +553,19 @@ static u8 encode_bMaxPower(enum usb_device_speed speed, return min(val, 900U) / 8; } +void check_remote_wakeup_config(struct usb_gadget *g, + struct usb_configuration *c) +{ + if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes) { + /* Reset the rw bit if gadget is not capable of it */ + if (!g->wakeup_capable && g->ops->set_remote_wakeup) { + WARN(c->cdev, "Clearing wakeup bit for config c.%d\n", + c->bConfigurationValue); + c->bmAttributes &= ~USB_CONFIG_ATT_WAKEUP; + } + } +} + static int config_buf(struct usb_configuration *config, enum usb_device_speed speed, void *buf, u8 type) { @@ -888,6 +941,9 @@ static void reset_config(struct usb_composite_dev *cdev) if (f->disable) f->disable(f); + /* Section 9.1.1.6, disable remote wakeup when device is reset */ + f->func_wakeup_armed = false; + bitmap_zero(f->endpoints, 32); } cdev->config = NULL; @@ -994,6 +1050,11 @@ static int set_config(struct usb_composite_dev *cdev, power = min(power, 500U); else power = min(power, 900U); + + if (USB_CONFIG_ATT_WAKEUP & c->bmAttributes) + usb_gadget_set_remote_wakeup(gadget, 1); + else + usb_gadget_set_remote_wakeup(gadget, 0); done: if (power <= USB_SELF_POWER_VBUS_MAX_DRAW) usb_gadget_set_selfpowered(gadget); @@ -1948,9 +2009,20 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) f = cdev->config->interface[intf]; if (!f) break; - status = f->get_status ? f->get_status(f) : 0; - if (status < 0) - break; + + if (f->get_status) { + status = f->get_status(f); + if (status < 0) + break; + } else { + /* Set D0 and D1 bits based on func wakeup capability */ + if (f->config->bmAttributes & USB_CONFIG_ATT_WAKEUP) { + status |= USB_INTRF_STAT_FUNC_RW_CAP; + if (f->func_wakeup_armed) + status |= USB_INTRF_STAT_FUNC_RW; + } + } + put_unaligned_le16(status & 0x0000ffff, req->buf); break; /* @@ -1972,8 +2044,44 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl) if (!f) break; value = 0; - if (f->func_suspend) + if (f->func_suspend) { value = f->func_suspend(f, w_index >> 8); + /* SetFeature(FUNCTION_SUSPEND) */ + } else if (ctrl->bRequest == USB_REQ_SET_FEATURE) { + if (!(f->config->bmAttributes & + USB_CONFIG_ATT_WAKEUP) && + (w_index & USB_INTRF_FUNC_SUSPEND_RW)) + break; + + f->func_wakeup_armed = !!(w_index & + USB_INTRF_FUNC_SUSPEND_RW); + + if (w_index & USB_INTRF_FUNC_SUSPEND_LP) { + if (f->suspend && !f->func_suspended) { + f->suspend(f); + f->func_suspended = true; + } + /* + * Handle cases where host sends function resume + * through SetFeature(FUNCTION_SUSPEND) but low power + * bit reset + */ + } else { + if (f->resume && f->func_suspended) { + f->resume(f); + f->func_suspended = false; + } + } + /* ClearFeature(FUNCTION_SUSPEND) */ + } else if (ctrl->bRequest == USB_REQ_CLEAR_FEATURE) { + f->func_wakeup_armed = false; + + if (f->resume && f->func_suspended) { + f->resume(f); + f->func_suspended = false; + } + } + if (value < 0) { ERROR(cdev, "func_suspend() returned error %d\n", @@ -2515,7 +2623,12 @@ void composite_resume(struct usb_gadget *gadget) cdev->driver->resume(cdev); if (cdev->config) { list_for_each_entry(f, &cdev->config->functions, list) { - if (f->resume) + /* + * Check for func_suspended flag to see if the function is + * in USB3 FUNCTION_SUSPEND state. In this case resume is + * done via FUNCTION_SUSPEND feature selector. + */ + if (f->resume && !f->func_suspended) f->resume(f); } @@ -2530,6 +2643,10 @@ void composite_resume(struct usb_gadget *gadget) usb_gadget_clear_selfpowered(gadget); usb_gadget_vbus_draw(gadget, maxpower); + } else { + maxpower = CONFIG_USB_GADGET_VBUS_DRAW; + maxpower = min(maxpower, 100U); + usb_gadget_vbus_draw(gadget, maxpower); } cdev->suspended = 0; diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index b9f1136aa0a2..4c639e9ddedc 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -1761,6 +1761,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget, if (gadget_is_otg(gadget)) c->descriptors = otg_desc; + /* Properly configure the bmAttributes wakeup bit */ + check_remote_wakeup_config(gadget, c); + cfg = container_of(c, struct config_usb_cfg, c); if (!list_empty(&cfg->string_list)) { i = 0; diff --git a/drivers/usb/gadget/function/f_ecm.c b/drivers/usb/gadget/function/f_ecm.c index a7ab30e603e2..c6e63ad77a40 100644 --- a/drivers/usb/gadget/function/f_ecm.c +++ b/drivers/usb/gadget/function/f_ecm.c @@ -885,6 +885,26 @@ static struct usb_function_instance *ecm_alloc_inst(void) return &opts->func_inst; } +static void ecm_suspend(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Suspend\n"); + + gether_suspend(&ecm->port); +} + +static void ecm_resume(struct usb_function *f) +{ + struct f_ecm *ecm = func_to_ecm(f); + struct usb_composite_dev *cdev = ecm->port.func.config->cdev; + + DBG(cdev, "ECM Resume\n"); + + gether_resume(&ecm->port); +} + static void ecm_free(struct usb_function *f) { struct f_ecm *ecm; @@ -952,6 +972,8 @@ static struct usb_function *ecm_alloc(struct usb_function_instance *fi) ecm->port.func.setup = ecm_setup; ecm->port.func.disable = ecm_disable; ecm->port.func.free_func = ecm_free; + ecm->port.func.suspend = ecm_suspend; + ecm->port.func.resume = ecm_resume; return &ecm->port.func; } diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 56cdfb2e4211..a13c946e0663 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -335,8 +335,6 @@ static ssize_t ffs_ep0_write(struct file *file, const char __user *buf, ssize_t ret; char *data; - ENTER(); - /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -512,8 +510,6 @@ static ssize_t ffs_ep0_read(struct file *file, char __user *buf, size_t n; int ret; - ENTER(); - /* Fast check if setup was canceled */ if (ffs_setup_state_clear_cancelled(ffs) == FFS_SETUP_CANCELLED) return -EIDRM; @@ -612,8 +608,6 @@ static int ffs_ep0_open(struct inode *inode, struct file *file) { struct ffs_data *ffs = inode->i_private; - ENTER(); - if (ffs->state == FFS_CLOSING) return -EBUSY; @@ -627,8 +621,6 @@ static int ffs_ep0_release(struct inode *inode, struct file *file) { struct ffs_data *ffs = file->private_data; - ENTER(); - ffs_data_closed(ffs); return 0; @@ -640,8 +632,6 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value) struct usb_gadget *gadget = ffs->gadget; long ret; - ENTER(); - if (code == FUNCTIONFS_INTERFACE_REVMAP) { struct ffs_function *func = ffs->func; ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV; @@ -715,7 +705,6 @@ static void ffs_epfile_io_complete(struct usb_ep *_ep, struct usb_request *req) { struct ffs_io_data *io_data = req->context; - ENTER(); if (req->status) io_data->status = req->status; else @@ -856,8 +845,6 @@ static void ffs_epfile_async_io_complete(struct usb_ep *_ep, struct ffs_io_data *io_data = req->context; struct ffs_data *ffs = io_data->ffs; - ENTER(); - io_data->status = req->status ? req->status : req->actual; usb_ep_free_request(_ep, req); @@ -1161,8 +1148,6 @@ ffs_epfile_open(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; - ENTER(); - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1179,8 +1164,6 @@ static int ffs_aio_cancel(struct kiocb *kiocb) unsigned long flags; int value; - ENTER(); - spin_lock_irqsave(&epfile->ffs->eps_lock, flags); if (io_data && io_data->ep && io_data->req) @@ -1198,8 +1181,6 @@ static ssize_t ffs_epfile_write_iter(struct kiocb *kiocb, struct iov_iter *from) struct ffs_io_data io_data, *p = &io_data; ssize_t res; - ENTER(); - if (!is_sync_kiocb(kiocb)) { p = kzalloc(sizeof(io_data), GFP_KERNEL); if (!p) @@ -1235,8 +1216,6 @@ static ssize_t ffs_epfile_read_iter(struct kiocb *kiocb, struct iov_iter *to) struct ffs_io_data io_data, *p = &io_data; ssize_t res; - ENTER(); - if (!is_sync_kiocb(kiocb)) { p = kzalloc(sizeof(io_data), GFP_KERNEL); if (!p) @@ -1284,8 +1263,6 @@ ffs_epfile_release(struct inode *inode, struct file *file) { struct ffs_epfile *epfile = inode->i_private; - ENTER(); - __ffs_epfile_read_buffer_free(epfile); ffs_data_closed(epfile->ffs); @@ -1299,8 +1276,6 @@ static long ffs_epfile_ioctl(struct file *file, unsigned code, struct ffs_ep *ep; int ret; - ENTER(); - if (WARN_ON(epfile->ffs->state != FFS_ACTIVE)) return -ENODEV; @@ -1399,8 +1374,6 @@ ffs_sb_make_inode(struct super_block *sb, void *data, { struct inode *inode; - ENTER(); - inode = new_inode(sb); if (inode) { @@ -1432,8 +1405,6 @@ static struct dentry *ffs_sb_create_file(struct super_block *sb, struct dentry *dentry; struct inode *inode; - ENTER(); - dentry = d_alloc_name(sb->s_root, name); if (!dentry) return NULL; @@ -1468,8 +1439,6 @@ static int ffs_sb_fill(struct super_block *sb, struct fs_context *fc) struct inode *inode; struct ffs_data *ffs = data->ffs_data; - ENTER(); - ffs->sb = sb; data->ffs_data = NULL; sb->s_fs_info = ffs; @@ -1521,8 +1490,6 @@ static int ffs_fs_parse_param(struct fs_context *fc, struct fs_parameter *param) struct fs_parse_result result; int opt; - ENTER(); - opt = fs_parse(fc, ffs_fs_fs_parameters, param, &result); if (opt < 0) return opt; @@ -1572,8 +1539,6 @@ static int ffs_fs_get_tree(struct fs_context *fc) struct ffs_data *ffs; int ret; - ENTER(); - if (!fc->source) return invalf(fc, "No source specified"); @@ -1640,8 +1605,6 @@ static int ffs_fs_init_fs_context(struct fs_context *fc) static void ffs_fs_kill_sb(struct super_block *sb) { - ENTER(); - kill_litter_super(sb); if (sb->s_fs_info) ffs_data_closed(sb->s_fs_info); @@ -1663,8 +1626,6 @@ static int functionfs_init(void) { int ret; - ENTER(); - ret = register_filesystem(&ffs_fs_type); if (!ret) pr_info("file system registered\n"); @@ -1676,8 +1637,6 @@ static int functionfs_init(void) static void functionfs_cleanup(void) { - ENTER(); - pr_info("unloading\n"); unregister_filesystem(&ffs_fs_type); } @@ -1690,15 +1649,11 @@ static void ffs_data_reset(struct ffs_data *ffs); static void ffs_data_get(struct ffs_data *ffs) { - ENTER(); - refcount_inc(&ffs->ref); } static void ffs_data_opened(struct ffs_data *ffs) { - ENTER(); - refcount_inc(&ffs->ref); if (atomic_add_return(1, &ffs->opened) == 1 && ffs->state == FFS_DEACTIVATED) { @@ -1709,8 +1664,6 @@ static void ffs_data_opened(struct ffs_data *ffs) static void ffs_data_put(struct ffs_data *ffs) { - ENTER(); - if (refcount_dec_and_test(&ffs->ref)) { pr_info("%s(): freeing\n", __func__); ffs_data_clear(ffs); @@ -1729,8 +1682,6 @@ static void ffs_data_closed(struct ffs_data *ffs) struct ffs_epfile *epfiles; unsigned long flags; - ENTER(); - if (atomic_dec_and_test(&ffs->opened)) { if (ffs->no_disconnect) { ffs->state = FFS_DEACTIVATED; @@ -1765,8 +1716,6 @@ static struct ffs_data *ffs_data_new(const char *dev_name) if (!ffs) return NULL; - ENTER(); - ffs->io_completion_wq = alloc_ordered_workqueue("%s", 0, dev_name); if (!ffs->io_completion_wq) { kfree(ffs); @@ -1793,8 +1742,6 @@ static void ffs_data_clear(struct ffs_data *ffs) struct ffs_epfile *epfiles; unsigned long flags; - ENTER(); - ffs_closed(ffs); BUG_ON(ffs->gadget); @@ -1826,8 +1773,6 @@ static void ffs_data_clear(struct ffs_data *ffs) static void ffs_data_reset(struct ffs_data *ffs) { - ENTER(); - ffs_data_clear(ffs); ffs->raw_descs_data = NULL; @@ -1861,8 +1806,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) struct usb_gadget_strings **lang; int first_id; - ENTER(); - if (WARN_ON(ffs->state != FFS_ACTIVE || test_and_set_bit(FFS_FL_BOUND, &ffs->flags))) return -EBADFD; @@ -1894,8 +1837,6 @@ static int functionfs_bind(struct ffs_data *ffs, struct usb_composite_dev *cdev) static void functionfs_unbind(struct ffs_data *ffs) { - ENTER(); - if (!WARN_ON(!ffs->gadget)) { /* dequeue before freeing ep0req */ usb_ep_dequeue(ffs->gadget->ep0, ffs->ep0req); @@ -1914,8 +1855,6 @@ static int ffs_epfiles_create(struct ffs_data *ffs) struct ffs_epfile *epfile, *epfiles; unsigned i, count; - ENTER(); - count = ffs->eps_count; epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); if (!epfiles) @@ -1946,8 +1885,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count) { struct ffs_epfile *epfile = epfiles; - ENTER(); - for (; count; --count, ++epfile) { BUG_ON(mutex_is_locked(&epfile->mutex)); if (epfile->dentry) { @@ -2064,8 +2001,6 @@ static int __must_check ffs_do_single_desc(char *data, unsigned len, u8 length; int ret; - ENTER(); - /* At least two bytes are required: length and type */ if (len < 2) { pr_vdebug("descriptor too short\n"); @@ -2204,8 +2139,6 @@ static int __must_check ffs_do_descs(unsigned count, char *data, unsigned len, unsigned long num = 0; int current_class = -1; - ENTER(); - for (;;) { int ret; @@ -2243,8 +2176,6 @@ static int __ffs_data_do_entity(enum ffs_entity_type type, struct ffs_desc_helper *helper = priv; struct usb_endpoint_descriptor *d; - ENTER(); - switch (type) { case FFS_DESCRIPTOR: break; @@ -2292,8 +2223,11 @@ static int __ffs_do_os_desc_header(enum ffs_os_desc_type *next_type, u16 bcd_version = le16_to_cpu(desc->bcdVersion); u16 w_index = le16_to_cpu(desc->wIndex); - if (bcd_version != 1) { - pr_vdebug("unsupported os descriptors version: %d", + if (bcd_version == 0x1) { + pr_warn("bcdVersion must be 0x0100, stored in Little Endian order. " + "Userspace driver should be fixed, accepting 0x0001 for compatibility.\n"); + } else if (bcd_version != 0x100) { + pr_vdebug("unsupported os descriptors version: 0x%x\n", bcd_version); return -EINVAL; } @@ -2326,8 +2260,6 @@ static int __must_check ffs_do_single_os_desc(char *data, unsigned len, int ret; const unsigned _len = len; - ENTER(); - /* loop over all ext compat/ext prop descriptors */ while (feature_count--) { ret = entity(type, h, data, len, priv); @@ -2349,8 +2281,6 @@ static int __must_check ffs_do_os_descs(unsigned count, const unsigned _len = len; unsigned long num = 0; - ENTER(); - for (num = 0; num < count; ++num) { int ret; enum ffs_os_desc_type type; @@ -2413,8 +2343,6 @@ static int __ffs_data_do_os_desc(enum ffs_os_desc_type type, struct ffs_data *ffs = priv; u8 length; - ENTER(); - switch (type) { case FFS_OS_DESC_EXT_COMPAT: { struct usb_ext_compat_desc *d = data; @@ -2490,8 +2418,6 @@ static int __ffs_data_got_descs(struct ffs_data *ffs, int ret = -EINVAL, i; struct ffs_desc_helper helper; - ENTER(); - if (get_unaligned_le32(data + 4) != len) goto error; @@ -2622,8 +2548,6 @@ static int __ffs_data_got_strings(struct ffs_data *ffs, const char *data = _data; struct usb_string *s; - ENTER(); - if (len < 16 || get_unaligned_le32(data) != FUNCTIONFS_STRINGS_MAGIC || get_unaligned_le32(data + 4) != len) @@ -3082,8 +3006,6 @@ static inline struct f_fs_opts *ffs_do_functionfs_bind(struct usb_function *f, struct ffs_data *ffs_data; int ret; - ENTER(); - /* * Legacy gadget triggers binding in functionfs_ready_callback, * which already uses locking; taking the same lock here would @@ -3160,8 +3082,6 @@ static int _ffs_func_bind(struct usb_configuration *c, vla_item_with_sz(d, char, raw_descs, ffs->raw_descs_length); char *vlabuf; - ENTER(); - /* Has descriptors only for speeds gadget does not support */ if (!(full | high | super)) return -ENOTSUPP; @@ -3365,8 +3285,6 @@ static int ffs_func_setup(struct usb_function *f, unsigned long flags; int ret; - ENTER(); - pr_vdebug("creq->bRequestType = %02x\n", creq->bRequestType); pr_vdebug("creq->bRequest = %02x\n", creq->bRequest); pr_vdebug("creq->wValue = %04x\n", le16_to_cpu(creq->wValue)); @@ -3441,13 +3359,11 @@ static bool ffs_func_req_match(struct usb_function *f, static void ffs_func_suspend(struct usb_function *f) { - ENTER(); ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_SUSPEND); } static void ffs_func_resume(struct usb_function *f) { - ENTER(); ffs_event_add(ffs_func_from_usb(f)->ffs, FUNCTIONFS_RESUME); } @@ -3611,7 +3527,6 @@ static void ffs_func_unbind(struct usb_configuration *c, unsigned count = ffs->eps_count; unsigned long flags; - ENTER(); if (ffs->func == func) { ffs_func_eps_disable(func); ffs->func = NULL; @@ -3651,8 +3566,6 @@ static struct usb_function *ffs_alloc(struct usb_function_instance *fi) { struct ffs_function *func; - ENTER(); - func = kzalloc(sizeof(*func), GFP_KERNEL); if (!func) return ERR_PTR(-ENOMEM); @@ -3753,7 +3666,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data) int ret = 0; struct ffs_dev *ffs_dev; - ENTER(); ffs_dev_lock(); ffs_dev = _ffs_find_dev(dev_name); @@ -3776,7 +3688,6 @@ static int ffs_acquire_dev(const char *dev_name, struct ffs_data *ffs_data) static void ffs_release_dev(struct ffs_dev *ffs_dev) { - ENTER(); ffs_dev_lock(); if (ffs_dev && ffs_dev->mounted) { @@ -3798,7 +3709,6 @@ static int ffs_ready(struct ffs_data *ffs) struct ffs_dev *ffs_obj; int ret = 0; - ENTER(); ffs_dev_lock(); ffs_obj = ffs->private_data; @@ -3831,7 +3741,6 @@ static void ffs_closed(struct ffs_data *ffs) struct f_fs_opts *opts; struct config_item *ci; - ENTER(); ffs_dev_lock(); ffs_obj = ffs->private_data; diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c index f259975dfba4..6956ad8ba8dd 100644 --- a/drivers/usb/gadget/function/u_ether.c +++ b/drivers/usb/gadget/function/u_ether.c @@ -437,6 +437,20 @@ static inline int is_promisc(u16 cdc_filter) return cdc_filter & USB_CDC_PACKET_TYPE_PROMISCUOUS; } +static int ether_wakeup_host(struct gether *port) +{ + int ret; + struct usb_function *func = &port->func; + struct usb_gadget *gadget = func->config->cdev->gadget; + + if (func->func_suspended) + ret = usb_func_wakeup(func); + else + ret = usb_gadget_wakeup(gadget); + + return ret; +} + static netdev_tx_t eth_start_xmit(struct sk_buff *skb, struct net_device *net) { @@ -456,6 +470,15 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb, in = NULL; cdc_filter = 0; } + + if (dev->port_usb && dev->port_usb->is_suspend) { + DBG(dev, "Port suspended. Triggering wakeup\n"); + netif_stop_queue(net); + spin_unlock_irqrestore(&dev->lock, flags); + ether_wakeup_host(dev->port_usb); + return NETDEV_TX_BUSY; + } + spin_unlock_irqrestore(&dev->lock, flags); if (!in) { @@ -1014,6 +1037,45 @@ int gether_set_ifname(struct net_device *net, const char *name, int len) } EXPORT_SYMBOL_GPL(gether_set_ifname); +void gether_suspend(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + if (atomic_read(&dev->tx_qlen)) { + /* + * There is a transfer in progress. So we trigger a remote + * wakeup to inform the host. + */ + ether_wakeup_host(dev->port_usb); + return; + } + spin_lock_irqsave(&dev->lock, flags); + link->is_suspend = true; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_suspend); + +void gether_resume(struct gether *link) +{ + struct eth_dev *dev = link->ioport; + unsigned long flags; + + if (!dev) + return; + + if (netif_queue_stopped(dev->net)) + netif_start_queue(dev->net); + + spin_lock_irqsave(&dev->lock, flags); + link->is_suspend = false; + spin_unlock_irqrestore(&dev->lock, flags); +} +EXPORT_SYMBOL_GPL(gether_resume); + /* * gether_cleanup - remove Ethernet-over-USB device * Context: may sleep @@ -1176,6 +1238,7 @@ void gether_disconnect(struct gether *link) spin_lock(&dev->lock); dev->port_usb = NULL; + link->is_suspend = false; spin_unlock(&dev->lock); } EXPORT_SYMBOL_GPL(gether_disconnect); diff --git a/drivers/usb/gadget/function/u_ether.h b/drivers/usb/gadget/function/u_ether.h index 40144546d1b0..851ee10d6e63 100644 --- a/drivers/usb/gadget/function/u_ether.h +++ b/drivers/usb/gadget/function/u_ether.h @@ -79,6 +79,7 @@ struct gether { /* called on network open/close */ void (*open)(struct gether *); void (*close)(struct gether *); + bool is_suspend; }; #define DEFAULT_FILTER (USB_CDC_PACKET_TYPE_BROADCAST \ @@ -258,6 +259,9 @@ int gether_set_ifname(struct net_device *net, const char *name, int len); void gether_cleanup(struct eth_dev *dev); +void gether_suspend(struct gether *link); +void gether_resume(struct gether *link); + /* connect/disconnect is handled by individual functions */ struct net_device *gether_connect(struct gether *); void gether_disconnect(struct gether *); diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h index f102ec23f3af..4b3365f23fd7 100644 --- a/drivers/usb/gadget/function/u_fs.h +++ b/drivers/usb/gadget/function/u_fs.h @@ -32,8 +32,6 @@ # define ffs_dump_mem(prefix, ptr, len) do { } while (0) #endif /* VERBOSE_DEBUG */ -#define ENTER() pr_vdebug("%s()\n", __func__) - struct f_fs_opts; struct ffs_dev { diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c index 62b759bb7613..9bf0e985acfa 100644 --- a/drivers/usb/gadget/function/uvc_configfs.c +++ b/drivers/usb/gadget/function/uvc_configfs.c @@ -334,6 +334,64 @@ UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, 8); #undef UVCG_DEFAULT_PROCESSING_ATTR +static ssize_t uvcg_default_processing_bm_controls_store( + struct config_item *item, const char *page, size_t len) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_processing_unit_descriptor *pd; + struct config_item *opts_item; + struct f_uvc_opts *opts; + u8 *bm_controls, *tmp; + unsigned int i; + int ret, n = 0; + + mutex_lock(su_mutex); + + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent; + opts = to_f_uvc_opts(opts_item); + pd = &opts->uvc_processing; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, + sizeof(u8)); + if (ret) + goto unlock; + + if (n > pd->bControlSize) { + ret = -EINVAL; + goto unlock; + } + + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); + if (!bm_controls) { + ret = -ENOMEM; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, + sizeof(u8)); + if (ret) + goto free_mem; + + for (i = 0; i < n; i++) + pd->bmControls[i] = bm_controls[i]; + + ret = len; + +free_mem: + kfree(bm_controls); +unlock: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + static ssize_t uvcg_default_processing_bm_controls_show( struct config_item *item, char *page) { @@ -363,7 +421,7 @@ static ssize_t uvcg_default_processing_bm_controls_show( return result; } -UVC_ATTR_RO(uvcg_default_processing_, bm_controls, bmControls); +UVC_ATTR(uvcg_default_processing_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_processing_attrs[] = { &uvcg_default_processing_attr_b_unit_id, @@ -445,6 +503,65 @@ UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength, #undef UVCG_DEFAULT_CAMERA_ATTR +static ssize_t uvcg_default_camera_bm_controls_store( + struct config_item *item, const char *page, size_t len) +{ + struct config_group *group = to_config_group(item); + struct mutex *su_mutex = &group->cg_subsys->su_mutex; + struct uvc_camera_terminal_descriptor *cd; + struct config_item *opts_item; + struct f_uvc_opts *opts; + u8 *bm_controls, *tmp; + unsigned int i; + int ret, n = 0; + + mutex_lock(su_mutex); + + opts_item = group->cg_item.ci_parent->ci_parent->ci_parent-> + ci_parent; + opts = to_f_uvc_opts(opts_item); + cd = &opts->uvc_camera_terminal; + + mutex_lock(&opts->lock); + if (opts->refcnt) { + ret = -EBUSY; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_count_item_entries, &n, + sizeof(u8)); + if (ret) + goto unlock; + + if (n > cd->bControlSize) { + ret = -EINVAL; + goto unlock; + } + + tmp = bm_controls = kcalloc(n, sizeof(u8), GFP_KERNEL); + if (!bm_controls) { + ret = -ENOMEM; + goto unlock; + } + + ret = __uvcg_iter_item_entries(page, len, __uvcg_fill_item_entries, &tmp, + sizeof(u8)); + if (ret) + goto free_mem; + + for (i = 0; i < n; i++) + cd->bmControls[i] = bm_controls[i]; + + ret = len; + +free_mem: + kfree(bm_controls); +unlock: + mutex_unlock(&opts->lock); + mutex_unlock(su_mutex); + return ret; +} + static ssize_t uvcg_default_camera_bm_controls_show( struct config_item *item, char *page) { @@ -474,7 +591,7 @@ static ssize_t uvcg_default_camera_bm_controls_show( return result; } -UVC_ATTR_RO(uvcg_default_camera_, bm_controls, bmControls); +UVC_ATTR(uvcg_default_camera_, bm_controls, bmControls); static struct configfs_attribute *uvcg_default_camera_attrs[] = { &uvcg_default_camera_attr_b_terminal_id, diff --git a/drivers/usb/gadget/legacy/g_ffs.c b/drivers/usb/gadget/legacy/g_ffs.c index ae6d8f7092b8..097854683e5b 100644 --- a/drivers/usb/gadget/legacy/g_ffs.c +++ b/drivers/usb/gadget/legacy/g_ffs.c @@ -180,8 +180,6 @@ static int __init gfs_init(void) int i; int ret = 0; - ENTER(); - if (func_num < 2) { gfs_single_func = true; func_num = 1; @@ -242,8 +240,6 @@ static void __exit gfs_exit(void) { int i; - ENTER(); - if (gfs_registered) usb_composite_unregister(&gfs_driver); gfs_registered = false; @@ -316,8 +312,6 @@ static int gfs_bind(struct usb_composite_dev *cdev) #endif int ret, i; - ENTER(); - if (missing_funcs) return -ENODEV; #if defined CONFIG_USB_FUNCTIONFS_ETH @@ -445,9 +439,6 @@ static int gfs_unbind(struct usb_composite_dev *cdev) { int i; - ENTER(); - - #ifdef CONFIG_USB_FUNCTIONFS_RNDIS usb_put_function(f_rndis); usb_put_function_instance(fi_rndis); diff --git a/drivers/usb/gadget/udc/aspeed-vhub/core.c b/drivers/usb/gadget/udc/aspeed-vhub/core.c index ac3ca24f8b04..86398a04a012 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/core.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/core.c @@ -21,7 +21,6 @@ #include <linux/clk.h> #include <linux/usb/gadget.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/dma-mapping.h> diff --git a/drivers/usb/gadget/udc/aspeed-vhub/dev.c b/drivers/usb/gadget/udc/aspeed-vhub/dev.c index 4f3bc27c1c62..573109ca5b79 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/dev.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/dev.c @@ -21,7 +21,6 @@ #include <linux/clk.h> #include <linux/usb/gadget.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/dma-mapping.h> #include <linux/usb.h> diff --git a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c index b4cf46249fea..e9aa74231760 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/ep0.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/ep0.c @@ -21,7 +21,6 @@ #include <linux/clk.h> #include <linux/usb/gadget.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/dma-mapping.h> diff --git a/drivers/usb/gadget/udc/aspeed-vhub/epn.c b/drivers/usb/gadget/udc/aspeed-vhub/epn.c index 56e55472daa1..148d7ec3ebf4 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/epn.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/epn.c @@ -21,7 +21,6 @@ #include <linux/clk.h> #include <linux/usb/gadget.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/dma-mapping.h> diff --git a/drivers/usb/gadget/udc/aspeed-vhub/hub.c b/drivers/usb/gadget/udc/aspeed-vhub/hub.c index e2207d014620..a63e4af60a56 100644 --- a/drivers/usb/gadget/udc/aspeed-vhub/hub.c +++ b/drivers/usb/gadget/udc/aspeed-vhub/hub.c @@ -21,7 +21,6 @@ #include <linux/clk.h> #include <linux/usb/gadget.h> #include <linux/of.h> -#include <linux/of_gpio.h> #include <linux/regmap.h> #include <linux/dma-mapping.h> #include <linux/bcd.h> diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 23b0629a8774..3dcbba739db6 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -514,6 +514,33 @@ out: EXPORT_SYMBOL_GPL(usb_gadget_wakeup); /** + * usb_gadget_set_remote_wakeup - configures the device remote wakeup feature. + * @gadget:the device being configured for remote wakeup + * @set:value to be configured. + * + * set to one to enable remote wakeup feature and zero to disable it. + * + * returns zero on success, else negative errno. + */ +int usb_gadget_set_remote_wakeup(struct usb_gadget *gadget, int set) +{ + int ret = 0; + + if (!gadget->ops->set_remote_wakeup) { + ret = -EOPNOTSUPP; + goto out; + } + + ret = gadget->ops->set_remote_wakeup(gadget, set); + +out: + trace_usb_gadget_set_remote_wakeup(gadget, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(usb_gadget_set_remote_wakeup); + +/** * usb_gadget_set_selfpowered - sets the device selfpowered feature. * @gadget:the device being declared as self-powered * diff --git a/drivers/usb/gadget/udc/max3420_udc.c b/drivers/usb/gadget/udc/max3420_udc.c index ddf0ed3eb4f2..12c519f32bf7 100644 --- a/drivers/usb/gadget/udc/max3420_udc.c +++ b/drivers/usb/gadget/udc/max3420_udc.c @@ -1319,7 +1319,7 @@ MODULE_DEVICE_TABLE(of, max3420_udc_of_match); static struct spi_driver max3420_driver = { .driver = { .name = "max3420-udc", - .of_match_table = of_match_ptr(max3420_udc_of_match), + .of_match_table = max3420_udc_of_match, }, .probe = max3420_probe, .remove = max3420_remove, diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c index b397f3a848cf..08474c08d874 100644 --- a/drivers/usb/gadget/udc/mv_udc_core.c +++ b/drivers/usb/gadget/udc/mv_udc_core.c @@ -2229,7 +2229,11 @@ static int mv_udc_probe(struct platform_device *pdev) INIT_LIST_HEAD(&udc->status_req->queue); /* allocate a small amount of memory to get valid address */ - udc->status_req->req.buf = kzalloc(8, GFP_KERNEL); + udc->status_req->req.buf = devm_kzalloc(&pdev->dev, 8, GFP_KERNEL); + if (!udc->status_req->req.buf) { + retval = -ENOMEM; + goto err_destroy_dma; + } udc->status_req->req.dma = DMA_ADDR_INVALID; udc->resume_state = USB_STATE_NOTATTACHED; diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index bee6bceafc4f..aac8bc185afa 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -22,7 +22,6 @@ #include <linux/sizes.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/sys_soc.h> #include <linux/uaccess.h> #include <linux/usb/ch9.h> #include <linux/usb/gadget.h> @@ -2661,6 +2660,7 @@ static int renesas_usb3_remove(struct platform_device *pdev) debugfs_remove_recursive(usb3->dentry); device_remove_file(&pdev->dev, &dev_attr_role); + cancel_work_sync(&usb3->role_work); usb_role_switch_unregister(usb3->role_sw); usb_del_gadget_udc(&usb3->gadget); @@ -2781,13 +2781,6 @@ static void renesas_usb3_init_ram(struct renesas_usb3 *usb3, struct device *dev, } } -static const struct renesas_usb3_priv renesas_usb3_priv_r8a7795_es1 = { - .ramsize_per_ramif = SZ_16K, - .num_ramif = 2, - .ramsize_per_pipe = SZ_4K, - .workaround_for_vbus = true, -}; - static const struct renesas_usb3_priv renesas_usb3_priv_gen3 = { .ramsize_per_ramif = SZ_16K, .num_ramif = 4, @@ -2829,14 +2822,6 @@ static const struct of_device_id usb3_of_match[] = { }; MODULE_DEVICE_TABLE(of, usb3_of_match); -static const struct soc_device_attribute renesas_usb3_quirks_match[] = { - { - .soc_id = "r8a7795", .revision = "ES1.*", - .data = &renesas_usb3_priv_r8a7795_es1, - }, - { /* sentinel */ } -}; - static const unsigned int renesas_usb3_cable[] = { EXTCON_USB, EXTCON_USB_HOST, @@ -2854,13 +2839,8 @@ static int renesas_usb3_probe(struct platform_device *pdev) struct renesas_usb3 *usb3; int irq, ret; const struct renesas_usb3_priv *priv; - const struct soc_device_attribute *attr; - attr = soc_device_match(renesas_usb3_quirks_match); - if (attr) - priv = attr->data; - else - priv = of_device_get_match_data(&pdev->dev); + priv = of_device_get_match_data(&pdev->dev); irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -3039,7 +3019,7 @@ static struct platform_driver renesas_usb3_driver = { .driver = { .name = udc_name, .pm = &renesas_usb3_pm_ops, - .of_match_table = of_match_ptr(usb3_of_match), + .of_match_table = usb3_of_match, }, }; module_platform_driver(renesas_usb3_driver); diff --git a/drivers/usb/gadget/udc/renesas_usbf.c b/drivers/usb/gadget/udc/renesas_usbf.c index cb23e62e8a87..84ac9fe4ce7f 100644 --- a/drivers/usb/gadget/udc/renesas_usbf.c +++ b/drivers/usb/gadget/udc/renesas_usbf.c @@ -545,17 +545,6 @@ static inline void usbf_ep_dma_reg_bitclr(struct usbf_ep *ep, uint offset, usbf_ep_dma_reg_writel(ep, offset, tmp); } -static inline void usbf_ep_dma_reg_clrset(struct usbf_ep *ep, uint offset, - u32 clr, u32 set) -{ - u32 tmp; - - tmp = usbf_ep_dma_reg_readl(ep, offset); - tmp &= ~clr; - tmp |= set; - usbf_ep_dma_reg_writel(ep, offset, tmp); -} - static void usbf_ep0_send_null(struct usbf_ep *ep0, bool is_data1) { u32 set; diff --git a/drivers/usb/gadget/udc/rzv2m_usb3drd.c b/drivers/usb/gadget/udc/rzv2m_usb3drd.c index 3c8bbf843038..8855d8e8d793 100644 --- a/drivers/usb/gadget/udc/rzv2m_usb3drd.c +++ b/drivers/usb/gadget/udc/rzv2m_usb3drd.c @@ -126,7 +126,7 @@ MODULE_DEVICE_TABLE(of, rzv2m_usb3drd_of_match); static struct platform_driver rzv2m_usb3drd_driver = { .driver = { .name = "rzv2m-usb3drd", - .of_match_table = of_match_ptr(rzv2m_usb3drd_of_match), + .of_match_table = rzv2m_usb3drd_of_match, }, .probe = rzv2m_usb3drd_probe, .remove = rzv2m_usb3drd_remove, diff --git a/drivers/usb/gadget/udc/snps_udc_plat.c b/drivers/usb/gadget/udc/snps_udc_plat.c index 8bbb89c80348..0d3e705655b9 100644 --- a/drivers/usb/gadget/udc/snps_udc_plat.c +++ b/drivers/usb/gadget/udc/snps_udc_plat.c @@ -158,7 +158,7 @@ static int udc_plat_probe(struct platform_device *pdev) } /* Register for extcon if supported */ - if (of_get_property(dev->of_node, "extcon", NULL)) { + if (of_property_present(dev->of_node, "extcon")) { udc->edev = extcon_get_edev_by_phandle(dev, 0); if (IS_ERR(udc->edev)) { if (PTR_ERR(udc->edev) == -EPROBE_DEFER) diff --git a/drivers/usb/gadget/udc/trace.h b/drivers/usb/gadget/udc/trace.h index abdbcb1bacb0..a5ed26fbc2da 100644 --- a/drivers/usb/gadget/udc/trace.h +++ b/drivers/usb/gadget/udc/trace.h @@ -91,6 +91,11 @@ DEFINE_EVENT(udc_log_gadget, usb_gadget_wakeup, TP_ARGS(g, ret) ); +DEFINE_EVENT(udc_log_gadget, usb_gadget_set_remote_wakeup, + TP_PROTO(struct usb_gadget *g, int ret), + TP_ARGS(g, ret) +); + DEFINE_EVENT(udc_log_gadget, usb_gadget_set_selfpowered, TP_PROTO(struct usb_gadget *g, int ret), TP_ARGS(g, ret) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index eacb603ad1b2..c170672f847e 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -622,33 +622,6 @@ config FHCI_DEBUG Say "y" to see some FHCI debug information and statistics through debugfs. -config USB_U132_HCD - tristate "Elan U132 Adapter Host Controller" - depends on USB_FTDI_ELAN - help - The U132 adapter is a USB to CardBus adapter specifically designed - for PC cards that contain an OHCI host controller. Typical PC cards - are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132 - adapter will *NOT* work with PC cards that do not contain an OHCI - controller. - - For those PC cards that contain multiple OHCI controllers only the - first one is used. - - The driver consists of two modules, the "ftdi-elan" module is a - USB client driver that interfaces to the FTDI chip within ELAN's - USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host - controller driver that talks to the OHCI controller within the - CardBus cards that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - It is safe to say M here. - - See also <http://www.elandigitalsystems.com/support/ufaq/u132linux.php> - config USB_SL811_HCD tristate "SL811HS HCD support" depends on HAS_IOMEM diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile index 5a13712f367d..be4e5245c52f 100644 --- a/drivers/usb/host/Makefile +++ b/drivers/usb/host/Makefile @@ -76,7 +76,6 @@ obj-$(CONFIG_USB_XHCI_MTK) += xhci-mtk-hcd.o obj-$(CONFIG_USB_XHCI_TEGRA) += xhci-tegra.o obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o -obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c index 62a0a193798c..b3aa464e9d2c 100644 --- a/drivers/usb/host/ehci-ppc-of.c +++ b/drivers/usb/host/ehci-ppc-of.c @@ -151,13 +151,13 @@ static int ehci_hcd_ppc_of_probe(struct platform_device *op) of_node_put(np); } - if (of_get_property(dn, "big-endian", NULL)) { + if (of_property_read_bool(dn, "big-endian")) { ehci->big_endian_mmio = 1; ehci->big_endian_desc = 1; } - if (of_get_property(dn, "big-endian-regs", NULL)) + if (of_property_read_bool(dn, "big-endian-regs")) ehci->big_endian_mmio = 1; - if (of_get_property(dn, "big-endian-desc", NULL)) + if (of_property_read_bool(dn, "big-endian-desc")) ehci->big_endian_desc = 1; ehci->caps = hcd->regs; diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c index 46c6a152b865..9db909d12354 100644 --- a/drivers/usb/host/fsl-mph-dr-of.c +++ b/drivers/usb/host/fsl-mph-dr-of.c @@ -200,19 +200,16 @@ static int fsl_usb2_mph_dr_of_probe(struct platform_device *ofdev) dev_data = get_dr_mode_data(np); if (of_device_is_compatible(np, "fsl-usb2-mph")) { - if (of_get_property(np, "port0", NULL)) + if (of_property_present(np, "port0")) pdata->port_enables |= FSL_USB2_PORT0_ENABLED; - if (of_get_property(np, "port1", NULL)) + if (of_property_present(np, "port1")) pdata->port_enables |= FSL_USB2_PORT1_ENABLED; pdata->operating_mode = FSL_USB2_MPH_HOST; } else { - if (of_get_property(np, "fsl,invert-drvvbus", NULL)) - pdata->invert_drvvbus = 1; - - if (of_get_property(np, "fsl,invert-pwr-fault", NULL)) - pdata->invert_pwr_fault = 1; + pdata->invert_drvvbus = of_property_read_bool(np, "fsl,invert-drvvbus"); + pdata->invert_pwr_fault = of_property_read_bool(np, "fsl,invert-pwr-fault"); /* setup mode selected in the device tree */ pdata->operating_mode = dev_data->op_mode; diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c index 28d1524ee2fa..d152d72de126 100644 --- a/drivers/usb/host/max3421-hcd.c +++ b/drivers/usb/host/max3421-hcd.c @@ -1951,7 +1951,7 @@ static struct spi_driver max3421_driver = { .remove = max3421_remove, .driver = { .name = "max3421-hcd", - .of_match_table = of_match_ptr(max3421_of_match_table), + .of_match_table = max3421_of_match_table, }, }; diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index 3a441310c713..f998d3f1a78a 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -169,7 +169,7 @@ struct ehci_regs { #define FLAG_CF (1<<0) /* true: we'll support "high speed" */ /* PORTSC: offset 0x44 */ - u32 port_status[0]; /* up to N_PORTS */ + u32 port_status[]; /* up to N_PORTS */ /* 31:23 reserved */ #define PORT_WKOC_E (1<<22) /* wake on overcurrent (enable) */ #define PORT_WKDISC_E (1<<21) /* wake on disconnect (enable) */ diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c index ef08d68b9714..2665832f9add 100644 --- a/drivers/usb/host/pci-quirks.c +++ b/drivers/usb/host/pci-quirks.c @@ -207,8 +207,7 @@ EXPORT_SYMBOL_GPL(sb800_prefetch); static void usb_amd_find_chipset_info(void) { unsigned long flags; - struct amd_chipset_info info; - info.need_pll_quirk = false; + struct amd_chipset_info info = { }; spin_lock_irqsave(&amd_lock, flags); @@ -218,7 +217,6 @@ static void usb_amd_find_chipset_info(void) spin_unlock_irqrestore(&amd_lock, flags); return; } - memset(&info, 0, sizeof(info)); spin_unlock_irqrestore(&amd_lock, flags); if (!amd_chipset_sb_type_init(&info)) { diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c deleted file mode 100644 index 95240c9c45bd..000000000000 --- a/drivers/usb/host/u132-hcd.c +++ /dev/null @@ -1,3219 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* -* Host Controller Driver for the Elan Digital Systems U132 adapter -* -* Copyright(C) 2006 Elan Digital Systems Limited -* http://www.elandigitalsystems.com -* -* Author and Maintainer - Tony Olech - Elan Digital Systems -* tony.olech@elandigitalsystems.com -* -* This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) -* based on various USB host drivers in the 2.6.15 linux kernel -* with constant reference to the 3rd Edition of Linux Device Drivers -* published by O'Reilly -* -* The U132 adapter is a USB to CardBus adapter specifically designed -* for PC cards that contain an OHCI host controller. Typical PC cards -* are the Orange Mobile 3G Option GlobeTrotter Fusion card. -* -* The U132 adapter will *NOT *work with PC cards that do not contain -* an OHCI controller. A simple way to test whether a PC card has an -* OHCI controller as an interface is to insert the PC card directly -* into a laptop(or desktop) with a CardBus slot and if "lspci" shows -* a new USB controller and "lsusb -v" shows a new OHCI Host Controller -* then there is a good chance that the U132 adapter will support the -* PC card.(you also need the specific client driver for the PC card) -* -* Please inform the Author and Maintainer about any PC cards that -* contain OHCI Host Controller and work when directly connected to -* an embedded CardBus slot but do not work when they are connected -* via an ELAN U132 adapter. -* -*/ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/delay.h> -#include <linux/ioport.h> -#include <linux/pci_ids.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/usb.h> -#include <linux/usb/hcd.h> -#include <linux/workqueue.h> -#include <linux/platform_device.h> -#include <linux/mutex.h> -#include <asm/io.h> -#include <asm/irq.h> -#include <asm/byteorder.h> - - /* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name <linux/usb/ohci.h> - */ - -#include "ohci.h" -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) -MODULE_AUTHOR("Tony Olech - Elan Digital Systems Limited"); -MODULE_DESCRIPTION("U132 USB Host Controller Driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -INT_MODULE_PARM(testing, 0); -/* Some boards misreport power switching/overcurrent*/ -static bool distrust_firmware = true; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent" - "t setup"); -static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); -/* -* u132_module_lock exists to protect access to global variables -* -*/ -static DEFINE_MUTEX(u132_module_lock); -static int u132_exiting; -static int u132_instances; -/* -* end of the global variables protected by u132_module_lock -*/ -static struct workqueue_struct *workqueue; -#define MAX_U132_PORTS 7 -#define MAX_U132_ADDRS 128 -#define MAX_U132_UDEVS 4 -#define MAX_U132_ENDPS 100 -#define MAX_U132_RINGS 4 -static const char *cc_to_text[16] = { - "No Error ", - "CRC Error ", - "Bit Stuff ", - "Data Togg ", - "Stall ", - "DevNotResp ", - "PIDCheck ", - "UnExpPID ", - "DataOver ", - "DataUnder ", - "(for hw) ", - "(for hw) ", - "BufferOver ", - "BuffUnder ", - "(for HCD) ", - "(for HCD) " -}; -struct u132_port { - struct u132 *u132; - int reset; - int enable; - int power; - int Status; -}; -struct u132_addr { - u8 address; -}; -struct u132_udev { - struct kref kref; - struct usb_device *usb_device; - u8 enumeration; - u8 udev_number; - u8 usb_addr; - u8 portnumber; - u8 endp_number_in[16]; - u8 endp_number_out[16]; -}; -#define ENDP_QUEUE_SHIFT 3 -#define ENDP_QUEUE_SIZE (1<<ENDP_QUEUE_SHIFT) -#define ENDP_QUEUE_MASK (ENDP_QUEUE_SIZE-1) -struct u132_urbq { - struct list_head urb_more; - struct urb *urb; -}; -struct u132_spin { - spinlock_t slock; -}; -struct u132_endp { - struct kref kref; - u8 udev_number; - u8 endp_number; - u8 usb_addr; - u8 usb_endp; - struct u132 *u132; - struct list_head endp_ring; - struct u132_ring *ring; - unsigned toggle_bits:2; - unsigned active:1; - unsigned delayed:1; - unsigned input:1; - unsigned output:1; - unsigned pipetype:2; - unsigned dequeueing:1; - unsigned edset_flush:1; - unsigned spare_bits:14; - unsigned long jiffies; - struct usb_host_endpoint *hep; - struct u132_spin queue_lock; - u16 queue_size; - u16 queue_last; - u16 queue_next; - struct urb *urb_list[ENDP_QUEUE_SIZE]; - struct list_head urb_more; - struct delayed_work scheduler; -}; -struct u132_ring { - unsigned in_use:1; - unsigned length:7; - u8 number; - struct u132 *u132; - struct u132_endp *curr_endp; - struct delayed_work scheduler; -}; -struct u132 { - struct kref kref; - struct mutex sw_lock; - struct mutex scheduler_lock; - struct u132_platform_data *board; - struct platform_device *platform_dev; - struct u132_ring ring[MAX_U132_RINGS]; - int sequence_num; - int going; - int power; - int reset; - int num_ports; - u32 hc_control; - u32 hc_fminterval; - u32 hc_roothub_status; - u32 hc_roothub_a; - u32 hc_roothub_portstatus[MAX_ROOT_PORTS]; - int flags; - unsigned long next_statechange; - struct delayed_work monitor; - int num_endpoints; - struct u132_addr addr[MAX_U132_ADDRS]; - struct u132_udev udev[MAX_U132_UDEVS]; - struct u132_port port[MAX_U132_PORTS]; - struct u132_endp *endp[MAX_U132_ENDPS]; -}; - -/* -* these cannot be inlines because we need the structure offset!! -* Does anyone have a better way????? -*/ -#define ftdi_read_pcimem(pdev, member, data) usb_ftdi_elan_read_pcimem(pdev, \ - offsetof(struct ohci_regs, member), 0, data); -#define ftdi_write_pcimem(pdev, member, data) usb_ftdi_elan_write_pcimem(pdev, \ - offsetof(struct ohci_regs, member), 0, data) -#define u132_read_pcimem(u132, member, data) \ - usb_ftdi_elan_read_pcimem(u132->platform_dev, offsetof(struct \ - ohci_regs, member), 0, data) -#define u132_write_pcimem(u132, member, data) \ - usb_ftdi_elan_write_pcimem(u132->platform_dev, offsetof(struct \ - ohci_regs, member), 0, data) -static inline struct u132 *udev_to_u132(struct u132_udev *udev) -{ - u8 udev_number = udev->udev_number; - return container_of(udev, struct u132, udev[udev_number]); -} - -static inline struct u132 *hcd_to_u132(struct usb_hcd *hcd) -{ - return (struct u132 *)(hcd->hcd_priv); -} - -static inline struct usb_hcd *u132_to_hcd(struct u132 *u132) -{ - return container_of((void *)u132, struct usb_hcd, hcd_priv); -} - -static inline void u132_disable(struct u132 *u132) -{ - u132_to_hcd(u132)->state = HC_STATE_HALT; -} - - -#define kref_to_u132(d) container_of(d, struct u132, kref) -#define kref_to_u132_endp(d) container_of(d, struct u132_endp, kref) -#define kref_to_u132_udev(d) container_of(d, struct u132_udev, kref) -#include "../misc/usb_u132.h" -static const char hcd_name[] = "u132_hcd"; -#define PORT_C_MASK ((USB_PORT_STAT_C_CONNECTION | USB_PORT_STAT_C_ENABLE | \ - USB_PORT_STAT_C_SUSPEND | USB_PORT_STAT_C_OVERCURRENT | \ - USB_PORT_STAT_C_RESET) << 16) -static void u132_hcd_delete(struct kref *kref) -{ - struct u132 *u132 = kref_to_u132(kref); - struct platform_device *pdev = u132->platform_dev; - struct usb_hcd *hcd = u132_to_hcd(u132); - u132->going += 1; - mutex_lock(&u132_module_lock); - u132_instances -= 1; - mutex_unlock(&u132_module_lock); - dev_warn(&u132->platform_dev->dev, "FREEING the hcd=%p and thus the u13" - "2=%p going=%d pdev=%p\n", hcd, u132, u132->going, pdev); - usb_put_hcd(hcd); -} - -static inline void u132_u132_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static inline void u132_u132_init_kref(struct u132 *u132) -{ - kref_init(&u132->kref); -} - -static void u132_udev_delete(struct kref *kref) -{ - struct u132_udev *udev = kref_to_u132_udev(kref); - udev->udev_number = 0; - udev->usb_device = NULL; - udev->usb_addr = 0; - udev->enumeration = 0; -} - -static inline void u132_udev_put_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_put(&udev->kref, u132_udev_delete); -} - -static inline void u132_udev_get_kref(struct u132 *u132, struct u132_udev *udev) -{ - kref_get(&udev->kref); -} - -static inline void u132_udev_init_kref(struct u132 *u132, - struct u132_udev *udev) -{ - kref_init(&udev->kref); -} - -static inline void u132_ring_put_kref(struct u132 *u132, struct u132_ring *ring) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_requeue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - if (delta > 0) { - if (queue_delayed_work(workqueue, &ring->scheduler, delta)) - return; - } else if (queue_delayed_work(workqueue, &ring->scheduler, 0)) - return; - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_ring_queue_work(struct u132 *u132, struct u132_ring *ring, - unsigned int delta) -{ - kref_get(&u132->kref); - u132_ring_requeue_work(u132, ring, delta); -} - -static void u132_ring_cancel_work(struct u132 *u132, struct u132_ring *ring) -{ - if (cancel_delayed_work(&ring->scheduler)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_endp_delete(struct kref *kref) -{ - struct u132_endp *endp = kref_to_u132_endp(kref); - struct u132 *u132 = endp->u132; - u8 usb_addr = endp->usb_addr; - u8 usb_endp = endp->usb_endp; - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - u8 endp_number = endp->endp_number; - struct usb_host_endpoint *hep = endp->hep; - struct u132_ring *ring = endp->ring; - struct list_head *head = &endp->endp_ring; - ring->length -= 1; - if (endp == ring->curr_endp) { - if (list_empty(head)) { - ring->curr_endp = NULL; - list_del(head); - } else { - struct u132_endp *next_endp = list_entry(head->next, - struct u132_endp, endp_ring); - ring->curr_endp = next_endp; - list_del(head); - } - } else - list_del(head); - if (endp->input) { - udev->endp_number_in[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - if (endp->output) { - udev->endp_number_out[usb_endp] = 0; - u132_udev_put_kref(u132, udev); - } - u132->endp[endp_number - 1] = NULL; - hep->hcpriv = NULL; - kfree(endp); - u132_u132_put_kref(u132); -} - -static inline void u132_endp_put_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_endp_get_kref(struct u132 *u132, struct u132_endp *endp) -{ - kref_get(&endp->kref); -} - -static inline void u132_endp_init_kref(struct u132 *u132, - struct u132_endp *endp) -{ - kref_init(&endp->kref); - kref_get(&u132->kref); -} - -static void u132_endp_queue_work(struct u132 *u132, struct u132_endp *endp, - unsigned int delta) -{ - if (queue_delayed_work(workqueue, &endp->scheduler, delta)) - kref_get(&endp->kref); -} - -static void u132_endp_cancel_work(struct u132 *u132, struct u132_endp *endp) -{ - if (cancel_delayed_work(&endp->scheduler)) - kref_put(&endp->kref, u132_endp_delete); -} - -static inline void u132_monitor_put_kref(struct u132 *u132) -{ - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_queue_work(struct u132 *u132, unsigned int delta) -{ - if (queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_get(&u132->kref); -} - -static void u132_monitor_requeue_work(struct u132 *u132, unsigned int delta) -{ - if (!queue_delayed_work(workqueue, &u132->monitor, delta)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static void u132_monitor_cancel_work(struct u132 *u132) -{ - if (cancel_delayed_work(&u132->monitor)) - kref_put(&u132->kref, u132_hcd_delete); -} - -static int read_roothub_info(struct u132 *u132) -{ - u32 revision; - int retval; - retval = u132_read_pcimem(u132, revision, &revision); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); - return retval; - } else if ((revision & 0xFF) == 0x10) { - } else if ((revision & 0xFF) == 0x11) { - } else { - dev_err(&u132->platform_dev->dev, "device revision is not valid" - " %08X\n", revision); - return -ENODEV; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device co" - "ntrol\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.status, - &u132->hc_roothub_status); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.status\n", retval); - return retval; - } - retval = u132_read_pcimem(u132, roothub.a, &u132->hc_roothub_a); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d accessing device re" - "g roothub.a\n", retval); - return retval; - } - { - int I = u132->num_ports; - int i = 0; - while (I-- > 0) { - retval = u132_read_pcimem(u132, roothub.portstatus[i], - &u132->hc_roothub_portstatus[i]); - if (retval) { - dev_err(&u132->platform_dev->dev, "error %d acc" - "essing device roothub.portstatus[%d]\n" - , retval, i); - return retval; - } else - i += 1; - } - } - return 0; -} - -static void u132_hcd_monitor_work(struct work_struct *work) -{ - struct u132 *u132 = container_of(work, struct u132, monitor.work); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - u132_monitor_put_kref(u132); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - u132_monitor_put_kref(u132); - return; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = read_roothub_info(u132); - if (retval) { - struct usb_hcd *hcd = u132_to_hcd(u132); - u132_disable(u132); - u132->going = 1; - mutex_unlock(&u132->sw_lock); - usb_hc_died(hcd); - ftdi_elan_gone_away(u132->platform_dev); - u132_monitor_put_kref(u132); - return; - } else { - u132_monitor_requeue_work(u132, 500); - mutex_unlock(&u132->sw_lock); - return; - } - } -} - -static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - struct u132_ring *ring; - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - ring->in_use = 0; - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - usb_hcd_giveback_urb(hcd, urb, status); -} - -static void u132_hcd_forget_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - u132_endp_put_kref(u132, endp); -} - -static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - struct usb_hcd *hcd = u132_to_hcd(u132); - urb->error_count = 0; - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_next += 1; - if (ENDP_QUEUE_SIZE > --endp->queue_size) { - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, struct u132_urbq, - urb_more); - list_del(next); - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urbq->urb; - endp->active = 0; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(urbq); - } - usb_hcd_giveback_urb(hcd, urb, status); -} - -static inline int edset_input(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_input(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_setup(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_setup(u132->platform_dev, ring->number, endp, - urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_single(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_single(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - -static inline int edset_output(struct u132 *u132, struct u132_ring *ring, - struct u132_endp *endp, struct urb *urb, u8 address, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - return usb_ftdi_elan_edset_output(u132->platform_dev, ring->number, - endp, urb, address, endp->usb_endp, toggle_bits, callback); -} - - -/* -* must not LOCK sw_lock -* -*/ -static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - if (urb->actual_length > 0) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, - retval); - } else { - ring->in_use = 0; - endp->active = 0; - endp->jiffies = jiffies + - msecs_to_jiffies(urb->interval); - u132_ring_cancel_work(u132, ring); - u132_ring_queue_work(u132, ring, 0); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - } - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 1 & toggle_bits); - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, - 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p givin" - "g back INTERRUPT %s\n", urb, - cc_to_text[condition_code]); - } - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - urb->actual_length += len; - endp->toggle_bits = toggle_bits; - if (urb->transfer_buffer_length > urb->actual_length) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_bulk_output_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer + urb->actual_length; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length += len; - if ((condition_code == TD_CC_NOERROR) && - (urb->transfer_buffer_length > urb->actual_length)) { - int retval; - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_NOERROR) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else if ((condition_code == TD_DATAUNDERRUN) && - ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0)) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_DATAUNDERRUN) { - endp->toggle_bits = toggle_bits; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, - 1 & toggle_bits); - dev_warn(&u132->platform_dev->dev, "urb=%p(SHORT NOT OK" - ") giving back BULK IN %s\n", urb, - cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else if (condition_code == TD_CC_STALL) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, endp->usb_endp, 0, 0); - dev_err(&u132->platform_dev->dev, "urb=%p giving back B" - "ULK IN code=%d %s\n", urb, condition_code, - cc_to_text[condition_code]); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - if ((condition_code == TD_CC_NOERROR) || ((condition_code == - TD_DATAUNDERRUN) && ((urb->transfer_flags & - URB_SHORT_NOT_OK) == 0))) { - int retval; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0x3, - u132_hcd_configure_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (condition_code == TD_CC_STALL) { - mutex_unlock(&u132->scheduler_lock); - dev_warn(&u132->platform_dev->dev, "giving back SETUP I" - "NPUT STALL urb %p\n", urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - dev_err(&u132->platform_dev->dev, "giving back SETUP IN" - "PUT %s urb %p\n", cc_to_text[condition_code], - urb); - u132_hcd_giveback_urb(u132, endp, urb, - cc_to_error[condition_code]); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - if (usb_pipein(urb->pipe)) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, - endp->usb_endp, 0, - u132_hcd_configure_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - u132->addr[0].address = 0; - endp->usb_addr = udev->usb_addr; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb, - u8 *buf, int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, 0, endp->usb_endp, 0, - u132_hcd_enumeration_empty_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - u8 *u = urb->transfer_buffer; - u8 *b = buf; - int L = len; - - while (L-- > 0) - *u++ = *b++; - - urb->actual_length = len; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_empty(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0x3, - u132_hcd_initial_empty_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf, - int len, int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, int non_null) -{ - struct u132_endp *endp = data; - struct u132 *u132 = endp->u132; - u8 address = u132->addr[endp->usb_addr].address; - mutex_lock(&u132->scheduler_lock); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_forget_urb(u132, endp, urb, -ENODEV); - return; - } else if (endp->dequeueing) { - endp->dequeueing = 0; - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -EINTR); - return; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, -ENODEV); - return; - } else if (!urb->unlinked) { - int retval; - struct u132_ring *ring = endp->ring; - mutex_unlock(&u132->scheduler_lock); - retval = usb_ftdi_elan_edset_input(u132->platform_dev, - ring->number, endp, urb, address, endp->usb_endp, 0, - u132_hcd_initial_input_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p " - "unlinked=%d\n", urb, urb->unlinked); - mutex_unlock(&u132->scheduler_lock); - u132_hcd_giveback_urb(u132, endp, urb, 0); - return; - } -} - -/* -* this work function is only executed from the work queue -* -*/ -static void u132_hcd_ring_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring = - container_of(work, struct u132_ring, scheduler.work); - struct u132 *u132 = ring->u132; - mutex_lock(&u132->scheduler_lock); - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else if (ring->curr_endp) { - struct u132_endp *endp, *last_endp = ring->curr_endp; - unsigned long wakeup = 0; - list_for_each_entry(endp, &last_endp->endp_ring, endp_ring) { - if (endp->queue_next == endp->queue_last) { - } else if ((endp->delayed == 0) - || time_after_eq(jiffies, endp->jiffies)) { - ring->curr_endp = endp; - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - } - if (last_endp->queue_next == last_endp->queue_last) { - } else if ((last_endp->delayed == 0) || time_after_eq(jiffies, - last_endp->jiffies)) { - u132_endp_cancel_work(u132, last_endp); - u132_endp_queue_work(u132, last_endp, 0); - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } else { - unsigned long delta = last_endp->jiffies - jiffies; - if (delta > wakeup) - wakeup = delta; - } - if (wakeup > 0) { - u132_ring_requeue_work(u132, ring, wakeup); - mutex_unlock(&u132->scheduler_lock); - return; - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } - } else { - mutex_unlock(&u132->scheduler_lock); - u132_ring_put_kref(u132, ring); - return; - } -} - -static void u132_hcd_endp_work_scheduler(struct work_struct *work) -{ - struct u132_ring *ring; - struct u132_endp *endp = - container_of(work, struct u132_endp, scheduler.work); - struct u132 *u132 = endp->u132; - mutex_lock(&u132->scheduler_lock); - ring = endp->ring; - if (endp->edset_flush) { - endp->edset_flush = 0; - if (endp->dequeueing) - usb_ftdi_elan_edset_flush(u132->platform_dev, - ring->number, endp); - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->active) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->queue_next == endp->queue_last) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (endp->pipetype == PIPE_INTERRUPT) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_single(u132, ring, endp, urb, address, - endp->toggle_bits, u132_hcd_interrupt_recv); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else if (endp->pipetype == PIPE_CONTROL) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else if (address == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_initial_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else if (endp->usb_addr == 0) { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, 0, 0x2, - u132_hcd_enumeration_address_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_next]; - address = u132->addr[endp->usb_addr].address; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_setup(u132, ring, endp, urb, address, - 0x2, u132_hcd_configure_setup_sent); - if (retval != 0) - u132_hcd_giveback_urb(u132, endp, urb, retval); - return; - } - } else { - if (endp->input) { - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_input(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_input_recv); - if (retval == 0) { - } else - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } else { /* output pipe */ - u8 address = u132->addr[endp->usb_addr].address; - if (ring->in_use) { - mutex_unlock(&u132->scheduler_lock); - u132_endp_put_kref(u132, endp); - return; - } else { - int retval; - struct urb *urb = endp->urb_list[ - ENDP_QUEUE_MASK & endp->queue_next]; - endp->active = 1; - ring->curr_endp = endp; - ring->in_use = 1; - mutex_unlock(&u132->scheduler_lock); - retval = edset_output(u132, ring, endp, urb, - address, endp->toggle_bits, - u132_hcd_bulk_output_sent); - if (retval == 0) { - } else - u132_hcd_giveback_urb(u132, endp, urb, - retval); - return; - } - } - } -} -#ifdef CONFIG_PM - -static void port_power(struct u132 *u132, int pn, int is_on) -{ - u132->port[pn].power = is_on; -} - -#endif - -static void u132_power(struct u132 *u132, int is_on) -{ - struct usb_hcd *hcd = u132_to_hcd(u132) - ; /* hub is inactive unless the port is powered */ - if (is_on) { - if (u132->power) - return; - u132->power = 1; - } else { - u132->power = 0; - hcd->state = HC_STATE_HALT; - } -} - -static int u132_periodic_reinit(struct u132 *u132) -{ - int retval; - u32 fi = u132->hc_fminterval & 0x03fff; - u32 fit; - u32 fminterval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - fit = fminterval & FIT; - retval = u132_write_pcimem(u132, fminterval, - (fit ^ FIT) | u132->hc_fminterval); - if (retval) - return retval; - return u132_write_pcimem(u132, periodicstart, - ((9 * fi) / 10) & 0x3fff); -} - -static char *hcfs2string(int state) -{ - switch (state) { - case OHCI_USB_RESET: - return "reset"; - case OHCI_USB_RESUME: - return "resume"; - case OHCI_USB_OPER: - return "operational"; - case OHCI_USB_SUSPEND: - return "suspend"; - } - return "?"; -} - -static int u132_init(struct u132 *u132) -{ - int retval; - u32 control; - u132_disable(u132); - u132->next_statechange = jiffies; - retval = u132_write_pcimem(u132, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - if (u132->num_ports == 0) { - u32 rh_a = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - u132->num_ports = rh_a & RH_A_NDP; - retval = read_roothub_info(u132); - if (retval) - return retval; - } - if (u132->num_ports > MAX_U132_PORTS) - return -EINVAL; - - return 0; -} - - -/* Start an OHCI controller, set the BUS operational -* resets USB and controller -* enable interrupts -*/ -static int u132_run(struct u132 *u132) -{ - int retval; - u32 control; - u32 status; - u32 fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int first = u132->hc_fminterval == 0; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - u132_disable(u132); - if (first) { - u32 temp; - retval = u132_read_pcimem(u132, fminterval, &temp); - if (retval) - return retval; - u132->hc_fminterval = temp & 0x3fff; - u132->hc_fminterval |= FSMP(u132->hc_fminterval) << 16; - } - retval = u132_read_pcimem(u132, control, &u132->hc_control); - if (retval) - return retval; - dev_info(&u132->platform_dev->dev, "resetting from state '%s', control " - "= %08X\n", hcfs2string(u132->hc_control & OHCI_CTRL_HCFS), - u132->hc_control); - switch (u132->hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { - int temp; /* power down each port */ - for (temp = 0; temp < u132->num_ports; temp++) { - retval = u132_write_pcimem(u132, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; -retry: - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_HCR); - if (retval) - return retval; -extra: { - retval = u132_read_pcimem(u132, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&u132->platform_dev->dev, "USB HC reset" - " timed out!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (u132->flags & OHCI_QUIRK_INITRESET) { - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = u132_write_pcimem(u132, hcca, 0x00000000); - if (retval) - return retval; - retval = u132_periodic_reinit(u132); - if (retval) - return retval; - retval = u132_read_pcimem(u132, fminterval, &fminterval); - if (retval) - return retval; - retval = u132_read_pcimem(u132, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(u132->flags & OHCI_QUIRK_INITRESET)) { - u132->flags |= OHCI_QUIRK_INITRESET; - goto retry; - } else - dev_err(&u132->platform_dev->dev, "init err(%08x %04x)" - "\n", fminterval, periodicstart); - } /* start controller operations */ - u132->hc_control &= OHCI_CTRL_RWC; - u132->hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = u132_write_pcimem(u132, control, u132->hc_control); - if (retval) - return retval; - retval = u132_write_pcimem(u132, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = u132_read_pcimem(u132, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - retval = u132_write_pcimem(u132, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrstatus, mask); - if (retval) - return retval; - retval = u132_write_pcimem(u132, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = u132_read_pcimem(u132, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (u132->flags & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((u132->flags & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = u132_write_pcimem(u132, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = u132_write_pcimem(u132, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = u132_write_pcimem(u132, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = u132_read_pcimem(u132, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - u132_to_hcd(u132)->state = HC_STATE_RUNNING; - return 0; -} - -static void u132_hcd_stop(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p) has b" - "een removed %d\n", u132, hcd, u132->going); - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); - } else { - mutex_lock(&u132->sw_lock); - msleep(100); - u132_power(u132, 0); - mutex_unlock(&u132->sw_lock); - } -} - -static int u132_hcd_start(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else if (hcd->self.controller) { - int retval; - struct platform_device *pdev = - to_platform_device(hcd->self.controller); - u16 vendor = ((struct u132_platform_data *) - dev_get_platdata(&pdev->dev))->vendor; - u16 device = ((struct u132_platform_data *) - dev_get_platdata(&pdev->dev))->device; - mutex_lock(&u132->sw_lock); - msleep(10); - if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) { - u132->flags = OHCI_QUIRK_AMD756; - } else if (vendor == PCI_VENDOR_ID_OPTI && device == 0xc861) { - dev_err(&u132->platform_dev->dev, "WARNING: OPTi workar" - "ounds unavailable\n"); - } else if (vendor == PCI_VENDOR_ID_COMPAQ && device == 0xa0f8) - u132->flags |= OHCI_QUIRK_ZFMICRO; - retval = u132_run(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - msleep(100); - mutex_unlock(&u132->sw_lock); - return retval; - } else { - dev_err(&u132->platform_dev->dev, "platform_device missing\n"); - return -ENODEV; - } -} - -static int u132_hcd_reset(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval; - mutex_lock(&u132->sw_lock); - retval = u132_init(u132); - if (retval) { - u132_disable(u132); - u132->going = 1; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int create_endpoint_and_queue_int(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, msecs_to_jiffies(urb->interval)); - return 0; -} - -static int queue_int_on_old_endpoint(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - endp->delayed = 1; - endp->jiffies = jiffies + msecs_to_jiffies(urb->interval); - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_bulk(struct u132 *u132, - struct u132_udev *udev, struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address, - gfp_t mem_flags) -{ - int ring_number; - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - endp->pipetype = usb_pipetype(urb->pipe); - u132_endp_init_kref(u132, endp); - if (usb_pipein(urb->pipe)) { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 0, 0); - ring_number = 3; - endp->input = 1; - endp->output = 0; - udev->endp_number_in[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } else { - endp->toggle_bits = 0x2; - usb_settoggle(udev->usb_device, usb_endp, 1, 0); - ring_number = 2; - endp->input = 0; - endp->output = 1; - udev->endp_number_out[usb_endp] = endp_number; - u132_udev_get_kref(u132, udev); - } - ring = endp->ring = &u132->ring[ring_number - 1]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - urb->hcpriv = u132; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; -} - -static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp, u8 address) -{ - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; -} - -static int create_endpoint_and_queue_control(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, - gfp_t mem_flags) -{ - struct u132_ring *ring; - unsigned long irqs; - int rc; - u8 endp_number; - struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags); - - if (!endp) - return -ENOMEM; - - spin_lock_init(&endp->queue_lock.slock); - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - kfree(endp); - return rc; - } - - endp_number = ++u132->num_endpoints; - urb->ep->hcpriv = u132->endp[endp_number - 1] = endp; - INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler); - INIT_LIST_HEAD(&endp->urb_more); - ring = endp->ring = &u132->ring[0]; - if (ring->curr_endp) { - list_add_tail(&endp->endp_ring, &ring->curr_endp->endp_ring); - } else { - INIT_LIST_HEAD(&endp->endp_ring); - ring->curr_endp = endp; - } - ring->length += 1; - endp->dequeueing = 0; - endp->edset_flush = 0; - endp->active = 0; - endp->delayed = 0; - endp->endp_number = endp_number; - endp->u132 = u132; - endp->hep = urb->ep; - u132_endp_init_kref(u132, endp); - u132_endp_get_kref(u132, endp); - if (usb_addr == 0) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_init_kref(u132, udev); - u132_udev_get_kref(u132, udev); - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - endp->udev_number = address; - endp->usb_addr = usb_addr; - endp->usb_endp = usb_endp; - endp->input = 1; - endp->output = 1; - endp->pipetype = usb_pipetype(urb->pipe); - u132_udev_get_kref(u132, udev); - udev->enumeration = 2; - udev->endp_number_in[usb_endp] = endp_number; - udev->endp_number_out[usb_endp] = endp_number; - urb->hcpriv = u132; - endp->queue_size = 1; - endp->queue_last = 0; - endp->queue_next = 0; - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_endp_queue_work(u132, endp, 0); - return 0; - } -} - -static int queue_control_on_old_endpoint(struct u132 *u132, - struct urb *urb, - struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr, - u8 usb_endp) -{ - if (usb_addr == 0) { - if (usb_pipein(urb->pipe)) { - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } else { /* usb_pipeout(urb->pipe) */ - struct u132_addr *addr = &u132->addr[usb_dev->devnum]; - int I = MAX_U132_UDEVS; - int i = 0; - while (--I > 0) { - struct u132_udev *udev = &u132->udev[++i]; - if (udev->usb_device) { - continue; - } else { - udev->enumeration = 1; - u132->addr[0].address = i; - endp->udev_number = i; - udev->udev_number = i; - udev->usb_addr = usb_dev->devnum; - u132_udev_init_kref(u132, udev); - udev->endp_number_in[usb_endp] = - endp->endp_number; - u132_udev_get_kref(u132, udev); - udev->endp_number_out[usb_endp] = - endp->endp_number; - udev->usb_device = usb_dev; - ((u8 *) (urb->setup_packet))[2] = - addr->address = i; - u132_udev_get_kref(u132, udev); - break; - } - } - if (I == 0) { - dev_err(&u132->platform_dev->dev, "run out of d" - "evice space\n"); - return -EINVAL; - } - urb->hcpriv = u132; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & - endp->queue_last++] = urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), - GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, - &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } - } else { /*(usb_addr > 0) */ - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - urb->hcpriv = u132; - if (udev->enumeration != 2) - udev->enumeration = 2; - if (endp->queue_size++ < ENDP_QUEUE_SIZE) { - endp->urb_list[ENDP_QUEUE_MASK & endp->queue_last++] = - urb; - } else { - struct u132_urbq *urbq = - kmalloc(sizeof(struct u132_urbq), GFP_ATOMIC); - if (urbq == NULL) { - endp->queue_size -= 1; - return -ENOMEM; - } else { - list_add_tail(&urbq->urb_more, &endp->urb_more); - urbq->urb = urb; - } - } - return 0; - } -} - -static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, - gfp_t mem_flags) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (irqs_disabled()) { - if (gfpflags_allow_blocking(mem_flags)) { - printk(KERN_ERR "invalid context for function that might sleep\n"); - return -EINVAL; - } - } - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed " - "urb=%p\n", urb); - return -ESHUTDOWN; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - struct usb_device *usb_dev = urb->dev; - if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_int_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, - msecs_to_jiffies(urb->interval)) - ; - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else { /*(endp == NULL) */ - return create_endpoint_and_queue_int(u132, udev, - urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } - } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { - dev_err(&u132->platform_dev->dev, "the hardware does no" - "t support PIPE_ISOCHRONOUS\n"); - return -EINVAL; - } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - struct u132_endp *endp = urb->ep->hcpriv; - urb->actual_length = 0; - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_bulk_on_old_endpoint( - u132, udev, urb, - usb_dev, endp, - usb_addr, usb_endp, - address); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else - return create_endpoint_and_queue_bulk(u132, - udev, urb, usb_dev, usb_addr, - usb_endp, address, mem_flags); - } else { - struct u132_endp *endp = urb->ep->hcpriv; - u16 urb_size = 8; - u8 *b = urb->setup_packet; - int i = 0; - char data[30 * 3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3; - int l = 0; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - l += w; - } else - d += sprintf(d, " .."); - } - if (endp) { - unsigned long irqs; - int retval; - spin_lock_irqsave(&endp->queue_lock.slock, - irqs); - retval = usb_hcd_link_urb_to_ep(hcd, urb); - if (retval == 0) { - retval = queue_control_on_old_endpoint( - u132, urb, usb_dev, - endp, usb_addr, - usb_endp); - if (retval) - usb_hcd_unlink_urb_from_ep( - hcd, urb); - } - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - if (retval) { - return retval; - } else { - u132_endp_queue_work(u132, endp, 0); - return 0; - } - } else if (u132->num_endpoints == MAX_U132_ENDPS) { - return -EINVAL; - } else - return create_endpoint_and_queue_control(u132, - urb, usb_dev, usb_addr, usb_endp, - mem_flags); - } - } -} - -static int dequeue_from_overflow_chain(struct u132 *u132, - struct u132_endp *endp, struct urb *urb) -{ - struct u132_urbq *urbq; - - list_for_each_entry(urbq, &endp->urb_more, urb_more) { - if (urbq->urb == urb) { - struct usb_hcd *hcd = u132_to_hcd(u132); - list_del(&urbq->urb_more); - endp->queue_size -= 1; - urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, 0); - return 0; - } - } - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]=%p ring" - "[%d] %c%c usb_endp=%d usb_addr=%d size=%d next=%04X last=%04X" - "\n", urb, endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - return -EINVAL; -} - -static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp, - struct urb *urb, int status) -{ - unsigned long irqs; - int rc; - - spin_lock_irqsave(&endp->queue_lock.slock, irqs); - rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status); - if (rc) { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return rc; - } - if (endp->queue_size == 0) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]" - "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb, - endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', endp->output ? 'O' : ' ', - endp->usb_endp, endp->usb_addr); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } - if (urb == endp->urb_list[ENDP_QUEUE_MASK & endp->queue_next]) { - if (endp->active) { - endp->dequeueing = 1; - endp->edset_flush = 1; - u132_endp_queue_work(u132, endp, 0); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return 0; - } else { - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - u132_hcd_abandon_urb(u132, endp, urb, status); - return 0; - } - } else { - u16 queue_list = 0; - u16 queue_size = endp->queue_size; - u16 queue_scan = endp->queue_next; - struct urb **urb_slot = NULL; - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - if (urb == endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]) { - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - break; - } - } - while (++queue_list < ENDP_QUEUE_SIZE && --queue_size > 0) { - *urb_slot = endp->urb_list[ENDP_QUEUE_MASK & - ++queue_scan]; - urb_slot = &endp->urb_list[ENDP_QUEUE_MASK & - queue_scan]; - } - if (urb_slot) { - struct usb_hcd *hcd = u132_to_hcd(u132); - - usb_hcd_unlink_urb_from_ep(hcd, urb); - endp->queue_size -= 1; - if (list_empty(&endp->urb_more)) { - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - } else { - struct list_head *next = endp->urb_more.next; - struct u132_urbq *urbq = list_entry(next, - struct u132_urbq, urb_more); - list_del(next); - *urb_slot = urbq->urb; - spin_unlock_irqrestore(&endp->queue_lock.slock, - irqs); - kfree(urbq); - } - urb->error_count = 0; - usb_hcd_giveback_urb(hcd, urb, status); - return 0; - } else if (list_empty(&endp->urb_more)) { - dev_err(&u132->platform_dev->dev, "urb=%p not found in " - "endp[%d]=%p ring[%d] %c%c usb_endp=%d usb_addr" - "=%d size=%d next=%04X last=%04X\n", urb, - endp->endp_number, endp, endp->ring->number, - endp->input ? 'I' : ' ', - endp->output ? 'O' : ' ', endp->usb_endp, - endp->usb_addr, endp->queue_size, - endp->queue_next, endp->queue_last); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return -EINVAL; - } else { - int retval; - - usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb); - retval = dequeue_from_overflow_chain(u132, endp, - urb); - spin_unlock_irqrestore(&endp->queue_lock.slock, irqs); - return retval; - } - } -} - -static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else { - u8 usb_addr = usb_pipedevice(urb->pipe); - u8 usb_endp = usb_pipeendpoint(urb->pipe); - u8 address = u132->addr[usb_addr].address; - struct u132_udev *udev = &u132->udev[address]; - if (usb_pipein(urb->pipe)) { - u8 endp_number = udev->endp_number_in[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } else { - u8 endp_number = udev->endp_number_out[usb_endp]; - struct u132_endp *endp = u132->endp[endp_number - 1]; - return u132_endp_urb_dequeue(u132, endp, urb, status); - } - } -} - -static void u132_endpoint_disable(struct usb_hcd *hcd, - struct usb_host_endpoint *hep) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 2) { - dev_err(&u132->platform_dev->dev, "u132 device %p(hcd=%p hep=%p" - ") has been removed %d\n", u132, hcd, hep, - u132->going); - } else { - struct u132_endp *endp = hep->hcpriv; - if (endp) - u132_endp_put_kref(u132, endp); - } -} - -static int u132_get_frame(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - dev_err(&u132->platform_dev->dev, "TODO: u132_get_frame\n"); - mdelay(100); - return 0; - } -} - -static int u132_roothub_descriptor(struct u132 *u132, - struct usb_hub_descriptor *desc) -{ - int retval; - u16 temp; - u32 rh_a = -1; - u32 rh_b = -1; - retval = u132_read_pcimem(u132, roothub.a, &rh_a); - if (retval) - return retval; - desc->bDescriptorType = USB_DT_HUB; - desc->bPwrOn2PwrGood = (rh_a & RH_A_POTPGT) >> 24; - desc->bHubContrCurrent = 0; - desc->bNbrPorts = u132->num_ports; - temp = 1 + (u132->num_ports / 8); - desc->bDescLength = 7 + 2 * temp; - temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM; - if (rh_a & RH_A_NPS) - temp |= HUB_CHAR_NO_LPSM; - if (rh_a & RH_A_PSM) - temp |= HUB_CHAR_INDV_PORT_LPSM; - if (rh_a & RH_A_NOCP) - temp |= HUB_CHAR_NO_OCPM; - else if (rh_a & RH_A_OCPM) - temp |= HUB_CHAR_INDV_PORT_OCPM; - desc->wHubCharacteristics = cpu_to_le16(temp); - retval = u132_read_pcimem(u132, roothub.b, &rh_b); - if (retval) - return retval; - memset(desc->u.hs.DeviceRemovable, 0xff, - sizeof(desc->u.hs.DeviceRemovable)); - desc->u.hs.DeviceRemovable[0] = rh_b & RH_B_DR; - if (u132->num_ports > 7) { - desc->u.hs.DeviceRemovable[1] = (rh_b & RH_B_DR) >> 8; - desc->u.hs.DeviceRemovable[2] = 0xff; - } else - desc->u.hs.DeviceRemovable[1] = 0xff; - return 0; -} - -static int u132_roothub_status(struct u132 *u132, __le32 *desc) -{ - u32 rh_status = -1; - int ret_status = u132_read_pcimem(u132, roothub.status, &rh_status); - *desc = cpu_to_le32(rh_status); - return ret_status; -} - -static int u132_roothub_portstatus(struct u132 *u132, __le32 *desc, u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port = wIndex - 1; - u32 rh_portstatus = -1; - int ret_portstatus = u132_read_pcimem(u132, - roothub.portstatus[port], &rh_portstatus); - *desc = cpu_to_le32(rh_portstatus); - if (*(u16 *) (desc + 2)) { - dev_info(&u132->platform_dev->dev, "Port %d Status Chan" - "ge = %08X\n", port, *desc); - } - return ret_portstatus; - } -} - - -/* this timer value might be vendor-specific ... */ -#define PORT_RESET_HW_MSEC 10 -#define PORT_RESET_MSEC 10 -/* wrap-aware logic morphed from <linux/jiffies.h> */ -#define tick_before(t1, t2) ((s16)(((s16)(t1))-((s16)(t2))) < 0) -static int u132_roothub_portreset(struct u132 *u132, int port_index) -{ - int retval; - u32 fmnumber; - u16 now; - u16 reset_done; - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - reset_done = now + PORT_RESET_MSEC; - do { - u32 portstat; - do { - retval = u132_read_pcimem(u132, - roothub.portstatus[port_index], &portstat); - if (retval) - return retval; - if (RH_PS_PRS & portstat) - continue; - else - break; - } while (tick_before(now, reset_done)); - if (RH_PS_PRS & portstat) - return -ENODEV; - if (RH_PS_CCS & portstat) { - if (RH_PS_PRSC & portstat) { - retval = u132_write_pcimem(u132, - roothub.portstatus[port_index], - RH_PS_PRSC); - if (retval) - return retval; - } - } else - break; /* start the next reset, - sleep till it's probably done */ - retval = u132_write_pcimem(u132, roothub.portstatus[port_index], - RH_PS_PRS); - if (retval) - return retval; - msleep(PORT_RESET_HW_MSEC); - retval = u132_read_pcimem(u132, fmnumber, &fmnumber); - if (retval) - return retval; - now = fmnumber; - } while (tick_before(now, reset_done)); - return 0; -} - -static int u132_roothub_setportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port_index = wIndex - 1; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_SUSPEND: - return u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PSS); - case USB_PORT_FEAT_POWER: - return u132_write_pcimem(u132, - roothub.portstatus[port_index], RH_PS_PPS); - case USB_PORT_FEAT_RESET: - return u132_roothub_portreset(u132, port_index); - default: - return -EPIPE; - } - } -} - -static int u132_roothub_clearportfeature(struct u132 *u132, u16 wValue, - u16 wIndex) -{ - if (wIndex == 0 || wIndex > u132->num_ports) { - return -EINVAL; - } else { - int port_index = wIndex - 1; - u32 temp; - struct u132_port *port = &u132->port[port_index]; - port->Status &= ~(1 << wValue); - switch (wValue) { - case USB_PORT_FEAT_ENABLE: - temp = RH_PS_CCS; - break; - case USB_PORT_FEAT_C_ENABLE: - temp = RH_PS_PESC; - break; - case USB_PORT_FEAT_SUSPEND: - temp = RH_PS_POCI; - if ((u132->hc_control & OHCI_CTRL_HCFS) - != OHCI_USB_OPER) { - dev_err(&u132->platform_dev->dev, "TODO resume_" - "root_hub\n"); - } - break; - case USB_PORT_FEAT_C_SUSPEND: - temp = RH_PS_PSSC; - break; - case USB_PORT_FEAT_POWER: - temp = RH_PS_LSDA; - break; - case USB_PORT_FEAT_C_CONNECTION: - temp = RH_PS_CSC; - break; - case USB_PORT_FEAT_C_OVER_CURRENT: - temp = RH_PS_OCIC; - break; - case USB_PORT_FEAT_C_RESET: - temp = RH_PS_PRSC; - break; - default: - return -EPIPE; - } - return u132_write_pcimem(u132, roothub.portstatus[port_index], - temp); - } -} - - -/* the virtual root hub timer IRQ checks for hub status*/ -static int u132_hub_status_data(struct usb_hcd *hcd, char *buf) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device hcd=%p has been remov" - "ed %d\n", hcd, u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov" - "ed\n", hcd); - return -ESHUTDOWN; - } else { - int i, changed = 0, length = 1; - if (u132->flags & OHCI_QUIRK_AMD756) { - if ((u132->hc_roothub_a & RH_A_NDP) > MAX_ROOT_PORTS) { - dev_err(&u132->platform_dev->dev, "bogus NDP, r" - "ereads as NDP=%d\n", - u132->hc_roothub_a & RH_A_NDP); - goto done; - } - } - if (u132->hc_roothub_status & (RH_HS_LPSC | RH_HS_OCIC)) - buf[0] = changed = 1; - else - buf[0] = 0; - if (u132->num_ports > 7) { - buf[1] = 0; - length++; - } - for (i = 0; i < u132->num_ports; i++) { - if (u132->hc_roothub_portstatus[i] & (RH_PS_CSC | - RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | - RH_PS_PRSC)) { - changed = 1; - if (i < 7) - buf[0] |= 1 << (i + 1); - else - buf[1] |= 1 << (i - 7); - continue; - } - if (!(u132->hc_roothub_portstatus[i] & RH_PS_CCS)) - continue; - - if ((u132->hc_roothub_portstatus[i] & RH_PS_PSS)) - continue; - } -done: - return changed ? length : 0; - } -} - -static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, - u16 wIndex, char *buf, u16 wLength) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - mutex_lock(&u132->sw_lock); - switch (typeReq) { - case ClearHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case SetHubFeature: - switch (wValue) { - case C_HUB_OVER_CURRENT: - case C_HUB_LOCAL_POWER: - break; - default: - goto stall; - } - break; - case ClearPortFeature:{ - retval = u132_roothub_clearportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - case GetHubDescriptor:{ - retval = u132_roothub_descriptor(u132, - (struct usb_hub_descriptor *)buf); - if (retval) - goto error; - break; - } - case GetHubStatus:{ - retval = u132_roothub_status(u132, - (__le32 *) buf); - if (retval) - goto error; - break; - } - case GetPortStatus:{ - retval = u132_roothub_portstatus(u132, - (__le32 *) buf, wIndex); - if (retval) - goto error; - break; - } - case SetPortFeature:{ - retval = u132_roothub_setportfeature(u132, - wValue, wIndex); - if (retval) - goto error; - break; - } - default: - goto stall; - error: - u132_disable(u132); - u132->going = 1; - break; - stall: - retval = -EPIPE; - break; - } - mutex_unlock(&u132->sw_lock); - return retval; - } -} - -static int u132_start_port_reset(struct usb_hcd *hcd, unsigned port_num) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - - -#ifdef CONFIG_PM -static int u132_bus_suspend(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - -static int u132_bus_resume(struct usb_hcd *hcd) -{ - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else - return 0; -} - -#else -#define u132_bus_suspend NULL -#define u132_bus_resume NULL -#endif -static const struct hc_driver u132_hc_driver = { - .description = hcd_name, - .hcd_priv_size = sizeof(struct u132), - .irq = NULL, - .flags = HCD_USB11 | HCD_MEMORY, - .reset = u132_hcd_reset, - .start = u132_hcd_start, - .stop = u132_hcd_stop, - .urb_enqueue = u132_urb_enqueue, - .urb_dequeue = u132_urb_dequeue, - .endpoint_disable = u132_endpoint_disable, - .get_frame_number = u132_get_frame, - .hub_status_data = u132_hub_status_data, - .hub_control = u132_hub_control, - .bus_suspend = u132_bus_suspend, - .bus_resume = u132_bus_resume, - .start_port_reset = u132_start_port_reset, -}; - -/* -* This function may be called by the USB core whilst the "usb_all_devices_rwsem" -* is held for writing, thus this module must not call usb_remove_hcd() -* synchronously - but instead should immediately stop activity to the -* device and asynchronously call usb_remove_hcd() -*/ -static int u132_remove(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - if (hcd) { - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going++ > 1) { - dev_err(&u132->platform_dev->dev, "already being remove" - "d\n"); - return -ENODEV; - } else { - int rings = MAX_U132_RINGS; - int endps = MAX_U132_ENDPS; - dev_err(&u132->platform_dev->dev, "removing device u132" - ".%d\n", u132->sequence_num); - msleep(100); - mutex_lock(&u132->sw_lock); - u132_monitor_cancel_work(u132); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - u132_ring_cancel_work(u132, ring); - } - while (endps-- > 0) { - struct u132_endp *endp = u132->endp[endps]; - if (endp) - u132_endp_cancel_work(u132, endp); - } - u132->going += 1; - printk(KERN_INFO "removing device u132.%d\n", - u132->sequence_num); - mutex_unlock(&u132->sw_lock); - usb_remove_hcd(hcd); - u132_u132_put_kref(u132); - return 0; - } - } else - return 0; -} - -static void u132_initialise(struct u132 *u132, struct platform_device *pdev) -{ - int rings = MAX_U132_RINGS; - int ports = MAX_U132_PORTS; - int addrs = MAX_U132_ADDRS; - int udevs = MAX_U132_UDEVS; - int endps = MAX_U132_ENDPS; - u132->board = dev_get_platdata(&pdev->dev); - u132->platform_dev = pdev; - u132->power = 0; - u132->reset = 0; - mutex_init(&u132->sw_lock); - mutex_init(&u132->scheduler_lock); - while (rings-- > 0) { - struct u132_ring *ring = &u132->ring[rings]; - ring->u132 = u132; - ring->number = rings + 1; - ring->length = 0; - ring->curr_endp = NULL; - INIT_DELAYED_WORK(&ring->scheduler, - u132_hcd_ring_work_scheduler); - } - mutex_lock(&u132->sw_lock); - INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work); - while (ports-- > 0) { - struct u132_port *port = &u132->port[ports]; - port->u132 = u132; - port->reset = 0; - port->enable = 0; - port->power = 0; - port->Status = 0; - } - while (addrs-- > 0) { - struct u132_addr *addr = &u132->addr[addrs]; - addr->address = 0; - } - while (udevs-- > 0) { - struct u132_udev *udev = &u132->udev[udevs]; - int i = ARRAY_SIZE(udev->endp_number_in); - int o = ARRAY_SIZE(udev->endp_number_out); - udev->usb_device = NULL; - udev->udev_number = 0; - udev->usb_addr = 0; - udev->portnumber = 0; - while (i-- > 0) - udev->endp_number_in[i] = 0; - - while (o-- > 0) - udev->endp_number_out[o] = 0; - - } - while (endps-- > 0) - u132->endp[endps] = NULL; - - mutex_unlock(&u132->sw_lock); -} - -static int u132_probe(struct platform_device *pdev) -{ - struct usb_hcd *hcd; - int retval; - u32 control; - u32 rh_a = -1; - - msleep(100); - if (u132_exiting > 0) - return -ENODEV; - - retval = ftdi_write_pcimem(pdev, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(pdev, roothub.a, &rh_a); - if (retval) - return retval; - - hcd = usb_create_hcd(&u132_hc_driver, &pdev->dev, dev_name(&pdev->dev)); - if (!hcd) { - printk(KERN_ERR "failed to create the usb hcd struct for U132\n" - ); - ftdi_elan_gone_away(pdev); - return -ENOMEM; - } else { - struct u132 *u132 = hcd_to_u132(hcd); - retval = 0; - hcd->rsrc_start = 0; - mutex_lock(&u132_module_lock); - u132->sequence_num = ++u132_instances; - mutex_unlock(&u132_module_lock); - u132_u132_init_kref(u132); - u132_initialise(u132, pdev); - hcd->product_desc = "ELAN U132 Host Controller"; - retval = usb_add_hcd(hcd, 0, 0); - if (retval != 0) { - dev_err(&u132->platform_dev->dev, "init error %d\n", - retval); - u132_u132_put_kref(u132); - return retval; - } else { - device_wakeup_enable(hcd->self.controller); - u132_monitor_queue_work(u132, 100); - return 0; - } - } -} - - -#ifdef CONFIG_PM -/* - * for this device there's no useful distinction between the controller - * and its root hub. - */ -static int u132_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0, ports; - - switch (state.event) { - case PM_EVENT_FREEZE: - retval = u132_bus_suspend(hcd); - break; - case PM_EVENT_SUSPEND: - case PM_EVENT_HIBERNATE: - ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 0); - } - break; - } - return retval; - } -} - -static int u132_resume(struct platform_device *pdev) -{ - struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct u132 *u132 = hcd_to_u132(hcd); - if (u132->going > 1) { - dev_err(&u132->platform_dev->dev, "device has been removed %d\n" - , u132->going); - return -ENODEV; - } else if (u132->going > 0) { - dev_err(&u132->platform_dev->dev, "device is being removed\n"); - return -ESHUTDOWN; - } else { - int retval = 0; - if (!u132->port[0].power) { - int ports = MAX_U132_PORTS; - while (ports-- > 0) { - port_power(u132, ports, 1); - } - retval = 0; - } else { - retval = u132_bus_resume(hcd); - } - return retval; - } -} - -#else -#define u132_suspend NULL -#define u132_resume NULL -#endif -/* -* this driver is loaded explicitly by ftdi_u132 -* -* the platform_driver struct is static because it is per type of module -*/ -static struct platform_driver u132_platform_driver = { - .probe = u132_probe, - .remove = u132_remove, - .suspend = u132_suspend, - .resume = u132_resume, - .driver = { - .name = hcd_name, - }, -}; -static int __init u132_hcd_init(void) -{ - int retval; - u132_instances = 0; - u132_exiting = 0; - if (usb_disabled()) - return -ENODEV; - workqueue = create_singlethread_workqueue("u132"); - if (!workqueue) - return -ENOMEM; - retval = platform_driver_register(&u132_platform_driver); - if (retval) - destroy_workqueue(workqueue); - - return retval; -} - - -module_init(u132_hcd_init); -static void __exit u132_hcd_exit(void) -{ - mutex_lock(&u132_module_lock); - u132_exiting += 1; - mutex_unlock(&u132_module_lock); - platform_driver_unregister(&u132_platform_driver); - printk(KERN_INFO "u132-hcd driver deregistered\n"); - wait_event(u132_hcd_wait, u132_instances == 0); - destroy_workqueue(workqueue); -} - - -module_exit(u132_hcd_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:u132_hcd"); diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index f1367b53b260..b40d9238d447 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -124,10 +124,10 @@ static void xhci_dbc_init_contexts(struct xhci_dbc *dbc, u32 string_length) /* Set DbC context and info registers: */ lo_hi_writeq(dbc->ctx->dma, &dbc->regs->dccp); - dev_info = cpu_to_le32((DBC_VENDOR_ID << 16) | DBC_PROTOCOL); + dev_info = (dbc->idVendor << 16) | dbc->bInterfaceProtocol; writel(dev_info, &dbc->regs->devinfo1); - dev_info = cpu_to_le32((DBC_DEVICE_REV << 16) | DBC_PRODUCT_ID); + dev_info = (dbc->bcdDevice << 16) | dbc->idProduct; writel(dev_info, &dbc->regs->devinfo2); } @@ -971,7 +971,186 @@ static ssize_t dbc_store(struct device *dev, return count; } +static ssize_t dbc_idVendor_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->idVendor); +} + +static ssize_t dbc_idVendor_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u16 value; + u32 dev_info; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->idVendor = value; + ptr = &dbc->regs->devinfo1; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16); + writel(dev_info, ptr); + + return size; +} + +static ssize_t dbc_idProduct_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->idProduct); +} + +static ssize_t dbc_idProduct_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u16 value; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->idProduct = value; + ptr = &dbc->regs->devinfo2; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu)) | value; + writel(dev_info, ptr); + return size; +} + +static ssize_t dbc_bcdDevice_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%04x\n", dbc->bcdDevice); +} + +static ssize_t dbc_bcdDevice_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u16 value; + + if (kstrtou16(buf, 0, &value)) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->bcdDevice = value; + ptr = &dbc->regs->devinfo2; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffffu << 16)) | (value << 16); + writel(dev_info, ptr); + + return size; +} + +static ssize_t dbc_bInterfaceProtocol_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + + return sprintf(buf, "%02x\n", dbc->bInterfaceProtocol); +} + +static ssize_t dbc_bInterfaceProtocol_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + struct xhci_dbc *dbc; + struct xhci_hcd *xhci; + void __iomem *ptr; + u32 dev_info; + u8 value; + int ret; + + /* bInterfaceProtocol is 8 bit, but xhci only supports values 0 and 1 */ + ret = kstrtou8(buf, 0, &value); + if (ret || value > 1) + return -EINVAL; + + xhci = hcd_to_xhci(dev_get_drvdata(dev)); + dbc = xhci->dbc; + if (dbc->state != DS_DISABLED) + return -EBUSY; + + dbc->bInterfaceProtocol = value; + ptr = &dbc->regs->devinfo1; + dev_info = readl(ptr); + dev_info = (dev_info & ~(0xffu)) | value; + writel(dev_info, ptr); + + return size; +} + static DEVICE_ATTR_RW(dbc); +static DEVICE_ATTR_RW(dbc_idVendor); +static DEVICE_ATTR_RW(dbc_idProduct); +static DEVICE_ATTR_RW(dbc_bcdDevice); +static DEVICE_ATTR_RW(dbc_bInterfaceProtocol); + +static struct attribute *dbc_dev_attributes[] = { + &dev_attr_dbc.attr, + &dev_attr_dbc_idVendor.attr, + &dev_attr_dbc_idProduct.attr, + &dev_attr_dbc_bcdDevice.attr, + &dev_attr_dbc_bInterfaceProtocol.attr, + NULL +}; + +static const struct attribute_group dbc_dev_attrib_grp = { + .attrs = dbc_dev_attributes, +}; struct xhci_dbc * xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver *driver) @@ -986,6 +1165,10 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * dbc->regs = base; dbc->dev = dev; dbc->driver = driver; + dbc->idProduct = DBC_PRODUCT_ID; + dbc->idVendor = DBC_VENDOR_ID; + dbc->bcdDevice = DBC_DEVICE_REV; + dbc->bInterfaceProtocol = DBC_PROTOCOL; if (readl(&dbc->regs->control) & DBC_CTRL_DBC_ENABLE) goto err; @@ -993,7 +1176,7 @@ xhci_alloc_dbc(struct device *dev, void __iomem *base, const struct dbc_driver * INIT_DELAYED_WORK(&dbc->event_work, xhci_dbc_handle_events); spin_lock_init(&dbc->lock); - ret = device_create_file(dev, &dev_attr_dbc); + ret = sysfs_create_group(&dev->kobj, &dbc_dev_attrib_grp); if (ret) goto err; @@ -1012,7 +1195,7 @@ void xhci_dbc_remove(struct xhci_dbc *dbc) xhci_dbc_stop(dbc); /* remove sysfs files */ - device_remove_file(dbc->dev, &dev_attr_dbc); + sysfs_remove_group(&dbc->dev->kobj, &dbc_dev_attrib_grp); kfree(dbc); } diff --git a/drivers/usb/host/xhci-dbgcap.h b/drivers/usb/host/xhci-dbgcap.h index ca04192fdab1..51a7ab3ba0ca 100644 --- a/drivers/usb/host/xhci-dbgcap.h +++ b/drivers/usb/host/xhci-dbgcap.h @@ -132,6 +132,10 @@ struct xhci_dbc { struct dbc_str_descs *string; dma_addr_t string_dma; size_t string_size; + u16 idVendor; + u16 idProduct; + u16 bcdDevice; + u8 bInterfaceProtocol; enum dbc_state state; struct delayed_work event_work; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index d0a9467aa5fc..7e106bd804ca 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -9,6 +9,7 @@ */ #include <linux/usb.h> +#include <linux/overflow.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/dmapool.h> @@ -543,14 +544,11 @@ static void xhci_free_stream_ctx(struct xhci_hcd *xhci, size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; if (size > MEDIUM_STREAM_ARRAY_SIZE) - dma_free_coherent(dev, size, - stream_ctx, dma); - else if (size <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_free(xhci->small_streams_pool, - stream_ctx, dma); + dma_free_coherent(dev, size, stream_ctx, dma); + else if (size > SMALL_STREAM_ARRAY_SIZE) + dma_pool_free(xhci->medium_streams_pool, stream_ctx, dma); else - return dma_pool_free(xhci->medium_streams_pool, - stream_ctx, dma); + dma_pool_free(xhci->small_streams_pool, stream_ctx, dma); } /* @@ -568,17 +566,14 @@ static struct xhci_stream_ctx *xhci_alloc_stream_ctx(struct xhci_hcd *xhci, gfp_t mem_flags) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - size_t size = sizeof(struct xhci_stream_ctx) * num_stream_ctxs; + size_t size = size_mul(sizeof(struct xhci_stream_ctx), num_stream_ctxs); if (size > MEDIUM_STREAM_ARRAY_SIZE) - return dma_alloc_coherent(dev, size, - dma, mem_flags); - else if (size <= SMALL_STREAM_ARRAY_SIZE) - return dma_pool_alloc(xhci->small_streams_pool, - mem_flags, dma); + return dma_alloc_coherent(dev, size, dma, mem_flags); + if (size > SMALL_STREAM_ARRAY_SIZE) + return dma_pool_zalloc(xhci->medium_streams_pool, mem_flags, dma); else - return dma_pool_alloc(xhci->medium_streams_pool, - mem_flags, dma); + return dma_pool_zalloc(xhci->small_streams_pool, mem_flags, dma); } struct xhci_ring *xhci_dma_to_transfer_ring( @@ -612,8 +607,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, int ret; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - xhci_dbg(xhci, "Allocating %u streams and %u " - "stream context array entries.\n", + xhci_dbg(xhci, "Allocating %u streams and %u stream context array entries.\n", num_streams, num_stream_ctxs); if (xhci->cmd_ring_reserved_trbs == MAX_RSVD_CMD_TRBS) { xhci_dbg(xhci, "Command ring has no reserved TRBs available\n"); @@ -642,8 +636,6 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, mem_flags); if (!stream_info->stream_ctx_array) goto cleanup_ring_array; - memset(stream_info->stream_ctx_array, 0, - sizeof(struct xhci_stream_ctx)*num_stream_ctxs); /* Allocate everything needed to free the stream rings later */ stream_info->free_streams_command = @@ -673,8 +665,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci, cur_ring->cycle_state; stream_info->stream_ctx_array[cur_stream].stream_ring = cpu_to_le64(addr); - xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", - cur_stream, (unsigned long long) addr); + xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n", cur_stream, addr); ret = xhci_update_stream_mapping(cur_ring, mem_flags); if (ret) { @@ -984,16 +975,14 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id, if (!dev->out_ctx) goto fail; - xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->out_ctx->dma); + xhci_dbg(xhci, "Slot %d output ctx = 0x%pad (dma)\n", slot_id, &dev->out_ctx->dma); /* Allocate the (input) device context for address device command */ dev->in_ctx = xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, flags); if (!dev->in_ctx) goto fail; - xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id, - (unsigned long long)dev->in_ctx->dma); + xhci_dbg(xhci, "Slot %d input ctx = 0x%pad (dma)\n", slot_id, &dev->in_ctx->dma); /* Initialize the cancellation and bandwidth list for each ep */ for (i = 0; i < 31; i++) { @@ -1400,8 +1389,9 @@ static u32 xhci_get_max_esit_payload(struct usb_device *udev, if ((udev->speed >= USB_SPEED_SUPER_PLUS) && USB_SS_SSP_ISOC_COMP(ep->ss_ep_comp.bmAttributes)) return le32_to_cpu(ep->ssp_isoc_ep_comp.dwBytesPerInterval); + /* SuperSpeed or SuperSpeedPlus Isoc ep with less than 48k per esit */ - else if (udev->speed >= USB_SPEED_SUPER) + if (udev->speed >= USB_SPEED_SUPER) return le16_to_cpu(ep->ss_ep_comp.wBytesPerInterval); max_packet = usb_endpoint_maxp(&ep->desc); @@ -1660,7 +1650,7 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) goto fail_sp; xhci->scratchpad->sp_array = dma_alloc_coherent(dev, - num_sp * sizeof(u64), + size_mul(sizeof(u64), num_sp), &xhci->scratchpad->sp_dma, flags); if (!xhci->scratchpad->sp_array) goto fail_sp2; @@ -1685,11 +1675,10 @@ static int scratchpad_alloc(struct xhci_hcd *xhci, gfp_t flags) return 0; fail_sp4: - for (i = i - 1; i >= 0; i--) { + while (i--) dma_free_coherent(dev, xhci->page_size, xhci->scratchpad->sp_buffers[i], xhci->scratchpad->sp_array[i]); - } kfree(xhci->scratchpad->sp_buffers); @@ -1799,7 +1788,7 @@ int xhci_alloc_erst(struct xhci_hcd *xhci, struct xhci_segment *seg; struct xhci_erst_entry *entry; - size = sizeof(struct xhci_erst_entry) * evt_ring->num_segs; + size = size_mul(sizeof(struct xhci_erst_entry), evt_ring->num_segs); erst->entries = dma_alloc_coherent(xhci_to_hcd(xhci)->self.sysdev, size, &erst->erst_dma_addr, flags); if (!erst->entries) @@ -1830,7 +1819,7 @@ xhci_free_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir) if (!ir) return; - erst_size = sizeof(struct xhci_erst_entry) * (ir->erst.num_entries); + erst_size = sizeof(struct xhci_erst_entry) * ir->erst.num_entries; if (ir->erst.entries) dma_free_coherent(dev, erst_size, ir->erst.entries, @@ -1960,8 +1949,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter deq = xhci_trb_virt_to_dma(ir->event_ring->deq_seg, ir->event_ring->dequeue); if (!deq) - xhci_warn(xhci, "WARN something wrong with SW event ring " - "dequeue ptr.\n"); + xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr.\n"); /* Update HC event ring dequeue pointer */ temp = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); temp &= ERST_PTR_MASK; @@ -1970,8 +1958,7 @@ static void xhci_set_hc_event_deq(struct xhci_hcd *xhci, struct xhci_interrupter */ temp &= ~ERST_EHB; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Write event ring dequeue pointer, " - "preserving EHB bit"); + "// Write event ring dequeue pointer, preserving EHB bit"); xhci_write_64(xhci, ((u64) deq & (u64) ~ERST_PTR_MASK) | temp, &ir->ir_set->erst_dequeue); } @@ -2004,8 +1991,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, } else if (major_revision <= 0x02) { rhub = &xhci->usb2_rhub; } else { - xhci_warn(xhci, "Ignoring unknown port speed, " - "Ext Cap %p, revision = 0x%x\n", + xhci_warn(xhci, "Ignoring unknown port speed, Ext Cap %p, revision = 0x%x\n", addr, major_revision); /* Ignoring port protocol we can't understand. FIXME */ return; @@ -2020,9 +2006,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, port_offset = XHCI_EXT_PORT_OFF(temp); port_count = XHCI_EXT_PORT_COUNT(temp); xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Ext Cap %p, port offset = %u, " - "count = %u, revision = 0x%x", - addr, port_offset, port_count, major_revision); + "Ext Cap %p, port offset = %u, count = %u, revision = 0x%x", + addr, port_offset, port_count, major_revision); /* Port count includes the current port offset */ if (port_offset == 0 || (port_offset + port_count - 1) > num_ports) /* WTF? "Valid values are ‘1’ to MaxPorts" */ @@ -2079,10 +2064,8 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, struct xhci_port *hw_port = &xhci->hw_ports[i]; /* Duplicate entry. Ignore the port if the revisions differ. */ if (hw_port->rhub) { - xhci_warn(xhci, "Duplicate port entry, Ext Cap %p," - " port %u\n", addr, i); - xhci_warn(xhci, "Port was marked as USB %u, " - "duplicated as USB %u\n", + xhci_warn(xhci, "Duplicate port entry, Ext Cap %p, port %u\n", addr, i); + xhci_warn(xhci, "Port was marked as USB %u, duplicated as USB %u\n", hw_port->rhub->maj_rev, major_revision); /* Only adjust the roothub port counts if we haven't * found a similar duplicate. @@ -2358,8 +2341,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; xhci->dcbaa->dma = dma; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Device context base array address = 0x%llx (DMA), %p (virt)", - (unsigned long long)xhci->dcbaa->dma, xhci->dcbaa); + "// Device context base array address = 0x%pad (DMA), %p (virt)", + &xhci->dcbaa->dma, xhci->dcbaa); xhci_write_64(xhci, dma, &xhci->op_regs->dcbaa_ptr); /* @@ -2400,8 +2383,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) goto fail; xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocated command ring at %p", xhci->cmd_ring); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%llx", - (unsigned long long)xhci->cmd_ring->first_seg->dma); + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "First segment DMA is 0x%pad", + &xhci->cmd_ring->first_seg->dma); /* Set the address in the Command Ring Control register */ val_64 = xhci_read_64(xhci, &xhci->op_regs->cmd_ring); @@ -2421,8 +2404,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags) val = readl(&xhci->cap_regs->db_off); val &= DBOFF_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "// Doorbell array is located at offset 0x%x" - " from cap regs base addr", val); + "// Doorbell array is located at offset 0x%x from cap regs base addr", + val); xhci->dba = (void __iomem *) xhci->cap_regs + val; /* Set ir_set to interrupt register set 0 */ diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 6db07ca419c3..ddb79f23fb3b 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -78,14 +78,207 @@ static const char hcd_name[] = "xhci_hcd"; static struct hc_driver __read_mostly xhci_pci_hc_driver; static int xhci_pci_setup(struct usb_hcd *hcd); +static int xhci_pci_run(struct usb_hcd *hcd); static int xhci_pci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev, struct usb_tt *tt, gfp_t mem_flags); static const struct xhci_driver_overrides xhci_pci_overrides __initconst = { .reset = xhci_pci_setup, + .start = xhci_pci_run, .update_hub_device = xhci_pci_update_hub_device, }; +static void xhci_msix_sync_irqs(struct xhci_hcd *xhci) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + + if (hcd->msix_enabled) { + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + int i; + + for (i = 0; i < xhci->msix_count; i++) + synchronize_irq(pci_irq_vector(pdev, i)); + } +} + +/* Free any IRQs and disable MSI-X */ +static void xhci_cleanup_msix(struct xhci_hcd *xhci) +{ + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + if (xhci->quirks & XHCI_PLAT) + return; + + /* return if using legacy interrupt */ + if (hcd->irq > 0) + return; + + if (hcd->msix_enabled) { + int i; + + for (i = 0; i < xhci->msix_count; i++) + free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); + } else { + free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci)); + } + + pci_free_irq_vectors(pdev); + hcd->msix_enabled = 0; +} + +/* + * Set up MSI + */ +static int xhci_setup_msi(struct xhci_hcd *xhci) +{ + int ret; + /* + * TODO:Check with MSI Soc for sysdev + */ + struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); + if (ret < 0) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "failed to allocate MSI entry"); + return ret; + } + + ret = request_irq(pdev->irq, xhci_msi_irq, + 0, "xhci_hcd", xhci_to_hcd(xhci)); + if (ret) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "disable MSI interrupt"); + pci_free_irq_vectors(pdev); + } + + return ret; +} + +/* + * Set up MSI-X + */ +static int xhci_setup_msix(struct xhci_hcd *xhci) +{ + int i, ret; + struct usb_hcd *hcd = xhci_to_hcd(xhci); + struct pci_dev *pdev = to_pci_dev(hcd->self.controller); + + /* + * calculate number of msi-x vectors supported. + * - HCS_MAX_INTRS: the max number of interrupts the host can handle, + * with max number of interrupters based on the xhci HCSPARAMS1. + * - num_online_cpus: maximum msi-x vectors per CPUs core. + * Add additional 1 vector to ensure always available interrupt. + */ + xhci->msix_count = min(num_online_cpus() + 1, + HCS_MAX_INTRS(xhci->hcs_params1)); + + ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count, + PCI_IRQ_MSIX); + if (ret < 0) { + xhci_dbg_trace(xhci, trace_xhci_dbg_init, + "Failed to enable MSI-X"); + return ret; + } + + for (i = 0; i < xhci->msix_count; i++) { + ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0, + "xhci_hcd", xhci_to_hcd(xhci)); + if (ret) + goto disable_msix; + } + + hcd->msix_enabled = 1; + return ret; + +disable_msix: + xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt"); + while (--i >= 0) + free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); + pci_free_irq_vectors(pdev); + return ret; +} + +static int xhci_try_enable_msi(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + struct pci_dev *pdev; + int ret; + + /* The xhci platform device has set up IRQs through usb_add_hcd. */ + if (xhci->quirks & XHCI_PLAT) + return 0; + + pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); + /* + * Some Fresco Logic host controllers advertise MSI, but fail to + * generate interrupts. Don't even try to enable MSI. + */ + if (xhci->quirks & XHCI_BROKEN_MSI) + goto legacy_irq; + + /* unregister the legacy interrupt */ + if (hcd->irq) + free_irq(hcd->irq, hcd); + hcd->irq = 0; + + ret = xhci_setup_msix(xhci); + if (ret) + /* fall back to msi*/ + ret = xhci_setup_msi(xhci); + + if (!ret) { + hcd->msi_enabled = 1; + return 0; + } + + if (!pdev->irq) { + xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n"); + return -EINVAL; + } + + legacy_irq: + if (!strlen(hcd->irq_descr)) + snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", + hcd->driver->description, hcd->self.busnum); + + /* fall back to legacy interrupt*/ + ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, + hcd->irq_descr, hcd); + if (ret) { + xhci_err(xhci, "request interrupt %d failed\n", + pdev->irq); + return ret; + } + hcd->irq = pdev->irq; + return 0; +} + +static int xhci_pci_run(struct usb_hcd *hcd) +{ + int ret; + + if (usb_hcd_is_primary_hcd(hcd)) { + ret = xhci_try_enable_msi(hcd); + if (ret) + return ret; + } + + return xhci_run(hcd); +} + +static void xhci_pci_stop(struct usb_hcd *hcd) +{ + struct xhci_hcd *xhci = hcd_to_xhci(hcd); + + xhci_stop(hcd); + + if (usb_hcd_is_primary_hcd(hcd)) + xhci_cleanup_msix(xhci); +} + /* called after powerup, by probe or system-pm "wakeup" */ static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev) { @@ -535,7 +728,6 @@ static void xhci_pci_remove(struct pci_dev *dev) usb_hcd_pci_remove(dev); } -#ifdef CONFIG_PM /* * In some Intel xHCI controllers, in order to get D3 working, * through a vendor specific SSIC CONFIG register at offset 0x883c, @@ -622,6 +814,10 @@ static int xhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) xhci_sparse_control_quirk(hcd); ret = xhci_suspend(xhci, do_wakeup); + + /* synchronize irq when using MSI-X */ + xhci_msix_sync_irqs(xhci); + if (ret && (xhci->quirks & XHCI_SSIC_PORT_UNUSED)) xhci_ssic_port_unused_quirk(hcd, false); @@ -724,12 +920,12 @@ static void xhci_pci_shutdown(struct usb_hcd *hcd) struct pci_dev *pdev = to_pci_dev(hcd->self.controller); xhci_shutdown(hcd); + xhci_cleanup_msix(xhci); /* Yet another workaround for spurious wakeups at shutdown with HSW */ if (xhci->quirks & XHCI_SPURIOUS_WAKEUP) pci_set_power_state(pdev, PCI_D3hot); } -#endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -771,22 +967,19 @@ static struct pci_driver xhci_pci_driver = { /* suspend and resume implemented later */ .shutdown = usb_hcd_pci_shutdown, -#ifdef CONFIG_PM .driver = { - .pm = &usb_hcd_pci_pm_ops + .pm = pm_ptr(&usb_hcd_pci_pm_ops), }, -#endif }; static int __init xhci_pci_init(void) { xhci_init_driver(&xhci_pci_hc_driver, &xhci_pci_overrides); -#ifdef CONFIG_PM - xhci_pci_hc_driver.pci_suspend = xhci_pci_suspend; - xhci_pci_hc_driver.pci_resume = xhci_pci_resume; - xhci_pci_hc_driver.pci_poweroff_late = xhci_pci_poweroff_late; - xhci_pci_hc_driver.shutdown = xhci_pci_shutdown; -#endif + xhci_pci_hc_driver.pci_suspend = pm_ptr(xhci_pci_suspend); + xhci_pci_hc_driver.pci_resume = pm_ptr(xhci_pci_resume); + xhci_pci_hc_driver.pci_poweroff_late = pm_ptr(xhci_pci_poweroff_late); + xhci_pci_hc_driver.shutdown = pm_ptr(xhci_pci_shutdown); + xhci_pci_hc_driver.stop = xhci_pci_stop; return pci_register_driver(&xhci_pci_driver); } module_init(xhci_pci_init); diff --git a/drivers/usb/host/xhci-rcar.c b/drivers/usb/host/xhci-rcar.c index 7f18509a1d39..ad966b797b89 100644 --- a/drivers/usb/host/xhci-rcar.c +++ b/drivers/usb/host/xhci-rcar.c @@ -12,26 +12,22 @@ #include <linux/of.h> #include <linux/of_device.h> #include <linux/usb/phy.h> -#include <linux/sys_soc.h> #include "xhci.h" #include "xhci-plat.h" #include "xhci-rzv2m.h" #define XHCI_RCAR_FIRMWARE_NAME_V1 "r8a779x_usb3_v1.dlmem" -#define XHCI_RCAR_FIRMWARE_NAME_V2 "r8a779x_usb3_v2.dlmem" #define XHCI_RCAR_FIRMWARE_NAME_V3 "r8a779x_usb3_v3.dlmem" /* -* - The V3 firmware is for almost all R-Car Gen3 (except r8a7795 ES1.x) -* - The V2 firmware is for r8a7795 ES1.x. +* - The V3 firmware is for all R-Car Gen3 * - The V2 firmware is possible to use on R-Car Gen2. However, the V2 causes * performance degradation. So, this driver continues to use the V1 if R-Car * Gen2. * - The V1 firmware is impossible to use on R-Car Gen3. */ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V1); -MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V2); MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); /*** Register Offset ***/ @@ -78,18 +74,6 @@ MODULE_FIRMWARE(XHCI_RCAR_FIRMWARE_NAME_V3); #define RCAR_USB3_RX_POL_VAL BIT(21) #define RCAR_USB3_TX_POL_VAL BIT(4) -/* For soc_device_attribute */ -#define RCAR_XHCI_FIRMWARE_V2 BIT(0) /* FIRMWARE V2 */ -#define RCAR_XHCI_FIRMWARE_V3 BIT(1) /* FIRMWARE V3 */ - -static const struct soc_device_attribute rcar_quirks_match[] = { - { - .soc_id = "r8a7795", .revision = "ES1.*", - .data = (void *)RCAR_XHCI_FIRMWARE_V2, - }, - { /* sentinel */ } -}; - static void xhci_rcar_start_gen2(struct usb_hcd *hcd) { /* LCLK Select */ @@ -135,9 +119,6 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) const struct firmware *fw; int retval, index, j; u32 data, val, temp; - u32 quirks = 0; - const struct soc_device_attribute *attr; - const char *firmware_name; /* * According to the datasheet, "Upon the completion of FW Download, @@ -146,19 +127,8 @@ static int xhci_rcar_download_firmware(struct usb_hcd *hcd) if (readl(regs + RCAR_USB3_DL_CTRL) & RCAR_USB3_DL_CTRL_FW_SUCCESS) return 0; - attr = soc_device_match(rcar_quirks_match); - if (attr) - quirks = (uintptr_t)attr->data; - - if (quirks & RCAR_XHCI_FIRMWARE_V2) - firmware_name = XHCI_RCAR_FIRMWARE_NAME_V2; - else if (quirks & RCAR_XHCI_FIRMWARE_V3) - firmware_name = XHCI_RCAR_FIRMWARE_NAME_V3; - else - firmware_name = priv->firmware_name; - /* request R-Car USB3.0 firmware */ - retval = request_firmware(&fw, firmware_name, dev); + retval = request_firmware(&fw, priv->firmware_name, dev); if (retval) return retval; @@ -312,7 +282,7 @@ static struct platform_driver usb_xhci_renesas_driver = { .driver = { .name = "xhci-renesas-hcd", .pm = &xhci_plat_pm_ops, - .of_match_table = of_match_ptr(usb_xhci_of_match), + .of_match_table = usb_xhci_of_match, }, }; module_platform_driver(usb_xhci_renesas_driver); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index eb788c60c1c0..1ad12d5a4857 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -3106,6 +3106,7 @@ irqreturn_t xhci_msi_irq(int irq, void *hcd) { return xhci_irq(hcd); } +EXPORT_SYMBOL_GPL(xhci_msi_irq); /**** Endpoint Ring Operations ****/ diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index a88c39e525c2..c75d93244143 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -1535,7 +1535,6 @@ static void tegra_xusb_deinit_usb_phy(struct tegra_xusb *tegra) static int tegra_xusb_probe(struct platform_device *pdev) { - struct of_phandle_args args; struct tegra_xusb *tegra; struct device_node *np; struct resource *regs; @@ -1594,15 +1593,13 @@ static int tegra_xusb_probe(struct platform_device *pdev) goto put_padctl; } - /* Older device-trees don't have padctrl interrupt */ - err = of_irq_parse_one(np, 0, &args); - if (!err) { - tegra->padctl_irq = of_irq_get(np, 0); - if (tegra->padctl_irq <= 0) { - err = (tegra->padctl_irq == 0) ? -ENODEV : tegra->padctl_irq; - goto put_padctl; - } - } else { + tegra->padctl_irq = of_irq_get(np, 0); + if (tegra->padctl_irq == -EPROBE_DEFER) { + err = tegra->padctl_irq; + goto put_padctl; + } else if (tegra->padctl_irq <= 0) { + /* Older device-trees don't have padctrl interrupt */ + tegra->padctl_irq = 0; dev_dbg(&pdev->dev, "%pOF is missing an interrupt, disabling PM support\n", np); } diff --git a/drivers/usb/host/xhci-trace.c b/drivers/usb/host/xhci-trace.c index d0070814d1ea..062662d23241 100644 --- a/drivers/usb/host/xhci-trace.c +++ b/drivers/usb/host/xhci-trace.c @@ -12,3 +12,4 @@ #include "xhci-trace.h" EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_quirks); +EXPORT_TRACEPOINT_SYMBOL_GPL(xhci_dbg_init); diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 61e93a3540a7..4286dba5b157 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -120,7 +120,6 @@ DECLARE_EVENT_CLASS(xhci_log_trb, __field(u32, field1) __field(u32, field2) __field(u32, field3) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->type = ring->type; @@ -130,8 +129,8 @@ DECLARE_EVENT_CLASS(xhci_log_trb, __entry->field3 = le32_to_cpu(trb->field[3]); ), TP_printk("%s: %s", xhci_ring_type_string(__entry->type), - xhci_decode_trb(__get_str(str), XHCI_MSG_MAX, __entry->field0, __entry->field1, - __entry->field2, __entry->field3) + xhci_decode_trb(__get_buf(XHCI_MSG_MAX), XHCI_MSG_MAX, __entry->field0, + __entry->field1, __entry->field2, __entry->field3) ) ); @@ -322,7 +321,6 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx, __field(u32, info2) __field(u64, deq) __field(u32, tx_info) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->ep_info); @@ -330,7 +328,7 @@ DECLARE_EVENT_CLASS(xhci_log_ep_ctx, __entry->deq = le64_to_cpu(ctx->deq); __entry->tx_info = le32_to_cpu(ctx->tx_info); ), - TP_printk("%s", xhci_decode_ep_context(__get_str(str), + TP_printk("%s", xhci_decode_ep_context(__get_buf(XHCI_MSG_MAX), __entry->info, __entry->info2, __entry->deq, __entry->tx_info) ) ); @@ -368,7 +366,6 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx, __field(u32, info2) __field(u32, tt_info) __field(u32, state) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->info = le32_to_cpu(ctx->dev_info); @@ -376,7 +373,7 @@ DECLARE_EVENT_CLASS(xhci_log_slot_ctx, __entry->tt_info = le64_to_cpu(ctx->tt_info); __entry->state = le32_to_cpu(ctx->dev_state); ), - TP_printk("%s", xhci_decode_slot_context(__get_str(str), + TP_printk("%s", xhci_decode_slot_context(__get_buf(XHCI_MSG_MAX), __entry->info, __entry->info2, __entry->tt_info, __entry->state) ) @@ -433,13 +430,12 @@ DECLARE_EVENT_CLASS(xhci_log_ctrl_ctx, TP_STRUCT__entry( __field(u32, drop) __field(u32, add) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->drop = le32_to_cpu(ctrl_ctx->drop_flags); __entry->add = le32_to_cpu(ctrl_ctx->add_flags); ), - TP_printk("%s", xhci_decode_ctrl_ctx(__get_str(str), __entry->drop, __entry->add) + TP_printk("%s", xhci_decode_ctrl_ctx(__get_buf(XHCI_MSG_MAX), __entry->drop, __entry->add) ) ); @@ -525,7 +521,6 @@ DECLARE_EVENT_CLASS(xhci_log_portsc, TP_STRUCT__entry( __field(u32, portnum) __field(u32, portsc) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->portnum = portnum; @@ -533,7 +528,7 @@ DECLARE_EVENT_CLASS(xhci_log_portsc, ), TP_printk("port-%d: %s", __entry->portnum, - xhci_decode_portsc(__get_str(str), __entry->portsc) + xhci_decode_portsc(__get_buf(XHCI_MSG_MAX), __entry->portsc) ) ); @@ -558,14 +553,13 @@ DECLARE_EVENT_CLASS(xhci_log_doorbell, TP_STRUCT__entry( __field(u32, slot) __field(u32, doorbell) - __dynamic_array(char, str, XHCI_MSG_MAX) ), TP_fast_assign( __entry->slot = slot; __entry->doorbell = doorbell; ), TP_printk("Ring doorbell for %s", - xhci_decode_doorbell(__get_str(str), __entry->slot, __entry->doorbell) + xhci_decode_doorbell(__get_buf(XHCI_MSG_MAX), __entry->slot, __entry->doorbell) ) ); diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 6307bae9cddf..78790dc13c5f 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -322,192 +322,6 @@ static int xhci_disable_interrupter(struct xhci_interrupter *ir) return 0; } -#ifdef CONFIG_USB_PCI -/* - * Set up MSI - */ -static int xhci_setup_msi(struct xhci_hcd *xhci) -{ - int ret; - /* - * TODO:Check with MSI Soc for sysdev - */ - struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - - ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); - if (ret < 0) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "failed to allocate MSI entry"); - return ret; - } - - ret = request_irq(pdev->irq, xhci_msi_irq, - 0, "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "disable MSI interrupt"); - pci_free_irq_vectors(pdev); - } - - return ret; -} - -/* - * Set up MSI-X - */ -static int xhci_setup_msix(struct xhci_hcd *xhci) -{ - int i, ret; - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - /* - * calculate number of msi-x vectors supported. - * - HCS_MAX_INTRS: the max number of interrupts the host can handle, - * with max number of interrupters based on the xhci HCSPARAMS1. - * - num_online_cpus: maximum msi-x vectors per CPUs core. - * Add additional 1 vector to ensure always available interrupt. - */ - xhci->msix_count = min(num_online_cpus() + 1, - HCS_MAX_INTRS(xhci->hcs_params1)); - - ret = pci_alloc_irq_vectors(pdev, xhci->msix_count, xhci->msix_count, - PCI_IRQ_MSIX); - if (ret < 0) { - xhci_dbg_trace(xhci, trace_xhci_dbg_init, - "Failed to enable MSI-X"); - return ret; - } - - for (i = 0; i < xhci->msix_count; i++) { - ret = request_irq(pci_irq_vector(pdev, i), xhci_msi_irq, 0, - "xhci_hcd", xhci_to_hcd(xhci)); - if (ret) - goto disable_msix; - } - - hcd->msix_enabled = 1; - return ret; - -disable_msix: - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "disable MSI-X interrupt"); - while (--i >= 0) - free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); - pci_free_irq_vectors(pdev); - return ret; -} - -/* Free any IRQs and disable MSI-X */ -static void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ - struct usb_hcd *hcd = xhci_to_hcd(xhci); - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - - if (xhci->quirks & XHCI_PLAT) - return; - - /* return if using legacy interrupt */ - if (hcd->irq > 0) - return; - - if (hcd->msix_enabled) { - int i; - - for (i = 0; i < xhci->msix_count; i++) - free_irq(pci_irq_vector(pdev, i), xhci_to_hcd(xhci)); - } else { - free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci)); - } - - pci_free_irq_vectors(pdev); - hcd->msix_enabled = 0; -} - -static void __maybe_unused xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ - struct usb_hcd *hcd = xhci_to_hcd(xhci); - - if (hcd->msix_enabled) { - struct pci_dev *pdev = to_pci_dev(hcd->self.controller); - int i; - - for (i = 0; i < xhci->msix_count; i++) - synchronize_irq(pci_irq_vector(pdev, i)); - } -} - -static int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - struct xhci_hcd *xhci = hcd_to_xhci(hcd); - struct pci_dev *pdev; - int ret; - - /* The xhci platform device has set up IRQs through usb_add_hcd. */ - if (xhci->quirks & XHCI_PLAT) - return 0; - - pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller); - /* - * Some Fresco Logic host controllers advertise MSI, but fail to - * generate interrupts. Don't even try to enable MSI. - */ - if (xhci->quirks & XHCI_BROKEN_MSI) - goto legacy_irq; - - /* unregister the legacy interrupt */ - if (hcd->irq) - free_irq(hcd->irq, hcd); - hcd->irq = 0; - - ret = xhci_setup_msix(xhci); - if (ret) - /* fall back to msi*/ - ret = xhci_setup_msi(xhci); - - if (!ret) { - hcd->msi_enabled = 1; - return 0; - } - - if (!pdev->irq) { - xhci_err(xhci, "No msi-x/msi found and no IRQ in BIOS\n"); - return -EINVAL; - } - - legacy_irq: - if (!strlen(hcd->irq_descr)) - snprintf(hcd->irq_descr, sizeof(hcd->irq_descr), "%s:usb%d", - hcd->driver->description, hcd->self.busnum); - - /* fall back to legacy interrupt*/ - ret = request_irq(pdev->irq, &usb_hcd_irq, IRQF_SHARED, - hcd->irq_descr, hcd); - if (ret) { - xhci_err(xhci, "request interrupt %d failed\n", - pdev->irq); - return ret; - } - hcd->irq = pdev->irq; - return 0; -} - -#else - -static inline int xhci_try_enable_msi(struct usb_hcd *hcd) -{ - return 0; -} - -static inline void xhci_cleanup_msix(struct xhci_hcd *xhci) -{ -} - -static inline void xhci_msix_sync_irqs(struct xhci_hcd *xhci) -{ -} - -#endif - static void compliance_mode_recovery(struct timer_list *t) { struct xhci_hcd *xhci; @@ -705,10 +519,6 @@ int xhci_run(struct usb_hcd *hcd) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_run"); - ret = xhci_try_enable_msi(hcd); - if (ret) - return ret; - temp_64 = xhci_read_64(xhci, &ir->ir_set->erst_dequeue); temp_64 &= ~ERST_PTR_MASK; xhci_dbg_trace(xhci, trace_xhci_dbg_init, @@ -758,7 +568,7 @@ EXPORT_SYMBOL_GPL(xhci_run); * Disable device contexts, disable IRQs, and quiesce the HC. * Reset the HC, finish any completed transactions, and cleanup memory. */ -static void xhci_stop(struct usb_hcd *hcd) +void xhci_stop(struct usb_hcd *hcd) { u32 temp; struct xhci_hcd *xhci = hcd_to_xhci(hcd); @@ -781,8 +591,6 @@ static void xhci_stop(struct usb_hcd *hcd) xhci_reset(xhci, XHCI_RESET_SHORT_USEC); spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); - /* Deleting Compliance Mode Recovery Timer */ if ((xhci->quirks & XHCI_COMP_MODE_QUIRK) && (!(xhci_all_ports_seen_u0(xhci)))) { @@ -809,6 +617,7 @@ static void xhci_stop(struct usb_hcd *hcd) readl(&xhci->op_regs->status)); mutex_unlock(&xhci->mutex); } +EXPORT_SYMBOL_GPL(xhci_stop); /* * Shutdown HC (not bus-specific) @@ -850,8 +659,6 @@ void xhci_shutdown(struct usb_hcd *hcd) spin_unlock_irq(&xhci->lock); - xhci_cleanup_msix(xhci); - xhci_dbg_trace(xhci, trace_xhci_dbg_init, "xhci_shutdown completed - status = %x", readl(&xhci->op_regs->status)); @@ -1143,10 +950,6 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup) __func__); } - /* step 5: remove core well power */ - /* synchronize irq when using MSI-X */ - xhci_msix_sync_irqs(xhci); - return rc; } EXPORT_SYMBOL_GPL(xhci_suspend); @@ -1250,7 +1053,6 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated) spin_unlock_irq(&xhci->lock); if (retval) return retval; - xhci_cleanup_msix(xhci); xhci_dbg(xhci, "// Disabling event ring interrupts\n"); temp = readl(&xhci->op_regs->status); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 786002bb35db..08d721921b7b 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2125,6 +2125,7 @@ int xhci_reset(struct xhci_hcd *xhci, u64 timeout_us); int xhci_run(struct usb_hcd *hcd); int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks); void xhci_shutdown(struct usb_hcd *hcd); +void xhci_stop(struct usb_hcd *hcd); void xhci_init_driver(struct hc_driver *drv, const struct xhci_driver_overrides *over); int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index a5f7652db7da..99b15b77dfd5 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -4,6 +4,35 @@ # comment "USB Miscellaneous drivers" +config USB_USS720 + tristate "USS720 parport driver" + depends on PARPORT + select PARPORT_NOT_PC + help + This driver is for USB parallel port adapters that use the Lucent + Technologies USS-720 chip. These cables are plugged into your USB + port and provide USB compatibility to peripherals designed with + parallel port interfaces. + + The chip has two modes: automatic mode and manual mode. In automatic + mode, it looks to the computer like a standard USB printer. Only + printers may be connected to the USS-720 in this mode. The generic + USB printer driver ("USB Printer support", above) may be used in + that mode, and you can say N here if you want to use the chip only + in this mode. + + Manual mode is not limited to printers, any parallel port + device should work. This driver utilizes manual mode. + Note however that some operations are three orders of magnitude + slower than on a PCI/ISA Parallel Port, so timing critical + applications might not work. + + Say Y here if you own an USS-720 USB->Parport cable and intend to + connect anything other than a printer to it. + + To compile this driver as a module, choose M here: the + module will be called uss720. + config USB_EMI62 tristate "EMI 6|2m USB Audio interface support" help @@ -108,28 +137,6 @@ config USB_IDMOUSE See also <https://www.fs.tum.de/~echtler/idmouse/>. -config USB_FTDI_ELAN - tristate "Elan PCMCIA CardBus Adapter USB Client" - help - ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters. - Currently only the U132 adapter is available. - - The U132 is specifically designed for CardBus PC cards that contain - an OHCI host controller. Typical PC cards are the Orange Mobile 3G - Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work - with PC cards that do not contain an OHCI controller. To use a U132 - adapter you will need this "ftdi-elan" module as well as the "u132-hcd" - module which is a USB host controller driver that talks to the OHCI - controller within CardBus card that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller" - - It is safe to say M here. - config USB_APPLEDISPLAY tristate "Apple Cinema Display support" select BACKLIGHT_CLASS_DEVICE diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile index 93581baec3a8..1992cc284d8a 100644 --- a/drivers/usb/misc/Makefile +++ b/drivers/usb/misc/Makefile @@ -10,7 +10,6 @@ obj-$(CONFIG_USB_CYTHERM) += cytherm.o obj-$(CONFIG_USB_EMI26) += emi26.o obj-$(CONFIG_USB_EMI62) += emi62.o obj-$(CONFIG_USB_EZUSB_FX2) += ezusb.o -obj-$(CONFIG_USB_FTDI_ELAN) += ftdi-elan.o obj-$(CONFIG_APPLE_MFI_FASTCHARGE) += apple-mfi-fastcharge.o obj-$(CONFIG_USB_IDMOUSE) += idmouse.o obj-$(CONFIG_USB_IOWARRIOR) += iowarrior.o diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c deleted file mode 100644 index 8ce191e3a4c0..000000000000 --- a/drivers/usb/misc/ftdi-elan.c +++ /dev/null @@ -1,2780 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * USB FTDI client driver for Elan Digital Systems's Uxxx adapters - * - * Copyright(C) 2006 Elan Digital Systems Limited - * http://www.elandigitalsystems.com - * - * Author and Maintainer - Tony Olech - Elan Digital Systems - * tony.olech@elandigitalsystems.com - * - * This driver was written by Tony Olech(tony.olech@elandigitalsystems.com) - * based on various USB client drivers in the 2.6.15 linux kernel - * with constant reference to the 3rd Edition of Linux Device Drivers - * published by O'Reilly - * - * The U132 adapter is a USB to CardBus adapter specifically designed - * for PC cards that contain an OHCI host controller. Typical PC cards - * are the Orange Mobile 3G Option GlobeTrotter Fusion card. - * - * The U132 adapter will *NOT *work with PC cards that do not contain - * an OHCI controller. A simple way to test whether a PC card has an - * OHCI controller as an interface is to insert the PC card directly - * into a laptop(or desktop) with a CardBus slot and if "lspci" shows - * a new USB controller and "lsusb -v" shows a new OHCI Host Controller - * then there is a good chance that the U132 adapter will support the - * PC card.(you also need the specific client driver for the PC card) - * - * Please inform the Author and Maintainer about any PC cards that - * contain OHCI Host Controller and work when directly connected to - * an embedded CardBus slot but do not work when they are connected - * via an ELAN U132 adapter. - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/list.h> -#include <linux/ioctl.h> -#include <linux/pci_ids.h> -#include <linux/slab.h> -#include <linux/module.h> -#include <linux/kref.h> -#include <linux/mutex.h> -#include <linux/uaccess.h> -#include <linux/usb.h> -#include <linux/workqueue.h> -#include <linux/platform_device.h> -MODULE_AUTHOR("Tony Olech"); -MODULE_DESCRIPTION("FTDI ELAN driver"); -MODULE_LICENSE("GPL"); -#define INT_MODULE_PARM(n, v) static int n = v;module_param(n, int, 0444) -static bool distrust_firmware = 1; -module_param(distrust_firmware, bool, 0); -MODULE_PARM_DESC(distrust_firmware, - "true to distrust firmware power/overcurrent setup"); -extern struct platform_driver u132_platform_driver; -/* - * ftdi_module_lock exists to protect access to global variables - * - */ -static struct mutex ftdi_module_lock; -static int ftdi_instances = 0; -static struct list_head ftdi_static_list; -/* - * end of the global variables protected by ftdi_module_lock - */ -#include "usb_u132.h" -#include <asm/io.h> -#include <linux/usb/hcd.h> - -/* FIXME ohci.h is ONLY for internal use by the OHCI driver. - * If you're going to try stuff like this, you need to split - * out shareable stuff (register declarations?) into its own - * file, maybe name <linux/usb/ohci.h> - */ - -#include "../host/ohci.h" -/* Define these values to match your devices*/ -#define USB_FTDI_ELAN_VENDOR_ID 0x0403 -#define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea -/* table of devices that work with this driver*/ -static const struct usb_device_id ftdi_elan_table[] = { - {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)}, - { /* Terminating entry */ } -}; - -MODULE_DEVICE_TABLE(usb, ftdi_elan_table); -/* only the jtag(firmware upgrade device) interface requires - * a device file and corresponding minor number, but the - * interface is created unconditionally - I suppose it could - * be configured or not according to a module parameter. - * But since we(now) require one interface per device, - * and since it unlikely that a normal installation would - * require more than a couple of elan-ftdi devices, 8 seems - * like a reasonable limit to have here, and if someone - * really requires more than 8 devices, then they can frig the - * code and recompile - */ -#define USB_FTDI_ELAN_MINOR_BASE 192 -#define COMMAND_BITS 5 -#define COMMAND_SIZE (1<<COMMAND_BITS) -#define COMMAND_MASK (COMMAND_SIZE-1) -struct u132_command { - u8 header; - u16 length; - u8 address; - u8 width; - u32 value; - int follows; - void *buffer; -}; -#define RESPOND_BITS 5 -#define RESPOND_SIZE (1<<RESPOND_BITS) -#define RESPOND_MASK (RESPOND_SIZE-1) -struct u132_respond { - u8 header; - u8 address; - u32 *value; - int *result; - struct completion wait_completion; -}; -struct u132_target { - void *endp; - struct urb *urb; - int toggle_bits; - int error_count; - int condition_code; - int repeat_number; - int halted; - int skipped; - int actual; - int non_null; - int active; - int abandoning; - void (*callback)(void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, - int repeat_number, int halted, int skipped, int actual, - int non_null); -}; -/* Structure to hold all of our device specific stuff*/ -struct usb_ftdi { - struct list_head ftdi_list; - struct mutex u132_lock; - int command_next; - int command_head; - struct u132_command command[COMMAND_SIZE]; - int respond_next; - int respond_head; - struct u132_respond respond[RESPOND_SIZE]; - struct u132_target target[4]; - char device_name[16]; - unsigned synchronized:1; - unsigned enumerated:1; - unsigned registered:1; - unsigned initialized:1; - unsigned card_ejected:1; - int function; - int sequence_num; - int disconnected; - int gone_away; - int stuck_status; - int status_queue_delay; - struct semaphore sw_lock; - struct usb_device *udev; - struct usb_interface *interface; - struct usb_class_driver *class; - struct delayed_work status_work; - struct delayed_work command_work; - struct delayed_work respond_work; - struct u132_platform_data platform_data; - struct resource resources[0]; - struct platform_device platform_dev; - unsigned char *bulk_in_buffer; - size_t bulk_in_size; - size_t bulk_in_last; - size_t bulk_in_left; - __u8 bulk_in_endpointAddr; - __u8 bulk_out_endpointAddr; - struct kref kref; - u32 controlreg; - u8 response[4 + 1024]; - int expected; - int received; - int ed_found; -}; -#define kref_to_usb_ftdi(d) container_of(d, struct usb_ftdi, kref) -#define platform_device_to_usb_ftdi(d) container_of(d, struct usb_ftdi, \ - platform_dev) -static struct usb_driver ftdi_elan_driver; -static void ftdi_elan_delete(struct kref *kref) -{ - struct usb_ftdi *ftdi = kref_to_usb_ftdi(kref); - dev_warn(&ftdi->udev->dev, "FREEING ftdi=%p\n", ftdi); - usb_put_dev(ftdi->udev); - ftdi->disconnected += 1; - mutex_lock(&ftdi_module_lock); - list_del_init(&ftdi->ftdi_list); - ftdi_instances -= 1; - mutex_unlock(&ftdi_module_lock); - kfree(ftdi->bulk_in_buffer); - ftdi->bulk_in_buffer = NULL; - kfree(ftdi); -} - -static void ftdi_elan_put_kref(struct usb_ftdi *ftdi) -{ - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_elan_get_kref(struct usb_ftdi *ftdi) -{ - kref_get(&ftdi->kref); -} - -static void ftdi_elan_init_kref(struct usb_ftdi *ftdi) -{ - kref_init(&ftdi->kref); -} - -static void ftdi_status_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->status_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_status_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->status_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_status_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->status_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_requeue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->command_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_command_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->command_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_command_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->command_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_response_requeue_work(struct usb_ftdi *ftdi, - unsigned int delta) -{ - if (!schedule_delayed_work(&ftdi->respond_work, delta)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -static void ftdi_respond_queue_work(struct usb_ftdi *ftdi, unsigned int delta) -{ - if (schedule_delayed_work(&ftdi->respond_work, delta)) - kref_get(&ftdi->kref); -} - -static void ftdi_response_cancel_work(struct usb_ftdi *ftdi) -{ - if (cancel_delayed_work_sync(&ftdi->respond_work)) - kref_put(&ftdi->kref, ftdi_elan_delete); -} - -void ftdi_elan_gone_away(struct platform_device *pdev) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - ftdi->gone_away += 1; - ftdi_elan_put_kref(ftdi); -} - - -EXPORT_SYMBOL_GPL(ftdi_elan_gone_away); -static void ftdi_release_platform_dev(struct device *dev) -{ - dev->parent = NULL; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length); -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi); -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi); -static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi); -static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi); -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi); -static int ftdi_elan_synchronize(struct usb_ftdi *ftdi); -static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi); -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi); -static int ftdi_elan_hcd_init(struct usb_ftdi *ftdi) -{ - if (ftdi->platform_dev.dev.parent) - return -EBUSY; - - ftdi_elan_get_kref(ftdi); - ftdi->platform_data.potpg = 100; - ftdi->platform_data.reset = NULL; - ftdi->platform_dev.id = ftdi->sequence_num; - ftdi->platform_dev.resource = ftdi->resources; - ftdi->platform_dev.num_resources = ARRAY_SIZE(ftdi->resources); - ftdi->platform_dev.dev.platform_data = &ftdi->platform_data; - ftdi->platform_dev.dev.parent = NULL; - ftdi->platform_dev.dev.release = ftdi_release_platform_dev; - ftdi->platform_dev.dev.dma_mask = NULL; - snprintf(ftdi->device_name, sizeof(ftdi->device_name), "u132_hcd"); - ftdi->platform_dev.name = ftdi->device_name; - dev_info(&ftdi->udev->dev, "requesting module '%s'\n", "u132_hcd"); - request_module("u132_hcd"); - dev_info(&ftdi->udev->dev, "registering '%s'\n", - ftdi->platform_dev.name); - - return platform_device_register(&ftdi->platform_dev); -} - -static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) -{ - mutex_lock(&ftdi->u132_lock); - while (ftdi->respond_next > ftdi->respond_head) { - struct u132_respond *respond = &ftdi->respond[RESPOND_MASK & - ftdi->respond_head++]; - *respond->result = -ESHUTDOWN; - *respond->value = 0; - complete(&respond->wait_completion); - } - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - if (target->active == 1) { - target->condition_code = TD_DEVNOTRESP; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, NULL, 0); - mutex_lock(&ftdi->u132_lock); - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_flush_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - wait_2:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x90 | (ed_number << 5); - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_2; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_cancel_targets(struct usb_ftdi *ftdi) -{ - int ed_number = 4; - mutex_lock(&ftdi->u132_lock); - while (ed_number-- > 0) { - struct u132_target *target = &ftdi->target[ed_number]; - target->abandoning = 1; - wait:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed_number << 5) | 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait; - } - } - } - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - mutex_unlock(&ftdi->u132_lock); -} - -static void ftdi_elan_kick_command_queue(struct usb_ftdi *ftdi) -{ - ftdi_command_queue_work(ftdi, 0); -} - -static void ftdi_elan_command_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, command_work.work); - - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_command_engine(ftdi); - if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval) - dev_err(&ftdi->udev->dev, "command error %d\n", retval); - ftdi_command_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - -static void ftdi_elan_kick_respond_queue(struct usb_ftdi *ftdi) -{ - ftdi_respond_queue_work(ftdi, 0); -} - -static void ftdi_elan_respond_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, respond_work.work); - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - int retval = ftdi_elan_respond_engine(ftdi); - if (retval == 0) { - } else if (retval == -ESHUTDOWN) { - ftdi->disconnected += 1; - } else if (retval == -ENODEV) { - ftdi->disconnected += 1; - } else if (retval == -EILSEQ) { - ftdi->disconnected += 1; - } else { - ftdi->disconnected += 1; - dev_err(&ftdi->udev->dev, "respond error %d\n", retval); - } - if (ftdi->disconnected > 0) { - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - } - ftdi_response_requeue_work(ftdi, msecs_to_jiffies(10)); - return; - } -} - - -/* - * the sw_lock is initially held and will be freed - * after the FTDI has been synchronized - * - */ -static void ftdi_elan_status_work(struct work_struct *work) -{ - struct usb_ftdi *ftdi = - container_of(work, struct usb_ftdi, status_work.work); - int work_delay_in_msec = 0; - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else if (ftdi->synchronized == 0) { - down(&ftdi->sw_lock); - if (ftdi_elan_synchronize(ftdi) == 0) { - ftdi->synchronized = 1; - ftdi_command_queue_work(ftdi, 1); - ftdi_respond_queue_work(ftdi, 1); - up(&ftdi->sw_lock); - work_delay_in_msec = 100; - } else { - dev_err(&ftdi->udev->dev, "synchronize failed\n"); - up(&ftdi->sw_lock); - work_delay_in_msec = 10 *1000; - } - } else if (ftdi->stuck_status > 0) { - if (ftdi_elan_stuck_waiting(ftdi) == 0) { - ftdi->stuck_status = 0; - ftdi->synchronized = 0; - } else if ((ftdi->stuck_status++ % 60) == 1) { - dev_err(&ftdi->udev->dev, "WRONG type of card inserted - please remove\n"); - } else - dev_err(&ftdi->udev->dev, "WRONG type of card inserted - checked %d times\n", - ftdi->stuck_status); - work_delay_in_msec = 100; - } else if (ftdi->enumerated == 0) { - if (ftdi_elan_enumeratePCI(ftdi) == 0) { - ftdi->enumerated = 1; - work_delay_in_msec = 250; - } else - work_delay_in_msec = 1000; - } else if (ftdi->initialized == 0) { - if (ftdi_elan_setupOHCI(ftdi) == 0) { - ftdi->initialized = 1; - work_delay_in_msec = 500; - } else { - dev_err(&ftdi->udev->dev, "initialized failed - trying again in 10 seconds\n"); - work_delay_in_msec = 1 *1000; - } - } else if (ftdi->registered == 0) { - work_delay_in_msec = 10; - if (ftdi_elan_hcd_init(ftdi) == 0) { - ftdi->registered = 1; - } else - dev_err(&ftdi->udev->dev, "register failed\n"); - work_delay_in_msec = 250; - } else { - if (ftdi_elan_checkingPCI(ftdi) == 0) { - work_delay_in_msec = 250; - } else if (ftdi->controlreg & 0x00400000) { - if (ftdi->gone_away > 0) { - dev_err(&ftdi->udev->dev, "PCI device eject confirmed platform_dev.dev.parent=%p platform_dev.dev=%p\n", - ftdi->platform_dev.dev.parent, - &ftdi->platform_dev.dev); - platform_device_unregister(&ftdi->platform_dev); - ftdi->platform_dev.dev.parent = NULL; - ftdi->registered = 0; - ftdi->enumerated = 0; - ftdi->card_ejected = 0; - ftdi->initialized = 0; - ftdi->gone_away = 0; - } else - ftdi_elan_flush_targets(ftdi); - work_delay_in_msec = 250; - } else { - dev_err(&ftdi->udev->dev, "PCI device has disappeared\n"); - ftdi_elan_cancel_targets(ftdi); - work_delay_in_msec = 500; - ftdi->enumerated = 0; - ftdi->initialized = 0; - } - } - if (ftdi->disconnected > 0) { - ftdi_elan_put_kref(ftdi); - return; - } else { - ftdi_status_requeue_work(ftdi, - msecs_to_jiffies(work_delay_in_msec)); - return; - } -} - - -/* - * file_operations for the jtag interface - * - * the usage count for the device is incremented on open() - * and decremented on release() - */ -static int ftdi_elan_open(struct inode *inode, struct file *file) -{ - int subminor; - struct usb_interface *interface; - - subminor = iminor(inode); - interface = usb_find_interface(&ftdi_elan_driver, subminor); - - if (!interface) { - pr_err("can't find device for minor %d\n", subminor); - return -ENODEV; - } else { - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - if (!ftdi) { - return -ENODEV; - } else { - if (down_interruptible(&ftdi->sw_lock)) { - return -EINTR; - } else { - ftdi_elan_get_kref(ftdi); - file->private_data = ftdi; - return 0; - } - } - } -} - -static int ftdi_elan_release(struct inode *inode, struct file *file) -{ - struct usb_ftdi *ftdi = file->private_data; - if (ftdi == NULL) - return -ENODEV; - up(&ftdi->sw_lock); /* decrement the count on our device */ - ftdi_elan_put_kref(ftdi); - return 0; -} - - -/* - * - * blocking bulk reads are used to get data from the device - * - */ -static ssize_t ftdi_elan_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3 - 1; - int bytes_read = 0; - int retry_on_empty = 10; - int retry_on_timeout = 5; - struct usb_ftdi *ftdi = file->private_data; - if (ftdi->disconnected > 0) { - return -ENODEV; - } - data[0] = 0; -have:if (ftdi->bulk_in_left > 0) { - if (count-- > 0) { - char *p = ++ftdi->bulk_in_last + ftdi->bulk_in_buffer; - ftdi->bulk_in_left -= 1; - if (bytes_read < m) { - d += sprintf(d, " %02X", 0x000000FF & *p); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - if (copy_to_user(buffer++, p, 1)) { - return -EFAULT; - } else { - bytes_read += 1; - goto have; - } - } else - return bytes_read; - } -more:if (count > 0) { - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 50); - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else if (bytes_read > 0) { - return bytes_read; - } else - return retval; - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else - return bytes_read; - } else - return retval; - } else - return bytes_read; -} - -static void ftdi_elan_write_bulk_callback(struct urb *urb) -{ - struct usb_ftdi *ftdi = urb->context; - int status = urb->status; - - if (status && !(status == -ENOENT || status == -ECONNRESET || - status == -ESHUTDOWN)) { - dev_err(&ftdi->udev->dev, - "urb=%p write bulk status received: %d\n", urb, status); - } - usb_free_coherent(urb->dev, urb->transfer_buffer_length, - urb->transfer_buffer, urb->transfer_dma); -} - -static int fill_buffer_with_all_queued_commands(struct usb_ftdi *ftdi, - char *buf, int command_size, int total_size) -{ - int ed_commands = 0; - int b = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - int F = command->follows; - u8 *f = command->buffer; - if (command->header & 0x80) { - ed_commands |= 1 << (0x3 & (command->header >> 5)); - } - buf[b++] = command->header; - buf[b++] = (command->length >> 0) & 0x00FF; - buf[b++] = (command->length >> 8) & 0x00FF; - buf[b++] = command->address; - buf[b++] = command->width; - while (F-- > 0) { - buf[b++] = *f++; - } - } - return ed_commands; -} - -static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size) -{ - int total_size = 0; - int I = command_size; - int i = ftdi->command_head; - while (I-- > 0) { - struct u132_command *command = &ftdi->command[COMMAND_MASK & - i++]; - total_size += 5 + command->follows; - } - return total_size; -} - -static int ftdi_elan_command_engine(struct usb_ftdi *ftdi) -{ - int retval; - char *buf; - int ed_commands; - int total_size; - struct urb *urb; - int command_size = ftdi->command_next - ftdi->command_head; - if (command_size == 0) - return 0; - total_size = ftdi_elan_total_command_size(ftdi, command_size); - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, total_size, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer to write %d commands totaling %d bytes to the Uxxx\n", - command_size, total_size); - usb_free_urb(urb); - return -ENOMEM; - } - ed_commands = fill_buffer_with_all_queued_commands(ftdi, buf, - command_size, total_size); - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, total_size, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - if (ed_commands) { - char diag[40 *3 + 4]; - char *d = diag; - int m = total_size; - u8 *c = buf; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - } - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed %d to submit urb %p to write %d commands totaling %d bytes to the Uxxx\n", - retval, urb, command_size, total_size); - usb_free_coherent(ftdi->udev, total_size, buf, urb->transfer_dma); - usb_free_urb(urb); - return retval; - } - usb_free_urb(urb); /* release our reference to this urb, - the USB core will eventually free it entirely */ - ftdi->command_head += command_size; - ftdi_elan_kick_respond_queue(ftdi); - return 0; -} - -static void ftdi_elan_do_callback(struct usb_ftdi *ftdi, - struct u132_target *target, u8 *buffer, int length) -{ - struct urb *urb = target->urb; - int halted = target->halted; - int skipped = target->skipped; - int actual = target->actual; - int non_null = target->non_null; - int toggle_bits = target->toggle_bits; - int error_count = target->error_count; - int condition_code = target->condition_code; - int repeat_number = target->repeat_number; - void (*callback) (void *, struct urb *, u8 *, int, int, int, int, int, - int, int, int, int) = target->callback; - target->active -= 1; - target->callback = NULL; - (*callback) (target->endp, urb, buffer, length, toggle_bits, - error_count, condition_code, repeat_number, halted, skipped, - actual, non_null); -} - -static char *have_ed_set_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - int payload = (ed_length >> 0) & 0x07FF; - mutex_lock(&ftdi->u132_lock); - target->actual = 0; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - if (ed_type == 0x02 || ed_type == 0x03) { - if (payload == 0 || target->abandoning > 0) { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } else { - ftdi->expected = 4 + payload; - ftdi->ed_found = 1; - mutex_unlock(&ftdi->u132_lock); - return b; - } - } else { - target->abandoning = 0; - mutex_unlock(&ftdi->u132_lock); - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; - } -} - -static char *have_ed_get_response(struct usb_ftdi *ftdi, - struct u132_target *target, u16 ed_length, int ed_number, int ed_type, - char *b) -{ - mutex_lock(&ftdi->u132_lock); - target->condition_code = TD_DEVNOTRESP; - target->actual = (ed_length >> 0) & 0x01FF; - target->non_null = (ed_length >> 15) & 0x0001; - target->repeat_number = (ed_length >> 11) & 0x000F; - mutex_unlock(&ftdi->u132_lock); - if (target->active) - ftdi_elan_do_callback(ftdi, target, NULL, 0); - target->abandoning = 0; - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - return ftdi->response; -} - - -/* - * The engine tries to empty the FTDI fifo - * - * all responses found in the fifo data are dispatched thus - * the response buffer can only ever hold a maximum sized - * response from the Uxxx. - * - */ -static int ftdi_elan_respond_engine(struct usb_ftdi *ftdi) -{ - u8 *b = ftdi->response + ftdi->received; - int bytes_read = 0; - int retry_on_empty = 1; - int retry_on_timeout = 3; -read:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - char diag[30 *3 + 4]; - char *d = diag; - int m = packet_bytes; - u8 *c = ftdi->bulk_in_buffer; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - if (packet_bytes > 2) { - ftdi->bulk_in_left = packet_bytes - 2; - ftdi->bulk_in_last = 1; - goto have; - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - goto more; - } else if (bytes_read > 0) { - dev_err(&ftdi->udev->dev, "ONLY %d bytes%s\n", - bytes_read, diag); - return -ENOMEM; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT with packet_bytes = %d with total %d bytes%s\n", - packet_bytes, bytes_read, diag); - return -ENOMEM; - } - } else if (retval == -EILSEQ) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", - retval, packet_bytes, bytes_read, diag); - return retval; - } else if (retval) { - dev_err(&ftdi->udev->dev, "error = %d with packet_bytes = %d with total %d bytes%s\n", - retval, packet_bytes, bytes_read, diag); - return retval; - } else { - if (retry_on_empty-- > 0) { - goto more; - } else - return 0; - } - } -more:{ - goto read; - } -have:if (ftdi->bulk_in_left > 0) { - u8 c = ftdi->bulk_in_buffer[++ftdi->bulk_in_last]; - bytes_read += 1; - ftdi->bulk_in_left -= 1; - if (ftdi->received == 0 && c == 0xFF) { - goto have; - } else - *b++ = c; - if (++ftdi->received < ftdi->expected) { - goto have; - } else if (ftdi->ed_found) { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ed_number]; - int payload = (ed_length >> 0) & 0x07FF; - char diag[30 *3 + 4]; - char *d = diag; - int m = payload; - u8 *c = 4 + ftdi->response; - int s = (sizeof(diag) - 1) / 3; - diag[0] = 0; - while (s-- > 0 && m-- > 0) { - if (s > 0 || m == 0) { - d += sprintf(d, " %02X", *c++); - } else - d += sprintf(d, " .."); - } - ftdi_elan_do_callback(ftdi, target, 4 + ftdi->response, - payload); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - goto have; - } else if (ftdi->expected == 8) { - u8 buscmd; - int respond_head = ftdi->respond_head++; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & respond_head]; - u32 data = ftdi->response[7]; - data <<= 8; - data |= ftdi->response[6]; - data <<= 8; - data |= ftdi->response[5]; - data <<= 8; - data |= ftdi->response[4]; - *respond->value = data; - *respond->result = 0; - complete(&respond->wait_completion); - ftdi->received = 0; - ftdi->expected = 4; - ftdi->ed_found = 0; - b = ftdi->response; - buscmd = (ftdi->response[0] >> 0) & 0x0F; - if (buscmd == 0x00) { - } else if (buscmd == 0x02) { - } else if (buscmd == 0x06) { - } else if (buscmd == 0x0A) { - } else - dev_err(&ftdi->udev->dev, "Uxxx unknown(%0X) value = %08X\n", - buscmd, data); - goto have; - } else { - if ((ftdi->response[0] & 0x80) == 0x00) { - ftdi->expected = 8; - goto have; - } else { - int ed_number = (ftdi->response[0] >> 5) & 0x03; - int ed_type = (ftdi->response[0] >> 0) & 0x03; - u16 ed_length = (ftdi->response[2] << 8) | - ftdi->response[1]; - struct u132_target *target = &ftdi->target[ - ed_number]; - target->halted = (ftdi->response[0] >> 3) & - 0x01; - target->skipped = (ftdi->response[0] >> 2) & - 0x01; - target->toggle_bits = (ftdi->response[3] >> 6) - & 0x03; - target->error_count = (ftdi->response[3] >> 4) - & 0x03; - target->condition_code = (ftdi->response[ - 3] >> 0) & 0x0F; - if ((ftdi->response[0] & 0x10) == 0x00) { - b = have_ed_set_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } else { - b = have_ed_get_response(ftdi, target, - ed_length, ed_number, ed_type, - b); - goto have; - } - } - } - } else - goto more; -} - - -/* - * create a urb, and a buffer for it, and copy the data to the urb - * - */ -static ssize_t ftdi_elan_write(struct file *file, - const char __user *user_buffer, size_t count, - loff_t *ppos) -{ - int retval = 0; - struct urb *urb; - char *buf; - struct usb_ftdi *ftdi = file->private_data; - - if (ftdi->disconnected > 0) { - return -ENODEV; - } - if (count == 0) { - goto exit; - } - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) { - retval = -ENOMEM; - goto error_1; - } - buf = usb_alloc_coherent(ftdi->udev, count, GFP_KERNEL, - &urb->transfer_dma); - if (!buf) { - retval = -ENOMEM; - goto error_2; - } - if (copy_from_user(buf, user_buffer, count)) { - retval = -EFAULT; - goto error_3; - } - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, count, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, - "failed submitting write urb, error %d\n", retval); - goto error_3; - } - usb_free_urb(urb); - -exit: - return count; -error_3: - usb_free_coherent(ftdi->udev, count, buf, urb->transfer_dma); -error_2: - usb_free_urb(urb); -error_1: - return retval; -} - -static const struct file_operations ftdi_elan_fops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = ftdi_elan_read, - .write = ftdi_elan_write, - .open = ftdi_elan_open, - .release = ftdi_elan_release, -}; - -/* - * usb class driver info in order to get a minor number from the usb core, - * and to have the device registered with the driver core - */ -static struct usb_class_driver ftdi_elan_jtag_class = { - .name = "ftdi-%d-jtag", - .fops = &ftdi_elan_fops, - .minor_base = USB_FTDI_ELAN_MINOR_BASE, -}; - -/* - * the following definitions are for the - * ELAN FPGA state machgine processor that - * lies on the other side of the FTDI chip - */ -#define cPCIu132rd 0x0 -#define cPCIu132wr 0x1 -#define cPCIiord 0x2 -#define cPCIiowr 0x3 -#define cPCImemrd 0x6 -#define cPCImemwr 0x7 -#define cPCIcfgrd 0xA -#define cPCIcfgwr 0xB -#define cPCInull 0xF -#define cU132cmd_status 0x0 -#define cU132flash 0x1 -#define cPIDsetup 0x0 -#define cPIDout 0x1 -#define cPIDin 0x2 -#define cPIDinonce 0x3 -#define cCCnoerror 0x0 -#define cCCcrc 0x1 -#define cCCbitstuff 0x2 -#define cCCtoggle 0x3 -#define cCCstall 0x4 -#define cCCnoresp 0x5 -#define cCCbadpid1 0x6 -#define cCCbadpid2 0x7 -#define cCCdataoverrun 0x8 -#define cCCdataunderrun 0x9 -#define cCCbuffoverrun 0xC -#define cCCbuffunderrun 0xD -#define cCCnotaccessed 0xF -static int ftdi_elan_write_reg(struct usb_ftdi *ftdi, u32 data) -{ -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | cPCIu132wr; - command->length = 0x04; - command->address = 0x00; - command->width = 0x00; - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_write_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 data) -{ - u8 addressofs = config_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCIcfgwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_write_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 data) -{ - u8 addressofs = mem_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x00 | (cPCImemwr & 0x0F); - command->length = 0x04; - command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 4; - command->value = data; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_write_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 data) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_write_pcimem(ftdi, mem_offset, width, data); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_write_pcimem); -static int ftdi_elan_read_reg(struct usb_ftdi *ftdi, u32 *data) -{ -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | cPCIu132rd; - command->length = 0x04; - respond->address = command->address = cU132cmd_status; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_read_config(struct usb_ftdi *ftdi, int config_offset, - u8 width, u32 *data) -{ - u8 addressofs = config_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCIcfgrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -static int ftdi_elan_read_pcimem(struct usb_ftdi *ftdi, int mem_offset, - u8 width, u32 *data) -{ - u8 addressofs = mem_offset / 4; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else { - int command_size; - int respond_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - respond_size = ftdi->respond_next - ftdi->respond_head; - if (command_size < COMMAND_SIZE && respond_size < RESPOND_SIZE) - { - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - struct u132_respond *respond = &ftdi->respond[ - RESPOND_MASK & ftdi->respond_next]; - int result = -ENODEV; - respond->result = &result; - respond->header = command->header = 0x00 | (cPCImemrd & - 0x0F); - command->length = 0x04; - respond->address = command->address = addressofs; - command->width = 0x00 | (width & 0x0F); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - respond->value = data; - init_completion(&respond->wait_completion); - ftdi->command_next += 1; - ftdi->respond_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - wait_for_completion(&respond->wait_completion); - return result; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_read_pcimem(struct platform_device *pdev, int mem_offset, - u8 width, u32 *data) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - if (ftdi->initialized == 0) { - return -ENODEV; - } else - return ftdi_elan_read_pcimem(ftdi, mem_offset, width, data); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_read_pcimem); -static int ftdi_elan_edset_setup(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x80 | (ed << 5); - command->length = 0x8007; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 8; - command->value = 0; - command->buffer = urb->setup_packet; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_setup(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_setup(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_setup); -static int ftdi_elan_edset_input(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - command->header = 0x82 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_input(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_input(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_input); -static int ftdi_elan_edset_empty(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->length = 0x0000; - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_empty(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_empty(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_empty); -static int ftdi_elan_edset_output(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u8 *b; - u16 urb_size; - int i = 0; - char data[30 *3 + 4]; - char *d = data; - int m = (sizeof(data) - 1) / 3 - 1; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x81 | (ed << 5); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = min_t(u32, 1024, - urb->transfer_buffer_length - - urb->actual_length); - command->value = 0; - command->buffer = urb->transfer_buffer + - urb->actual_length; - command->length = 0x8000 | (command->follows - 1); - b = command->buffer; - urb_size = command->follows; - data[0] = 0; - while (urb_size-- > 0) { - if (i > m) { - } else if (i++ < m) { - int w = sprintf(d, " %02X", *b++); - d += w; - } else - d += sprintf(d, " .."); - } - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_output(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_output(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_output); -static int ftdi_elan_edset_single(struct usb_ftdi *ftdi, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - u8 ed = ed_number - 1; -wait:if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - int command_size; - mutex_lock(&ftdi->u132_lock); - command_size = ftdi->command_next - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - u32 remaining_length = urb->transfer_buffer_length - - urb->actual_length; - struct u132_target *target = &ftdi->target[ed]; - struct u132_command *command = &ftdi->command[ - COMMAND_MASK & ftdi->command_next]; - command->header = 0x83 | (ed << 5); - if (remaining_length == 0) { - command->length = 0x0000; - } else if (remaining_length > 1024) { - command->length = 0x8000 | 1023; - } else - command->length = 0x8000 | (remaining_length - - 1); - command->address = (toggle_bits << 6) | (ep_number << 2) - | (address << 0); - command->width = usb_maxpacket(urb->dev, urb->pipe); - command->follows = 0; - command->value = 0; - command->buffer = NULL; - target->callback = callback; - target->endp = endp; - target->urb = urb; - target->active = 1; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - goto wait; - } - } -} - -int usb_ftdi_elan_edset_single(struct platform_device *pdev, u8 ed_number, - void *endp, struct urb *urb, u8 address, u8 ep_number, u8 toggle_bits, - void (*callback) (void *endp, struct urb *urb, u8 *buf, int len, - int toggle_bits, int error_count, int condition_code, int repeat_number, - int halted, int skipped, int actual, int non_null)) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_single(ftdi, ed_number, endp, urb, address, - ep_number, toggle_bits, callback); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_single); -static int ftdi_elan_edset_flush(struct usb_ftdi *ftdi, u8 ed_number, - void *endp) -{ - u8 ed = ed_number - 1; - if (ftdi->disconnected > 0) { - return -ENODEV; - } else if (ftdi->initialized == 0) { - return -ENODEV; - } else { - struct u132_target *target = &ftdi->target[ed]; - mutex_lock(&ftdi->u132_lock); - if (target->abandoning > 0) { - mutex_unlock(&ftdi->u132_lock); - return 0; - } else { - target->abandoning = 1; - wait_1:if (target->active == 1) { - int command_size = ftdi->command_next - - ftdi->command_head; - if (command_size < COMMAND_SIZE) { - struct u132_command *command = - &ftdi->command[COMMAND_MASK & - ftdi->command_next]; - command->header = 0x80 | (ed << 5) | - 0x4; - command->length = 0x00; - command->address = 0x00; - command->width = 0x00; - command->follows = 0; - command->value = 0; - command->buffer = &command->value; - ftdi->command_next += 1; - ftdi_elan_kick_command_queue(ftdi); - } else { - mutex_unlock(&ftdi->u132_lock); - msleep(100); - mutex_lock(&ftdi->u132_lock); - goto wait_1; - } - } - mutex_unlock(&ftdi->u132_lock); - return 0; - } - } -} - -int usb_ftdi_elan_edset_flush(struct platform_device *pdev, u8 ed_number, - void *endp) -{ - struct usb_ftdi *ftdi = platform_device_to_usb_ftdi(pdev); - return ftdi_elan_edset_flush(ftdi, ed_number, endp); -} - - -EXPORT_SYMBOL_GPL(usb_ftdi_elan_edset_flush); -static int ftdi_elan_flush_input_fifo(struct usb_ftdi *ftdi) -{ - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 20; -more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 100); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3 - 1; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); - return -EFAULT; - } - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", - b1); - if (retry_on_status-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return retval; - } - } - return -1; -} - - -/* - * send the long flush sequence - * - */ -static int ftdi_elan_synchronize_flush(struct usb_ftdi *ftdi) -{ - int retval; - struct urb *urb; - char *buf; - int I = 257; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for flush sequence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - while (I-- > 0) - buf[i++] = 0x55; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the flush sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; -} - - -/* - * send the reset sequence - * - */ -static int ftdi_elan_synchronize_reset(struct usb_ftdi *ftdi) -{ - int retval; - struct urb *urb; - char *buf; - int I = 4; - int i = 0; - urb = usb_alloc_urb(0, GFP_KERNEL); - if (!urb) - return -ENOMEM; - buf = usb_alloc_coherent(ftdi->udev, I, GFP_KERNEL, &urb->transfer_dma); - if (!buf) { - dev_err(&ftdi->udev->dev, "could not get a buffer for the reset sequence\n"); - usb_free_urb(urb); - return -ENOMEM; - } - buf[i++] = 0x55; - buf[i++] = 0xAA; - buf[i++] = 0x5A; - buf[i++] = 0xA5; - usb_fill_bulk_urb(urb, ftdi->udev, usb_sndbulkpipe(ftdi->udev, - ftdi->bulk_out_endpointAddr), buf, i, - ftdi_elan_write_bulk_callback, ftdi); - urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - retval = usb_submit_urb(urb, GFP_KERNEL); - if (retval) { - dev_err(&ftdi->udev->dev, "failed to submit urb containing the reset sequence\n"); - usb_free_coherent(ftdi->udev, i, buf, urb->transfer_dma); - usb_free_urb(urb); - return -ENOMEM; - } - usb_free_urb(urb); - return 0; -} - -static int ftdi_elan_synchronize(struct usb_ftdi *ftdi) -{ - int retval; - int long_stop = 10; - int retry_on_timeout = 5; - int retry_on_empty = 10; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - ftdi->bulk_in_left = 0; - ftdi->bulk_in_last = -1; - while (long_stop-- > 0) { - int read_stop; - int read_stuck; - retval = ftdi_elan_synchronize_flush(ftdi); - if (retval) - return retval; - retval = ftdi_elan_flush_input_fifo(ftdi); - if (retval) - return retval; - reset:retval = ftdi_elan_synchronize_reset(ftdi); - if (retval) - return retval; - read_stop = 100; - read_stuck = 10; - read:{ - int packet_bytes = 0; - retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, - ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 500); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3 - 1; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - unsigned char c = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - continue; - } - if (c == 0x7E) { - return 0; - } else { - if (c == 0x55) { - goto read; - } else if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } - } else if (packet_bytes > 1) { - unsigned char s1 = ftdi->bulk_in_buffer[0]; - unsigned char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x00) { - if (read_stuck-- > 0) { - goto read; - } else - goto reset; - } else { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } - } else if (packet_bytes > 0) { - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); - continue; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); - continue; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", - retval); - if (read_stop-- > 0) { - goto read; - } else { - dev_err(&ftdi->udev->dev, "retry limit reached\n"); - continue; - } - } - } - } - dev_err(&ftdi->udev->dev, "failed to synchronize\n"); - return -EFAULT; -} - -static int ftdi_elan_stuck_waiting(struct usb_ftdi *ftdi) -{ - int retry_on_empty = 10; - int retry_on_timeout = 5; - int retry_on_status = 50; -more:{ - int packet_bytes = 0; - int retval = usb_bulk_msg(ftdi->udev, - usb_rcvbulkpipe(ftdi->udev, ftdi->bulk_in_endpointAddr), - ftdi->bulk_in_buffer, ftdi->bulk_in_size, - &packet_bytes, 1000); - if (packet_bytes > 2) { - char diag[30 *3 + 4]; - char *d = diag; - int m = (sizeof(diag) - 1) / 3 - 1; - char *b = ftdi->bulk_in_buffer; - int bytes_read = 0; - diag[0] = 0; - while (packet_bytes-- > 0) { - char c = *b++; - if (bytes_read < m) { - d += sprintf(d, " %02X", - 0x000000FF & c); - } else if (bytes_read > m) { - } else - d += sprintf(d, " .."); - bytes_read += 1; - } - goto more; - } else if (packet_bytes > 1) { - char s1 = ftdi->bulk_in_buffer[0]; - char s2 = ftdi->bulk_in_buffer[1]; - if (s1 == 0x31 && s2 == 0x60) { - return 0; - } else if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else - return -EFAULT; - } else if (packet_bytes > 0) { - char b1 = ftdi->bulk_in_buffer[0]; - dev_err(&ftdi->udev->dev, "only one byte flushed from FTDI = %02X\n", b1); - if (retry_on_status-- > 0) { - msleep(5); - goto more; - } else { - dev_err(&ftdi->udev->dev, "STATUS ERROR retry limit reached\n"); - return -EFAULT; - } - } else if (retval == -ETIMEDOUT) { - if (retry_on_timeout-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "TIMED OUT retry limit reached\n"); - return -ENOMEM; - } - } else if (retval == 0) { - if (retry_on_empty-- > 0) { - goto more; - } else { - dev_err(&ftdi->udev->dev, "empty packet retry limit reached\n"); - return -ENOMEM; - } - } else { - dev_err(&ftdi->udev->dev, "error = %d\n", retval); - return -ENOMEM; - } - } - return -1; -} - -static int ftdi_elan_checkingPCI(struct usb_ftdi *ftdi) -{ - int UxxxStatus = ftdi_elan_read_reg(ftdi, &ftdi->controlreg); - if (UxxxStatus) - return UxxxStatus; - if (ftdi->controlreg & 0x00400000) { - if (ftdi->card_ejected) { - } else { - ftdi->card_ejected = 1; - dev_err(&ftdi->udev->dev, "CARD EJECTED - controlreg = %08X\n", - ftdi->controlreg); - } - return -ENODEV; - } else { - u8 fn = ftdi->function - 1; - int activePCIfn = fn << 8; - u32 pcidata; - u32 pciVID; - u32 pciPID; - int reg = 0; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if (pciVID == ftdi->platform_data.vendor && pciPID == - ftdi->platform_data.device) { - return 0; - } else { - dev_err(&ftdi->udev->dev, "vendor=%04X pciVID=%04X device=%04X pciPID=%04X\n", - ftdi->platform_data.vendor, pciVID, - ftdi->platform_data.device, pciPID); - return -ENODEV; - } - } -} - - -#define ftdi_read_pcimem(ftdi, member, data) ftdi_elan_read_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); -#define ftdi_write_pcimem(ftdi, member, data) ftdi_elan_write_pcimem(ftdi, \ - offsetof(struct ohci_regs, member), 0, data); - -#define OHCI_CONTROL_INIT OHCI_CTRL_CBSR -#define OHCI_INTR_INIT (OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_RD | \ - OHCI_INTR_WDH) -static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk) -{ - int devices = 0; - int retval; - u32 hc_control; - int num_ports; - u32 control; - u32 rh_a = -1; - u32 status; - u32 fminterval; - u32 hc_fminterval; - u32 periodicstart; - u32 cmdstatus; - u32 roothub_a; - int mask = OHCI_INTR_INIT; - int sleep_time = 0; - int reset_timeout = 30; /* ... allow extra time */ - int temp; - retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a); - if (retval) - return retval; - num_ports = rh_a & RH_A_NDP; - retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval); - if (retval) - return retval; - hc_fminterval &= 0x3fff; - if (hc_fminterval != FI) { - } - hc_fminterval |= FSMP(hc_fminterval) << 16; - retval = ftdi_read_pcimem(ftdi, control, &hc_control); - if (retval) - return retval; - switch (hc_control & OHCI_CTRL_HCFS) { - case OHCI_USB_OPER: - sleep_time = 0; - break; - case OHCI_USB_SUSPEND: - case OHCI_USB_RESUME: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESUME; - sleep_time = 10; - break; - default: - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_USB_RESET; - sleep_time = 50; - break; - } - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - msleep(sleep_time); - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - if (!(roothub_a & RH_A_NPS)) { /* power down each port */ - for (temp = 0; temp < num_ports; temp++) { - retval = ftdi_write_pcimem(ftdi, - roothub.portstatus[temp], RH_PS_LSDA); - if (retval) - return retval; - } - } - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; -retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR); - if (retval) - return retval; -extra:{ - retval = ftdi_read_pcimem(ftdi, cmdstatus, &status); - if (retval) - return retval; - if (0 != (status & OHCI_HCR)) { - if (--reset_timeout == 0) { - dev_err(&ftdi->udev->dev, "USB HC reset timed out!\n"); - return -ENODEV; - } else { - msleep(5); - goto extra; - } - } - } - if (quirk & OHCI_QUIRK_INITRESET) { - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, fminterval, - ((fminterval & FIT) ^ FIT) | hc_fminterval); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, periodicstart, - ((9 *hc_fminterval) / 10) & 0x3fff); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart); - if (retval) - return retval; - if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) { - if (!(quirk & OHCI_QUIRK_INITRESET)) { - quirk |= OHCI_QUIRK_INITRESET; - goto retry; - } else - dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n", - fminterval, periodicstart); - } /* start controller operations */ - hc_control &= OHCI_CTRL_RWC; - hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER; - retval = ftdi_write_pcimem(ftdi, control, hc_control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrstatus, mask); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, intrdisable, - OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO | - OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH | - OHCI_INTR_SO); - if (retval) - return retval; /* handle root hub init quirks ... */ - retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a); - if (retval) - return retval; - roothub_a &= ~(RH_A_PSM | RH_A_OCPM); - if (quirk & OHCI_QUIRK_SUPERIO) { - roothub_a |= RH_A_NOCP; - roothub_a &= ~(RH_A_POTPGT | RH_A_NPS); - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) { - roothub_a |= RH_A_NPS; - retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a); - if (retval) - return retval; - } - retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC); - if (retval) - return retval; - retval = ftdi_write_pcimem(ftdi, roothub.b, - (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM); - if (retval) - return retval; - retval = ftdi_read_pcimem(ftdi, control, &control); - if (retval) - return retval; - mdelay((roothub_a >> 23) & 0x1fe); - for (temp = 0; temp < num_ports; temp++) { - u32 portstatus; - retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp], - &portstatus); - if (retval) - return retval; - if (1 & portstatus) - devices += 1; - } - return devices; -} - -static int ftdi_elan_setup_controller(struct usb_ftdi *ftdi, int fn) -{ - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xF0000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x06); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - for (reg = 0; reg <= 0x54; reg += 4) { - UxxxStatus = ftdi_elan_read_pcimem(ftdi, reg, 0, &pcidata); - if (UxxxStatus) - return UxxxStatus; - } - return 0; -} - -static int ftdi_elan_close_controller(struct usb_ftdi *ftdi, int fn) -{ - u32 latence_timer; - int UxxxStatus; - u32 pcidata; - int reg = 0; - int activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x2800); - if (UxxxStatus) - return UxxxStatus; - reg = 16; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0xFFFFFFFF); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0, - 0x00000000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 12; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &latence_timer); - if (UxxxStatus) - return UxxxStatus; - latence_timer &= 0xFFFF00FF; - latence_timer |= 0x00001600; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - latence_timer); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - reg = 4; - UxxxStatus = ftdi_elan_write_config(ftdi, activePCIfn | reg, 0x00, - 0x00); - if (UxxxStatus) - return UxxxStatus; - return ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, &pcidata); -} - -static int ftdi_elan_found_controller(struct usb_ftdi *ftdi, int fn, int quirk) -{ - int result; - int UxxxStatus; - UxxxStatus = ftdi_elan_setup_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - result = ftdi_elan_check_controller(ftdi, quirk); - UxxxStatus = ftdi_elan_close_controller(ftdi, fn); - if (UxxxStatus) - return UxxxStatus; - return result; -} - -static int ftdi_elan_enumeratePCI(struct usb_ftdi *ftdi) -{ - u32 controlreg; - u8 sensebits; - int UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000000L); - if (UxxxStatus) - return UxxxStatus; - msleep(750); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x100); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x00000200L | 0x500); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020CL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020DL | 0x000); - if (UxxxStatus) - return UxxxStatus; - msleep(250); - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000020FL | 0x000); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_write_reg(ftdi, 0x0000025FL | 0x800); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - UxxxStatus = ftdi_elan_read_reg(ftdi, &controlreg); - if (UxxxStatus) - return UxxxStatus; - msleep(1000); - sensebits = (controlreg >> 16) & 0x000F; - if (0x0D == sensebits) - return 0; - else - return - ENXIO; -} - -static int ftdi_elan_setupOHCI(struct usb_ftdi *ftdi) -{ - int UxxxStatus; - u32 pcidata; - int reg = 0; - u8 fn; - int activePCIfn = 0; - int max_devices = 0; - int controllers = 0; - int unrecognized = 0; - ftdi->function = 0; - for (fn = 0; (fn < 4); fn++) { - u32 pciVID = 0; - u32 pciPID = 0; - int devices = 0; - activePCIfn = fn << 8; - UxxxStatus = ftdi_elan_read_config(ftdi, activePCIfn | reg, 0, - &pcidata); - if (UxxxStatus) - return UxxxStatus; - pciVID = pcidata & 0xFFFF; - pciPID = (pcidata >> 16) & 0xFFFF; - if ((pciVID == PCI_VENDOR_ID_OPTI) && (pciPID == 0xc861)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_NEC) && (pciPID == 0x0035)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_AL) && (pciPID == 0x5237)) { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if ((pciVID == PCI_VENDOR_ID_ATT) && (pciPID == 0x5802)) - { - devices = ftdi_elan_found_controller(ftdi, fn, 0); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_AMD && pciPID == 0x740c) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_AMD756); - controllers += 1; - } else if (pciVID == PCI_VENDOR_ID_COMPAQ && pciPID == 0xa0f8) { - devices = ftdi_elan_found_controller(ftdi, fn, - OHCI_QUIRK_ZFMICRO); - controllers += 1; - } else if (0 == pcidata) { - } else - unrecognized += 1; - if (devices > max_devices) { - max_devices = devices; - ftdi->function = fn + 1; - ftdi->platform_data.vendor = pciVID; - ftdi->platform_data.device = pciPID; - } - } - if (ftdi->function > 0) { - return ftdi_elan_setup_controller(ftdi, ftdi->function - 1); - } else if (controllers > 0) { - return -ENXIO; - } else if (unrecognized > 0) { - return -ENXIO; - } else { - ftdi->enumerated = 0; - return -ENXIO; - } -} - - -/* - * we use only the first bulk-in and bulk-out endpoints - */ -static int ftdi_elan_probe(struct usb_interface *interface, - const struct usb_device_id *id) -{ - struct usb_host_interface *iface_desc; - struct usb_endpoint_descriptor *bulk_in, *bulk_out; - int retval; - struct usb_ftdi *ftdi; - - ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL); - if (!ftdi) - return -ENOMEM; - - mutex_lock(&ftdi_module_lock); - list_add_tail(&ftdi->ftdi_list, &ftdi_static_list); - ftdi->sequence_num = ++ftdi_instances; - mutex_unlock(&ftdi_module_lock); - ftdi_elan_init_kref(ftdi); - sema_init(&ftdi->sw_lock, 1); - ftdi->udev = usb_get_dev(interface_to_usbdev(interface)); - ftdi->interface = interface; - mutex_init(&ftdi->u132_lock); - ftdi->expected = 4; - - iface_desc = interface->cur_altsetting; - retval = usb_find_common_endpoints(iface_desc, - &bulk_in, &bulk_out, NULL, NULL); - if (retval) { - dev_err(&ftdi->udev->dev, "Could not find both bulk-in and bulk-out endpoints\n"); - goto error; - } - - ftdi->bulk_in_size = usb_endpoint_maxp(bulk_in); - ftdi->bulk_in_endpointAddr = bulk_in->bEndpointAddress; - ftdi->bulk_in_buffer = kmalloc(ftdi->bulk_in_size, GFP_KERNEL); - if (!ftdi->bulk_in_buffer) { - retval = -ENOMEM; - goto error; - } - - ftdi->bulk_out_endpointAddr = bulk_out->bEndpointAddress; - - dev_info(&ftdi->udev->dev, "interface %d has I=%02X O=%02X\n", - iface_desc->desc.bInterfaceNumber, ftdi->bulk_in_endpointAddr, - ftdi->bulk_out_endpointAddr); - usb_set_intfdata(interface, ftdi); - if (iface_desc->desc.bInterfaceNumber == 0 && - ftdi->bulk_in_endpointAddr == 0x81 && - ftdi->bulk_out_endpointAddr == 0x02) { - retval = usb_register_dev(interface, &ftdi_elan_jtag_class); - if (retval) { - dev_err(&ftdi->udev->dev, "Not able to get a minor for this device\n"); - usb_set_intfdata(interface, NULL); - retval = -ENOMEM; - goto error; - } else { - ftdi->class = &ftdi_elan_jtag_class; - dev_info(&ftdi->udev->dev, "USB FDTI=%p JTAG interface %d now attached to ftdi%d\n", - ftdi, iface_desc->desc.bInterfaceNumber, - interface->minor); - return 0; - } - } else if (iface_desc->desc.bInterfaceNumber == 1 && - ftdi->bulk_in_endpointAddr == 0x83 && - ftdi->bulk_out_endpointAddr == 0x04) { - ftdi->class = NULL; - dev_info(&ftdi->udev->dev, "USB FDTI=%p ELAN interface %d now activated\n", - ftdi, iface_desc->desc.bInterfaceNumber); - INIT_DELAYED_WORK(&ftdi->status_work, ftdi_elan_status_work); - INIT_DELAYED_WORK(&ftdi->command_work, ftdi_elan_command_work); - INIT_DELAYED_WORK(&ftdi->respond_work, ftdi_elan_respond_work); - ftdi_status_queue_work(ftdi, msecs_to_jiffies(3 *1000)); - return 0; - } else { - dev_err(&ftdi->udev->dev, - "Could not find ELAN's U132 device\n"); - retval = -ENODEV; - goto error; - } -error:if (ftdi) { - ftdi_elan_put_kref(ftdi); - } - return retval; -} - -static void ftdi_elan_disconnect(struct usb_interface *interface) -{ - struct usb_ftdi *ftdi = usb_get_intfdata(interface); - ftdi->disconnected += 1; - if (ftdi->class) { - int minor = interface->minor; - struct usb_class_driver *class = ftdi->class; - usb_set_intfdata(interface, NULL); - usb_deregister_dev(interface, class); - dev_info(&ftdi->udev->dev, "USB FTDI U132 jtag interface on minor %d now disconnected\n", - minor); - } else { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - ftdi_elan_abandon_completions(ftdi); - ftdi_elan_abandon_targets(ftdi); - if (ftdi->registered) { - platform_device_unregister(&ftdi->platform_dev); - ftdi->synchronized = 0; - ftdi->enumerated = 0; - ftdi->initialized = 0; - ftdi->registered = 0; - } - ftdi->disconnected += 1; - usb_set_intfdata(interface, NULL); - dev_info(&ftdi->udev->dev, "USB FTDI U132 host controller interface now disconnected\n"); - } - ftdi_elan_put_kref(ftdi); -} - -static struct usb_driver ftdi_elan_driver = { - .name = "ftdi-elan", - .probe = ftdi_elan_probe, - .disconnect = ftdi_elan_disconnect, - .id_table = ftdi_elan_table, -}; -static int __init ftdi_elan_init(void) -{ - int result; - pr_info("driver %s\n", ftdi_elan_driver.name); - mutex_init(&ftdi_module_lock); - INIT_LIST_HEAD(&ftdi_static_list); - result = usb_register(&ftdi_elan_driver); - if (result) { - pr_err("usb_register failed. Error number %d\n", result); - } - return result; - -} - -static void __exit ftdi_elan_exit(void) -{ - struct usb_ftdi *ftdi; - struct usb_ftdi *temp; - usb_deregister(&ftdi_elan_driver); - pr_info("ftdi_u132 driver deregistered\n"); - list_for_each_entry_safe(ftdi, temp, &ftdi_static_list, ftdi_list) { - ftdi_status_cancel_work(ftdi); - ftdi_command_cancel_work(ftdi); - ftdi_response_cancel_work(ftdi); - } -} - - -module_init(ftdi_elan_init); -module_exit(ftdi_elan_exit); diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index e3abe67a155d..ce1da80d3365 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -377,7 +377,6 @@ out_err: return err; } -#ifdef CONFIG_OF static void usb251xb_get_ports_field(struct usb251xb *hub, const char *prop_name, u8 port_cnt, bool ds_only, u8 *fld) @@ -410,10 +409,7 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, return -ENODEV; } - if (of_get_property(np, "skip-config", NULL)) - hub->skip_config = 1; - else - hub->skip_config = 0; + hub->skip_config = of_property_read_bool(np, "skip-config"); hub->gpio_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(hub->gpio_reset)) @@ -431,40 +427,40 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, hub->device_id = USB251XB_DEF_DEVICE_ID; hub->conf_data1 = USB251XB_DEF_CONFIG_DATA_1; - if (of_get_property(np, "self-powered", NULL)) { + if (of_property_read_bool(np, "self-powered")) { hub->conf_data1 |= BIT(7); /* Configure Over-Current sens when self-powered */ hub->conf_data1 &= ~BIT(2); - if (of_get_property(np, "ganged-sensing", NULL)) + if (of_property_read_bool(np, "ganged-sensing")) hub->conf_data1 &= ~BIT(1); - else if (of_get_property(np, "individual-sensing", NULL)) + else if (of_property_read_bool(np, "individual-sensing")) hub->conf_data1 |= BIT(1); - } else if (of_get_property(np, "bus-powered", NULL)) { + } else if (of_property_read_bool(np, "bus-powered")) { hub->conf_data1 &= ~BIT(7); /* Disable Over-Current sense when bus-powered */ hub->conf_data1 |= BIT(2); } - if (of_get_property(np, "disable-hi-speed", NULL)) + if (of_property_read_bool(np, "disable-hi-speed")) hub->conf_data1 |= BIT(5); - if (of_get_property(np, "multi-tt", NULL)) + if (of_property_read_bool(np, "multi-tt")) hub->conf_data1 |= BIT(4); - else if (of_get_property(np, "single-tt", NULL)) + else if (of_property_read_bool(np, "single-tt")) hub->conf_data1 &= ~BIT(4); - if (of_get_property(np, "disable-eop", NULL)) + if (of_property_read_bool(np, "disable-eop")) hub->conf_data1 |= BIT(3); - if (of_get_property(np, "individual-port-switching", NULL)) + if (of_property_read_bool(np, "individual-port-switching")) hub->conf_data1 |= BIT(0); - else if (of_get_property(np, "ganged-port-switching", NULL)) + else if (of_property_read_bool(np, "ganged-port-switching")) hub->conf_data1 &= ~BIT(0); hub->conf_data2 = USB251XB_DEF_CONFIG_DATA_2; - if (of_get_property(np, "dynamic-power-switching", NULL)) + if (of_property_read_bool(np, "dynamic-power-switching")) hub->conf_data2 |= BIT(7); if (!of_property_read_u32(np, "oc-delay-us", &property_u32)) { @@ -487,17 +483,17 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, } } - if (of_get_property(np, "compound-device", NULL)) + if (of_property_read_bool(np, "compound-device")) hub->conf_data2 |= BIT(3); hub->conf_data3 = USB251XB_DEF_CONFIG_DATA_3; - if (of_get_property(np, "port-mapping-mode", NULL)) + if (of_property_read_bool(np, "port-mapping-mode")) hub->conf_data3 |= BIT(3); if (data->led_support && of_get_property(np, "led-usb-mode", NULL)) hub->conf_data3 &= ~BIT(1); - if (of_get_property(np, "string-support", NULL)) + if (of_property_read_bool(np, "string-support")) hub->conf_data3 |= BIT(0); hub->non_rem_dev = USB251XB_DEF_NON_REMOVABLE_DEVICES; @@ -626,13 +622,6 @@ static const struct of_device_id usb251xb_of_match[] = { } }; MODULE_DEVICE_TABLE(of, usb251xb_of_match); -#else /* CONFIG_OF */ -static int usb251xb_get_ofdata(struct usb251xb *hub, - const struct usb251xb_data *data) -{ - return 0; -} -#endif /* CONFIG_OF */ static void usb251xb_regulator_disable_action(void *data) { @@ -754,7 +743,7 @@ MODULE_DEVICE_TABLE(i2c, usb251xb_id); static struct i2c_driver usb251xb_i2c_driver = { .driver = { .name = DRIVER_NAME, - .of_match_table = of_match_ptr(usb251xb_of_match), + .of_match_table = usb251xb_of_match, .pm = &usb251xb_pm_ops, }, .probe_new = usb251xb_i2c_probe, diff --git a/drivers/usb/misc/usb3503.c b/drivers/usb/misc/usb3503.c index bd47c4437ca4..c6cfd1edaf76 100644 --- a/drivers/usb/misc/usb3503.c +++ b/drivers/usb/misc/usb3503.c @@ -46,34 +46,18 @@ struct usb3503 { struct device *dev; struct clk *clk; u8 port_off_mask; + struct gpio_desc *bypass; struct gpio_desc *intn; struct gpio_desc *reset; struct gpio_desc *connect; bool secondary_ref_clk; }; -static int usb3503_reset(struct usb3503 *hub, int state) -{ - if (!state && hub->connect) - gpiod_set_value_cansleep(hub->connect, 0); - - if (hub->reset) - gpiod_set_value_cansleep(hub->reset, !state); - - /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ - if (state) - usleep_range(4000, 10000); - - return 0; -} - static int usb3503_connect(struct usb3503 *hub) { struct device *dev = hub->dev; int err; - usb3503_reset(hub, 1); - if (hub->regmap) { /* SP_ILOCK: set connect_n, config_n for config */ err = regmap_write(hub->regmap, USB3503_SP_ILOCK, @@ -126,25 +110,46 @@ static int usb3503_connect(struct usb3503 *hub) static int usb3503_switch_mode(struct usb3503 *hub, enum usb3503_mode mode) { struct device *dev = hub->dev; - int err = 0; + int rst, bypass, conn; switch (mode) { case USB3503_MODE_HUB: - err = usb3503_connect(hub); + conn = 1; + rst = 0; + bypass = 0; break; - case USB3503_MODE_STANDBY: - usb3503_reset(hub, 0); + conn = 0; + rst = 1; + bypass = 1; dev_info(dev, "switched to STANDBY mode\n"); break; - + case USB3503_MODE_BYPASS: + conn = 0; + rst = 0; + bypass = 1; + break; default: dev_err(dev, "unknown mode is requested\n"); - err = -EINVAL; - break; + return -EINVAL; } - return err; + if (!conn && hub->connect) + gpiod_set_value_cansleep(hub->connect, 0); + + if (hub->reset) + gpiod_set_value_cansleep(hub->reset, rst); + + if (hub->bypass) + gpiod_set_value_cansleep(hub->bypass, bypass); + + if (conn) { + /* Wait T_HUBINIT == 4ms for hub logic to stabilize */ + usleep_range(4000, 10000); + return usb3503_connect(hub); + } + + return 0; } static const struct regmap_config usb3503_regmap_config = { @@ -253,6 +258,14 @@ static int usb3503_probe(struct usb3503 *hub) if (hub->connect) gpiod_set_consumer_name(hub->connect, "usb3503 connect"); + hub->bypass = devm_gpiod_get_optional(dev, "bypass", GPIOD_OUT_HIGH); + if (IS_ERR(hub->bypass)) { + err = PTR_ERR(hub->bypass); + goto err_clk; + } + if (hub->bypass) + gpiod_set_consumer_name(hub->bypass, "usb3503 bypass"); + hub->reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(hub->reset)) { err = PTR_ERR(hub->reset); @@ -388,6 +401,7 @@ MODULE_DEVICE_TABLE(i2c, usb3503_id); static const struct of_device_id usb3503_of_match[] = { { .compatible = "smsc,usb3503", }, { .compatible = "smsc,usb3503a", }, + { .compatible = "smsc,usb3803", }, {}, }; MODULE_DEVICE_TABLE(of, usb3503_of_match); diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig index 3a1f4bcea80c..9a8cf3de0617 100644 --- a/drivers/usb/musb/Kconfig +++ b/drivers/usb/musb/Kconfig @@ -113,7 +113,7 @@ config USB_MUSB_MEDIATEK config USB_MUSB_POLARFIRE_SOC tristate "Microchip PolarFire SoC platforms" - depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST + depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST depends on NOP_USB_XCEIV select USB_MUSB_DUAL_ROLE help diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c index d47e5c94587b..912e32b78ac6 100644 --- a/drivers/usb/musb/da8xx.c +++ b/drivers/usb/musb/da8xx.c @@ -576,14 +576,12 @@ static int da8xx_probe(struct platform_device *pdev) return ret; } -static int da8xx_remove(struct platform_device *pdev) +static void da8xx_remove(struct platform_device *pdev) { struct da8xx_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); usb_phy_generic_unregister(glue->usb_phy); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -626,7 +624,7 @@ MODULE_DEVICE_TABLE(of, da8xx_id_table); static struct platform_driver da8xx_driver = { .probe = da8xx_probe, - .remove = da8xx_remove, + .remove_new = da8xx_remove, .driver = { .name = "musb-da8xx", .pm = &da8xx_pm_ops, diff --git a/drivers/usb/musb/jz4740.c b/drivers/usb/musb/jz4740.c index c7b1d2a394d9..5aabdd7e2511 100644 --- a/drivers/usb/musb/jz4740.c +++ b/drivers/usb/musb/jz4740.c @@ -308,14 +308,12 @@ err_platform_device_put: return ret; } -static int jz4740_remove(struct platform_device *pdev) +static void jz4740_remove(struct platform_device *pdev) { struct jz4740_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->pdev); clk_disable_unprepare(glue->clk); - - return 0; } static const struct of_device_id jz4740_musb_of_match[] = { @@ -327,7 +325,7 @@ MODULE_DEVICE_TABLE(of, jz4740_musb_of_match); static struct platform_driver jz4740_driver = { .probe = jz4740_probe, - .remove = jz4740_remove, + .remove_new = jz4740_remove, .driver = { .name = "musb-jz4740", .of_match_table = jz4740_musb_of_match, diff --git a/drivers/usb/musb/mediatek.c b/drivers/usb/musb/mediatek.c index 27b9bd258340..598ee5c0bf34 100644 --- a/drivers/usb/musb/mediatek.c +++ b/drivers/usb/musb/mediatek.c @@ -508,15 +508,13 @@ err_unregister_usb_phy: return ret; } -static int mtk_musb_remove(struct platform_device *pdev) +static void mtk_musb_remove(struct platform_device *pdev) { struct mtk_glue *glue = platform_get_drvdata(pdev); struct platform_device *usb_phy = glue->usb_phy; platform_device_unregister(glue->musb_pdev); usb_phy_generic_unregister(usb_phy); - - return 0; } #ifdef CONFIG_OF @@ -529,7 +527,7 @@ MODULE_DEVICE_TABLE(of, mtk_musb_match); static struct platform_driver mtk_musb_driver = { .probe = mtk_musb_probe, - .remove = mtk_musb_remove, + .remove_new = mtk_musb_remove, .driver = { .name = "musb-mtk", .of_match_table = of_match_ptr(mtk_musb_match), diff --git a/drivers/usb/musb/mpfs.c b/drivers/usb/musb/mpfs.c index cea2e8108867..24b98716f7fc 100644 --- a/drivers/usb/musb/mpfs.c +++ b/drivers/usb/musb/mpfs.c @@ -235,15 +235,13 @@ err_phy_release: return ret; } -static int mpfs_remove(struct platform_device *pdev) +static void mpfs_remove(struct platform_device *pdev) { struct mpfs_glue *glue = platform_get_drvdata(pdev); clk_disable_unprepare(glue->clk); platform_device_unregister(glue->musb); usb_phy_generic_unregister(pdev); - - return 0; } #ifdef CONFIG_OF @@ -256,7 +254,7 @@ MODULE_DEVICE_TABLE(of, mpfs_id_table); static struct platform_driver mpfs_musb_driver = { .probe = mpfs_probe, - .remove = mpfs_remove, + .remove_new = mpfs_remove, .driver = { .name = "mpfs-musb", .of_match_table = of_match_ptr(mpfs_id_table) diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 648bb6021c5e..d162afbbe19f 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2621,7 +2621,7 @@ static int musb_probe(struct platform_device *pdev) return musb_init_controller(dev, irq, base); } -static int musb_remove(struct platform_device *pdev) +static void musb_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct musb *musb = dev_to_musb(dev); @@ -2657,7 +2657,6 @@ static int musb_remove(struct platform_device *pdev) usb_phy_shutdown(musb->xceiv); musb_free(musb); device_init_wakeup(dev, 0); - return 0; } #ifdef CONFIG_PM @@ -2955,7 +2954,7 @@ static struct platform_driver musb_driver = { .dev_groups = musb_groups, }, .probe = musb_probe, - .remove = musb_remove, + .remove_new = musb_remove, }; module_platform_driver(musb_driver); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index f75cde0f2b43..9119b1d51370 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -915,7 +915,7 @@ err: return ret; } -static int dsps_remove(struct platform_device *pdev) +static void dsps_remove(struct platform_device *pdev) { struct dsps_glue *glue = platform_get_drvdata(pdev); @@ -923,8 +923,6 @@ static int dsps_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); iounmap(glue->usbss_base); - - return 0; } static const struct dsps_musb_wrapper am33xx_driver_data = { @@ -1036,7 +1034,7 @@ static SIMPLE_DEV_PM_OPS(dsps_pm_ops, dsps_suspend, dsps_resume); static struct platform_driver dsps_usbss_driver = { .probe = dsps_probe, - .remove = dsps_remove, + .remove_new = dsps_remove, .driver = { .name = "musb-dsps", .pm = &dsps_pm_ops, diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c index 44a21ec865fb..b4a4c1df4e0d 100644 --- a/drivers/usb/musb/omap2430.c +++ b/drivers/usb/musb/omap2430.c @@ -334,7 +334,7 @@ static int omap2430_probe(struct platform_device *pdev) * Legacy SoCs using omap_device get confused if node is moved * because of interconnect properties mixed into the node. */ - if (of_get_property(np, "ti,hwmods", NULL)) { + if (of_property_present(np, "ti,hwmods")) { dev_warn(&pdev->dev, "please update to probe with ti-sysc\n"); populate_irqs = true; } else { @@ -471,14 +471,12 @@ err0: return ret; } -static int omap2430_remove(struct platform_device *pdev) +static void omap2430_remove(struct platform_device *pdev) { struct omap2430_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); pm_runtime_disable(glue->dev); - - return 0; } #ifdef CONFIG_PM @@ -610,7 +608,7 @@ MODULE_DEVICE_TABLE(of, omap2430_id_table); static struct platform_driver omap2430_driver = { .probe = omap2430_probe, - .remove = omap2430_remove, + .remove_new = omap2430_remove, .driver = { .name = "musb-omap2430", .pm = DEV_PM_OPS, diff --git a/drivers/usb/musb/sunxi.c b/drivers/usb/musb/sunxi.c index 9b622cd9b2bd..c5c6c4e09300 100644 --- a/drivers/usb/musb/sunxi.c +++ b/drivers/usb/musb/sunxi.c @@ -805,15 +805,13 @@ err_unregister_usb_phy: return ret; } -static int sunxi_musb_remove(struct platform_device *pdev) +static void sunxi_musb_remove(struct platform_device *pdev) { struct sunxi_glue *glue = platform_get_drvdata(pdev); struct platform_device *usb_phy = glue->usb_phy; platform_device_unregister(glue->musb_pdev); usb_phy_generic_unregister(usb_phy); - - return 0; } static const struct sunxi_musb_cfg sun4i_a10_musb_cfg = { @@ -862,7 +860,7 @@ MODULE_DEVICE_TABLE(of, sunxi_musb_match); static struct platform_driver sunxi_musb_driver = { .probe = sunxi_musb_probe, - .remove = sunxi_musb_remove, + .remove_new = sunxi_musb_remove, .driver = { .name = "musb-sunxi", .of_match_table = sunxi_musb_match, diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c index 5609b4e84d40..a1f29dbc62e6 100644 --- a/drivers/usb/musb/tusb6010.c +++ b/drivers/usb/musb/tusb6010.c @@ -1258,19 +1258,17 @@ static int tusb_probe(struct platform_device *pdev) return 0; } -static int tusb_remove(struct platform_device *pdev) +static void tusb_remove(struct platform_device *pdev) { struct tusb6010_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); usb_phy_generic_unregister(glue->phy); - - return 0; } static struct platform_driver tusb_driver = { .probe = tusb_probe, - .remove = tusb_remove, + .remove_new = tusb_remove, .driver = { .name = "musb-tusb", }, diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c index 8ea62c344328..c8d9d2a1d2f0 100644 --- a/drivers/usb/musb/ux500.c +++ b/drivers/usb/musb/ux500.c @@ -303,14 +303,12 @@ err0: return ret; } -static int ux500_remove(struct platform_device *pdev) +static void ux500_remove(struct platform_device *pdev) { struct ux500_glue *glue = platform_get_drvdata(pdev); platform_device_unregister(glue->musb); clk_disable_unprepare(glue->clk); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -357,7 +355,7 @@ MODULE_DEVICE_TABLE(of, ux500_match); static struct platform_driver ux500_driver = { .probe = ux500_probe, - .remove = ux500_remove, + .remove_new = ux500_remove, .driver = { .name = "musb-ux500", .pm = &ux500_pm_ops, diff --git a/drivers/usb/phy/phy-ab8500-usb.c b/drivers/usb/phy/phy-ab8500-usb.c index 4c52ba96f17e..408f47e39025 100644 --- a/drivers/usb/phy/phy-ab8500-usb.c +++ b/drivers/usb/phy/phy-ab8500-usb.c @@ -965,7 +965,7 @@ static int ab8500_usb_probe(struct platform_device *pdev) return 0; } -static int ab8500_usb_remove(struct platform_device *pdev) +static void ab8500_usb_remove(struct platform_device *pdev) { struct ab8500_usb *ab = platform_get_drvdata(pdev); @@ -977,8 +977,6 @@ static int ab8500_usb_remove(struct platform_device *pdev) ab8500_usb_host_phy_dis(ab); else if (ab->mode == USB_PERIPHERAL) ab8500_usb_peri_phy_dis(ab); - - return 0; } static const struct platform_device_id ab8500_usb_devtype[] = { @@ -989,7 +987,7 @@ MODULE_DEVICE_TABLE(platform, ab8500_usb_devtype); static struct platform_driver ab8500_usb_driver = { .probe = ab8500_usb_probe, - .remove = ab8500_usb_remove, + .remove_new = ab8500_usb_remove, .id_table = ab8500_usb_devtype, .driver = { .name = "abx5x0-usb", diff --git a/drivers/usb/phy/phy-am335x.c b/drivers/usb/phy/phy-am335x.c index 8524475d942d..e39665cf4b4a 100644 --- a/drivers/usb/phy/phy-am335x.c +++ b/drivers/usb/phy/phy-am335x.c @@ -82,12 +82,11 @@ static int am335x_phy_probe(struct platform_device *pdev) return usb_add_phy_dev(&am_phy->usb_phy_gen.phy); } -static int am335x_phy_remove(struct platform_device *pdev) +static void am335x_phy_remove(struct platform_device *pdev) { struct am335x_phy *am_phy = platform_get_drvdata(pdev); usb_remove_phy(&am_phy->usb_phy_gen.phy); - return 0; } #ifdef CONFIG_PM_SLEEP @@ -134,7 +133,7 @@ MODULE_DEVICE_TABLE(of, am335x_phy_ids); static struct platform_driver am335x_phy_driver = { .probe = am335x_phy_probe, - .remove = am335x_phy_remove, + .remove_new = am335x_phy_remove, .driver = { .name = "am335x-phy-driver", .pm = &am335x_pm_ops, diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c index 972704262b02..79617bb0a70e 100644 --- a/drivers/usb/phy/phy-fsl-usb.c +++ b/drivers/usb/phy/phy-fsl-usb.c @@ -983,7 +983,7 @@ static int fsl_otg_probe(struct platform_device *pdev) return ret; } -static int fsl_otg_remove(struct platform_device *pdev) +static void fsl_otg_remove(struct platform_device *pdev) { struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -998,13 +998,11 @@ static int fsl_otg_remove(struct platform_device *pdev) if (pdata->exit) pdata->exit(pdev); - - return 0; } struct platform_driver fsl_otg_driver = { .probe = fsl_otg_probe, - .remove = fsl_otg_remove, + .remove_new = fsl_otg_remove, .driver = { .name = driver_name, .owner = THIS_MODULE, diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index c1309ea24a52..770081b828a4 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -330,13 +330,11 @@ static int usb_phy_generic_probe(struct platform_device *pdev) return 0; } -static int usb_phy_generic_remove(struct platform_device *pdev) +static void usb_phy_generic_remove(struct platform_device *pdev) { struct usb_phy_generic *nop = platform_get_drvdata(pdev); usb_remove_phy(&nop->phy); - - return 0; } static const struct of_device_id nop_xceiv_dt_ids[] = { @@ -348,7 +346,7 @@ MODULE_DEVICE_TABLE(of, nop_xceiv_dt_ids); static struct platform_driver usb_phy_generic_driver = { .probe = usb_phy_generic_probe, - .remove = usb_phy_generic_remove, + .remove_new = usb_phy_generic_remove, .driver = { .name = "usb_phy_generic", .of_match_table = nop_xceiv_dt_ids, diff --git a/drivers/usb/phy/phy-gpio-vbus-usb.c b/drivers/usb/phy/phy-gpio-vbus-usb.c index 12dfeff7de3d..817c242a76ca 100644 --- a/drivers/usb/phy/phy-gpio-vbus-usb.c +++ b/drivers/usb/phy/phy-gpio-vbus-usb.c @@ -325,7 +325,7 @@ static int gpio_vbus_probe(struct platform_device *pdev) return 0; } -static int gpio_vbus_remove(struct platform_device *pdev) +static void gpio_vbus_remove(struct platform_device *pdev) { struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev); @@ -333,8 +333,6 @@ static int gpio_vbus_remove(struct platform_device *pdev) cancel_delayed_work_sync(&gpio_vbus->work); usb_remove_phy(&gpio_vbus->phy); - - return 0; } #ifdef CONFIG_PM @@ -386,7 +384,7 @@ static struct platform_driver gpio_vbus_driver = { .of_match_table = gpio_vbus_of_match, }, .probe = gpio_vbus_probe, - .remove = gpio_vbus_remove, + .remove_new = gpio_vbus_remove, }; module_platform_driver(gpio_vbus_driver); diff --git a/drivers/usb/phy/phy-keystone.c b/drivers/usb/phy/phy-keystone.c index f75912279b39..bd9a98ad1b30 100644 --- a/drivers/usb/phy/phy-keystone.c +++ b/drivers/usb/phy/phy-keystone.c @@ -88,13 +88,11 @@ static int keystone_usbphy_probe(struct platform_device *pdev) return usb_add_phy_dev(&k_phy->usb_phy_gen.phy); } -static int keystone_usbphy_remove(struct platform_device *pdev) +static void keystone_usbphy_remove(struct platform_device *pdev) { struct keystone_usbphy *k_phy = platform_get_drvdata(pdev); usb_remove_phy(&k_phy->usb_phy_gen.phy); - - return 0; } static const struct of_device_id keystone_usbphy_ids[] = { @@ -105,7 +103,7 @@ MODULE_DEVICE_TABLE(of, keystone_usbphy_ids); static struct platform_driver keystone_usbphy_driver = { .probe = keystone_usbphy_probe, - .remove = keystone_usbphy_remove, + .remove_new = keystone_usbphy_remove, .driver = { .name = "keystone-usbphy", .of_match_table = keystone_usbphy_ids, diff --git a/drivers/usb/phy/phy-mv-usb.c b/drivers/usb/phy/phy-mv-usb.c index 86503b7d695c..df7c27474a75 100644 --- a/drivers/usb/phy/phy-mv-usb.c +++ b/drivers/usb/phy/phy-mv-usb.c @@ -644,7 +644,7 @@ static const struct attribute_group *mv_otg_groups[] = { NULL, }; -static int mv_otg_remove(struct platform_device *pdev) +static void mv_otg_remove(struct platform_device *pdev) { struct mv_otg *mvotg = platform_get_drvdata(pdev); @@ -654,8 +654,6 @@ static int mv_otg_remove(struct platform_device *pdev) mv_otg_disable(mvotg); usb_remove_phy(&mvotg->phy); - - return 0; } static int mv_otg_probe(struct platform_device *pdev) @@ -869,7 +867,7 @@ static int mv_otg_resume(struct platform_device *pdev) static struct platform_driver mv_otg_driver = { .probe = mv_otg_probe, - .remove = mv_otg_remove, + .remove_new = mv_otg_remove, .driver = { .name = driver_name, .dev_groups = mv_otg_groups, diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c index d2836ef5d15c..e1a2b2ea098b 100644 --- a/drivers/usb/phy/phy-mxs-usb.c +++ b/drivers/usb/phy/phy-mxs-usb.c @@ -733,7 +733,7 @@ static int mxs_phy_probe(struct platform_device *pdev) return -ENOMEM; /* Some SoCs don't have anatop registers */ - if (of_get_property(np, "fsl,anatop", NULL)) { + if (of_property_present(np, "fsl,anatop")) { mxs_phy->regmap_anatop = syscon_regmap_lookup_by_phandle (np, "fsl,anatop"); if (IS_ERR(mxs_phy->regmap_anatop)) { @@ -801,13 +801,11 @@ static int mxs_phy_probe(struct platform_device *pdev) return usb_add_phy_dev(&mxs_phy->phy); } -static int mxs_phy_remove(struct platform_device *pdev) +static void mxs_phy_remove(struct platform_device *pdev) { struct mxs_phy *mxs_phy = platform_get_drvdata(pdev); usb_remove_phy(&mxs_phy->phy); - - return 0; } #ifdef CONFIG_PM_SLEEP @@ -853,7 +851,7 @@ static SIMPLE_DEV_PM_OPS(mxs_phy_pm, mxs_phy_system_suspend, static struct platform_driver mxs_phy_driver = { .probe = mxs_phy_probe, - .remove = mxs_phy_remove, + .remove_new = mxs_phy_remove, .driver = { .name = DRIVER_NAME, .of_match_table = mxs_phy_dt_ids, diff --git a/drivers/usb/phy/phy-tahvo.c b/drivers/usb/phy/phy-tahvo.c index f2d2cc586c5b..47562d49dfc1 100644 --- a/drivers/usb/phy/phy-tahvo.c +++ b/drivers/usb/phy/phy-tahvo.c @@ -412,7 +412,7 @@ err_disable_clk: return ret; } -static int tahvo_usb_remove(struct platform_device *pdev) +static void tahvo_usb_remove(struct platform_device *pdev) { struct tahvo_usb *tu = platform_get_drvdata(pdev); @@ -420,13 +420,11 @@ static int tahvo_usb_remove(struct platform_device *pdev) usb_remove_phy(&tu->phy); if (!IS_ERR(tu->ick)) clk_disable(tu->ick); - - return 0; } static struct platform_driver tahvo_usb_driver = { .probe = tahvo_usb_probe, - .remove = tahvo_usb_remove, + .remove_new = tahvo_usb_remove, .driver = { .name = "tahvo-usb", .dev_groups = tahvo_groups, diff --git a/drivers/usb/phy/phy-tegra-usb.c b/drivers/usb/phy/phy-tegra-usb.c index f0240107edb1..8b2ff3a8882d 100644 --- a/drivers/usb/phy/phy-tegra-usb.c +++ b/drivers/usb/phy/phy-tegra-usb.c @@ -1375,7 +1375,7 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) tegra_phy->is_legacy_phy = of_property_read_bool(np, "nvidia,has-legacy-mode"); - if (of_find_property(np, "dr_mode", NULL)) + if (of_property_present(np, "dr_mode")) tegra_phy->mode = usb_get_dr_mode(&pdev->dev); else tegra_phy->mode = USB_DR_MODE_HOST; @@ -1486,18 +1486,16 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) return usb_add_phy_dev(&tegra_phy->u_phy); } -static int tegra_usb_phy_remove(struct platform_device *pdev) +static void tegra_usb_phy_remove(struct platform_device *pdev) { struct tegra_usb_phy *tegra_phy = platform_get_drvdata(pdev); usb_remove_phy(&tegra_phy->u_phy); - - return 0; } static struct platform_driver tegra_usb_phy_driver = { .probe = tegra_usb_phy_probe, - .remove = tegra_usb_phy_remove, + .remove_new = tegra_usb_phy_remove, .driver = { .name = "tegra-phy", .of_match_table = tegra_usb_phy_id_table, diff --git a/drivers/usb/phy/phy-twl6030-usb.c b/drivers/usb/phy/phy-twl6030-usb.c index ab3c38a7d8ac..c3ce6b1054f1 100644 --- a/drivers/usb/phy/phy-twl6030-usb.c +++ b/drivers/usb/phy/phy-twl6030-usb.c @@ -409,7 +409,7 @@ err_put_regulator: return status; } -static int twl6030_usb_remove(struct platform_device *pdev) +static void twl6030_usb_remove(struct platform_device *pdev) { struct twl6030_usb *twl = platform_get_drvdata(pdev); @@ -422,8 +422,6 @@ static int twl6030_usb_remove(struct platform_device *pdev) free_irq(twl->irq2, twl); regulator_put(twl->usb3v3); cancel_work_sync(&twl->set_vbus_work); - - return 0; } static const struct of_device_id twl6030_usb_id_table[] = { @@ -434,7 +432,7 @@ MODULE_DEVICE_TABLE(of, twl6030_usb_id_table); static struct platform_driver twl6030_usb_driver = { .probe = twl6030_usb_probe, - .remove = twl6030_usb_remove, + .remove_new = twl6030_usb_remove, .driver = { .name = "twl6030_usb", .of_match_table = of_match_ptr(twl6030_usb_id_table), diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 96f3939a65e2..fa34efabcccf 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -823,7 +823,7 @@ static struct platform_driver renesas_usbhs_driver = { .driver = { .name = "renesas_usbhs", .pm = &usbhsc_pm_ops, - .of_match_table = of_match_ptr(usbhs_of_match), + .of_match_table = usbhs_of_match, }, .probe = usbhs_probe, .remove = usbhs_remove, diff --git a/drivers/usb/serial/quatech2.c b/drivers/usb/serial/quatech2.c index 6fca40ace83a..fee581409bf6 100644 --- a/drivers/usb/serial/quatech2.c +++ b/drivers/usb/serial/quatech2.c @@ -176,14 +176,6 @@ static inline int qt2_control_msg(struct usb_device *dev, 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_getregister(struct usb_device *dev, u8 uart, u8 reg, diff --git a/drivers/usb/typec/hd3ss3220.c b/drivers/usb/typec/hd3ss3220.c index 746ef3a75b76..8bbeb9b1e439 100644 --- a/drivers/usb/typec/hd3ss3220.c +++ b/drivers/usb/typec/hd3ss3220.c @@ -290,7 +290,7 @@ MODULE_DEVICE_TABLE(of, dev_ids); static struct i2c_driver hd3ss3220_driver = { .driver = { .name = "hd3ss3220", - .of_match_table = of_match_ptr(dev_ids), + .of_match_table = dev_ids, }, .probe_new = hd3ss3220_probe, .remove = hd3ss3220_remove, diff --git a/drivers/usb/typec/tcpm/fusb302.c b/drivers/usb/typec/tcpm/fusb302.c index 1ffce00d94b4..62ba53357612 100644 --- a/drivers/usb/typec/tcpm/fusb302.c +++ b/drivers/usb/typec/tcpm/fusb302.c @@ -190,7 +190,7 @@ static void fusb302_log(struct fusb302_chip *chip, const char *fmt, ...) static int fusb302_debug_show(struct seq_file *s, void *v) { - struct fusb302_chip *chip = (struct fusb302_chip *)s->private; + struct fusb302_chip *chip = s->private; int tail; mutex_lock(&chip->logbuffer_lock); @@ -1813,7 +1813,7 @@ static int fusb302_pm_resume(struct device *dev) return 0; } -static const struct of_device_id fusb302_dt_match[] = { +static const struct of_device_id fusb302_dt_match[] __maybe_unused = { {.compatible = "fcs,fusb302"}, {}, }; diff --git a/drivers/usb/typec/tcpm/tcpci_mt6360.c b/drivers/usb/typec/tcpm/tcpci_mt6360.c index 1b7c31278ebb..6fa8fd5c8041 100644 --- a/drivers/usb/typec/tcpm/tcpci_mt6360.c +++ b/drivers/usb/typec/tcpm/tcpci_mt6360.c @@ -43,12 +43,6 @@ struct mt6360_tcpc_info { int irq; }; -static inline int mt6360_tcpc_read16(struct regmap *regmap, - unsigned int reg, u16 *val) -{ - return regmap_raw_read(regmap, reg, val, sizeof(u16)); -} - static inline int mt6360_tcpc_write16(struct regmap *regmap, unsigned int reg, u16 val) { diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 1ee774c263f0..4e276d2f15d1 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -737,7 +737,7 @@ static void tcpm_log_source_caps(struct tcpm_port *port) static int tcpm_debug_show(struct seq_file *s, void *v) { - struct tcpm_port *port = (struct tcpm_port *)s->private; + struct tcpm_port *port = s->private; int tail; mutex_lock(&port->logbuffer_lock); @@ -6577,6 +6577,8 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) port->port_type = port->typec_caps.type; port->role_sw = usb_role_switch_get(port->dev); + if (!port->role_sw) + port->role_sw = fwnode_usb_role_switch_get(tcpc->fwnode); if (IS_ERR(port->role_sw)) { err = PTR_ERR(port->role_sw); goto out_destroy_wq; diff --git a/drivers/usb/typec/tipd/core.c b/drivers/usb/typec/tipd/core.c index 485b90c13078..8b075ca82ef6 100644 --- a/drivers/usb/typec/tipd/core.c +++ b/drivers/usb/typec/tipd/core.c @@ -16,6 +16,7 @@ #include <linux/usb/typec.h> #include <linux/usb/typec_altmode.h> #include <linux/usb/role.h> +#include <linux/workqueue.h> #include "tps6598x.h" #include "trace.h" @@ -97,6 +98,8 @@ struct tps6598x { int wakeup; u16 pwr_status; + struct delayed_work wq_poll; + irq_handler_t irq_handler; }; static enum power_supply_property tps6598x_psy_props[] = { @@ -177,16 +180,6 @@ static inline int tps6598x_read64(struct tps6598x *tps, u8 reg, u64 *val) return tps6598x_block_read(tps, reg, val, sizeof(u64)); } -static inline int tps6598x_write16(struct tps6598x *tps, u8 reg, u16 val) -{ - return tps6598x_block_write(tps, reg, &val, sizeof(u16)); -} - -static inline int tps6598x_write32(struct tps6598x *tps, u8 reg, u32 val) -{ - return tps6598x_block_write(tps, reg, &val, sizeof(u32)); -} - static inline int tps6598x_write64(struct tps6598x *tps, u8 reg, u64 val) { return tps6598x_block_write(tps, reg, &val, sizeof(u64)); @@ -568,6 +561,18 @@ err_unlock: return IRQ_NONE; } +/* Time interval for Polling */ +#define POLL_INTERVAL 500 /* msecs */ +static void tps6598x_poll_work(struct work_struct *work) +{ + struct tps6598x *tps = container_of(to_delayed_work(work), + struct tps6598x, wq_poll); + + tps->irq_handler(0, tps); + queue_delayed_work(system_power_efficient_wq, + &tps->wq_poll, msecs_to_jiffies(POLL_INTERVAL)); +} + static int tps6598x_check_mode(struct tps6598x *tps) { char mode[5] = { }; @@ -746,6 +751,7 @@ static int tps6598x_probe(struct i2c_client *client) TPS_REG_INT_PLUG_EVENT; } + tps->irq_handler = irq_handler; /* Make sure the controller has application firmware running */ ret = tps6598x_check_mode(tps); if (ret) @@ -837,10 +843,18 @@ static int tps6598x_probe(struct i2c_client *client) dev_err(&client->dev, "failed to register partner\n"); } - ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, - irq_handler, - IRQF_SHARED | IRQF_ONESHOT, - dev_name(&client->dev), tps); + if (client->irq) { + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, + irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + dev_name(&client->dev), tps); + } else { + dev_warn(tps->dev, "Unable to find the interrupt, switching to polling\n"); + INIT_DELAYED_WORK(&tps->wq_poll, tps6598x_poll_work); + queue_delayed_work(system_power_efficient_wq, &tps->wq_poll, + msecs_to_jiffies(POLL_INTERVAL)); + } + if (ret) goto err_disconnect; @@ -848,7 +862,7 @@ static int tps6598x_probe(struct i2c_client *client) fwnode_handle_put(fwnode); tps->wakeup = device_property_read_bool(tps->dev, "wakeup-source"); - if (tps->wakeup) { + if (tps->wakeup && client->irq) { device_init_wakeup(&client->dev, true); enable_irq_wake(client->irq); } @@ -887,6 +901,9 @@ static int __maybe_unused tps6598x_suspend(struct device *dev) enable_irq_wake(client->irq); } + if (!client->irq) + cancel_delayed_work_sync(&tps->wq_poll); + return 0; } @@ -900,6 +917,10 @@ static int __maybe_unused tps6598x_resume(struct device *dev) enable_irq(client->irq); } + if (client->irq) + queue_delayed_work(system_power_efficient_wq, &tps->wq_poll, + msecs_to_jiffies(POLL_INTERVAL)); + return 0; } diff --git a/drivers/usb/typec/ucsi/Kconfig b/drivers/usb/typec/ucsi/Kconfig index 8f9c4b9f31f7..b3bb0191987e 100644 --- a/drivers/usb/typec/ucsi/Kconfig +++ b/drivers/usb/typec/ucsi/Kconfig @@ -58,4 +58,14 @@ config UCSI_STM32G0 To compile the driver as a module, choose M here: the module will be called ucsi_stm32g0. +config UCSI_PMIC_GLINK + tristate "UCSI Qualcomm PMIC GLINK Interface Driver" + depends on QCOM_PMIC_GLINK + help + This driver enables UCSI support on platforms that expose UCSI + interface as PMIC GLINK device. + + To compile the driver as a module, choose M here: the module will be + called ucsi_glink. + endif diff --git a/drivers/usb/typec/ucsi/Makefile b/drivers/usb/typec/ucsi/Makefile index 480d533d762f..77f09e136956 100644 --- a/drivers/usb/typec/ucsi/Makefile +++ b/drivers/usb/typec/ucsi/Makefile @@ -18,3 +18,4 @@ endif obj-$(CONFIG_UCSI_ACPI) += ucsi_acpi.o obj-$(CONFIG_UCSI_CCG) += ucsi_ccg.o obj-$(CONFIG_UCSI_STM32G0) += ucsi_stm32g0.o +obj-$(CONFIG_UCSI_PMIC_GLINK) += ucsi_glink.o diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index 62206a6b8ea7..217355f1f9b9 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -9,6 +9,7 @@ #include <linux/platform_device.h> #include <linux/module.h> #include <linux/acpi.h> +#include <linux/dmi.h> #include "ucsi.h" @@ -23,6 +24,7 @@ struct ucsi_acpi { struct completion complete; unsigned long flags; guid_t guid; + u64 cmd; }; static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func) @@ -62,6 +64,7 @@ static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset, struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); memcpy(ua->base + offset, val, val_len); + ua->cmd = *(u64 *)val; return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE); } @@ -93,13 +96,46 @@ static const struct ucsi_operations ucsi_acpi_ops = { .async_write = ucsi_acpi_async_write }; +static int +ucsi_zenbook_read(struct ucsi *ucsi, unsigned int offset, void *val, size_t val_len) +{ + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); + int ret; + + if (offset == UCSI_VERSION || UCSI_COMMAND(ua->cmd) == UCSI_PPM_RESET) { + ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); + if (ret) + return ret; + } + + memcpy(val, ua->base + offset, val_len); + + return 0; +} + +static const struct ucsi_operations ucsi_zenbook_ops = { + .read = ucsi_zenbook_read, + .sync_write = ucsi_acpi_sync_write, + .async_write = ucsi_acpi_async_write +}; + +static const struct dmi_system_id zenbook_dmi_id[] = { + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "ZenBook UX325UA_UM325UA"), + }, + }, + { } +}; + static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) { struct ucsi_acpi *ua = data; u32 cci; int ret; - ret = ucsi_acpi_read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci)); + ret = ua->ucsi->ops->read(ua->ucsi, UCSI_CCI, &cci, sizeof(cci)); if (ret) return; @@ -114,6 +150,7 @@ static void ucsi_acpi_notify(acpi_handle handle, u32 event, void *data) static int ucsi_acpi_probe(struct platform_device *pdev) { struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); + const struct ucsi_operations *ops = &ucsi_acpi_ops; struct ucsi_acpi *ua; struct resource *res; acpi_status status; @@ -143,7 +180,10 @@ static int ucsi_acpi_probe(struct platform_device *pdev) init_completion(&ua->complete); ua->dev = &pdev->dev; - ua->ucsi = ucsi_create(&pdev->dev, &ucsi_acpi_ops); + if (dmi_check_system(zenbook_dmi_id)) + ops = &ucsi_zenbook_ops; + + ua->ucsi = ucsi_create(&pdev->dev, ops); if (IS_ERR(ua->ucsi)) return PTR_ERR(ua->ucsi); diff --git a/drivers/usb/typec/ucsi/ucsi_glink.c b/drivers/usb/typec/ucsi/ucsi_glink.c new file mode 100644 index 000000000000..b454a5159896 --- /dev/null +++ b/drivers/usb/typec/ucsi/ucsi_glink.c @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2019-2020, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Linaro Ltd + */ +#include <linux/auxiliary_bus.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/mutex.h> +#include <linux/property.h> +#include <linux/soc/qcom/pdr.h> +#include <linux/soc/qcom/pmic_glink.h> +#include "ucsi.h" + +#define UCSI_BUF_SIZE 48 + +#define MSG_TYPE_REQ_RESP 1 +#define UCSI_BUF_SIZE 48 + +#define UC_NOTIFY_RECEIVER_UCSI 0x0 +#define UC_UCSI_READ_BUF_REQ 0x11 +#define UC_UCSI_WRITE_BUF_REQ 0x12 +#define UC_UCSI_USBC_NOTIFY_IND 0x13 + +struct ucsi_read_buf_req_msg { + struct pmic_glink_hdr hdr; +}; + +struct ucsi_read_buf_resp_msg { + struct pmic_glink_hdr hdr; + u8 buf[UCSI_BUF_SIZE]; + u32 ret_code; +}; + +struct ucsi_write_buf_req_msg { + struct pmic_glink_hdr hdr; + u8 buf[UCSI_BUF_SIZE]; + u32 reserved; +}; + +struct ucsi_write_buf_resp_msg { + struct pmic_glink_hdr hdr; + u32 ret_code; +}; + +struct ucsi_notify_ind_msg { + struct pmic_glink_hdr hdr; + u32 notification; + u32 receiver; + u32 reserved; +}; + +struct pmic_glink_ucsi { + struct device *dev; + + struct pmic_glink_client *client; + + struct ucsi *ucsi; + struct completion read_ack; + struct completion write_ack; + struct completion sync_ack; + bool sync_pending; + struct mutex lock; /* protects concurrent access to PMIC Glink interface */ + + int sync_val; + + struct work_struct notify_work; + struct work_struct register_work; + + u8 read_buf[UCSI_BUF_SIZE]; +}; + +static int pmic_glink_ucsi_read(struct ucsi *__ucsi, unsigned int offset, + void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + struct ucsi_read_buf_req_msg req = {}; + unsigned long left; + int ret; + + req.hdr.owner = PMIC_GLINK_OWNER_USBC; + req.hdr.type = MSG_TYPE_REQ_RESP; + req.hdr.opcode = UC_UCSI_READ_BUF_REQ; + + mutex_lock(&ucsi->lock); + memset(ucsi->read_buf, 0, sizeof(ucsi->read_buf)); + reinit_completion(&ucsi->read_ack); + + ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); + if (ret < 0) { + dev_err(ucsi->dev, "failed to send UCSI read request: %d\n", ret); + goto out_unlock; + } + + left = wait_for_completion_timeout(&ucsi->read_ack, 5 * HZ); + if (!left) { + dev_err(ucsi->dev, "timeout waiting for UCSI read response\n"); + ret = -ETIMEDOUT; + goto out_unlock; + } + + memcpy(val, &ucsi->read_buf[offset], val_len); + ret = 0; + +out_unlock: + mutex_unlock(&ucsi->lock); + + return ret; +} + +static int pmic_glink_ucsi_locked_write(struct pmic_glink_ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct ucsi_write_buf_req_msg req = {}; + unsigned long left; + int ret; + + req.hdr.owner = PMIC_GLINK_OWNER_USBC; + req.hdr.type = MSG_TYPE_REQ_RESP; + req.hdr.opcode = UC_UCSI_WRITE_BUF_REQ; + memcpy(&req.buf[offset], val, val_len); + + reinit_completion(&ucsi->write_ack); + + ret = pmic_glink_send(ucsi->client, &req, sizeof(req)); + if (ret < 0) { + dev_err(ucsi->dev, "failed to send UCSI write request: %d\n", ret); + return ret; + } + + left = wait_for_completion_timeout(&ucsi->write_ack, 5 * HZ); + if (!left) { + dev_err(ucsi->dev, "timeout waiting for UCSI write response\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static int pmic_glink_ucsi_async_write(struct ucsi *__ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + int ret; + + mutex_lock(&ucsi->lock); + ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); + mutex_unlock(&ucsi->lock); + + return ret; +} + +static int pmic_glink_ucsi_sync_write(struct ucsi *__ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct pmic_glink_ucsi *ucsi = ucsi_get_drvdata(__ucsi); + unsigned long left; + int ret; + + /* TOFIX: Downstream forces recipient to CON when UCSI_GET_ALTERNATE_MODES command */ + + mutex_lock(&ucsi->lock); + ucsi->sync_val = 0; + reinit_completion(&ucsi->sync_ack); + ucsi->sync_pending = true; + ret = pmic_glink_ucsi_locked_write(ucsi, offset, val, val_len); + mutex_unlock(&ucsi->lock); + + left = wait_for_completion_timeout(&ucsi->sync_ack, 5 * HZ); + if (!left) { + dev_err(ucsi->dev, "timeout waiting for UCSI sync write response\n"); + ret = -ETIMEDOUT; + } else if (ucsi->sync_val) { + dev_err(ucsi->dev, "sync write returned: %d\n", ucsi->sync_val); + } + + ucsi->sync_pending = false; + + return ret; +} + +static const struct ucsi_operations pmic_glink_ucsi_ops = { + .read = pmic_glink_ucsi_read, + .sync_write = pmic_glink_ucsi_sync_write, + .async_write = pmic_glink_ucsi_async_write +}; + +static void pmic_glink_ucsi_read_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) +{ + const struct ucsi_read_buf_resp_msg *resp = data; + + if (resp->ret_code) + return; + + memcpy(ucsi->read_buf, resp->buf, UCSI_BUF_SIZE); + complete(&ucsi->read_ack); +} + +static void pmic_glink_ucsi_write_ack(struct pmic_glink_ucsi *ucsi, const void *data, int len) +{ + const struct ucsi_write_buf_resp_msg *resp = data; + + if (resp->ret_code) + return; + + ucsi->sync_val = resp->ret_code; + complete(&ucsi->write_ack); +} + +static void pmic_glink_ucsi_notify(struct work_struct *work) +{ + struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, notify_work); + unsigned int con_num; + u32 cci; + int ret; + + ret = pmic_glink_ucsi_read(ucsi->ucsi, UCSI_CCI, &cci, sizeof(cci)); + if (ret) { + dev_err(ucsi->dev, "failed to read CCI on notification\n"); + return; + } + + con_num = UCSI_CCI_CONNECTOR(cci); + if (con_num) + ucsi_connector_change(ucsi->ucsi, con_num); + + if (ucsi->sync_pending && cci & UCSI_CCI_BUSY) { + ucsi->sync_val = -EBUSY; + complete(&ucsi->sync_ack); + } else if (ucsi->sync_pending && + (cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE))) { + complete(&ucsi->sync_ack); + } +} + +static void pmic_glink_ucsi_register(struct work_struct *work) +{ + struct pmic_glink_ucsi *ucsi = container_of(work, struct pmic_glink_ucsi, register_work); + + ucsi_register(ucsi->ucsi); +} + +static void pmic_glink_ucsi_callback(const void *data, size_t len, void *priv) +{ + struct pmic_glink_ucsi *ucsi = priv; + const struct pmic_glink_hdr *hdr = data; + + switch (hdr->opcode) { + case UC_UCSI_READ_BUF_REQ: + pmic_glink_ucsi_read_ack(ucsi, data, len); + break; + case UC_UCSI_WRITE_BUF_REQ: + pmic_glink_ucsi_write_ack(ucsi, data, len); + break; + case UC_UCSI_USBC_NOTIFY_IND: + schedule_work(&ucsi->notify_work); + break; + }; +} + +static void pmic_glink_ucsi_pdr_notify(void *priv, int state) +{ + struct pmic_glink_ucsi *ucsi = priv; + + if (state == SERVREG_SERVICE_STATE_UP) + schedule_work(&ucsi->register_work); + else if (state == SERVREG_SERVICE_STATE_DOWN) + ucsi_unregister(ucsi->ucsi); +} + +static void pmic_glink_ucsi_destroy(void *data) +{ + struct pmic_glink_ucsi *ucsi = data; + + /* Protect to make sure we're not in a middle of a transaction from a glink callback */ + mutex_lock(&ucsi->lock); + ucsi_destroy(ucsi->ucsi); + mutex_unlock(&ucsi->lock); +} + +static int pmic_glink_ucsi_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *id) +{ + struct pmic_glink_ucsi *ucsi; + struct device *dev = &adev->dev; + int ret; + + ucsi = devm_kzalloc(dev, sizeof(*ucsi), GFP_KERNEL); + if (!ucsi) + return -ENOMEM; + + ucsi->dev = dev; + dev_set_drvdata(dev, ucsi); + + INIT_WORK(&ucsi->notify_work, pmic_glink_ucsi_notify); + INIT_WORK(&ucsi->register_work, pmic_glink_ucsi_register); + init_completion(&ucsi->read_ack); + init_completion(&ucsi->write_ack); + init_completion(&ucsi->sync_ack); + mutex_init(&ucsi->lock); + + ucsi->ucsi = ucsi_create(dev, &pmic_glink_ucsi_ops); + if (IS_ERR(ucsi->ucsi)) + return PTR_ERR(ucsi->ucsi); + + /* Make sure we destroy *after* pmic_glink unregister */ + ret = devm_add_action_or_reset(dev, pmic_glink_ucsi_destroy, ucsi); + if (ret) + return ret; + + ucsi_set_drvdata(ucsi->ucsi, ucsi); + + ucsi->client = devm_pmic_glink_register_client(dev, + PMIC_GLINK_OWNER_USBC, + pmic_glink_ucsi_callback, + pmic_glink_ucsi_pdr_notify, + ucsi); + return PTR_ERR_OR_ZERO(ucsi->client); +} + +static void pmic_glink_ucsi_remove(struct auxiliary_device *adev) +{ + struct pmic_glink_ucsi *ucsi = dev_get_drvdata(&adev->dev); + + /* Unregister first to stop having read & writes */ + ucsi_unregister(ucsi->ucsi); +} + +static const struct auxiliary_device_id pmic_glink_ucsi_id_table[] = { + { .name = "pmic_glink.ucsi", }, + {}, +}; +MODULE_DEVICE_TABLE(auxiliary, pmic_glink_ucsi_id_table); + +static struct auxiliary_driver pmic_glink_ucsi_driver = { + .name = "pmic_glink_ucsi", + .probe = pmic_glink_ucsi_probe, + .remove = pmic_glink_ucsi_remove, + .id_table = pmic_glink_ucsi_id_table, +}; + +module_auxiliary_driver(pmic_glink_ucsi_driver); + +MODULE_DESCRIPTION("Qualcomm PMIC GLINK UCSI driver"); +MODULE_LICENSE("GPL"); |