diff options
Diffstat (limited to 'drivers/usb')
98 files changed, 2228 insertions, 2289 deletions
diff --git a/drivers/usb/cdns3/core.c b/drivers/usb/cdns3/core.c index 1109dc5a4c39..c2123ef8d8a3 100644 --- a/drivers/usb/cdns3/core.c +++ b/drivers/usb/cdns3/core.c @@ -166,7 +166,6 @@ static int cdns3_core_init_role(struct cdns3 *cdns) goto err; switch (cdns->dr_mode) { - case USB_DR_MODE_UNKNOWN: case USB_DR_MODE_OTG: ret = cdns3_hw_role_switch(cdns); if (ret) @@ -182,6 +181,9 @@ static int cdns3_core_init_role(struct cdns3 *cdns) if (ret) goto err; break; + default: + ret = -EINVAL; + goto err; } return ret; diff --git a/drivers/usb/cdns3/gadget.c b/drivers/usb/cdns3/gadget.c index 2ca280f4c054..4c1e75509303 100644 --- a/drivers/usb/cdns3/gadget.c +++ b/drivers/usb/cdns3/gadget.c @@ -1145,6 +1145,14 @@ static void cdns3_transfer_completed(struct cdns3_device *priv_dev, request = cdns3_next_request(&priv_ep->pending_req_list); priv_req = to_cdns3_request(request); + trb = priv_ep->trb_pool + priv_ep->dequeue; + + /* Request was dequeued and TRB was changed to TRB_LINK. */ + if (TRB_FIELD_TO_TYPE(trb->control) == TRB_LINK) { + trace_cdns3_complete_trb(priv_ep, trb); + cdns3_move_deq_to_next_trb(priv_req); + } + /* Re-select endpoint. It could be changed by other CPU during * handling usb_gadget_giveback_request. */ @@ -2067,6 +2075,7 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, struct usb_request *req, *req_temp; struct cdns3_request *priv_req; struct cdns3_trb *link_trb; + u8 req_on_hw_ring = 0; unsigned long flags; int ret = 0; @@ -2083,8 +2092,10 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, list_for_each_entry_safe(req, req_temp, &priv_ep->pending_req_list, list) { - if (request == req) + if (request == req) { + req_on_hw_ring = 1; goto found; + } } list_for_each_entry_safe(req, req_temp, &priv_ep->deferred_req_list, @@ -2096,27 +2107,21 @@ int cdns3_gadget_ep_dequeue(struct usb_ep *ep, goto not_found; found: - - if (priv_ep->wa1_trb == priv_req->trb) - cdns3_wa1_restore_cycle_bit(priv_ep); - link_trb = priv_req->trb; - cdns3_move_deq_to_next_trb(priv_req); - cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET); - - /* Update ring */ - request = cdns3_next_request(&priv_ep->deferred_req_list); - if (request) { - priv_req = to_cdns3_request(request); + /* Update ring only if removed request is on pending_req_list list */ + if (req_on_hw_ring) { link_trb->buffer = TRB_BUFFER(priv_ep->trb_pool_dma + (priv_req->start_trb * TRB_SIZE)); link_trb->control = (link_trb->control & TRB_CYCLE) | - TRB_TYPE(TRB_LINK) | TRB_CHAIN | TRB_TOGGLE; - } else { - priv_ep->flags |= EP_UPDATE_EP_TRBADDR; + TRB_TYPE(TRB_LINK) | TRB_CHAIN; + + if (priv_ep->wa1_trb == priv_req->trb) + cdns3_wa1_restore_cycle_bit(priv_ep); } + cdns3_gadget_giveback(priv_ep, priv_req, -ECONNRESET); + not_found: spin_unlock_irqrestore(&priv_dev->lock, flags); return ret; @@ -2324,8 +2329,6 @@ static void cdns3_gadget_config(struct cdns3_device *priv_dev) writel(USB_CONF_CLK2OFFDS | USB_CONF_L1DS, ®s->usb_conf); cdns3_configure_dmult(priv_dev, NULL); - - cdns3_gadget_pullup(&priv_dev->gadget, 1); } /** @@ -2340,9 +2343,35 @@ static int cdns3_gadget_udc_start(struct usb_gadget *gadget, { struct cdns3_device *priv_dev = gadget_to_cdns3_device(gadget); unsigned long flags; + enum usb_device_speed max_speed = driver->max_speed; spin_lock_irqsave(&priv_dev->lock, flags); priv_dev->gadget_driver = driver; + + /* limit speed if necessary */ + max_speed = min(driver->max_speed, gadget->max_speed); + + switch (max_speed) { + case USB_SPEED_FULL: + writel(USB_CONF_SFORCE_FS, &priv_dev->regs->usb_conf); + writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf); + break; + case USB_SPEED_HIGH: + writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf); + break; + case USB_SPEED_SUPER: + break; + default: + dev_err(priv_dev->dev, + "invalid maximum_speed parameter %d\n", + max_speed); + /* fall through */ + case USB_SPEED_UNKNOWN: + /* default to superspeed */ + max_speed = USB_SPEED_SUPER; + break; + } + cdns3_gadget_config(priv_dev); spin_unlock_irqrestore(&priv_dev->lock, flags); return 0; @@ -2376,6 +2405,8 @@ static int cdns3_gadget_udc_stop(struct usb_gadget *gadget) writel(EP_CMD_EPRST, &priv_dev->regs->ep_cmd); readl_poll_timeout_atomic(&priv_dev->regs->ep_cmd, val, !(val & EP_CMD_EPRST), 1, 100); + + priv_ep->flags &= ~EP_CLAIMED; } /* disable interrupt for device */ @@ -2570,12 +2601,7 @@ static int cdns3_gadget_start(struct cdns3 *cdns) /* Check the maximum_speed parameter */ switch (max_speed) { case USB_SPEED_FULL: - writel(USB_CONF_SFORCE_FS, &priv_dev->regs->usb_conf); - writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf); - break; case USB_SPEED_HIGH: - writel(USB_CONF_USB3DIS, &priv_dev->regs->usb_conf); - break; case USB_SPEED_SUPER: break; default: @@ -2708,8 +2734,6 @@ static int cdns3_gadget_suspend(struct cdns3 *cdns, bool do_wakeup) /* disable interrupt for device */ writel(0, &priv_dev->regs->usb_ien); - cdns3_gadget_pullup(&priv_dev->gadget, 0); - return 0; } diff --git a/drivers/usb/cdns3/host-export.h b/drivers/usb/cdns3/host-export.h index b498a170b7e8..ae11810f8826 100644 --- a/drivers/usb/cdns3/host-export.h +++ b/drivers/usb/cdns3/host-export.h @@ -12,7 +12,6 @@ #ifdef CONFIG_USB_CDNS3_HOST int cdns3_host_init(struct cdns3 *cdns); -void cdns3_host_exit(struct cdns3 *cdns); #else diff --git a/drivers/usb/cdns3/host.c b/drivers/usb/cdns3/host.c index 2733a8f71fcd..ad788bf3fe4f 100644 --- a/drivers/usb/cdns3/host.c +++ b/drivers/usb/cdns3/host.c @@ -12,6 +12,7 @@ #include <linux/platform_device.h> #include "core.h" #include "drd.h" +#include "host-export.h" static int __cdns3_host_init(struct cdns3 *cdns) { diff --git a/drivers/usb/chipidea/ci_hdrc_tegra.c b/drivers/usb/chipidea/ci_hdrc_tegra.c index 12025358bb3c..0c9911d44ee5 100644 --- a/drivers/usb/chipidea/ci_hdrc_tegra.c +++ b/drivers/usb/chipidea/ci_hdrc_tegra.c @@ -24,35 +24,23 @@ struct tegra_udc_soc_info { unsigned long flags; }; -static const struct tegra_udc_soc_info tegra20_udc_soc_info = { - .flags = CI_HDRC_REQUIRES_ALIGNED_DMA, -}; - -static const struct tegra_udc_soc_info tegra30_udc_soc_info = { - .flags = CI_HDRC_REQUIRES_ALIGNED_DMA, -}; - -static const struct tegra_udc_soc_info tegra114_udc_soc_info = { - .flags = CI_HDRC_REQUIRES_ALIGNED_DMA, -}; - -static const struct tegra_udc_soc_info tegra124_udc_soc_info = { +static const struct tegra_udc_soc_info tegra_udc_soc_info = { .flags = CI_HDRC_REQUIRES_ALIGNED_DMA, }; static const struct of_device_id tegra_udc_of_match[] = { { .compatible = "nvidia,tegra20-udc", - .data = &tegra20_udc_soc_info, + .data = &tegra_udc_soc_info, }, { .compatible = "nvidia,tegra30-udc", - .data = &tegra30_udc_soc_info, + .data = &tegra_udc_soc_info, }, { .compatible = "nvidia,tegra114-udc", - .data = &tegra114_udc_soc_info, + .data = &tegra_udc_soc_info, }, { .compatible = "nvidia,tegra124-udc", - .data = &tegra124_udc_soc_info, + .data = &tegra_udc_soc_info, }, { /* sentinel */ } diff --git a/drivers/usb/chipidea/debug.c b/drivers/usb/chipidea/debug.c index fcc91a338875..e0376ee646ad 100644 --- a/drivers/usb/chipidea/debug.c +++ b/drivers/usb/chipidea/debug.c @@ -342,7 +342,7 @@ DEFINE_SHOW_ATTRIBUTE(ci_registers); */ void dbg_create_files(struct ci_hdrc *ci) { - ci->debugfs = debugfs_create_dir(dev_name(ci->dev), NULL); + ci->debugfs = debugfs_create_dir(dev_name(ci->dev), usb_debug_root); debugfs_create_file("device", S_IRUGO, ci->debugfs, ci, &ci_device_fops); diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index 8f18e7b6cadf..0b6166a64d72 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1612,7 +1612,7 @@ static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on) } /* Change Data+ pullup status - * this func is used by usb_gadget_connect/disconnet + * this func is used by usb_gadget_connect/disconnect */ static int ci_udc_pullup(struct usb_gadget *_gadget, int is_on) { diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c index fb8bd60c83f4..0d8e3f3804a3 100644 --- a/drivers/usb/class/usblp.c +++ b/drivers/usb/class/usblp.c @@ -445,6 +445,7 @@ static void usblp_cleanup(struct usblp *usblp) kfree(usblp->readbuf); kfree(usblp->device_id_string); kfree(usblp->statusbuf); + usb_put_intf(usblp->intf); kfree(usblp); } @@ -1113,7 +1114,7 @@ static int usblp_probe(struct usb_interface *intf, init_waitqueue_head(&usblp->wwait); init_usb_anchor(&usblp->urbs); usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber; - usblp->intf = intf; + usblp->intf = usb_get_intf(intf); /* Malloc device ID string buffer to the largest expected length, * since we can re-query it on an ioctl and a dynamic string @@ -1198,6 +1199,7 @@ abort: kfree(usblp->readbuf); kfree(usblp->statusbuf); kfree(usblp->device_id_string); + usb_put_intf(usblp->intf); kfree(usblp); abort_ret: return retval; diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 151a74a54386..5f40117e68e7 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -348,6 +348,11 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum, /* Validate the wMaxPacketSize field */ maxp = usb_endpoint_maxp(&endpoint->desc); + if (maxp == 0) { + dev_warn(ddev, "config %d interface %d altsetting %d endpoint 0x%X has wMaxPacketSize 0, skipping\n", + cfgno, inum, asnum, d->bEndpointAddress); + goto skip_to_next_endpoint_or_interface_descriptor; + } /* Find the highest legal maxpacket size for this endpoint */ i = 0; /* additional transactions per microframe */ @@ -800,10 +805,10 @@ int usb_get_configuration(struct usb_device *dev) { struct device *ddev = &dev->dev; int ncfg = dev->descriptor.bNumConfigurations; - int result = -ENOMEM; unsigned int cfgno, length; unsigned char *bigbuffer; struct usb_config_descriptor *desc; + int result; if (ncfg > USB_MAXCONFIG) { dev_warn(ddev, "too many configurations: %d, " @@ -819,16 +824,16 @@ int usb_get_configuration(struct usb_device *dev) length = ncfg * sizeof(struct usb_host_config); dev->config = kzalloc(length, GFP_KERNEL); if (!dev->config) - goto err2; + return -ENOMEM; length = ncfg * sizeof(char *); dev->rawdescriptors = kzalloc(length, GFP_KERNEL); if (!dev->rawdescriptors) - goto err2; + return -ENOMEM; desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); if (!desc) - goto err2; + return -ENOMEM; for (cfgno = 0; cfgno < ncfg; cfgno++) { /* We grab just the first descriptor so we know how long @@ -890,9 +895,7 @@ int usb_get_configuration(struct usb_device *dev) err: kfree(desc); dev->descriptor.bNumConfigurations = cfgno; -err2: - if (result == -ENOMEM) - dev_err(ddev, "out of memory\n"); + return result; } diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index 3f899552f6e3..879d03f5127c 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -764,8 +764,15 @@ static int claimintf(struct usb_dev_state *ps, unsigned int ifnum) intf = usb_ifnum_to_if(dev, ifnum); if (!intf) err = -ENOENT; - else + else { + unsigned int old_suppress; + + /* suppress uevents while claiming interface */ + old_suppress = dev_get_uevent_suppress(&intf->dev); + dev_set_uevent_suppress(&intf->dev, 1); err = usb_driver_claim_interface(&usbfs_driver, intf, ps); + dev_set_uevent_suppress(&intf->dev, old_suppress); + } if (err == 0) set_bit(ifnum, &ps->ifclaimed); return err; @@ -785,7 +792,13 @@ static int releaseintf(struct usb_dev_state *ps, unsigned int ifnum) if (!intf) err = -ENOENT; else if (test_and_clear_bit(ifnum, &ps->ifclaimed)) { + unsigned int old_suppress; + + /* suppress uevents while releasing interface */ + old_suppress = dev_get_uevent_suppress(&intf->dev); + dev_set_uevent_suppress(&intf->dev, 1); usb_driver_release_interface(&usbfs_driver, intf); + dev_set_uevent_suppress(&intf->dev, old_suppress); err = 0; } return err; @@ -1550,10 +1563,10 @@ static int proc_do_submiturb(struct usb_dev_state *ps, struct usbdevfs_urb *uurb uurb->buffer_length = le16_to_cpu(dr->wLength); uurb->buffer += 8; if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) { - is_in = 1; + is_in = true; uurb->endpoint |= USB_DIR_IN; } else { - is_in = 0; + is_in = false; uurb->endpoint &= ~USB_DIR_IN; } if (is_in) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 236313f41f4a..1709895387b9 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -4930,6 +4930,91 @@ hub_power_remaining(struct usb_hub *hub) return remaining; } + +static int descriptors_changed(struct usb_device *udev, + struct usb_device_descriptor *old_device_descriptor, + struct usb_host_bos *old_bos) +{ + int changed = 0; + unsigned index; + unsigned serial_len = 0; + unsigned len; + unsigned old_length; + int length; + char *buf; + + if (memcmp(&udev->descriptor, old_device_descriptor, + sizeof(*old_device_descriptor)) != 0) + return 1; + + if ((old_bos && !udev->bos) || (!old_bos && udev->bos)) + return 1; + if (udev->bos) { + len = le16_to_cpu(udev->bos->desc->wTotalLength); + if (len != le16_to_cpu(old_bos->desc->wTotalLength)) + return 1; + if (memcmp(udev->bos->desc, old_bos->desc, len)) + return 1; + } + + /* Since the idVendor, idProduct, and bcdDevice values in the + * device descriptor haven't changed, we will assume the + * Manufacturer and Product strings haven't changed either. + * But the SerialNumber string could be different (e.g., a + * different flash card of the same brand). + */ + if (udev->serial) + serial_len = strlen(udev->serial) + 1; + + len = serial_len; + for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { + old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); + len = max(len, old_length); + } + + buf = kmalloc(len, GFP_NOIO); + if (!buf) + /* assume the worst */ + return 1; + + for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { + old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); + length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf, + old_length); + if (length != old_length) { + dev_dbg(&udev->dev, "config index %d, error %d\n", + index, length); + changed = 1; + break; + } + if (memcmp(buf, udev->rawdescriptors[index], old_length) + != 0) { + dev_dbg(&udev->dev, "config index %d changed (#%d)\n", + index, + ((struct usb_config_descriptor *) buf)-> + bConfigurationValue); + changed = 1; + break; + } + } + + if (!changed && serial_len) { + length = usb_string(udev, udev->descriptor.iSerialNumber, + buf, serial_len); + if (length + 1 != serial_len) { + dev_dbg(&udev->dev, "serial string error %d\n", + length); + changed = 1; + } else if (memcmp(buf, udev->serial, length) != 0) { + dev_dbg(&udev->dev, "serial string changed\n"); + changed = 1; + } + } + + kfree(buf); + return changed; +} + static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, u16 portchange) { @@ -5167,7 +5252,9 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, { struct usb_port *port_dev = hub->ports[port1 - 1]; struct usb_device *udev = port_dev->child; + struct usb_device_descriptor descriptor; int status = -ENODEV; + int retval; dev_dbg(&port_dev->dev, "status %04x, change %04x, %s\n", portstatus, portchange, portspeed(hub, portstatus)); @@ -5188,7 +5275,30 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1, if ((portstatus & USB_PORT_STAT_CONNECTION) && udev && udev->state != USB_STATE_NOTATTACHED) { if (portstatus & USB_PORT_STAT_ENABLE) { - status = 0; /* Nothing to do */ + /* + * USB-3 connections are initialized automatically by + * the hostcontroller hardware. Therefore check for + * changed device descriptors before resuscitating the + * device. + */ + descriptor = udev->descriptor; + retval = usb_get_device_descriptor(udev, + sizeof(udev->descriptor)); + if (retval < 0) { + dev_dbg(&udev->dev, + "can't read device descriptor %d\n", + retval); + } else { + if (descriptors_changed(udev, &descriptor, + udev->bos)) { + dev_dbg(&udev->dev, + "device descriptor has changed\n"); + /* for disconnect() calls */ + udev->descriptor = descriptor; + } else { + status = 0; /* Nothing to do */ + } + } #ifdef CONFIG_PM } else if (udev->state == USB_STATE_SUSPENDED && udev->persist_enabled) { @@ -5550,90 +5660,6 @@ void usb_hub_cleanup(void) usb_deregister(&hub_driver); } /* usb_hub_cleanup() */ -static int descriptors_changed(struct usb_device *udev, - struct usb_device_descriptor *old_device_descriptor, - struct usb_host_bos *old_bos) -{ - int changed = 0; - unsigned index; - unsigned serial_len = 0; - unsigned len; - unsigned old_length; - int length; - char *buf; - - if (memcmp(&udev->descriptor, old_device_descriptor, - sizeof(*old_device_descriptor)) != 0) - return 1; - - if ((old_bos && !udev->bos) || (!old_bos && udev->bos)) - return 1; - if (udev->bos) { - len = le16_to_cpu(udev->bos->desc->wTotalLength); - if (len != le16_to_cpu(old_bos->desc->wTotalLength)) - return 1; - if (memcmp(udev->bos->desc, old_bos->desc, len)) - return 1; - } - - /* Since the idVendor, idProduct, and bcdDevice values in the - * device descriptor haven't changed, we will assume the - * Manufacturer and Product strings haven't changed either. - * But the SerialNumber string could be different (e.g., a - * different flash card of the same brand). - */ - if (udev->serial) - serial_len = strlen(udev->serial) + 1; - - len = serial_len; - for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { - old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); - len = max(len, old_length); - } - - buf = kmalloc(len, GFP_NOIO); - if (!buf) - /* assume the worst */ - return 1; - - for (index = 0; index < udev->descriptor.bNumConfigurations; index++) { - old_length = le16_to_cpu(udev->config[index].desc.wTotalLength); - length = usb_get_descriptor(udev, USB_DT_CONFIG, index, buf, - old_length); - if (length != old_length) { - dev_dbg(&udev->dev, "config index %d, error %d\n", - index, length); - changed = 1; - break; - } - if (memcmp(buf, udev->rawdescriptors[index], old_length) - != 0) { - dev_dbg(&udev->dev, "config index %d changed (#%d)\n", - index, - ((struct usb_config_descriptor *) buf)-> - bConfigurationValue); - changed = 1; - break; - } - } - - if (!changed && serial_len) { - length = usb_string(udev, udev->descriptor.iSerialNumber, - buf, serial_len); - if (length + 1 != serial_len) { - dev_dbg(&udev->dev, "serial string error %d\n", - length); - changed = 1; - } else if (memcmp(buf, udev->serial, length) != 0) { - dev_dbg(&udev->dev, "serial string changed\n"); - changed = 1; - } - } - - kfree(buf); - return changed; -} - /** * usb_reset_and_verify_device - perform a USB port reset to reinitialize a device * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) @@ -5814,7 +5840,7 @@ re_enumerate_no_bos: /** * usb_reset_device - warn interface drivers and perform a USB port reset - * @udev: device to reset (not in SUSPENDED or NOTATTACHED state) + * @udev: device to reset (not in NOTATTACHED state) * * Warns all drivers bound to registered interfaces (using their pre_reset * method), performs the port reset, and then lets the drivers know that @@ -5842,8 +5868,7 @@ int usb_reset_device(struct usb_device *udev) struct usb_host_config *config = udev->actconfig; struct usb_hub *hub = usb_hub_to_struct_hub(udev->parent); - if (udev->state == USB_STATE_NOTATTACHED || - udev->state == USB_STATE_SUSPENDED) { + if (udev->state == USB_STATE_NOTATTACHED) { dev_dbg(&udev->dev, "device reset not allowed in state %d\n", udev->state); return -EINVAL; diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h index d08d070a0fb6..968e03b89d04 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h @@ -134,7 +134,7 @@ struct dwc2_hsotg_req; * @target_frame: Targeted frame num to setup next ISOC transfer * @frame_overrun: Indicates SOF number overrun in DSTS * - * This is the driver's state for each registered enpoint, allowing it + * This is the driver's state for each registered endpoint, allowing it * to keep track of transactions that need doing. Each endpoint has a * lock to protect the state, to try and avoid using an overall lock * for the host controller as much as possible. diff --git a/drivers/usb/dwc2/debugfs.c b/drivers/usb/dwc2/debugfs.c index 7f62f4cdc265..b8f2790abf91 100644 --- a/drivers/usb/dwc2/debugfs.c +++ b/drivers/usb/dwc2/debugfs.c @@ -770,7 +770,7 @@ int dwc2_debugfs_init(struct dwc2_hsotg *hsotg) int ret; struct dentry *root; - root = debugfs_create_dir(dev_name(hsotg->dev), NULL); + root = debugfs_create_dir(dev_name(hsotg->dev), usb_debug_root); hsotg->debug_root = root; debugfs_create_file("params", 0444, root, hsotg, ¶ms_fops); diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig index 89abc6078703..0d97e6bfaf36 100644 --- a/drivers/usb/dwc3/Kconfig +++ b/drivers/usb/dwc3/Kconfig @@ -102,8 +102,9 @@ config USB_DWC3_MESON_G12A depends on ARCH_MESON || COMPILE_TEST default USB_DWC3 select USB_ROLE_SWITCH + select REGMAP_MMIO help - Support USB2/3 functionality in Amlogic G12A platforms. + Support USB2/3 functionality in Amlogic G12A platforms. Say 'Y' or 'M' if you have one such device. config USB_DWC3_OF_SIMPLE @@ -111,7 +112,7 @@ config USB_DWC3_OF_SIMPLE depends on OF && COMMON_CLK default USB_DWC3 help - Support USB2/3 functionality in simple SoC integrations. + Support USB2/3 functionality in simple SoC integrations. Currently supports Xilinx and Qualcomm DWC USB3 IP. Say 'Y' or 'M' if you have one such device. diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 2991e5056600..f561c6c9e8a9 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -312,8 +312,7 @@ static void dwc3_frame_length_adjustment(struct dwc3 *dwc) reg = dwc3_readl(dwc->regs, DWC3_GFLADJ); dft = reg & DWC3_GFLADJ_30MHZ_MASK; - if (!dev_WARN_ONCE(dwc->dev, dft == dwc->fladj, - "request value same as default, ignoring\n")) { + if (dft != dwc->fladj) { reg &= ~DWC3_GFLADJ_30MHZ_MASK; reg |= DWC3_GFLADJ_30MHZ_SDBND_SEL | dwc->fladj; dwc3_writel(dwc->regs, DWC3_GFLADJ, reg); diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 1c792710348f..4fe8b1e1485c 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -916,7 +916,7 @@ void dwc3_debugfs_init(struct dwc3 *dwc) dwc->regset->nregs = ARRAY_SIZE(dwc3_regs); dwc->regset->base = dwc->regs - DWC3_GLOBALS_REGS_START; - root = debugfs_create_dir(dev_name(dwc->dev), NULL); + root = debugfs_create_dir(dev_name(dwc->dev), usb_debug_root); dwc->root = root; debugfs_create_regset32("regdump", S_IRUGO, root, dwc->regset); diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 5e8e18222f92..023f0357efd7 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -258,7 +258,7 @@ static int dwc3_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) ret = platform_device_add_properties(dwc->dwc3, p); if (ret < 0) - return ret; + goto err; ret = dwc3_pci_quirks(dwc); if (ret) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 86dc1db788a9..a9aba716bf80 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -707,6 +707,12 @@ static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep) dwc3_gadget_giveback(dep, req, -ESHUTDOWN); } + + while (!list_empty(&dep->cancelled_list)) { + req = next_request(&dep->cancelled_list); + + dwc3_gadget_giveback(dep, req, -ESHUTDOWN); + } } /** diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index bb0c744d5b44..3b4f67000315 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -2170,14 +2170,18 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev) usb_ep_dequeue(cdev->gadget->ep0, cdev->os_desc_req); kfree(cdev->os_desc_req->buf); + cdev->os_desc_req->buf = NULL; usb_ep_free_request(cdev->gadget->ep0, cdev->os_desc_req); + cdev->os_desc_req = NULL; } if (cdev->req) { if (cdev->setup_pending) usb_ep_dequeue(cdev->gadget->ep0, cdev->req); kfree(cdev->req->buf); + cdev->req->buf = NULL; usb_ep_free_request(cdev->gadget->ep0, cdev->req); + cdev->req = NULL; } cdev->next_string_id = 0; device_remove_file(&cdev->gadget->dev, &dev_attr_suspended); diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig index 69ff7f8c86f5..38eaa9417b38 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -154,16 +154,16 @@ config USB_ETH_EEM select USB_LIBCOMPOSITE select USB_F_EEM help - CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM - and therefore can be supported by more hardware. Technically ECM and - EEM are designed for different applications. The ECM model extends - the network interface to the target (e.g. a USB cable modem), and the - EEM model is for mobile devices to communicate with hosts using - ethernet over USB. For Linux gadgets, however, the interface with - the host is the same (a usbX device), so the differences are minimal. - - If you say "y" here, the Ethernet gadget driver will use the EEM - protocol rather than ECM. If unsure, say "n". + CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM + and therefore can be supported by more hardware. Technically ECM and + EEM are designed for different applications. The ECM model extends + the network interface to the target (e.g. a USB cable modem), and the + EEM model is for mobile devices to communicate with hosts using + ethernet over USB. For Linux gadgets, however, the interface with + the host is the same (a usbX device), so the differences are minimal. + + If you say "y" here, the Ethernet gadget driver will use the EEM + protocol rather than ECM. If unsure, say "n". config USB_G_NCM tristate "Network Control Model (NCM) support" diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig index c1f93647280c..acaec3ae6ad7 100644 --- a/drivers/usb/gadget/udc/Kconfig +++ b/drivers/usb/gadget/udc/Kconfig @@ -123,7 +123,7 @@ config USB_GR_UDC tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver" depends on HAS_DMA help - Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB + Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB VHDL IP core library. config USB_OMAP diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c index 86ffc8307864..1d0d8952a74b 100644 --- a/drivers/usb/gadget/udc/atmel_usba_udc.c +++ b/drivers/usb/gadget/udc/atmel_usba_udc.c @@ -449,9 +449,11 @@ static void submit_request(struct usba_ep *ep, struct usba_request *req) next_fifo_transaction(ep, req); if (req->last_transaction) { usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY); - usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); + if (ep_is_control(ep)) + usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE); } else { - usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); + if (ep_is_control(ep)) + usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE); usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY); } } diff --git a/drivers/usb/gadget/udc/bcm63xx_udc.c b/drivers/usb/gadget/udc/bcm63xx_udc.c index 7fcf4a8eaeb6..54501814dc3f 100644 --- a/drivers/usb/gadget/udc/bcm63xx_udc.c +++ b/drivers/usb/gadget/udc/bcm63xx_udc.c @@ -2248,7 +2248,7 @@ static void bcm63xx_udc_init_debugfs(struct bcm63xx_udc *udc) if (!IS_ENABLED(CONFIG_USB_GADGET_DEBUG_FS)) return; - root = debugfs_create_dir(udc->gadget.name, NULL); + root = debugfs_create_dir(udc->gadget.name, usb_debug_root); udc->debugfs_root = root; debugfs_create_file("usbd", 0400, root, udc, &bcm63xx_usbd_dbg_fops); diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c index 92af8dc98c3d..51fa614b4079 100644 --- a/drivers/usb/gadget/udc/core.c +++ b/drivers/usb/gadget/udc/core.c @@ -98,6 +98,17 @@ int usb_ep_enable(struct usb_ep *ep) if (ep->enabled) goto out; + /* UDC drivers can't handle endpoints with maxpacket size 0 */ + if (usb_endpoint_maxp(ep->desc) == 0) { + /* + * We should log an error message here, but we can't call + * dev_err() because there's no way to find the gadget + * given only ep. + */ + ret = -EINVAL; + goto out; + } + ret = ep->ops->enable(ep, ep->desc); if (ret) goto out; diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.h b/drivers/usb/gadget/udc/fsl_qe_udc.h index 2c537a904ee7..53ca0ff7c2cb 100644 --- a/drivers/usb/gadget/udc/fsl_qe_udc.h +++ b/drivers/usb/gadget/udc/fsl_qe_udc.h @@ -333,8 +333,8 @@ struct qe_udc { u32 resume_state; /* USB state to resume*/ u32 usb_state; /* USB current state */ u32 usb_next_state; /* USB next state */ - u32 ep0_state; /* Enpoint zero state */ - u32 ep0_dir; /* Enpoint zero direction: can be + u32 ep0_state; /* Endpoint zero state */ + u32 ep0_dir; /* Endpoint zero direction: can be USB_DIR_IN or USB_DIR_OUT*/ u32 usb_sof_count; /* SOF count */ u32 errors; /* USB ERRORs count */ diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c index 334b160333a1..ec6eda426223 100644 --- a/drivers/usb/gadget/udc/fsl_udc_core.c +++ b/drivers/usb/gadget/udc/fsl_udc_core.c @@ -1209,7 +1209,7 @@ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA) } /* Change Data+ pullup status - * this func is used by usb_gadget_connect/disconnet + * this func is used by usb_gadget_connect/disconnect */ static int fsl_pullup(struct usb_gadget *gadget, int is_on) { @@ -2574,7 +2574,7 @@ static int fsl_udc_remove(struct platform_device *pdev) dma_pool_destroy(udc_controller->td_pool); free_irq(udc_controller->irq, udc_controller); iounmap(dr_regs); - if (pdata->operating_mode == FSL_USB2_DR_DEVICE) + if (res && (pdata->operating_mode == FSL_USB2_DR_DEVICE)) release_mem_region(res->start, resource_size(res)); /* free udc --wait for the release() finished */ diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c index 4939343e8176..d14b2bb3f67c 100644 --- a/drivers/usb/gadget/udc/lpc32xx_udc.c +++ b/drivers/usb/gadget/udc/lpc32xx_udc.c @@ -1177,11 +1177,11 @@ static void udc_pop_fifo(struct lpc32xx_udc *udc, u8 *data, u32 bytes) tmp = readl(USBD_RXDATA(udc->udp_baseaddr)); bl = bytes - n; - if (bl > 3) - bl = 3; + if (bl > 4) + bl = 4; for (i = 0; i < bl; i++) - data[n + i] = (u8) ((tmp >> (n * 8)) & 0xFF); + data[n + i] = (u8) ((tmp >> (i * 8)) & 0xFF); } break; diff --git a/drivers/usb/gadget/udc/mv_u3d.h b/drivers/usb/gadget/udc/mv_u3d.h index 982625b7197a..66b84f792f64 100644 --- a/drivers/usb/gadget/udc/mv_u3d.h +++ b/drivers/usb/gadget/udc/mv_u3d.h @@ -138,7 +138,7 @@ struct mv_u3d_op_regs { u32 doorbell; /* doorbell register */ }; -/* control enpoint enable registers */ +/* control endpoint enable registers */ struct epxcr { u32 epxoutcr0; /* ep out control 0 register */ u32 epxoutcr1; /* ep out control 1 register */ diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c index 265dab2bbfac..3344fb8c4181 100644 --- a/drivers/usb/gadget/udc/pch_udc.c +++ b/drivers/usb/gadget/udc/pch_udc.c @@ -1519,7 +1519,6 @@ static void pch_udc_free_dma_chain(struct pch_udc_dev *dev, td = phys_to_virt(addr); addr2 = (dma_addr_t)td->next; dma_pool_free(dev->data_requests, td, addr); - td->next = 0x00; addr = addr2; } req->chain_len = 1; diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index 5f107f277f30..78902d13fc27 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -207,7 +207,7 @@ static void pxa_init_debugfs(struct pxa_udc *udc) { struct dentry *root; - root = debugfs_create_dir(udc->gadget.name, NULL); + root = debugfs_create_dir(udc->gadget.name, usb_debug_root); udc->debugfs_root = root; debugfs_create_file("udcstate", 0400, root, udc, &state_dbg_fops); diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c index 3ba66a13d789..c5c3c14df67a 100644 --- a/drivers/usb/gadget/udc/renesas_usb3.c +++ b/drivers/usb/gadget/udc/renesas_usb3.c @@ -1559,10 +1559,10 @@ static void usb3_set_device_address(struct renesas_usb3 *usb3, u16 addr) static bool usb3_std_req_set_address(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { - if (ctrl->wValue >= 128) + if (le16_to_cpu(ctrl->wValue) >= 128) return true; /* stall */ - usb3_set_device_address(usb3, ctrl->wValue); + usb3_set_device_address(usb3, le16_to_cpu(ctrl->wValue)); usb3_set_p0_con_for_no_data(usb3); return false; @@ -1597,6 +1597,7 @@ static bool usb3_std_req_get_status(struct renesas_usb3 *usb3, struct renesas_usb3_ep *usb3_ep; int num; u16 status = 0; + __le16 tx_data; switch (ctrl->bRequestType & USB_RECIP_MASK) { case USB_RECIP_DEVICE: @@ -1619,10 +1620,10 @@ static bool usb3_std_req_get_status(struct renesas_usb3 *usb3, } if (!stall) { - status = cpu_to_le16(status); + tx_data = cpu_to_le16(status); dev_dbg(usb3_to_dev(usb3), "get_status: req = %p\n", usb_req_to_usb3_req(usb3->ep0_req)); - usb3_pipe0_internal_xfer(usb3, &status, sizeof(status), + usb3_pipe0_internal_xfer(usb3, &tx_data, sizeof(tx_data), usb3_pipe0_get_status_completion); } @@ -1787,7 +1788,7 @@ static bool usb3_std_req_set_sel(struct renesas_usb3 *usb3, static bool usb3_std_req_set_configuration(struct renesas_usb3 *usb3, struct usb_ctrlrequest *ctrl) { - if (ctrl->wValue > 0) + if (le16_to_cpu(ctrl->wValue) > 0) usb3_set_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON); else usb3_clear_bit(usb3, USB_COM_CON_CONF, USB3_USB_COM_CON); @@ -2550,7 +2551,7 @@ static const struct file_operations renesas_usb3_b_device_fops = { static void renesas_usb3_debugfs_init(struct renesas_usb3 *usb3, struct device *dev) { - usb3->dentry = debugfs_create_dir(dev_name(dev), NULL); + usb3->dentry = debugfs_create_dir(dev_name(dev), usb_debug_root); debugfs_create_file("b_device", 0644, usb3->dentry, usb3, &renesas_usb3_b_device_fops); diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c index f82208fbc249..0507a2ca0f55 100644 --- a/drivers/usb/gadget/udc/s3c2410_udc.c +++ b/drivers/usb/gadget/udc/s3c2410_udc.c @@ -1978,7 +1978,8 @@ static int __init udc_init(void) dprintk(DEBUG_NORMAL, "%s\n", gadget_name); - s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL); + s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, + usb_debug_root); retval = platform_driver_register(&udc_driver_24x0); if (retval) diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig index 79b2e79dddd0..d6164ede63d3 100644 --- a/drivers/usb/host/Kconfig +++ b/drivers/usb/host/Kconfig @@ -220,12 +220,12 @@ config USB_EHCI_HCD_ORION Marvell PXA/MMP USB controller" for those. config USB_EHCI_HCD_SPEAR - tristate "Support for ST SPEAr on-chip EHCI USB controller" - depends on USB_EHCI_HCD && PLAT_SPEAR - default y - ---help--- - Enables support for the on-chip EHCI controller on - ST SPEAr chips. + tristate "Support for ST SPEAr on-chip EHCI USB controller" + depends on USB_EHCI_HCD && PLAT_SPEAR + default y + ---help--- + Enables support for the on-chip EHCI controller on + ST SPEAr chips. config USB_EHCI_HCD_STI tristate "Support for ST STiHxxx on-chip EHCI USB controller" @@ -237,12 +237,12 @@ config USB_EHCI_HCD_STI STMicroelectronics consumer electronics SoC's. config USB_EHCI_HCD_AT91 - tristate "Support for Atmel on-chip EHCI USB controller" - depends on USB_EHCI_HCD && ARCH_AT91 - default y - ---help--- - Enables support for the on-chip EHCI controller on - Atmel chips. + tristate "Support for Atmel on-chip EHCI USB controller" + depends on USB_EHCI_HCD && ARCH_AT91 + default y + ---help--- + Enables support for the on-chip EHCI controller on + Atmel chips. config USB_EHCI_TEGRA tristate "NVIDIA Tegra HCD support" @@ -250,8 +250,8 @@ config USB_EHCI_TEGRA select USB_EHCI_ROOT_HUB_TT select USB_TEGRA_PHY help - This driver enables support for the internal USB Host Controllers - found in NVIDIA Tegra SoCs. The controllers are EHCI compliant. + This driver enables support for the internal USB Host Controllers + found in NVIDIA Tegra SoCs. The controllers are EHCI compliant. config USB_EHCI_HCD_PPC_OF bool "EHCI support for PPC USB controller on OF platform bus" @@ -409,12 +409,12 @@ config USB_OHCI_HCD_OMAP1 Enables support for the OHCI controller on OMAP1/2 chips. config USB_OHCI_HCD_SPEAR - tristate "Support for ST SPEAr on-chip OHCI USB controller" - depends on USB_OHCI_HCD && PLAT_SPEAR - default y - ---help--- - Enables support for the on-chip OHCI controller on - ST SPEAr chips. + tristate "Support for ST SPEAr on-chip OHCI USB controller" + depends on USB_OHCI_HCD && PLAT_SPEAR + default y + ---help--- + Enables support for the on-chip OHCI controller on + ST SPEAr chips. config USB_OHCI_HCD_STI tristate "Support for ST STiHxxx on-chip OHCI USB controller" @@ -426,12 +426,12 @@ config USB_OHCI_HCD_STI STMicroelectronics consumer electronics SoC's. config USB_OHCI_HCD_S3C2410 - tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series" - depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX) - default y - ---help--- - Enables support for the on-chip OHCI controller on - S3C24xx/S3C64xx chips. + tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series" + depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX) + default y + ---help--- + Enables support for the on-chip OHCI controller on + S3C24xx/S3C64xx chips. config USB_OHCI_HCD_LPC32XX tristate "Support for LPC on-chip OHCI USB controller" @@ -440,8 +440,8 @@ config USB_OHCI_HCD_LPC32XX depends on USB_ISP1301 default y ---help--- - Enables support for the on-chip OHCI controller on - NXP chips. + Enables support for the on-chip OHCI controller on + NXP chips. config USB_OHCI_HCD_PXA27X tristate "Support for PXA27X/PXA3XX on-chip OHCI USB controller" @@ -456,8 +456,8 @@ config USB_OHCI_HCD_AT91 depends on USB_OHCI_HCD && ARCH_AT91 && OF default y ---help--- - Enables support for the on-chip OHCI controller on - Atmel chips. + Enables support for the on-chip OHCI controller on + Atmel chips. config USB_OHCI_HCD_OMAP3 tristate "OHCI support for OMAP3 and later chips" @@ -716,11 +716,11 @@ config USB_IMX21_HCD tristate "i.MX21 HCD support" depends on ARM && ARCH_MXC help - This driver enables support for the on-chip USB host in the - i.MX21 processor. + This driver enables support for the on-chip USB host in the + i.MX21 processor. - To compile this driver as a module, choose M here: the - module will be called "imx21-hcd". + To compile this driver as a module, choose M here: the + module will be called "imx21-hcd". config USB_HCD_BCMA tristate "BCMA usb host driver" diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c index 2400a826397a..652fa29beb27 100644 --- a/drivers/usb/host/bcma-hcd.c +++ b/drivers/usb/host/bcma-hcd.c @@ -406,9 +406,12 @@ static int bcma_hcd_probe(struct bcma_device *core) return -ENOMEM; usb_dev->core = core; - if (core->dev.of_node) + if (core->dev.of_node) { usb_dev->gpio_desc = devm_gpiod_get(&core->dev, "vcc", GPIOD_OUT_HIGH); + if (IS_ERR(usb_dev->gpio_desc)) + return PTR_ERR(usb_dev->gpio_desc); + } switch (core->id.id) { case BCMA_CORE_USB20_HOST: diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c index 9e0c98d6bdb0..f967adf2d8df 100644 --- a/drivers/usb/host/fotg210-hcd.c +++ b/drivers/usb/host/fotg210-hcd.c @@ -5646,8 +5646,10 @@ static int fotg210_hcd_probe(struct platform_device *pdev) return retval; failed_dis_clk: - if (!IS_ERR(fotg210->pclk)) + if (!IS_ERR(fotg210->pclk)) { clk_disable_unprepare(fotg210->pclk); + clk_put(fotg210->pclk); + } failed_put_hcd: usb_put_hcd(hcd); fail_create_hcd: @@ -5665,8 +5667,10 @@ static int fotg210_hcd_remove(struct platform_device *pdev) struct usb_hcd *hcd = platform_get_drvdata(pdev); struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd); - if (!IS_ERR(fotg210->pclk)) + if (!IS_ERR(fotg210->pclk)) { clk_disable_unprepare(fotg210->pclk); + clk_put(fotg210->pclk); + } usb_remove_hcd(hcd); usb_put_hcd(hcd); diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c index 7fcf1d9dd7f3..02a1344fbd6a 100644 --- a/drivers/usb/host/imx21-dbg.c +++ b/drivers/usb/host/imx21-dbg.c @@ -419,7 +419,7 @@ static void create_debug_files(struct imx21 *imx21) { struct dentry *root; - root = debugfs_create_dir(dev_name(imx21->dev), NULL); + root = debugfs_create_dir(dev_name(imx21->dev), usb_debug_root); imx21->debug_root = root; debugfs_create_file("status", S_IRUGO, root, imx21, &debug_status_fops); diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c index 96f8daa11f25..4a3a2852523f 100644 --- a/drivers/usb/host/isp1362-hcd.c +++ b/drivers/usb/host/isp1362-hcd.c @@ -2627,7 +2627,7 @@ static int isp1362_probe(struct platform_device *pdev) { struct usb_hcd *hcd; struct isp1362_hcd *isp1362_hcd; - struct resource *addr, *data, *irq_res; + struct resource *data, *irq_res; void __iomem *addr_reg; void __iomem *data_reg; int irq; @@ -2651,8 +2651,7 @@ static int isp1362_probe(struct platform_device *pdev) irq = irq_res->start; - addr = platform_get_resource(pdev, IORESOURCE_MEM, 1); - addr_reg = devm_ioremap_resource(&pdev->dev, addr); + addr_reg = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(addr_reg)) return PTR_ERR(addr_reg); diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c index fc35a7993b7b..b635c6a1b1a9 100644 --- a/drivers/usb/host/ohci-at91.c +++ b/drivers/usb/host/ohci-at91.c @@ -115,7 +115,6 @@ static void at91_start_hc(struct platform_device *pdev) static void at91_stop_hc(struct platform_device *pdev) { struct usb_hcd *hcd = platform_get_drvdata(pdev); - struct ohci_regs __iomem *regs = hcd->regs; struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd); dev_dbg(&pdev->dev, "stop\n"); @@ -123,7 +122,7 @@ static void at91_stop_hc(struct platform_device *pdev) /* * Put the USB host controller into reset. */ - writel(0, ®s->control); + usb_hcd_platform_shutdown(pdev); /* * Stop the USB clocks. @@ -628,6 +627,7 @@ ohci_hcd_at91_drv_suspend(struct device *dev) /* flush the writes */ (void) ohci_readl (ohci, &ohci->regs->control); + msleep(1); at91_stop_clock(ohci_at91); } @@ -642,8 +642,8 @@ ohci_hcd_at91_drv_resume(struct device *dev) if (ohci_at91->wakeup) disable_irq_wake(hcd->irq); - - at91_start_clock(ohci_at91); + else + at91_start_clock(ohci_at91); ohci_resume(hcd, false); diff --git a/drivers/usb/host/ohci-nxp.c b/drivers/usb/host/ohci-nxp.c index c561881d0e79..85878e8ad331 100644 --- a/drivers/usb/host/ohci-nxp.c +++ b/drivers/usb/host/ohci-nxp.c @@ -150,7 +150,7 @@ static void ohci_nxp_stop_hc(void) static int ohci_hcd_nxp_probe(struct platform_device *pdev) { - struct usb_hcd *hcd = 0; + struct usb_hcd *hcd = NULL; const struct hc_driver *driver = &ohci_nxp_hc_driver; struct resource *res; int ret = 0, irq; diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c index e67242e437ed..fe09b8626329 100644 --- a/drivers/usb/host/oxu210hp-hcd.c +++ b/drivers/usb/host/oxu210hp-hcd.c @@ -676,12 +676,12 @@ static int oxu_hub_control(struct usb_hcd *hcd, */ /* Low level read/write registers functions */ -static inline u32 oxu_readl(void *base, u32 reg) +static inline u32 oxu_readl(void __iomem *base, u32 reg) { return readl(base + reg); } -static inline void oxu_writel(void *base, u32 reg, u32 val) +static inline void oxu_writel(void __iomem *base, u32 reg, u32 val) { writel(val, base + reg); } @@ -4063,7 +4063,7 @@ static const struct hc_driver oxu_hc_driver = { * Module stuff */ -static void oxu_configuration(struct platform_device *pdev, void *base) +static void oxu_configuration(struct platform_device *pdev, void __iomem *base) { u32 tmp; @@ -4093,7 +4093,7 @@ static void oxu_configuration(struct platform_device *pdev, void *base) oxu_writel(base, OXU_CHIPIRQEN_SET, OXU_USBSPHLPWUI | OXU_USBOTGLPWUI); } -static int oxu_verify_id(struct platform_device *pdev, void *base) +static int oxu_verify_id(struct platform_device *pdev, void __iomem *base) { u32 id; static const char * const bo[] = { @@ -4121,7 +4121,7 @@ static int oxu_verify_id(struct platform_device *pdev, void *base) static const struct hc_driver oxu_hc_driver; static struct usb_hcd *oxu_create(struct platform_device *pdev, unsigned long memstart, unsigned long memlen, - void *base, int irq, int otg) + void __iomem *base, int irq, int otg) { struct device *dev = &pdev->dev; @@ -4158,7 +4158,7 @@ static struct usb_hcd *oxu_create(struct platform_device *pdev, static int oxu_init(struct platform_device *pdev, unsigned long memstart, unsigned long memlen, - void *base, int irq) + void __iomem *base, int irq) { struct oxu_info *info = platform_get_drvdata(pdev); struct usb_hcd *hcd; @@ -4207,7 +4207,7 @@ error_create_otg: static int oxu_drv_probe(struct platform_device *pdev) { struct resource *res; - void *base; + void __iomem *base; unsigned long memstart, memlen; int irq, ret; struct oxu_info *info; diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c index 4efee34f154f..e9209e3e6248 100644 --- a/drivers/usb/host/u132-hcd.c +++ b/drivers/usb/host/u132-hcd.c @@ -71,7 +71,7 @@ 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/overcurren" +MODULE_PARM_DESC(distrust_firmware, "true to distrust firmware power/overcurrent" "t setup"); static DECLARE_WAIT_QUEUE_HEAD(u132_hcd_wait); /* diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 7ba6afc7ef23..76c3f29562d2 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -202,10 +202,10 @@ static void xhci_ring_dump_segment(struct seq_file *s, trb = &seg->trbs[i]; dma = seg->dma + i * sizeof(*trb); seq_printf(s, "%pad: %s\n", &dma, - xhci_decode_trb(trb->generic.field[0], - trb->generic.field[1], - trb->generic.field[2], - trb->generic.field[3])); + xhci_decode_trb(le32_to_cpu(trb->generic.field[0]), + le32_to_cpu(trb->generic.field[1]), + le32_to_cpu(trb->generic.field[2]), + le32_to_cpu(trb->generic.field[3]))); } } @@ -263,10 +263,10 @@ static int xhci_slot_context_show(struct seq_file *s, void *unused) xhci = hcd_to_xhci(bus_to_hcd(dev->udev->bus)); slot_ctx = xhci_get_slot_ctx(xhci, dev->out_ctx); seq_printf(s, "%pad: %s\n", &dev->out_ctx->dma, - xhci_decode_slot_context(slot_ctx->dev_info, - slot_ctx->dev_info2, - slot_ctx->tt_info, - slot_ctx->dev_state)); + xhci_decode_slot_context(le32_to_cpu(slot_ctx->dev_info), + le32_to_cpu(slot_ctx->dev_info2), + le32_to_cpu(slot_ctx->tt_info), + le32_to_cpu(slot_ctx->dev_state))); return 0; } @@ -286,10 +286,10 @@ static int xhci_endpoint_context_show(struct seq_file *s, void *unused) ep_ctx = xhci_get_ep_ctx(xhci, dev->out_ctx, dci); dma = dev->out_ctx->dma + dci * CTX_SIZE(xhci->hcc_params); seq_printf(s, "%pad: %s\n", &dma, - xhci_decode_ep_context(ep_ctx->ep_info, - ep_ctx->ep_info2, - ep_ctx->deq, - ep_ctx->tx_info)); + xhci_decode_ep_context(le32_to_cpu(ep_ctx->ep_info), + le32_to_cpu(ep_ctx->ep_info2), + le64_to_cpu(ep_ctx->deq), + le32_to_cpu(ep_ctx->tx_info))); } return 0; diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index 1e0236e90687..a0025d23b257 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -48,6 +48,7 @@ #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI 0x15e9 #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec #define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI 0x15f0 +#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13 #define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 #define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba @@ -212,7 +213,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) pdev->device == PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_C_4C_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_2C_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI || - pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI)) + pdev->device == PCI_DEVICE_ID_INTEL_TITAN_RIDGE_DD_XHCI || + pdev->device == PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI)) xhci->quirks |= XHCI_DEFAULT_PM_RUNTIME_ALLOW; if (pdev->vendor == PCI_VENDOR_ID_ETRON && diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 85ceb43e3405..6475c3d3b43b 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -280,6 +280,9 @@ void xhci_ring_cmd_db(struct xhci_hcd *xhci) return; xhci_dbg(xhci, "// Ding dong!\n"); + + trace_xhci_ring_host_doorbell(0, DB_VALUE_HOST); + writel(DB_VALUE_HOST, &xhci->dba->doorbell[0]); /* Flush PCI posted writes */ readl(&xhci->dba->doorbell[0]); @@ -401,6 +404,9 @@ void xhci_ring_ep_doorbell(struct xhci_hcd *xhci, if ((ep_state & EP_STOP_CMD_PENDING) || (ep_state & SET_DEQ_PENDING) || (ep_state & EP_HALTED) || (ep_state & EP_CLEARING_TT)) return; + + trace_xhci_ring_ep_doorbell(slot_id, DB_VALUE(ep_index, stream_id)); + writel(DB_VALUE(ep_index, stream_id), db_addr); /* The CPU has better things to do at this point than wait for a * write-posting flush. It'll get there soon enough. @@ -651,10 +657,8 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci, } xhci_urb_free_priv(urb_priv); usb_hcd_unlink_urb_from_ep(hcd, urb); - spin_unlock(&xhci->lock); trace_xhci_urb_giveback(urb); usb_hcd_giveback_urb(hcd, urb, status); - spin_lock(&xhci->lock); } static void xhci_unmap_td_bounce_buffer(struct xhci_hcd *xhci, @@ -2741,6 +2745,42 @@ static int xhci_handle_event(struct xhci_hcd *xhci) } /* + * Update Event Ring Dequeue Pointer: + * - When all events have finished + * - To avoid "Event Ring Full Error" condition + */ +static void xhci_update_erst_dequeue(struct xhci_hcd *xhci, + union xhci_trb *event_ring_deq) +{ + u64 temp_64; + dma_addr_t deq; + + temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); + /* If necessary, update the HW's version of the event ring deq ptr. */ + if (event_ring_deq != xhci->event_ring->dequeue) { + deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, + xhci->event_ring->dequeue); + if (deq == 0) + xhci_warn(xhci, "WARN something wrong with SW event ring dequeue ptr\n"); + /* + * Per 4.9.4, Software writes to the ERDP register shall + * always advance the Event Ring Dequeue Pointer value. + */ + if ((temp_64 & (u64) ~ERST_PTR_MASK) == + ((u64) deq & (u64) ~ERST_PTR_MASK)) + return; + + /* Update HC event ring dequeue pointer */ + temp_64 &= ERST_PTR_MASK; + temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK); + } + + /* Clear the event handler busy flag (RW1C) */ + temp_64 |= ERST_EHB; + xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue); +} + +/* * xHCI spec says we can get an interrupt, and if the HC has an error condition, * we might get bad data out of the event ring. Section 4.10.2.7 has a list of * indicators of an event TRB error, but we check the status *first* to be safe. @@ -2751,9 +2791,9 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) union xhci_trb *event_ring_deq; irqreturn_t ret = IRQ_NONE; unsigned long flags; - dma_addr_t deq; u64 temp_64; u32 status; + int event_loop = 0; spin_lock_irqsave(&xhci->lock, flags); /* Check if the xHC generated the interrupt, or the irq is shared */ @@ -2807,24 +2847,14 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) /* FIXME this should be a delayed service routine * that clears the EHB. */ - while (xhci_handle_event(xhci) > 0) {} - - temp_64 = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue); - /* If necessary, update the HW's version of the event ring deq ptr. */ - if (event_ring_deq != xhci->event_ring->dequeue) { - deq = xhci_trb_virt_to_dma(xhci->event_ring->deq_seg, - xhci->event_ring->dequeue); - if (deq == 0) - xhci_warn(xhci, "WARN something wrong with SW event " - "ring dequeue ptr.\n"); - /* Update HC event ring dequeue pointer */ - temp_64 &= ERST_PTR_MASK; - temp_64 |= ((u64) deq & (u64) ~ERST_PTR_MASK); + while (xhci_handle_event(xhci) > 0) { + if (event_loop++ < TRBS_PER_SEGMENT / 2) + continue; + xhci_update_erst_dequeue(xhci, event_ring_deq); + event_loop = 0; } - /* Clear the event handler busy flag (RW1C); event ring is empty. */ - temp_64 |= ERST_EHB; - xhci_write_64(xhci, temp_64, &xhci->ir_set->erst_dequeue); + xhci_update_erst_dequeue(xhci, event_ring_deq); ret = IRQ_HANDLED; out: @@ -3330,6 +3360,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (xhci_urb_suitable_for_idt(urb)) { memcpy(&send_addr, urb->transfer_buffer, trb_buff_len); + le64_to_cpus(&send_addr); field |= TRB_IDT; } } @@ -3475,6 +3506,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags, if (xhci_urb_suitable_for_idt(urb)) { memcpy(&addr, urb->transfer_buffer, urb->transfer_buffer_length); + le64_to_cpus(&addr); field |= TRB_IDT; } else { addr = (u64) urb->transfer_dma; diff --git a/drivers/usb/host/xhci-tegra.c b/drivers/usb/host/xhci-tegra.c index 2ff7c911fbd0..540b47a99824 100644 --- a/drivers/usb/host/xhci-tegra.c +++ b/drivers/usb/host/xhci-tegra.c @@ -42,19 +42,18 @@ #define XUSB_CFG_CSB_BASE_ADDR 0x800 /* FPCI mailbox registers */ -#define XUSB_CFG_ARU_MBOX_CMD 0x0e4 +/* XUSB_CFG_ARU_MBOX_CMD */ #define MBOX_DEST_FALC BIT(27) #define MBOX_DEST_PME BIT(28) #define MBOX_DEST_SMI BIT(29) #define MBOX_DEST_XHCI BIT(30) #define MBOX_INT_EN BIT(31) -#define XUSB_CFG_ARU_MBOX_DATA_IN 0x0e8 +/* XUSB_CFG_ARU_MBOX_DATA_IN and XUSB_CFG_ARU_MBOX_DATA_OUT */ #define CMD_DATA_SHIFT 0 #define CMD_DATA_MASK 0xffffff #define CMD_TYPE_SHIFT 24 #define CMD_TYPE_MASK 0xff -#define XUSB_CFG_ARU_MBOX_DATA_OUT 0x0ec -#define XUSB_CFG_ARU_MBOX_OWNER 0x0f0 +/* XUSB_CFG_ARU_MBOX_OWNER */ #define MBOX_OWNER_NONE 0 #define MBOX_OWNER_FW 1 #define MBOX_OWNER_SW 2 @@ -146,6 +145,13 @@ struct tegra_xusb_phy_type { unsigned int num; }; +struct tega_xusb_mbox_regs { + u16 cmd; + u16 data_in; + u16 data_out; + u16 owner; +}; + struct tegra_xusb_soc { const char *firmware; const char * const *supply_names; @@ -160,6 +166,8 @@ struct tegra_xusb_soc { } usb2, ulpi, hsic, usb3; } ports; + struct tega_xusb_mbox_regs mbox; + bool scale_ss_clock; bool has_ipfs; }; @@ -395,15 +403,15 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra, * ACK/NAK messages. */ if (!(msg->cmd == MBOX_CMD_ACK || msg->cmd == MBOX_CMD_NAK)) { - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); + value = fpci_readl(tegra, tegra->soc->mbox.owner); if (value != MBOX_OWNER_NONE) { dev_err(tegra->dev, "mailbox is busy\n"); return -EBUSY; } - fpci_writel(tegra, MBOX_OWNER_SW, XUSB_CFG_ARU_MBOX_OWNER); + fpci_writel(tegra, MBOX_OWNER_SW, tegra->soc->mbox.owner); - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); + value = fpci_readl(tegra, tegra->soc->mbox.owner); if (value != MBOX_OWNER_SW) { dev_err(tegra->dev, "failed to acquire mailbox\n"); return -EBUSY; @@ -413,17 +421,17 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra, } value = tegra_xusb_mbox_pack(msg); - fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_DATA_IN); + fpci_writel(tegra, value, tegra->soc->mbox.data_in); - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD); + value = fpci_readl(tegra, tegra->soc->mbox.cmd); value |= MBOX_INT_EN | MBOX_DEST_FALC; - fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD); + fpci_writel(tegra, value, tegra->soc->mbox.cmd); if (wait_for_idle) { unsigned long timeout = jiffies + msecs_to_jiffies(250); while (time_before(jiffies, timeout)) { - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); + value = fpci_readl(tegra, tegra->soc->mbox.owner); if (value == MBOX_OWNER_NONE) break; @@ -431,7 +439,7 @@ static int tegra_xusb_mbox_send(struct tegra_xusb *tegra, } if (time_after(jiffies, timeout)) - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_OWNER); + value = fpci_readl(tegra, tegra->soc->mbox.owner); if (value != MBOX_OWNER_NONE) return -ETIMEDOUT; @@ -598,16 +606,16 @@ static irqreturn_t tegra_xusb_mbox_thread(int irq, void *data) mutex_lock(&tegra->lock); - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_DATA_OUT); + value = fpci_readl(tegra, tegra->soc->mbox.data_out); tegra_xusb_mbox_unpack(&msg, value); - value = fpci_readl(tegra, XUSB_CFG_ARU_MBOX_CMD); + value = fpci_readl(tegra, tegra->soc->mbox.cmd); value &= ~MBOX_DEST_SMI; - fpci_writel(tegra, value, XUSB_CFG_ARU_MBOX_CMD); + fpci_writel(tegra, value, tegra->soc->mbox.cmd); /* clear mailbox owner if no ACK/NAK is required */ if (!tegra_xusb_mbox_cmd_requires_ack(msg.cmd)) - fpci_writel(tegra, MBOX_OWNER_NONE, XUSB_CFG_ARU_MBOX_OWNER); + fpci_writel(tegra, MBOX_OWNER_NONE, tegra->soc->mbox.owner); tegra_xusb_mbox_handle(tegra, &msg); @@ -970,7 +978,7 @@ static int tegra_xusb_powerdomain_init(struct device *dev, static int tegra_xusb_probe(struct platform_device *pdev) { struct tegra_xusb_mbox_msg msg; - struct resource *res, *regs; + struct resource *regs; struct tegra_xusb *tegra; struct xhci_hcd *xhci; unsigned int i, j, k; @@ -992,14 +1000,12 @@ static int tegra_xusb_probe(struct platform_device *pdev) if (IS_ERR(tegra->regs)) return PTR_ERR(tegra->regs); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - tegra->fpci_base = devm_ioremap_resource(&pdev->dev, res); + tegra->fpci_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(tegra->fpci_base)) return PTR_ERR(tegra->fpci_base); if (tegra->soc->has_ipfs) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 2); - tegra->ipfs_base = devm_ioremap_resource(&pdev->dev, res); + tegra->ipfs_base = devm_platform_ioremap_resource(pdev, 2); if (IS_ERR(tegra->ipfs_base)) return PTR_ERR(tegra->ipfs_base); } @@ -1128,8 +1134,9 @@ static int tegra_xusb_probe(struct platform_device *pdev) goto put_powerdomains; } - for (i = 0; i < tegra->soc->num_supplies; i++) - tegra->supplies[i].supply = tegra->soc->supply_names[i]; + regulator_bulk_set_supply_names(tegra->supplies, + tegra->soc->supply_names, + tegra->soc->num_supplies); err = devm_regulator_bulk_get(&pdev->dev, tegra->soc->num_supplies, tegra->supplies); @@ -1375,6 +1382,12 @@ static const struct tegra_xusb_soc tegra124_soc = { }, .scale_ss_clock = true, .has_ipfs = true, + .mbox = { + .cmd = 0xe4, + .data_in = 0xe8, + .data_out = 0xec, + .owner = 0xf0, + }, }; MODULE_FIRMWARE("nvidia/tegra124/xusb.bin"); @@ -1407,6 +1420,12 @@ static const struct tegra_xusb_soc tegra210_soc = { }, .scale_ss_clock = false, .has_ipfs = true, + .mbox = { + .cmd = 0xe4, + .data_in = 0xe8, + .data_out = 0xec, + .owner = 0xf0, + }, }; MODULE_FIRMWARE("nvidia/tegra210/xusb.bin"); @@ -1432,12 +1451,48 @@ static const struct tegra_xusb_soc tegra186_soc = { }, .scale_ss_clock = false, .has_ipfs = false, + .mbox = { + .cmd = 0xe4, + .data_in = 0xe8, + .data_out = 0xec, + .owner = 0xf0, + }, +}; + +static const char * const tegra194_supply_names[] = { +}; + +static const struct tegra_xusb_phy_type tegra194_phy_types[] = { + { .name = "usb3", .num = 4, }, + { .name = "usb2", .num = 4, }, +}; + +static const struct tegra_xusb_soc tegra194_soc = { + .firmware = "nvidia/tegra194/xusb.bin", + .supply_names = tegra194_supply_names, + .num_supplies = ARRAY_SIZE(tegra194_supply_names), + .phy_types = tegra194_phy_types, + .num_types = ARRAY_SIZE(tegra194_phy_types), + .ports = { + .usb3 = { .offset = 0, .count = 4, }, + .usb2 = { .offset = 4, .count = 4, }, + }, + .scale_ss_clock = false, + .has_ipfs = false, + .mbox = { + .cmd = 0x68, + .data_in = 0x6c, + .data_out = 0x70, + .owner = 0x74, + }, }; +MODULE_FIRMWARE("nvidia/tegra194/xusb.bin"); static const struct of_device_id tegra_xusb_of_match[] = { { .compatible = "nvidia,tegra124-xusb", .data = &tegra124_soc }, { .compatible = "nvidia,tegra210-xusb", .data = &tegra210_soc }, { .compatible = "nvidia,tegra186-xusb", .data = &tegra186_soc }, + { .compatible = "nvidia,tegra194-xusb", .data = &tegra194_soc }, { }, }; MODULE_DEVICE_TABLE(of, tegra_xusb_of_match); diff --git a/drivers/usb/host/xhci-trace.h b/drivers/usb/host/xhci-trace.h index 052a269d86f2..56eb867803a6 100644 --- a/drivers/usb/host/xhci-trace.h +++ b/drivers/usb/host/xhci-trace.h @@ -560,6 +560,32 @@ DEFINE_EVENT(xhci_log_portsc, xhci_hub_status_data, TP_ARGS(portnum, portsc) ); +DECLARE_EVENT_CLASS(xhci_log_doorbell, + TP_PROTO(u32 slot, u32 doorbell), + TP_ARGS(slot, doorbell), + TP_STRUCT__entry( + __field(u32, slot) + __field(u32, doorbell) + ), + TP_fast_assign( + __entry->slot = slot; + __entry->doorbell = doorbell; + ), + TP_printk("Ring doorbell for %s", + xhci_decode_doorbell(__entry->slot, __entry->doorbell) + ) +); + +DEFINE_EVENT(xhci_log_doorbell, xhci_ring_ep_doorbell, + TP_PROTO(u32 slot, u32 doorbell), + TP_ARGS(slot, doorbell) +); + +DEFINE_EVENT(xhci_log_doorbell, xhci_ring_host_doorbell, + TP_PROTO(u32 slot, u32 doorbell), + TP_ARGS(slot, doorbell) +); + DECLARE_EVENT_CLASS(xhci_dbc_log_request, TP_PROTO(struct dbc_request *req), TP_ARGS(req), diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 517ec3206f6e..6721d059f58a 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -3071,6 +3071,48 @@ void xhci_cleanup_stalled_ring(struct xhci_hcd *xhci, unsigned int ep_index, } } +static void xhci_endpoint_disable(struct usb_hcd *hcd, + struct usb_host_endpoint *host_ep) +{ + struct xhci_hcd *xhci; + struct xhci_virt_device *vdev; + struct xhci_virt_ep *ep; + struct usb_device *udev; + unsigned long flags; + unsigned int ep_index; + + xhci = hcd_to_xhci(hcd); +rescan: + spin_lock_irqsave(&xhci->lock, flags); + + udev = (struct usb_device *)host_ep->hcpriv; + if (!udev || !udev->slot_id) + goto done; + + vdev = xhci->devs[udev->slot_id]; + if (!vdev) + goto done; + + ep_index = xhci_get_endpoint_index(&host_ep->desc); + ep = &vdev->eps[ep_index]; + if (!ep) + goto done; + + /* wait for hub_tt_work to finish clearing hub TT */ + if (ep->ep_state & EP_CLEARING_TT) { + spin_unlock_irqrestore(&xhci->lock, flags); + schedule_timeout_uninterruptible(1); + goto rescan; + } + + if (ep->ep_state) + xhci_dbg(xhci, "endpoint disable with ep_state 0x%x\n", + ep->ep_state); +done: + host_ep->hcpriv = NULL; + spin_unlock_irqrestore(&xhci->lock, flags); +} + /* * Called after usb core issues a clear halt control message. * The host side of the halt should already be cleared by a reset endpoint @@ -5238,20 +5280,13 @@ static void xhci_clear_tt_buffer_complete(struct usb_hcd *hcd, unsigned int ep_index; unsigned long flags; - /* - * udev might be NULL if tt buffer is cleared during a failed device - * enumeration due to a halted control endpoint. Usb core might - * have allocated a new udev for the next enumeration attempt. - */ - xhci = hcd_to_xhci(hcd); + + spin_lock_irqsave(&xhci->lock, flags); udev = (struct usb_device *)ep->hcpriv; - if (!udev) - return; slot_id = udev->slot_id; ep_index = xhci_get_endpoint_index(&ep->desc); - spin_lock_irqsave(&xhci->lock, flags); xhci->devs[slot_id]->eps[ep_index].ep_state &= ~EP_CLEARING_TT; xhci_ring_doorbell_for_active_rings(xhci, slot_id, ep_index); spin_unlock_irqrestore(&xhci->lock, flags); @@ -5266,7 +5301,8 @@ static const struct hc_driver xhci_hc_driver = { * generic hardware linkage */ .irq = xhci_irq, - .flags = HCD_MEMORY | HCD_DMA | HCD_USB3 | HCD_SHARED, + .flags = HCD_MEMORY | HCD_DMA | HCD_USB3 | HCD_SHARED | + HCD_BH, /* * basic lifecycle operations @@ -5288,6 +5324,7 @@ static const struct hc_driver xhci_hc_driver = { .free_streams = xhci_free_streams, .add_endpoint = xhci_add_endpoint, .drop_endpoint = xhci_drop_endpoint, + .endpoint_disable = xhci_endpoint_disable, .endpoint_reset = xhci_endpoint_reset, .check_bandwidth = xhci_check_bandwidth, .reset_bandwidth = xhci_reset_bandwidth, diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index f9f88626a57a..dc6f62a4b197 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -2580,6 +2580,35 @@ static inline const char *xhci_decode_portsc(u32 portsc) return str; } +static inline const char *xhci_decode_doorbell(u32 slot, u32 doorbell) +{ + static char str[256]; + u8 ep; + u16 stream; + int ret; + + ep = (doorbell & 0xff); + stream = doorbell >> 16; + + if (slot == 0) { + sprintf(str, "Command Ring %d", doorbell); + return str; + } + ret = sprintf(str, "Slot %d ", slot); + if (ep > 0 && ep < 32) + ret = sprintf(str + ret, "ep%d%s", + ep / 2, + ep % 2 ? "in" : "out"); + else if (ep == 0 || ep < 248) + ret = sprintf(str + ret, "Reserved %d", ep); + else + ret = sprintf(str + ret, "Vendor Defined %d", ep); + if (stream) + ret = sprintf(str + ret, " Stream %d", stream); + + return str; +} + static inline const char *xhci_ep_state_string(u8 state) { switch (state) { diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index 7a6b122c833f..360416680e82 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -566,7 +566,6 @@ static int mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback) { struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); - int err = 0; int res; MTS_DEBUG_GOT_HERE(); @@ -613,7 +612,7 @@ mts_scsi_queuecommand_lck(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback } out: - return err; + return 0; } static DEF_SCSI_QCMD(mts_scsi_queuecommand) diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c index 320fc4739835..579a21bd70ad 100644 --- a/drivers/usb/isp1760/isp1760-hcd.c +++ b/drivers/usb/isp1760/isp1760-hcd.c @@ -1032,8 +1032,6 @@ static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd, urb->status = -EOVERFLOW; else if (FROM_DW3_CERR(ptd->dw3)) urb->status = -EPIPE; /* Stall */ - else if (ptd->dw3 & DW3_ERROR_BIT) - urb->status = -EPROTO; /* XactErr */ else urb->status = -EPROTO; /* Unknown */ /* diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig index 9bce583aada3..653aa34aba6c 100644 --- a/drivers/usb/misc/Kconfig +++ b/drivers/usb/misc/Kconfig @@ -181,8 +181,8 @@ config USB_TEST including sample test device firmware and "how to use it". config USB_EHSET_TEST_FIXTURE - tristate "USB EHSET Test Fixture driver" - help + tristate "USB EHSET Test Fixture driver" + help Say Y here if you want to support the special test fixture device used for the USB-IF Embedded Host High-Speed Electrical Test procedure. @@ -237,13 +237,13 @@ config USB_HSIC_USB3503 depends on I2C select REGMAP_I2C help - This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. + This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. config USB_HSIC_USB4604 tristate "USB4604 HSIC to USB20 Driver" depends on I2C help - This option enables support for SMSC USB4604 HSIC to USB 2.0 Driver. + This option enables support for SMSC USB4604 HSIC to USB 2.0 Driver. config USB_LINK_LAYER_TEST tristate "USB Link Layer Test driver" diff --git a/drivers/usb/misc/appledisplay.c b/drivers/usb/misc/appledisplay.c index ac92725458b5..ba1eaabc7796 100644 --- a/drivers/usb/misc/appledisplay.c +++ b/drivers/usb/misc/appledisplay.c @@ -164,7 +164,12 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd) 0, pdata->msgdata, 2, ACD_USB_TIMEOUT); - brightness = pdata->msgdata[1]; + if (retval < 2) { + if (retval >= 0) + retval = -EMSGSIZE; + } else { + brightness = pdata->msgdata[1]; + } mutex_unlock(&pdata->sysfslock); if (retval < 0) @@ -299,6 +304,7 @@ error: if (pdata) { if (pdata->urb) { usb_kill_urb(pdata->urb); + cancel_delayed_work_sync(&pdata->work); if (pdata->urbdata) usb_free_coherent(pdata->udev, ACD_URB_BUFFER_LEN, pdata->urbdata, pdata->urb->transfer_dma); diff --git a/drivers/usb/misc/chaoskey.c b/drivers/usb/misc/chaoskey.c index 34e6cd6f40d3..87067c3d6109 100644 --- a/drivers/usb/misc/chaoskey.c +++ b/drivers/usb/misc/chaoskey.c @@ -384,13 +384,17 @@ static int _chaoskey_fill(struct chaoskey *dev) !dev->reading, (started ? NAK_TIMEOUT : ALEA_FIRST_TIMEOUT) ); - if (result < 0) + if (result < 0) { + usb_kill_urb(dev->urb); goto out; + } - if (result == 0) + if (result == 0) { result = -ETIMEDOUT; - else + usb_kill_urb(dev->urb); + } else { result = dev->valid; + } out: /* Let the device go back to sleep eventually */ usb_autopm_put_interface(dev->interface); @@ -526,7 +530,21 @@ static int chaoskey_suspend(struct usb_interface *interface, static int chaoskey_resume(struct usb_interface *interface) { + struct chaoskey *dev; + struct usb_device *udev = interface_to_usbdev(interface); + usb_dbg(interface, "resume"); + dev = usb_get_intfdata(interface); + + /* + * We may have lost power. + * In that case the device that needs a long time + * for the first requests needs an extended timeout + * again + */ + if (le16_to_cpu(udev->descriptor.idVendor) == ALEA_VENDOR_ID) + dev->reads_started = false; + return 0; } #else diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index cdee3af33ad7..8a3d9c0c8d8b 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -333,7 +333,8 @@ static void ftdi_elan_abandon_completions(struct usb_ftdi *ftdi) *respond->result = -ESHUTDOWN; *respond->value = 0; complete(&respond->wait_completion); - } mutex_unlock(&ftdi->u132_lock); + } + mutex_unlock(&ftdi->u132_lock); } static void ftdi_elan_abandon_targets(struct usb_ftdi *ftdi) @@ -763,7 +764,8 @@ static int ftdi_elan_total_command_size(struct usb_ftdi *ftdi, int command_size) struct u132_command *command = &ftdi->command[COMMAND_MASK & i++]; total_size += 5 + command->follows; - } return total_size; + } + return total_size; } static int ftdi_elan_command_engine(struct usb_ftdi *ftdi) diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 20b0f91a5d9b..4afb5ddfd361 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -56,11 +56,10 @@ static const struct usb_device_id idmouse_table[] = { #define FTIP_SCROLL 0x24 #define ftip_command(dev, command, value, index) \ - usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), command, \ + usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), command, \ USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000) MODULE_DEVICE_TABLE(usb, idmouse_table); -static DEFINE_MUTEX(open_disc_mutex); /* structure to hold all of our device specific stuff */ struct usb_idmouse { @@ -158,8 +157,8 @@ static int idmouse_create_image(struct usb_idmouse *dev) /* loop over a blocking bulk read to get data from the device */ while (bytes_read < IMGSIZE) { - result = usb_bulk_msg (dev->udev, - usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr), + result = usb_bulk_msg(dev->udev, + usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr), dev->bulk_in_buffer + bytes_read, dev->bulk_in_size, &bulk_read, 5000); if (result < 0) { @@ -223,21 +222,17 @@ static int idmouse_open(struct inode *inode, struct file *file) int result; /* get the interface from minor number and driver information */ - interface = usb_find_interface (&idmouse_driver, iminor (inode)); + interface = usb_find_interface(&idmouse_driver, iminor(inode)); if (!interface) return -ENODEV; - mutex_lock(&open_disc_mutex); /* get the device information block from the interface */ dev = usb_get_intfdata(interface); - if (!dev) { - mutex_unlock(&open_disc_mutex); + if (!dev) return -ENODEV; - } /* lock this device */ mutex_lock(&dev->lock); - mutex_unlock(&open_disc_mutex); /* check if already open */ if (dev->open) { @@ -251,7 +246,7 @@ static int idmouse_open(struct inode *inode, struct file *file) result = usb_autopm_get_interface(interface); if (result) goto error; - result = idmouse_create_image (dev); + result = idmouse_create_image(dev); usb_autopm_put_interface(interface); if (result) goto error; @@ -280,27 +275,17 @@ static int idmouse_release(struct inode *inode, struct file *file) if (dev == NULL) return -ENODEV; - mutex_lock(&open_disc_mutex); /* lock our device */ mutex_lock(&dev->lock); - /* are we really open? */ - if (dev->open <= 0) { - mutex_unlock(&dev->lock); - mutex_unlock(&open_disc_mutex); - return -ENODEV; - } - --dev->open; if (!dev->present) { /* the device was unplugged before the file was released */ mutex_unlock(&dev->lock); - mutex_unlock(&open_disc_mutex); idmouse_delete(dev); } else { mutex_unlock(&dev->lock); - mutex_unlock(&open_disc_mutex); } return 0; } @@ -379,7 +364,6 @@ static int idmouse_probe(struct usb_interface *interface, if (result) { /* something prevented us from registering this device */ dev_err(&interface->dev, "Unable to allocate minor number.\n"); - usb_set_intfdata(interface, NULL); idmouse_delete(dev); return result; } @@ -392,19 +376,13 @@ static int idmouse_probe(struct usb_interface *interface, static void idmouse_disconnect(struct usb_interface *interface) { - struct usb_idmouse *dev; - - /* get device structure */ - dev = usb_get_intfdata(interface); + struct usb_idmouse *dev = usb_get_intfdata(interface); /* give back our minor */ usb_deregister_dev(interface, &idmouse_class); - mutex_lock(&open_disc_mutex); - usb_set_intfdata(interface, NULL); /* lock the device */ mutex_lock(&dev->lock); - mutex_unlock(&open_disc_mutex); /* prevent device read, write and ioctl */ dev->present = 0; diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index f3108d85e768..8f86b4ebca89 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -380,10 +380,7 @@ static int ld_usb_release(struct inode *inode, struct file *file) goto exit; } - if (mutex_lock_interruptible(&dev->mutex)) { - retval = -ERESTARTSYS; - goto exit; - } + mutex_lock(&dev->mutex); if (dev->open_count != 1) { retval = -ENODEV; @@ -467,7 +464,7 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, /* wait for data */ spin_lock_irq(&dev->rbsl); - if (dev->ring_head == dev->ring_tail) { + while (dev->ring_head == dev->ring_tail) { dev->interrupt_in_done = 0; spin_unlock_irq(&dev->rbsl); if (file->f_flags & O_NONBLOCK) { @@ -477,15 +474,20 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done); if (retval < 0) goto unlock_exit; - } else { - spin_unlock_irq(&dev->rbsl); + + spin_lock_irq(&dev->rbsl); } + spin_unlock_irq(&dev->rbsl); /* actual_buffer contains actual_length + interrupt_in_buffer */ actual_buffer = (size_t *)(dev->ring_buffer + dev->ring_tail * (sizeof(size_t)+dev->interrupt_in_endpoint_size)); + if (*actual_buffer > dev->interrupt_in_endpoint_size) { + retval = -EIO; + goto unlock_exit; + } bytes_to_read = min(count, *actual_buffer); if (bytes_to_read < *actual_buffer) - dev_warn(&dev->intf->dev, "Read buffer overflow, %zd bytes dropped\n", + dev_warn(&dev->intf->dev, "Read buffer overflow, %zu bytes dropped\n", *actual_buffer-bytes_to_read); /* copy one interrupt_in_buffer from ring_buffer into userspace */ @@ -493,11 +495,11 @@ static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count, retval = -EFAULT; goto unlock_exit; } - dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size; - retval = bytes_to_read; spin_lock_irq(&dev->rbsl); + dev->ring_tail = (dev->ring_tail + 1) % ring_buffer_size; + if (dev->buffer_overflow) { dev->buffer_overflow = 0; spin_unlock_irq(&dev->rbsl); @@ -560,8 +562,9 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, /* write the data into interrupt_out_buffer from userspace */ bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size); if (bytes_to_write < count) - dev_warn(&dev->intf->dev, "Write buffer overflow, %zd bytes dropped\n", count-bytes_to_write); - dev_dbg(&dev->intf->dev, "%s: count = %zd, bytes_to_write = %zd\n", + dev_warn(&dev->intf->dev, "Write buffer overflow, %zu bytes dropped\n", + count - bytes_to_write); + dev_dbg(&dev->intf->dev, "%s: count = %zu, bytes_to_write = %zu\n", __func__, count, bytes_to_write); if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { @@ -578,7 +581,7 @@ static ssize_t ld_usb_write(struct file *file, const char __user *buffer, 1 << 8, 0, dev->interrupt_out_buffer, bytes_to_write, - USB_CTRL_SET_TIMEOUT * HZ); + USB_CTRL_SET_TIMEOUT); if (retval < 0) dev_err(&dev->intf->dev, "Couldn't submit HID_REQ_SET_REPORT %d\n", @@ -693,10 +696,9 @@ static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id * dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n"); dev->interrupt_in_endpoint_size = usb_endpoint_maxp(dev->interrupt_in_endpoint); - dev->ring_buffer = - kmalloc_array(ring_buffer_size, - sizeof(size_t) + dev->interrupt_in_endpoint_size, - GFP_KERNEL); + dev->ring_buffer = kcalloc(ring_buffer_size, + sizeof(size_t) + dev->interrupt_in_endpoint_size, + GFP_KERNEL); if (!dev->ring_buffer) goto error; dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL); diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index 9d4c52a7ebe0..ab4b98b04115 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -157,19 +157,19 @@ MODULE_PARM_DESC(interrupt_out_interval, "Interrupt out interval in ms"); #define LEGO_USB_TOWER_REQUEST_GET_VERSION 0xFD struct tower_reset_reply { - __le16 size; /* little-endian */ + __le16 size; __u8 err_code; __u8 spare; -} __attribute__ ((packed)); +}; struct tower_get_version_reply { - __le16 size; /* little-endian */ + __le16 size; __u8 err_code; __u8 spare; __u8 major; __u8 minor; - __le16 build_no; /* little-endian */ -} __attribute__ ((packed)); + __le16 build_no; +}; /* table of devices that work with this driver */ @@ -178,7 +178,7 @@ static const struct usb_device_id tower_table[] = { { } /* Terminating entry */ }; -MODULE_DEVICE_TABLE (usb, tower_table); +MODULE_DEVICE_TABLE(usb, tower_table); #define LEGO_USB_TOWER_MINOR_BASE 160 @@ -186,13 +186,13 @@ MODULE_DEVICE_TABLE (usb, tower_table); /* Structure to hold all of our device specific stuff */ struct lego_usb_tower { struct mutex lock; /* locks this structure */ - struct usb_device* udev; /* save off the usb device pointer */ + struct usb_device *udev; /* save off the usb device pointer */ unsigned char minor; /* the starting minor number for this device */ int open_count; /* number of times this port has been opened */ unsigned long disconnected:1; - char* read_buffer; + char *read_buffer; size_t read_buffer_length; /* this much came in */ size_t read_packet_length; /* this much will be returned on read */ spinlock_t read_buffer_lock; @@ -202,16 +202,15 @@ struct lego_usb_tower { wait_queue_head_t read_wait; wait_queue_head_t write_wait; - char* interrupt_in_buffer; - struct usb_endpoint_descriptor* interrupt_in_endpoint; - struct urb* interrupt_in_urb; + char *interrupt_in_buffer; + struct usb_endpoint_descriptor *interrupt_in_endpoint; + struct urb *interrupt_in_urb; int interrupt_in_interval; - int interrupt_in_running; int interrupt_in_done; - char* interrupt_out_buffer; - struct usb_endpoint_descriptor* interrupt_out_endpoint; - struct urb* interrupt_out_urb; + char *interrupt_out_buffer; + struct usb_endpoint_descriptor *interrupt_out_endpoint; + struct urb *interrupt_out_urb; int interrupt_out_interval; int interrupt_out_busy; @@ -219,21 +218,20 @@ struct lego_usb_tower { /* local function prototypes */ -static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos); -static ssize_t tower_write (struct file *file, const char __user *buffer, size_t count, loff_t *ppos); -static inline void tower_delete (struct lego_usb_tower *dev); -static int tower_open (struct inode *inode, struct file *file); -static int tower_release (struct inode *inode, struct file *file); -static __poll_t tower_poll (struct file *file, poll_table *wait); -static loff_t tower_llseek (struct file *file, loff_t off, int whence); +static ssize_t tower_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos); +static ssize_t tower_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos); +static inline void tower_delete(struct lego_usb_tower *dev); +static int tower_open(struct inode *inode, struct file *file); +static int tower_release(struct inode *inode, struct file *file); +static __poll_t tower_poll(struct file *file, poll_table *wait); +static loff_t tower_llseek(struct file *file, loff_t off, int whence); -static void tower_abort_transfers (struct lego_usb_tower *dev); -static void tower_check_for_read_packet (struct lego_usb_tower *dev); -static void tower_interrupt_in_callback (struct urb *urb); -static void tower_interrupt_out_callback (struct urb *urb); +static void tower_check_for_read_packet(struct lego_usb_tower *dev); +static void tower_interrupt_in_callback(struct urb *urb); +static void tower_interrupt_out_callback(struct urb *urb); -static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id); -static void tower_disconnect (struct usb_interface *interface); +static int tower_probe(struct usb_interface *interface, const struct usb_device_id *id); +static void tower_disconnect(struct usb_interface *interface); /* file operations needed when we register this driver */ @@ -288,23 +286,23 @@ static inline void lego_usb_tower_debug_data(struct device *dev, /** * tower_delete */ -static inline void tower_delete (struct lego_usb_tower *dev) +static inline void tower_delete(struct lego_usb_tower *dev) { /* free data structures */ usb_free_urb(dev->interrupt_in_urb); usb_free_urb(dev->interrupt_out_urb); - kfree (dev->read_buffer); - kfree (dev->interrupt_in_buffer); - kfree (dev->interrupt_out_buffer); + kfree(dev->read_buffer); + kfree(dev->interrupt_in_buffer); + kfree(dev->interrupt_out_buffer); usb_put_dev(dev->udev); - kfree (dev); + kfree(dev); } /** * tower_open */ -static int tower_open (struct inode *inode, struct file *file) +static int tower_open(struct inode *inode, struct file *file) { struct lego_usb_tower *dev = NULL; int subminor; @@ -314,7 +312,6 @@ static int tower_open (struct inode *inode, struct file *file) int result; reset_reply = kmalloc(sizeof(*reset_reply), GFP_KERNEL); - if (!reset_reply) { retval = -ENOMEM; goto exit; @@ -323,8 +320,7 @@ static int tower_open (struct inode *inode, struct file *file) nonseekable_open(inode, file); subminor = iminor(inode); - interface = usb_find_interface (&tower_driver, subminor); - + interface = usb_find_interface(&tower_driver, subminor); if (!interface) { pr_err("error, can't find device for minor %d\n", subminor); retval = -ENODEV; @@ -351,15 +347,15 @@ static int tower_open (struct inode *inode, struct file *file) } /* reset the tower */ - result = usb_control_msg (dev->udev, - usb_rcvctrlpipe(dev->udev, 0), - LEGO_USB_TOWER_REQUEST_RESET, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - reset_reply, - sizeof(*reset_reply), - 1000); + result = usb_control_msg(dev->udev, + usb_rcvctrlpipe(dev->udev, 0), + LEGO_USB_TOWER_REQUEST_RESET, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + reset_reply, + sizeof(*reset_reply), + 1000); if (result < 0) { dev_err(&dev->udev->dev, "LEGO USB Tower reset control request failed\n"); @@ -370,24 +366,22 @@ static int tower_open (struct inode *inode, struct file *file) /* initialize in direction */ dev->read_buffer_length = 0; dev->read_packet_length = 0; - usb_fill_int_urb (dev->interrupt_in_urb, - dev->udev, - usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress), - dev->interrupt_in_buffer, - usb_endpoint_maxp(dev->interrupt_in_endpoint), - tower_interrupt_in_callback, - dev, - dev->interrupt_in_interval); - - dev->interrupt_in_running = 1; + usb_fill_int_urb(dev->interrupt_in_urb, + dev->udev, + usb_rcvintpipe(dev->udev, dev->interrupt_in_endpoint->bEndpointAddress), + dev->interrupt_in_buffer, + usb_endpoint_maxp(dev->interrupt_in_endpoint), + tower_interrupt_in_callback, + dev, + dev->interrupt_in_interval); + dev->interrupt_in_done = 0; mb(); - retval = usb_submit_urb (dev->interrupt_in_urb, GFP_KERNEL); + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL); if (retval) { dev_err(&dev->udev->dev, "Couldn't submit interrupt_in_urb %d\n", retval); - dev->interrupt_in_running = 0; goto unlock_exit; } @@ -407,73 +401,45 @@ exit: /** * tower_release */ -static int tower_release (struct inode *inode, struct file *file) +static int tower_release(struct inode *inode, struct file *file) { struct lego_usb_tower *dev; int retval = 0; dev = file->private_data; - if (dev == NULL) { retval = -ENODEV; goto exit; } - if (mutex_lock_interruptible(&dev->lock)) { - retval = -ERESTARTSYS; - goto exit; - } - - if (dev->open_count != 1) { - dev_dbg(&dev->udev->dev, "%s: device not opened exactly once\n", - __func__); - retval = -ENODEV; - goto unlock_exit; - } + mutex_lock(&dev->lock); if (dev->disconnected) { /* the device was unplugged before the file was released */ /* unlock here as tower_delete frees dev */ mutex_unlock(&dev->lock); - tower_delete (dev); + tower_delete(dev); goto exit; } /* wait until write transfer is finished */ if (dev->interrupt_out_busy) { - wait_event_interruptible_timeout (dev->write_wait, !dev->interrupt_out_busy, 2 * HZ); + wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, + 2 * HZ); } - tower_abort_transfers (dev); + + /* shutdown transfers */ + usb_kill_urb(dev->interrupt_in_urb); + usb_kill_urb(dev->interrupt_out_urb); + dev->open_count = 0; -unlock_exit: mutex_unlock(&dev->lock); exit: return retval; } - -/** - * tower_abort_transfers - * aborts transfers and frees associated data structures - */ -static void tower_abort_transfers (struct lego_usb_tower *dev) -{ - if (dev == NULL) - return; - - /* shutdown transfer */ - if (dev->interrupt_in_running) { - dev->interrupt_in_running = 0; - mb(); - usb_kill_urb(dev->interrupt_in_urb); - } - if (dev->interrupt_out_busy) - usb_kill_urb(dev->interrupt_out_urb); -} - - /** * tower_check_for_read_packet * @@ -482,23 +448,23 @@ static void tower_abort_transfers (struct lego_usb_tower *dev) * until it has been there unchanged for at least * dev->packet_timeout_jiffies, or until the buffer is full. */ -static void tower_check_for_read_packet (struct lego_usb_tower *dev) +static void tower_check_for_read_packet(struct lego_usb_tower *dev) { - spin_lock_irq (&dev->read_buffer_lock); + spin_lock_irq(&dev->read_buffer_lock); if (!packet_timeout || time_after(jiffies, dev->read_last_arrival + dev->packet_timeout_jiffies) || dev->read_buffer_length == read_buffer_size) { dev->read_packet_length = dev->read_buffer_length; } dev->interrupt_in_done = 0; - spin_unlock_irq (&dev->read_buffer_lock); + spin_unlock_irq(&dev->read_buffer_lock); } /** * tower_poll */ -static __poll_t tower_poll (struct file *file, poll_table *wait) +static __poll_t tower_poll(struct file *file, poll_table *wait) { struct lego_usb_tower *dev; __poll_t mask = 0; @@ -512,12 +478,10 @@ static __poll_t tower_poll (struct file *file, poll_table *wait) poll_wait(file, &dev->write_wait, wait); tower_check_for_read_packet(dev); - if (dev->read_packet_length > 0) { + if (dev->read_packet_length > 0) mask |= EPOLLIN | EPOLLRDNORM; - } - if (!dev->interrupt_out_busy) { + if (!dev->interrupt_out_busy) mask |= EPOLLOUT | EPOLLWRNORM; - } return mask; } @@ -526,7 +490,7 @@ static __poll_t tower_poll (struct file *file, poll_table *wait) /** * tower_llseek */ -static loff_t tower_llseek (struct file *file, loff_t off, int whence) +static loff_t tower_llseek(struct file *file, loff_t off, int whence) { return -ESPIPE; /* unseekable */ } @@ -535,7 +499,7 @@ static loff_t tower_llseek (struct file *file, loff_t off, int whence) /** * tower_read */ -static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos) +static ssize_t tower_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos) { struct lego_usb_tower *dev; size_t bytes_to_read; @@ -554,7 +518,6 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, /* verify that the device wasn't unplugged */ if (dev->disconnected) { retval = -ENODEV; - pr_err("No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -564,21 +527,19 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, goto unlock_exit; } - if (read_timeout) { + if (read_timeout) timeout = jiffies + msecs_to_jiffies(read_timeout); - } /* wait for data */ - tower_check_for_read_packet (dev); + tower_check_for_read_packet(dev); while (dev->read_packet_length == 0) { if (file->f_flags & O_NONBLOCK) { retval = -EAGAIN; goto unlock_exit; } retval = wait_event_interruptible_timeout(dev->read_wait, dev->interrupt_in_done, dev->packet_timeout_jiffies); - if (retval < 0) { + if (retval < 0) goto unlock_exit; - } /* reset read timeout during read or write activity */ if (read_timeout @@ -586,28 +547,27 @@ static ssize_t tower_read (struct file *file, char __user *buffer, size_t count, timeout = jiffies + msecs_to_jiffies(read_timeout); } /* check for read timeout */ - if (read_timeout && time_after (jiffies, timeout)) { + if (read_timeout && time_after(jiffies, timeout)) { retval = -ETIMEDOUT; goto unlock_exit; } - tower_check_for_read_packet (dev); + tower_check_for_read_packet(dev); } /* copy the data from read_buffer into userspace */ bytes_to_read = min(count, dev->read_packet_length); - if (copy_to_user (buffer, dev->read_buffer, bytes_to_read)) { + if (copy_to_user(buffer, dev->read_buffer, bytes_to_read)) { retval = -EFAULT; goto unlock_exit; } - spin_lock_irq (&dev->read_buffer_lock); + spin_lock_irq(&dev->read_buffer_lock); dev->read_buffer_length -= bytes_to_read; dev->read_packet_length -= bytes_to_read; - for (i=0; i<dev->read_buffer_length; i++) { + for (i = 0; i < dev->read_buffer_length; i++) dev->read_buffer[i] = dev->read_buffer[i+bytes_to_read]; - } - spin_unlock_irq (&dev->read_buffer_lock); + spin_unlock_irq(&dev->read_buffer_lock); retval = bytes_to_read; @@ -623,7 +583,7 @@ exit: /** * tower_write */ -static ssize_t tower_write (struct file *file, const char __user *buffer, size_t count, loff_t *ppos) +static ssize_t tower_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct lego_usb_tower *dev; size_t bytes_to_write; @@ -640,7 +600,6 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t /* verify that the device wasn't unplugged */ if (dev->disconnected) { retval = -ENODEV; - pr_err("No device or device unplugged %d\n", retval); goto unlock_exit; } @@ -656,10 +615,10 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t retval = -EAGAIN; goto unlock_exit; } - retval = wait_event_interruptible (dev->write_wait, !dev->interrupt_out_busy); - if (retval) { + retval = wait_event_interruptible(dev->write_wait, + !dev->interrupt_out_busy); + if (retval) goto unlock_exit; - } } /* write the data into interrupt_out_buffer from userspace */ @@ -667,7 +626,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t dev_dbg(&dev->udev->dev, "%s: count = %zd, bytes_to_write = %zd\n", __func__, count, bytes_to_write); - if (copy_from_user (dev->interrupt_out_buffer, buffer, bytes_to_write)) { + if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) { retval = -EFAULT; goto unlock_exit; } @@ -685,7 +644,7 @@ static ssize_t tower_write (struct file *file, const char __user *buffer, size_t dev->interrupt_out_busy = 1; wmb(); - retval = usb_submit_urb (dev->interrupt_out_urb, GFP_KERNEL); + retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL); if (retval) { dev->interrupt_out_busy = 0; dev_err(&dev->udev->dev, @@ -706,7 +665,7 @@ exit: /** * tower_interrupt_in_callback */ -static void tower_interrupt_in_callback (struct urb *urb) +static void tower_interrupt_in_callback(struct urb *urb) { struct lego_usb_tower *dev = urb->context; int status = urb->status; @@ -732,9 +691,9 @@ static void tower_interrupt_in_callback (struct urb *urb) if (urb->actual_length > 0) { spin_lock_irqsave(&dev->read_buffer_lock, flags); if (dev->read_buffer_length + urb->actual_length < read_buffer_size) { - memcpy (dev->read_buffer + dev->read_buffer_length, - dev->interrupt_in_buffer, - urb->actual_length); + memcpy(dev->read_buffer + dev->read_buffer_length, + dev->interrupt_in_buffer, + urb->actual_length); dev->read_buffer_length += urb->actual_length; dev->read_last_arrival = jiffies; dev_dbg(&dev->udev->dev, "%s: received %d bytes\n", @@ -747,25 +706,21 @@ static void tower_interrupt_in_callback (struct urb *urb) } resubmit: - /* resubmit if we're still running */ - if (dev->interrupt_in_running) { - retval = usb_submit_urb (dev->interrupt_in_urb, GFP_ATOMIC); - if (retval) - dev_err(&dev->udev->dev, - "%s: usb_submit_urb failed (%d)\n", - __func__, retval); + retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC); + if (retval) { + dev_err(&dev->udev->dev, "%s: usb_submit_urb failed (%d)\n", + __func__, retval); } - exit: dev->interrupt_in_done = 1; - wake_up_interruptible (&dev->read_wait); + wake_up_interruptible(&dev->read_wait); } /** * tower_interrupt_out_callback */ -static void tower_interrupt_out_callback (struct urb *urb) +static void tower_interrupt_out_callback(struct urb *urb) { struct lego_usb_tower *dev = urb->context; int status = urb->status; @@ -793,48 +748,27 @@ static void tower_interrupt_out_callback (struct urb *urb) * Called by the usb core when a new device is connected that it thinks * this driver might be interested in. */ -static int tower_probe (struct usb_interface *interface, const struct usb_device_id *id) +static int tower_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct device *idev = &interface->dev; struct usb_device *udev = interface_to_usbdev(interface); - struct lego_usb_tower *dev = NULL; + struct lego_usb_tower *dev; struct tower_get_version_reply *get_version_reply = NULL; int retval = -ENOMEM; int result; /* allocate memory for our device state and initialize it */ - - dev = kmalloc (sizeof(struct lego_usb_tower), GFP_KERNEL); - + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) goto exit; mutex_init(&dev->lock); - dev->udev = usb_get_dev(udev); - dev->open_count = 0; - dev->disconnected = 0; - - dev->read_buffer = NULL; - dev->read_buffer_length = 0; - dev->read_packet_length = 0; - spin_lock_init (&dev->read_buffer_lock); + spin_lock_init(&dev->read_buffer_lock); dev->packet_timeout_jiffies = msecs_to_jiffies(packet_timeout); dev->read_last_arrival = jiffies; - - init_waitqueue_head (&dev->read_wait); - init_waitqueue_head (&dev->write_wait); - - dev->interrupt_in_buffer = NULL; - dev->interrupt_in_endpoint = NULL; - dev->interrupt_in_urb = NULL; - dev->interrupt_in_running = 0; - dev->interrupt_in_done = 0; - - dev->interrupt_out_buffer = NULL; - dev->interrupt_out_endpoint = NULL; - dev->interrupt_out_urb = NULL; - dev->interrupt_out_busy = 0; + init_waitqueue_head(&dev->read_wait); + init_waitqueue_head(&dev->write_wait); result = usb_find_common_endpoints_reverse(interface->cur_altsetting, NULL, NULL, @@ -846,16 +780,16 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device goto error; } - dev->read_buffer = kmalloc (read_buffer_size, GFP_KERNEL); + dev->read_buffer = kmalloc(read_buffer_size, GFP_KERNEL); if (!dev->read_buffer) goto error; - dev->interrupt_in_buffer = kmalloc (usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL); + dev->interrupt_in_buffer = kmalloc(usb_endpoint_maxp(dev->interrupt_in_endpoint), GFP_KERNEL); if (!dev->interrupt_in_buffer) goto error; dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL); if (!dev->interrupt_in_urb) goto error; - dev->interrupt_out_buffer = kmalloc (write_buffer_size, GFP_KERNEL); + dev->interrupt_out_buffer = kmalloc(write_buffer_size, GFP_KERNEL); if (!dev->interrupt_out_buffer) goto error; dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL); @@ -865,23 +799,22 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device dev->interrupt_out_interval = interrupt_out_interval ? interrupt_out_interval : dev->interrupt_out_endpoint->bInterval; get_version_reply = kmalloc(sizeof(*get_version_reply), GFP_KERNEL); - if (!get_version_reply) { retval = -ENOMEM; goto error; } /* get the firmware version and log it */ - result = usb_control_msg (udev, - usb_rcvctrlpipe(udev, 0), - LEGO_USB_TOWER_REQUEST_GET_VERSION, - USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, - 0, - 0, - get_version_reply, - sizeof(*get_version_reply), - 1000); - if (result < sizeof(*get_version_reply)) { + result = usb_control_msg(udev, + usb_rcvctrlpipe(udev, 0), + LEGO_USB_TOWER_REQUEST_GET_VERSION, + USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE, + 0, + 0, + get_version_reply, + sizeof(*get_version_reply), + 1000); + if (result != sizeof(*get_version_reply)) { if (result >= 0) result = -EIO; dev_err(idev, "get version request failed: %d\n", result); @@ -895,10 +828,9 @@ static int tower_probe (struct usb_interface *interface, const struct usb_device le16_to_cpu(get_version_reply->build_no)); /* we can register the device now, as it is ready */ - usb_set_intfdata (interface, dev); - - retval = usb_register_dev (interface, &tower_class); + usb_set_intfdata(interface, dev); + retval = usb_register_dev(interface, &tower_class); if (retval) { /* something prevented us from registering this driver */ dev_err(idev, "Not able to get a minor for this device.\n"); @@ -927,17 +859,17 @@ error: * * Called by the usb core when the device is removed from the system. */ -static void tower_disconnect (struct usb_interface *interface) +static void tower_disconnect(struct usb_interface *interface) { struct lego_usb_tower *dev; int minor; - dev = usb_get_intfdata (interface); + dev = usb_get_intfdata(interface); minor = dev->minor; /* give back our minor and prevent further open() */ - usb_deregister_dev (interface, &tower_class); + usb_deregister_dev(interface, &tower_class); /* stop I/O */ usb_poison_urb(dev->interrupt_in_urb); @@ -948,7 +880,7 @@ static void tower_disconnect (struct usb_interface *interface) /* if the device is not opened, then we clean up right now */ if (!dev->open_count) { mutex_unlock(&dev->lock); - tower_delete (dev); + tower_delete(dev); } else { dev->disconnected = 1; /* wake up pollers */ @@ -965,6 +897,4 @@ module_usb_driver(tower_driver); MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif diff --git a/drivers/usb/misc/sisusbvga/Kconfig b/drivers/usb/misc/sisusbvga/Kconfig index 9b632ab24f03..c16121276a21 100644 --- a/drivers/usb/misc/sisusbvga/Kconfig +++ b/drivers/usb/misc/sisusbvga/Kconfig @@ -4,7 +4,7 @@ config USB_SISUSBVGA tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)" depends on (USB_MUSB_HDRC || USB_EHCI_HCD) select FONT_SUPPORT if USB_SISUSBVGA_CON - ---help--- + ---help--- Say Y here if you intend to attach a USB2VGA dongle based on a Net2280 and a SiS315 chip. diff --git a/drivers/usb/misc/usb251xb.c b/drivers/usb/misc/usb251xb.c index 6ca9111d150a..10c9e7f6273e 100644 --- a/drivers/usb/misc/usb251xb.c +++ b/drivers/usb/misc/usb251xb.c @@ -17,6 +17,7 @@ #include <linux/module.h> #include <linux/nls.h> #include <linux/of_device.h> +#include <linux/regulator/consumer.h> #include <linux/slab.h> /* Internal Register Set Addresses & Default Values acc. to DS00001692C */ @@ -26,10 +27,6 @@ #define USB251XB_ADDR_PRODUCT_ID_LSB 0x02 #define USB251XB_ADDR_PRODUCT_ID_MSB 0x03 -#define USB251XB_DEF_PRODUCT_ID_12 0x2512 /* USB2512B/12Bi */ -#define USB251XB_DEF_PRODUCT_ID_13 0x2513 /* USB2513B/13Bi */ -#define USB251XB_DEF_PRODUCT_ID_14 0x2514 /* USB2514B/14Bi */ -#define USB251XB_DEF_PRODUCT_ID_17 0x2517 /* USB2517/17i */ #define USB251XB_ADDR_DEVICE_ID_LSB 0x04 #define USB251XB_ADDR_DEVICE_ID_MSB 0x05 @@ -74,7 +71,6 @@ #define USB251XB_ADDR_PRODUCT_STRING_LEN 0x14 #define USB251XB_ADDR_PRODUCT_STRING 0x54 -#define USB251XB_DEF_PRODUCT_STRING "USB251xB/xBi/7i" #define USB251XB_ADDR_SERIAL_STRING_LEN 0x15 #define USB251XB_ADDR_SERIAL_STRING 0x92 @@ -116,6 +112,7 @@ struct usb251xb { struct device *dev; struct i2c_client *i2c; + struct regulator *vdd; u8 skip_config; struct gpio_desc *gpio_reset; u16 vendor_id; @@ -159,6 +156,14 @@ struct usb251xb_data { char product_str[USB251XB_STRING_BUFSIZE / 2]; /* ASCII string */ }; +static const struct usb251xb_data usb2422_data = { + .product_id = 0x2422, + .port_cnt = 2, + .led_support = false, + .bat_support = true, + .product_str = "USB2422", +}; + static const struct usb251xb_data usb2512b_data = { .product_id = 0x2512, .port_cnt = 2, @@ -261,20 +266,19 @@ static int usb251x_check_gpio_chip(struct usb251xb *hub) } #endif -static void usb251xb_reset(struct usb251xb *hub, int state) +static void usb251xb_reset(struct usb251xb *hub) { if (!hub->gpio_reset) return; i2c_lock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); - gpiod_set_value_cansleep(hub->gpio_reset, state); + gpiod_set_value_cansleep(hub->gpio_reset, 1); + usleep_range(1, 10); /* >=1us RESET_N asserted */ + gpiod_set_value_cansleep(hub->gpio_reset, 0); /* wait for hub recovery/stabilization */ - if (!state) - usleep_range(500, 750); /* >=500us at power on */ - else - usleep_range(1, 10); /* >=1us at power down */ + usleep_range(500, 750); /* >=500us after RESET_N deasserted */ i2c_unlock_bus(hub->i2c->adapter, I2C_LOCK_SEGMENT); } @@ -292,7 +296,7 @@ static int usb251xb_connect(struct usb251xb *hub) i2c_wb[0] = 0x01; i2c_wb[1] = USB251XB_STATUS_COMMAND_ATTACH; - usb251xb_reset(hub, 0); + usb251xb_reset(hub); err = i2c_smbus_write_i2c_block_data(hub->i2c, USB251XB_ADDR_STATUS_COMMAND, 2, i2c_wb); @@ -342,7 +346,7 @@ static int usb251xb_connect(struct usb251xb *hub) i2c_wb[USB251XB_ADDR_PORT_MAP_7] = hub->port_map7; i2c_wb[USB251XB_ADDR_STATUS_COMMAND] = USB251XB_STATUS_COMMAND_ATTACH; - usb251xb_reset(hub, 0); + usb251xb_reset(hub); /* write registers */ for (i = 0; i < (USB251XB_I2C_REG_SZ / USB251XB_I2C_WRITE_SZ); i++) { @@ -420,6 +424,10 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, return err; } + hub->vdd = devm_regulator_get(dev, "vdd"); + if (IS_ERR(hub->vdd)) + return PTR_ERR(hub->vdd); + if (of_property_read_u16_array(np, "vendor-id", &hub->vendor_id, 1)) hub->vendor_id = USB251XB_DEF_VENDOR_ID; @@ -593,6 +601,9 @@ static int usb251xb_get_ofdata(struct usb251xb *hub, static const struct of_device_id usb251xb_of_match[] = { { + .compatible = "microchip,usb2422", + .data = &usb2422_data, + }, { .compatible = "microchip,usb2512b", .data = &usb2512b_data, }, { @@ -665,6 +676,10 @@ static int usb251xb_probe(struct usb251xb *hub) if (err) return err; + err = regulator_enable(hub->vdd); + if (err) + return err; + err = usb251xb_connect(hub); if (err) { dev_err(dev, "Failed to connect hub (%d)\n", err); @@ -692,7 +707,31 @@ static int usb251xb_i2c_probe(struct i2c_client *i2c, return usb251xb_probe(hub); } +static int __maybe_unused usb251xb_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb251xb *hub = i2c_get_clientdata(client); + + return regulator_disable(hub->vdd); +} + +static int __maybe_unused usb251xb_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct usb251xb *hub = i2c_get_clientdata(client); + int err; + + err = regulator_enable(hub->vdd); + if (err) + return err; + + return usb251xb_connect(hub); +} + +static SIMPLE_DEV_PM_OPS(usb251xb_pm_ops, usb251xb_suspend, usb251xb_resume); + static const struct i2c_device_id usb251xb_id[] = { + { "usb2422", 0 }, { "usb2512b", 0 }, { "usb2512bi", 0 }, { "usb2513b", 0 }, @@ -709,6 +748,7 @@ static struct i2c_driver usb251xb_i2c_driver = { .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(usb251xb_of_match), + .pm = &usb251xb_pm_ops, }, .probe = usb251xb_i2c_probe, .id_table = usb251xb_id, diff --git a/drivers/usb/mtu3/mtu3_core.c b/drivers/usb/mtu3/mtu3_core.c index c3d5c1206eec..9dd02160cca9 100644 --- a/drivers/usb/mtu3/mtu3_core.c +++ b/drivers/usb/mtu3/mtu3_core.c @@ -16,6 +16,7 @@ #include <linux/platform_device.h> #include "mtu3.h" +#include "mtu3_dr.h" #include "mtu3_debug.h" #include "mtu3_trace.h" diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index bd63450af76a..15cca912c53e 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -2431,14 +2431,12 @@ static int musb_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; int irq = platform_get_irq_byname(pdev, "mc"); - struct resource *iomem; void __iomem *base; if (irq <= 0) return -ENODEV; - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(dev, iomem); + base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 327d4f7baaf7..88923175f71e 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -411,7 +411,7 @@ static int dsps_musb_dbg_init(struct musb *musb, struct dsps_glue *glue) char buf[128]; sprintf(buf, "%s.dsps", dev_name(musb->controller)); - root = debugfs_create_dir(buf, NULL); + root = debugfs_create_dir(buf, usb_debug_root); glue->dbgfs_root = root; glue->regset.regs = dsps_musb_regs; diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c index ffe462a657b1..f62ffaede1ab 100644 --- a/drivers/usb/musb/musb_gadget.c +++ b/drivers/usb/musb/musb_gadget.c @@ -1085,7 +1085,6 @@ static int musb_gadget_disable(struct usb_ep *ep) u8 epnum; struct musb_ep *musb_ep; void __iomem *epio; - int status = 0; musb_ep = to_musb_ep(ep); musb = musb_ep->musb; @@ -1118,7 +1117,7 @@ static int musb_gadget_disable(struct usb_ep *ep) musb_dbg(musb, "%s", musb_ep->end_point.name); - return status; + return 0; } /* @@ -1316,7 +1315,7 @@ done: } /* - * Set or clear the halt bit of an endpoint. A halted enpoint won't tx/rx any + * Set or clear the halt bit of an endpoint. A halted endpoint won't tx/rx any * data but will queue requests. * * exported to ep0 code diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 18d5d1a0593e..d438b7871446 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -162,17 +162,17 @@ void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) req->bRequest = (val >> 8) & 0xFF; req->bRequestType = (val >> 0) & 0xFF; - req->wValue = usbhs_read(priv, USBVAL); - req->wIndex = usbhs_read(priv, USBINDX); - req->wLength = usbhs_read(priv, USBLENG); + req->wValue = cpu_to_le16(usbhs_read(priv, USBVAL)); + req->wIndex = cpu_to_le16(usbhs_read(priv, USBINDX)); + req->wLength = cpu_to_le16(usbhs_read(priv, USBLENG)); } void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) { usbhs_write(priv, USBREQ, (req->bRequest << 8) | req->bRequestType); - usbhs_write(priv, USBVAL, req->wValue); - usbhs_write(priv, USBINDX, req->wIndex); - usbhs_write(priv, USBLENG, req->wLength); + usbhs_write(priv, USBVAL, le16_to_cpu(req->wValue)); + usbhs_write(priv, USBINDX, le16_to_cpu(req->wIndex)); + usbhs_write(priv, USBLENG, le16_to_cpu(req->wLength)); usbhs_bset(priv, DCPCTR, SUREQ, SUREQ); } diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c index 86637cd066cf..01c6a48c41bc 100644 --- a/drivers/usb/renesas_usbhs/fifo.c +++ b/drivers/usb/renesas_usbhs/fifo.c @@ -1273,11 +1273,11 @@ static void usbhsf_dma_init_dt(struct device *dev, struct usbhs_fifo *fifo, */ snprintf(name, sizeof(name), "ch%d", channel); if (channel & 1) { - fifo->tx_chan = dma_request_slave_channel_reason(dev, name); + fifo->tx_chan = dma_request_chan(dev, name); if (IS_ERR(fifo->tx_chan)) fifo->tx_chan = NULL; } else { - fifo->rx_chan = dma_request_slave_channel_reason(dev, name); + fifo->rx_chan = dma_request_chan(dev, name); if (IS_ERR(fifo->rx_chan)) fifo->rx_chan = NULL; } diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index b47e70ffeda6..53489cafecc1 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -265,7 +265,7 @@ static int usbhsg_recip_handler_std_set_device(struct usbhs_priv *priv, case USB_DEVICE_TEST_MODE: usbhsg_recip_handler_std_control_done(priv, uep, ctrl); udelay(100); - usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex >> 8)); + usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex) >> 8); break; default: usbhsg_recip_handler_std_control_done(priv, uep, ctrl); @@ -315,7 +315,7 @@ static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv, struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp); struct device *dev = usbhsg_gpriv_to_dev(gpriv); struct usb_request *req; - unsigned short *buf; + __le16 *buf; /* alloc new usb_request for recip */ req = usb_ep_alloc_request(&dcp->ep, GFP_ATOMIC); diff --git a/drivers/usb/roles/class.c b/drivers/usb/roles/class.c index 94b4e7db2b94..8273126ffdf4 100644 --- a/drivers/usb/roles/class.c +++ b/drivers/usb/roles/class.c @@ -175,6 +175,27 @@ void usb_role_switch_put(struct usb_role_switch *sw) } EXPORT_SYMBOL_GPL(usb_role_switch_put); +/** + * usb_role_switch_find_by_fwnode - Find USB role switch with its fwnode + * @fwnode: fwnode of the USB Role Switch + * + * Finds and returns role switch with @fwnode. The reference count for the + * found switch is incremented. + */ +struct usb_role_switch * +usb_role_switch_find_by_fwnode(const struct fwnode_handle *fwnode) +{ + struct device *dev; + + if (!fwnode) + return NULL; + + dev = class_find_device_by_fwnode(role_class, fwnode); + + return dev ? to_role_switch(dev) : NULL; +} +EXPORT_SYMBOL_GPL(usb_role_switch_find_by_fwnode); + static umode_t usb_role_switch_is_visible(struct kobject *kobj, struct attribute *attr, int n) { diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig index 67279c6bce33..0a8c16a8cda2 100644 --- a/drivers/usb/serial/Kconfig +++ b/drivers/usb/serial/Kconfig @@ -271,17 +271,17 @@ config USB_SERIAL_F8153X config USB_SERIAL_GARMIN tristate "USB Garmin GPS driver" help - Say Y here if you want to connect to your Garmin GPS. - Should work with most Garmin GPS devices which have a native USB port. + Say Y here if you want to connect to your Garmin GPS. + Should work with most Garmin GPS devices which have a native USB port. - See <http://sourceforge.net/projects/garmin-gps> for the latest - version of the driver. + See <http://sourceforge.net/projects/garmin-gps> for the latest + version of the driver. - To compile this driver as a module, choose M here: the - module will be called garmin_gps. + To compile this driver as a module, choose M here: the + module will be called garmin_gps. config USB_SERIAL_IPW - tristate "USB IPWireless (3G UMTS TDD) Driver" + tristate "USB IPWireless (3G UMTS TDD) Driver" select USB_SERIAL_WWAN help Say Y here if you want to use a IPWireless USB modem such as @@ -341,20 +341,20 @@ config USB_SERIAL_KLSI module will be called kl5kusb105. config USB_SERIAL_KOBIL_SCT - tristate "USB KOBIL chipcard reader" - ---help--- - Say Y here if you want to use one of the following KOBIL USB chipcard - readers: - - - USB TWIN - - KAAN Standard Plus - - KAAN SIM - - SecOVID Reader Plus - - B1 Professional - - KAAN Professional - - Note that you need a current CT-API. - To compile this driver as a module, choose M here: the + tristate "USB KOBIL chipcard reader" + ---help--- + Say Y here if you want to use one of the following KOBIL USB chipcard + readers: + + - USB TWIN + - KAAN Standard Plus + - KAAN SIM + - SecOVID Reader Plus + - B1 Professional + - KAAN Professional + + Note that you need a current CT-API. + To compile this driver as a module, choose M here: the module will be called kobil_sct. config USB_SERIAL_MCT_U232 @@ -458,7 +458,7 @@ config USB_SERIAL_OTI6858 tristate "USB Ours Technology Inc. OTi-6858 USB To RS232 Bridge Controller" help Say Y here if you want to use the OTi-6858 single port USB to serial - converter device. + converter device. To compile this driver as a module, choose M here: the module will be called oti6858. diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c index 3bb1fff02bed..df582fe855f0 100644 --- a/drivers/usb/serial/ch341.c +++ b/drivers/usb/serial/ch341.c @@ -48,12 +48,6 @@ #define CH341_BIT_DCD 0x08 #define CH341_BITS_MODEM_STAT 0x0f /* all bits */ -/*******************************/ -/* baudrate calculation factor */ -/*******************************/ -#define CH341_BAUDBASE_FACTOR 1532620800 -#define CH341_BAUDBASE_DIVMAX 3 - /* Break support - the information used to implement this was gleaned from * the Net/FreeBSD uchcom.c driver by Takanori Watanabe. Domo arigato. */ @@ -144,37 +138,96 @@ static int ch341_control_in(struct usb_device *dev, return 0; } +#define CH341_CLKRATE 48000000 +#define CH341_CLK_DIV(ps, fact) (1 << (12 - 3 * (ps) - (fact))) +#define CH341_MIN_RATE(ps) (CH341_CLKRATE / (CH341_CLK_DIV((ps), 1) * 512)) + +static const speed_t ch341_min_rates[] = { + CH341_MIN_RATE(0), + CH341_MIN_RATE(1), + CH341_MIN_RATE(2), + CH341_MIN_RATE(3), +}; + +/* + * The device line speed is given by the following equation: + * + * baudrate = 48000000 / (2^(12 - 3 * ps - fact) * div), where + * + * 0 <= ps <= 3, + * 0 <= fact <= 1, + * 2 <= div <= 256 if fact = 0, or + * 9 <= div <= 256 if fact = 1 + */ +static int ch341_get_divisor(speed_t speed) +{ + unsigned int fact, div, clk_div; + int ps; + + /* + * Clamp to supported range, this makes the (ps < 0) and (div < 2) + * sanity checks below redundant. + */ + speed = clamp(speed, 46U, 3000000U); + + /* + * Start with highest possible base clock (fact = 1) that will give a + * divisor strictly less than 512. + */ + fact = 1; + for (ps = 3; ps >= 0; ps--) { + if (speed > ch341_min_rates[ps]) + break; + } + + if (ps < 0) + return -EINVAL; + + /* Determine corresponding divisor, rounding down. */ + clk_div = CH341_CLK_DIV(ps, fact); + div = CH341_CLKRATE / (clk_div * speed); + + /* Halve base clock (fact = 0) if required. */ + if (div < 9 || div > 255) { + div /= 2; + clk_div *= 2; + fact = 0; + } + + if (div < 2) + return -EINVAL; + + /* + * Pick next divisor if resulting rate is closer to the requested one, + * scale up to avoid rounding errors on low rates. + */ + if (16 * CH341_CLKRATE / (clk_div * div) - 16 * speed >= + 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) + div++; + + return (0x100 - div) << 8 | fact << 2 | ps; +} + static int ch341_set_baudrate_lcr(struct usb_device *dev, struct ch341_private *priv, u8 lcr) { - short a; + int val; int r; - unsigned long factor; - short divisor; if (!priv->baud_rate) return -EINVAL; - factor = (CH341_BAUDBASE_FACTOR / priv->baud_rate); - divisor = CH341_BAUDBASE_DIVMAX; - - while ((factor > 0xfff0) && divisor) { - factor >>= 3; - divisor--; - } - if (factor > 0xfff0) + val = ch341_get_divisor(priv->baud_rate); + if (val < 0) return -EINVAL; - factor = 0x10000 - factor; - a = (factor & 0xff00) | divisor; - /* * CH341A buffers data until a full endpoint-size packet (32 bytes) * has been received unless bit 7 is set. */ - a |= BIT(7); + val |= BIT(7); - r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x1312, a); + r = ch341_control_out(dev, CH341_REQ_WRITE_REG, 0x1312, val); if (r) return r; diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 25e81faf4c24..9ad44a96dfe3 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -1033,6 +1033,9 @@ static const struct usb_device_id id_table_combined[] = { /* Sienna devices */ { USB_DEVICE(FTDI_VID, FTDI_SIENNA_PID) }, { USB_DEVICE(ECHELON_VID, ECHELON_U20_PID) }, + /* U-Blox devices */ + { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ZED_PID) }, + { USB_DEVICE(UBLOX_VID, UBLOX_C099F9P_ODIN_PID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h index 22d66217cb41..e8373528264c 100644 --- a/drivers/usb/serial/ftdi_sio_ids.h +++ b/drivers/usb/serial/ftdi_sio_ids.h @@ -1558,3 +1558,10 @@ */ #define UNJO_VID 0x22B7 #define UNJO_ISODEBUG_V1_PID 0x150D + +/* + * U-Blox products (http://www.u-blox.com). + */ +#define UBLOX_VID 0x1546 +#define UBLOX_C099F9P_ZED_PID 0x0502 +#define UBLOX_C099F9P_ODIN_PID 0x0503 diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c index 18110225d506..2ec4eeacebc7 100644 --- a/drivers/usb/serial/mos7720.c +++ b/drivers/usb/serial/mos7720.c @@ -1833,10 +1833,6 @@ static int mos7720_startup(struct usb_serial *serial) product = le16_to_cpu(serial->dev->descriptor.idProduct); dev = serial->dev; - /* setting configuration feature to one */ - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - (__u8)0x03, 0x00, 0x01, 0x00, NULL, 0x00, 5000); - if (product == MOSCHIP_DEVICE_ID_7715) { struct urb *urb = serial->port[0]->interrupt_in_urb; diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c index a698d46ba773..23f91d658cb4 100644 --- a/drivers/usb/serial/mos7840.c +++ b/drivers/usb/serial/mos7840.c @@ -89,17 +89,10 @@ /* For higher baud Rates use TIOCEXBAUD */ #define TIOCEXBAUD 0x5462 -/* vendor id and device id defines */ - -/* The native mos7840/7820 component */ -#define USB_VENDOR_ID_MOSCHIP 0x9710 -#define MOSCHIP_DEVICE_ID_7840 0x7840 -#define MOSCHIP_DEVICE_ID_7843 0x7843 -#define MOSCHIP_DEVICE_ID_7820 0x7820 -#define MOSCHIP_DEVICE_ID_7810 0x7810 -/* The native component can have its vendor/device id's overridden - * in vendor-specific implementations. Such devices can be handled - * by making a change here, in id_table. +/* + * Vendor id and device id defines + * + * NOTE: Do not add new defines, add entries directly to the id_table instead. */ #define USB_VENDOR_ID_BANDB 0x0856 #define BANDB_DEVICE_ID_USO9ML2_2 0xAC22 @@ -116,14 +109,6 @@ #define BANDB_DEVICE_ID_USOPTL4_4P 0xBC03 #define BANDB_DEVICE_ID_USOPTL2_4 0xAC24 -/* This driver also supports - * ATEN UC2324 device using Moschip MCS7840 - * ATEN UC2322 device using Moschip MCS7820 - */ -#define USB_VENDOR_ID_ATENINTL 0x0557 -#define ATENINTL_DEVICE_ID_UC2324 0x2011 -#define ATENINTL_DEVICE_ID_UC2322 0x7820 - /* Interrupt Routine Defines */ #define SERIAL_IIR_RLS 0x06 @@ -171,30 +156,37 @@ #define LED_OFF_MS 500 enum mos7840_flag { - MOS7840_FLAG_CTRL_BUSY, MOS7840_FLAG_LED_BUSY, }; +#define MCS_PORT_MASK GENMASK(2, 0) +#define MCS_PORTS(nr) ((nr) & MCS_PORT_MASK) +#define MCS_LED BIT(3) + +#define MCS_DEVICE(vid, pid, flags) \ + USB_DEVICE((vid), (pid)), .driver_info = (flags) + static const struct usb_device_id id_table[] = { - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7843)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)}, - {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7810)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P)}, - {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2324)}, - {USB_DEVICE(USB_VENDOR_ID_ATENINTL, ATENINTL_DEVICE_ID_UC2322)}, + { MCS_DEVICE(0x0557, 0x2011, MCS_PORTS(4)) }, /* ATEN UC2324 */ + { MCS_DEVICE(0x0557, 0x7820, MCS_PORTS(2)) }, /* ATEN UC2322 */ + { MCS_DEVICE(0x110a, 0x2210, MCS_PORTS(2)) }, /* Moxa UPort 2210 */ + { MCS_DEVICE(0x9710, 0x7810, MCS_PORTS(1) | MCS_LED) }, /* ASIX MCS7810 */ + { MCS_DEVICE(0x9710, 0x7820, MCS_PORTS(2)) }, /* MosChip MCS7820 */ + { MCS_DEVICE(0x9710, 0x7840, MCS_PORTS(4)) }, /* MosChip MCS7840 */ + { MCS_DEVICE(0x9710, 0x7843, MCS_PORTS(3)) }, /* ASIX MCS7840 3 port */ + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2P) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_4P) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_2) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_US9ML2_4) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_2) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USPTL4_4) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_2P) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL4_4P) }, + { USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USOPTL2_4) }, {} /* terminating entry */ }; MODULE_DEVICE_TABLE(usb, id_table); @@ -206,19 +198,12 @@ struct moschip_port { struct urb *read_urb; /* read URB for this port */ __u8 shadowLCR; /* last LCR value received */ __u8 shadowMCR; /* last MCR value received */ - char open; - char open_ports; struct usb_serial_port *port; /* loop back to the owner of this object */ /* Offsets */ __u8 SpRegOffset; __u8 ControlRegOffset; __u8 DcrRegOffset; - /* for processing control URBS in interrupt context */ - struct urb *control_urb; - struct usb_ctrlrequest *dr; - char *ctrl_buf; - int MsrLsr; spinlock_t pool_lock; struct urb *write_urb_pool[NUM_URBS]; @@ -360,150 +345,11 @@ static void mos7840_dump_serial_port(struct usb_serial_port *port, /************************************************************************/ /************************************************************************/ -/* I N T E R F A C E F U N C T I O N S */ -/* I N T E R F A C E F U N C T I O N S */ -/************************************************************************/ -/************************************************************************/ - -static inline void mos7840_set_port_private(struct usb_serial_port *port, - struct moschip_port *data) -{ - usb_set_serial_port_data(port, (void *)data); -} - -static inline struct moschip_port *mos7840_get_port_private(struct - usb_serial_port - *port) -{ - return (struct moschip_port *)usb_get_serial_port_data(port); -} - -static void mos7840_handle_new_msr(struct moschip_port *port, __u8 new_msr) -{ - struct moschip_port *mos7840_port; - struct async_icount *icount; - mos7840_port = port; - if (new_msr & - (MOS_MSR_DELTA_CTS | MOS_MSR_DELTA_DSR | MOS_MSR_DELTA_RI | - MOS_MSR_DELTA_CD)) { - icount = &mos7840_port->port->icount; - - /* update input line counters */ - if (new_msr & MOS_MSR_DELTA_CTS) - icount->cts++; - if (new_msr & MOS_MSR_DELTA_DSR) - icount->dsr++; - if (new_msr & MOS_MSR_DELTA_CD) - icount->dcd++; - if (new_msr & MOS_MSR_DELTA_RI) - icount->rng++; - - wake_up_interruptible(&port->port->port.delta_msr_wait); - } -} - -static void mos7840_handle_new_lsr(struct moschip_port *port, __u8 new_lsr) -{ - struct async_icount *icount; - - if (new_lsr & SERIAL_LSR_BI) { - /* - * Parity and Framing errors only count if they - * occur exclusive of a break being - * received. - */ - new_lsr &= (__u8) (SERIAL_LSR_OE | SERIAL_LSR_BI); - } - - /* update input line counters */ - icount = &port->port->icount; - if (new_lsr & SERIAL_LSR_BI) - icount->brk++; - if (new_lsr & SERIAL_LSR_OE) - icount->overrun++; - if (new_lsr & SERIAL_LSR_PE) - icount->parity++; - if (new_lsr & SERIAL_LSR_FE) - icount->frame++; -} - -/************************************************************************/ -/************************************************************************/ /* U S B C A L L B A C K F U N C T I O N S */ /* U S B C A L L B A C K F U N C T I O N S */ /************************************************************************/ /************************************************************************/ -static void mos7840_control_callback(struct urb *urb) -{ - unsigned char *data; - struct moschip_port *mos7840_port; - struct device *dev = &urb->dev->dev; - __u8 regval = 0x0; - int status = urb->status; - - mos7840_port = urb->context; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dev_dbg(dev, "%s - urb shutting down with status: %d\n", __func__, status); - goto out; - default: - dev_dbg(dev, "%s - nonzero urb status received: %d\n", __func__, status); - goto out; - } - - dev_dbg(dev, "%s urb buffer size is %d\n", __func__, urb->actual_length); - if (urb->actual_length < 1) - goto out; - - dev_dbg(dev, "%s mos7840_port->MsrLsr is %d port %d\n", __func__, - mos7840_port->MsrLsr, mos7840_port->port_num); - data = urb->transfer_buffer; - regval = (__u8) data[0]; - dev_dbg(dev, "%s data is %x\n", __func__, regval); - if (mos7840_port->MsrLsr == 0) - mos7840_handle_new_msr(mos7840_port, regval); - else if (mos7840_port->MsrLsr == 1) - mos7840_handle_new_lsr(mos7840_port, regval); -out: - clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mos7840_port->flags); -} - -static int mos7840_get_reg(struct moschip_port *mcs, __u16 Wval, __u16 reg, - __u16 *val) -{ - struct usb_device *dev = mcs->port->serial->dev; - struct usb_ctrlrequest *dr = mcs->dr; - unsigned char *buffer = mcs->ctrl_buf; - int ret; - - if (test_and_set_bit_lock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags)) - return -EBUSY; - - dr->bRequestType = MCS_RD_RTYPE; - dr->bRequest = MCS_RDREQ; - dr->wValue = cpu_to_le16(Wval); /* 0 */ - dr->wIndex = cpu_to_le16(reg); - dr->wLength = cpu_to_le16(2); - - usb_fill_control_urb(mcs->control_urb, dev, usb_rcvctrlpipe(dev, 0), - (unsigned char *)dr, buffer, 2, - mos7840_control_callback, mcs); - mcs->control_urb->transfer_buffer_length = 2; - ret = usb_submit_urb(mcs->control_urb, GFP_ATOMIC); - if (ret) - clear_bit_unlock(MOS7840_FLAG_CTRL_BUSY, &mcs->flags); - - return ret; -} - static void mos7840_set_led_callback(struct urb *urb) { switch (urb->status) { @@ -580,146 +426,6 @@ static void mos7840_led_activity(struct usb_serial_port *port) } /***************************************************************************** - * mos7840_interrupt_callback - * this is the callback function for when we have received data on the - * interrupt endpoint. - *****************************************************************************/ - -static void mos7840_interrupt_callback(struct urb *urb) -{ - int result; - int length; - struct moschip_port *mos7840_port; - struct usb_serial *serial; - __u16 Data; - unsigned char *data; - __u8 sp[5]; - int i, rv = 0; - __u16 wval, wreg = 0; - int status = urb->status; - - switch (status) { - case 0: - /* success */ - break; - case -ECONNRESET: - case -ENOENT: - case -ESHUTDOWN: - /* this urb is terminated, clean up */ - dev_dbg(&urb->dev->dev, "%s - urb shutting down with status: %d\n", - __func__, status); - return; - default: - dev_dbg(&urb->dev->dev, "%s - nonzero urb status received: %d\n", - __func__, status); - goto exit; - } - - length = urb->actual_length; - data = urb->transfer_buffer; - - serial = urb->context; - - /* Moschip get 5 bytes - * Byte 1 IIR Port 1 (port.number is 0) - * Byte 2 IIR Port 2 (port.number is 1) - * Byte 3 IIR Port 3 (port.number is 2) - * Byte 4 IIR Port 4 (port.number is 3) - * Byte 5 FIFO status for both */ - - if (length > 5) { - dev_dbg(&urb->dev->dev, "%s", "Wrong data !!!\n"); - return; - } - - sp[0] = (__u8) data[0]; - sp[1] = (__u8) data[1]; - sp[2] = (__u8) data[2]; - sp[3] = (__u8) data[3]; - - for (i = 0; i < serial->num_ports; i++) { - mos7840_port = mos7840_get_port_private(serial->port[i]); - wval = ((__u16)serial->port[i]->port_number + 1) << 8; - if (mos7840_port->open) { - if (sp[i] & 0x01) { - dev_dbg(&urb->dev->dev, "SP%d No Interrupt !!!\n", i); - } else { - switch (sp[i] & 0x0f) { - case SERIAL_IIR_RLS: - dev_dbg(&urb->dev->dev, "Serial Port %d: Receiver status error or \n", i); - dev_dbg(&urb->dev->dev, "address bit detected in 9-bit mode\n"); - mos7840_port->MsrLsr = 1; - wreg = LINE_STATUS_REGISTER; - break; - case SERIAL_IIR_MS: - dev_dbg(&urb->dev->dev, "Serial Port %d: Modem status change\n", i); - mos7840_port->MsrLsr = 0; - wreg = MODEM_STATUS_REGISTER; - break; - } - rv = mos7840_get_reg(mos7840_port, wval, wreg, &Data); - } - } - } - if (!(rv < 0)) - /* the completion handler for the control urb will resubmit */ - return; -exit: - result = usb_submit_urb(urb, GFP_ATOMIC); - if (result) { - dev_err(&urb->dev->dev, - "%s - Error %d submitting interrupt urb\n", - __func__, result); - } -} - -static int mos7840_port_paranoia_check(struct usb_serial_port *port, - const char *function) -{ - if (!port) { - pr_debug("%s - port == NULL\n", function); - return -1; - } - if (!port->serial) { - pr_debug("%s - port->serial == NULL\n", function); - return -1; - } - - return 0; -} - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static int mos7840_serial_paranoia_check(struct usb_serial *serial, - const char *function) -{ - if (!serial) { - pr_debug("%s - serial == NULL\n", function); - return -1; - } - if (!serial->type) { - pr_debug("%s - serial->type == NULL!\n", function); - return -1; - } - - return 0; -} - -static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port, - const char *function) -{ - /* if no port was specified, or it fails a paranoia check */ - if (!port || - mos7840_port_paranoia_check(port, function) || - mos7840_serial_paranoia_check(port->serial, function)) { - /* then say that we don't have a valid usb_serial thing, - * which will end up genrating -ENODEV return values */ - return NULL; - } - - return port->serial; -} - -/***************************************************************************** * mos7840_bulk_in_callback * this is the callback function for when we have received data on the * bulk in endpoint. @@ -727,35 +433,18 @@ static struct usb_serial *mos7840_get_usb_serial(struct usb_serial_port *port, static void mos7840_bulk_in_callback(struct urb *urb) { + struct moschip_port *mos7840_port = urb->context; + struct usb_serial_port *port = mos7840_port->port; int retval; unsigned char *data; - struct usb_serial *serial; - struct usb_serial_port *port; - struct moschip_port *mos7840_port; int status = urb->status; - mos7840_port = urb->context; - if (!mos7840_port) - return; - if (status) { dev_dbg(&urb->dev->dev, "nonzero read bulk status received: %d\n", status); mos7840_port->read_urb_busy = false; return; } - port = mos7840_port->port; - if (mos7840_port_paranoia_check(port, __func__)) { - mos7840_port->read_urb_busy = false; - return; - } - - serial = mos7840_get_usb_serial(port, __func__); - if (!serial) { - mos7840_port->read_urb_busy = false; - return; - } - data = urb->transfer_buffer; usb_serial_debug_data(&port->dev, __func__, urb->actual_length, data); @@ -767,12 +456,6 @@ static void mos7840_bulk_in_callback(struct urb *urb) dev_dbg(&port->dev, "icount.rx is %d:\n", port->icount.rx); } - if (!mos7840_port->read_urb) { - dev_dbg(&port->dev, "%s", "URB KILLED !!!\n"); - mos7840_port->read_urb_busy = false; - return; - } - if (mos7840_port->has_led) mos7840_led_activity(port); @@ -793,14 +476,12 @@ static void mos7840_bulk_in_callback(struct urb *urb) static void mos7840_bulk_out_data_callback(struct urb *urb) { - struct moschip_port *mos7840_port; - struct usb_serial_port *port; + struct moschip_port *mos7840_port = urb->context; + struct usb_serial_port *port = mos7840_port->port; int status = urb->status; unsigned long flags; int i; - mos7840_port = urb->context; - port = mos7840_port->port; spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; i++) { if (urb == mos7840_port->write_urb_pool[i]) { @@ -815,11 +496,7 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) return; } - if (mos7840_port_paranoia_check(port, __func__)) - return; - - if (mos7840_port->open) - tty_port_tty_wakeup(&port->port); + tty_port_tty_wakeup(&port->port); } @@ -836,32 +513,16 @@ static void mos7840_bulk_out_data_callback(struct urb *urb) static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) { + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; int response; int j; - struct usb_serial *serial; struct urb *urb; __u16 Data; int status; - struct moschip_port *mos7840_port; - struct moschip_port *port0; - - if (mos7840_port_paranoia_check(port, __func__)) - return -ENODEV; - - serial = port->serial; - - if (mos7840_serial_paranoia_check(serial, __func__)) - return -ENODEV; - - mos7840_port = mos7840_get_port_private(port); - port0 = mos7840_get_port_private(serial->port[0]); - - if (mos7840_port == NULL || port0 == NULL) - return -ENODEV; usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); - port0->open_ports++; /* Initialising the write urb pool */ for (j = 0; j < NUM_URBS; ++j) { @@ -1012,41 +673,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) status = mos7840_set_reg_sync(port, mos7840_port->ControlRegOffset, Data); - /* Check to see if we've set up our endpoint info yet * - * (can't set it up in mos7840_startup as the structures * - * were not set up at that time.) */ - if (port0->open_ports == 1) { - /* FIXME: Buffer never NULL, so URB is not submitted. */ - if (serial->port[0]->interrupt_in_buffer == NULL) { - /* set up interrupt urb */ - usb_fill_int_urb(serial->port[0]->interrupt_in_urb, - serial->dev, - usb_rcvintpipe(serial->dev, - serial->port[0]->interrupt_in_endpointAddress), - serial->port[0]->interrupt_in_buffer, - serial->port[0]->interrupt_in_urb-> - transfer_buffer_length, - mos7840_interrupt_callback, - serial, - serial->port[0]->interrupt_in_urb->interval); - - /* start interrupt read for mos7840 */ - response = - usb_submit_urb(serial->port[0]->interrupt_in_urb, - GFP_KERNEL); - if (response) { - dev_err(&port->dev, "%s - Error %d submitting " - "interrupt urb\n", __func__, response); - } - - } - - } - - /* see if we've set up our endpoint info yet * - * (can't set it up in mos7840_startup as the * - * structures were not set up at that time.) */ - dev_dbg(&port->dev, "port number is %d\n", port->port_number); dev_dbg(&port->dev, "minor number is %d\n", port->minor); dev_dbg(&port->dev, "Bulkin endpoint is %d\n", port->bulk_in_endpointAddress); @@ -1086,9 +712,6 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port) /* initialize our port settings */ /* Must set to enable ints! */ mos7840_port->shadowMCR = MCR_MASTER_IE; - /* send a open port command */ - mos7840_port->open = 1; - /* mos7840_change_port_settings(mos7840_port,old_termios); */ return 0; err: @@ -1115,17 +738,10 @@ err: static int mos7840_chars_in_buffer(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); int i; int chars = 0; unsigned long flags; - struct moschip_port *mos7840_port; - - if (mos7840_port_paranoia_check(port, __func__)) - return 0; - - mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) - return 0; spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { @@ -1147,25 +763,10 @@ static int mos7840_chars_in_buffer(struct tty_struct *tty) static void mos7840_close(struct usb_serial_port *port) { - struct usb_serial *serial; - struct moschip_port *mos7840_port; - struct moschip_port *port0; + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); int j; __u16 Data; - if (mos7840_port_paranoia_check(port, __func__)) - return; - - serial = mos7840_get_usb_serial(port, __func__); - if (!serial) - return; - - mos7840_port = mos7840_get_port_private(port); - port0 = mos7840_get_port_private(serial->port[0]); - - if (mos7840_port == NULL || port0 == NULL) - return; - for (j = 0; j < NUM_URBS; ++j) usb_kill_urb(mos7840_port->write_urb_pool[j]); @@ -1180,22 +781,11 @@ static void mos7840_close(struct usb_serial_port *port) usb_kill_urb(mos7840_port->read_urb); mos7840_port->read_urb_busy = false; - port0->open_ports--; - dev_dbg(&port->dev, "%s in close%d\n", __func__, port0->open_ports); - if (port0->open_ports == 0) { - if (serial->port[0]->interrupt_in_urb) { - dev_dbg(&port->dev, "Shutdown interrupt_in_urb\n"); - usb_kill_urb(serial->port[0]->interrupt_in_urb); - } - } - Data = 0x0; mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER, Data); Data = 0x00; mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data); - - mos7840_port->open = 0; } /***************************************************************************** @@ -1205,21 +795,8 @@ static void mos7840_close(struct usb_serial_port *port) static void mos7840_break(struct tty_struct *tty, int break_state) { struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); unsigned char data; - struct usb_serial *serial; - struct moschip_port *mos7840_port; - - if (mos7840_port_paranoia_check(port, __func__)) - return; - - serial = mos7840_get_usb_serial(port, __func__); - if (!serial) - return; - - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return; if (break_state == -1) data = mos7840_port->shadowLCR | LCR_SET_BREAK; @@ -1244,17 +821,10 @@ static void mos7840_break(struct tty_struct *tty, int break_state) static int mos7840_write_room(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); int i; int room = 0; unsigned long flags; - struct moschip_port *mos7840_port; - - if (mos7840_port_paranoia_check(port, __func__)) - return -1; - - mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) - return -1; spin_lock_irqsave(&mos7840_port->pool_lock, flags); for (i = 0; i < NUM_URBS; ++i) { @@ -1280,29 +850,17 @@ static int mos7840_write_room(struct tty_struct *tty) static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port, const unsigned char *data, int count) { + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); + struct usb_serial *serial = port->serial; int status; int i; int bytes_sent = 0; int transfer_size; unsigned long flags; - - struct moschip_port *mos7840_port; - struct usb_serial *serial; struct urb *urb; /* __u16 Data; */ const unsigned char *current_position = data; - if (mos7840_port_paranoia_check(port, __func__)) - return -1; - - serial = port->serial; - if (mos7840_serial_paranoia_check(serial, __func__)) - return -1; - - mos7840_port = mos7840_get_port_private(port); - if (mos7840_port == NULL) - return -1; - /* try to find a free urb in the list */ urb = NULL; @@ -1383,22 +941,9 @@ exit: static void mos7840_throttle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port; + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); int status; - if (mos7840_port_paranoia_check(port, __func__)) - return; - - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return; - - if (!mos7840_port->open) { - dev_dbg(&port->dev, "%s", "port not opened\n"); - return; - } - /* if we are implementing XON/XOFF, send the stop character */ if (I_IXOFF(tty)) { unsigned char stop_char = STOP_CHAR(tty); @@ -1425,19 +970,8 @@ static void mos7840_throttle(struct tty_struct *tty) static void mos7840_unthrottle(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); int status; - struct moschip_port *mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port_paranoia_check(port, __func__)) - return; - - if (mos7840_port == NULL) - return; - - if (!mos7840_port->open) { - dev_dbg(&port->dev, "%s - port not opened\n", __func__); - return; - } /* if we are implementing XON/XOFF, send the start character */ if (I_IXOFF(tty)) { @@ -1460,15 +994,10 @@ static void mos7840_unthrottle(struct tty_struct *tty) static int mos7840_tiocmget(struct tty_struct *tty) { struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port; unsigned int result; __u16 msr; __u16 mcr; int status; - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return -ENODEV; status = mos7840_get_uart_reg(port, MODEM_STATUS_REGISTER, &msr); if (status < 0) @@ -1493,15 +1022,10 @@ static int mos7840_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port; + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); unsigned int mcr; int status; - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return -ENODEV; - /* FIXME: What locks the port registers ? */ mcr = mos7840_port->shadowMCR; if (clear & TIOCM_RTS) @@ -1578,21 +1102,11 @@ static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port, static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, int baudRate) { + struct usb_serial_port *port = mos7840_port->port; int divisor = 0; int status; __u16 Data; __u16 clk_sel_val; - struct usb_serial_port *port; - - if (mos7840_port == NULL) - return -1; - - port = mos7840_port->port; - if (mos7840_port_paranoia_check(port, __func__)) - return -1; - - if (mos7840_serial_paranoia_check(port->serial, __func__)) - return -1; dev_dbg(&port->dev, "%s - baud = %d\n", __func__, baudRate); /* reset clk_uart_sel in spregOffset */ @@ -1681,6 +1195,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port, static void mos7840_change_port_settings(struct tty_struct *tty, struct moschip_port *mos7840_port, struct ktermios *old_termios) { + struct usb_serial_port *port = mos7840_port->port; int baud; unsigned cflag; __u8 lData; @@ -1688,23 +1203,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty, __u8 lStop; int status; __u16 Data; - struct usb_serial_port *port; - - if (mos7840_port == NULL) - return; - - port = mos7840_port->port; - - if (mos7840_port_paranoia_check(port, __func__)) - return; - - if (mos7840_serial_paranoia_check(port->serial, __func__)) - return; - - if (!mos7840_port->open) { - dev_dbg(&port->dev, "%s - port not opened\n", __func__); - return; - } lData = LCR_BITS_8; lStop = LCR_STOP_1; @@ -1839,37 +1337,13 @@ static void mos7840_set_termios(struct tty_struct *tty, struct usb_serial_port *port, struct ktermios *old_termios) { + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); int status; - struct usb_serial *serial; - struct moschip_port *mos7840_port; - - if (mos7840_port_paranoia_check(port, __func__)) - return; - - serial = port->serial; - - if (mos7840_serial_paranoia_check(serial, __func__)) - return; - - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return; - - if (!mos7840_port->open) { - dev_dbg(&port->dev, "%s - port not opened\n", __func__); - return; - } /* change the port settings to the new ones specified */ mos7840_change_port_settings(tty, mos7840_port, old_termios); - if (!mos7840_port->read_urb) { - dev_dbg(&port->dev, "%s", "URB KILLED !!!!!\n"); - return; - } - if (!mos7840_port->read_urb_busy) { mos7840_port->read_urb_busy = true; status = usb_submit_urb(mos7840_port->read_urb, GFP_KERNEL); @@ -1916,7 +1390,7 @@ static int mos7840_get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct usb_serial_port *port = tty->driver_data; - struct moschip_port *mos7840_port = mos7840_get_port_private(port); + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); ss->type = PORT_16550A; ss->line = mos7840_port->port->minor; @@ -1939,15 +1413,6 @@ static int mos7840_ioctl(struct tty_struct *tty, { struct usb_serial_port *port = tty->driver_data; void __user *argp = (void __user *)arg; - struct moschip_port *mos7840_port; - - if (mos7840_port_paranoia_check(port, __func__)) - return -1; - - mos7840_port = mos7840_get_port_private(port); - - if (mos7840_port == NULL) - return -1; switch (cmd) { /* return number of bytes available */ @@ -1962,6 +1427,13 @@ static int mos7840_ioctl(struct tty_struct *tty, return -ENOIOCTLCMD; } +/* + * Check if GPO (pin 42) is connected to GPI (pin 33) as recommended by ASIX + * for MCS7810 by bit-banging a 16-bit word. + * + * Note that GPO is really RTS of the third port so this will toggle RTS of + * port two or three on two- and four-port devices. + */ static int mos7810_check(struct usb_serial *serial) { int i, pass_count = 0; @@ -2019,16 +1491,12 @@ static int mos7810_check(struct usb_serial *serial) static int mos7840_probe(struct usb_serial *serial, const struct usb_device_id *id) { - u16 product = le16_to_cpu(serial->dev->descriptor.idProduct); + unsigned long device_flags = id->driver_info; u8 *buf; - int device_type; - if (product == MOSCHIP_DEVICE_ID_7810 || - product == MOSCHIP_DEVICE_ID_7820 || - product == MOSCHIP_DEVICE_ID_7843) { - device_type = product; + /* Skip device-type detection if we already have device flags. */ + if (device_flags) goto out; - } buf = kzalloc(VENDOR_READ_LENGTH, GFP_KERNEL); if (!buf) @@ -2040,15 +1508,15 @@ static int mos7840_probe(struct usb_serial *serial, /* For a MCS7840 device GPIO0 must be set to 1 */ if (buf[0] & 0x01) - device_type = MOSCHIP_DEVICE_ID_7840; + device_flags = MCS_PORTS(4); else if (mos7810_check(serial)) - device_type = MOSCHIP_DEVICE_ID_7810; + device_flags = MCS_PORTS(1) | MCS_LED; else - device_type = MOSCHIP_DEVICE_ID_7820; + device_flags = MCS_PORTS(2); kfree(buf); out: - usb_set_serial_data(serial, (void *)(unsigned long)device_type); + usb_set_serial_data(serial, (void *)device_flags); return 0; } @@ -2056,19 +1524,10 @@ out: static int mos7840_calc_num_ports(struct usb_serial *serial, struct usb_serial_endpoints *epds) { - int device_type = (unsigned long)usb_get_serial_data(serial); - int num_ports; + unsigned long device_flags = (unsigned long)usb_get_serial_data(serial); + int num_ports = MCS_PORTS(device_flags); - if (device_type == MOSCHIP_DEVICE_ID_7843) - num_ports = 3; - else - num_ports = (device_type >> 4) & 0x000F; - - /* - * num_ports is currently never zero as device_type is one of - * MOSCHIP_DEVICE_ID_78{1,2,4}0. - */ - if (num_ports == 0) + if (num_ports == 0 || num_ports > 4) return -ENODEV; if (epds->num_bulk_in < num_ports || epds->num_bulk_out < num_ports) { @@ -2079,10 +1538,27 @@ static int mos7840_calc_num_ports(struct usb_serial *serial, return num_ports; } +static int mos7840_attach(struct usb_serial *serial) +{ + struct device *dev = &serial->interface->dev; + int status; + u16 val; + + /* Zero Length flag enable */ + val = 0x0f; + status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, val); + if (status < 0) + dev_dbg(dev, "Writing ZLP_REG5 failed status-0x%x\n", status); + else + dev_dbg(dev, "ZLP_REG5 Writing success status%d\n", status); + + return status; +} + static int mos7840_port_probe(struct usb_serial_port *port) { struct usb_serial *serial = port->serial; - int device_type = (unsigned long)usb_get_serial_data(serial); + unsigned long device_flags = (unsigned long)usb_get_serial_data(serial); struct moschip_port *mos7840_port; int status; int pnum; @@ -2103,7 +1579,6 @@ static int mos7840_port_probe(struct usb_serial_port *port) * common to all port */ mos7840_port->port = port; - mos7840_set_port_private(port, mos7840_port); spin_lock_init(&mos7840_port->pool_lock); /* minor is not initialised until later by @@ -2129,14 +1604,14 @@ static int mos7840_port_probe(struct usb_serial_port *port) mos7840_port->DcrRegOffset = 0x16 + 3 * (phy_num - 2); } mos7840_dump_serial_port(port, mos7840_port); - mos7840_set_port_private(port, mos7840_port); + usb_set_serial_port_data(port, mos7840_port); /* enable rx_disable bit in control register */ status = mos7840_get_reg_sync(port, mos7840_port->ControlRegOffset, &Data); if (status < 0) { dev_dbg(&port->dev, "Reading ControlReg failed status-0x%x\n", status); - goto out; + goto error; } else dev_dbg(&port->dev, "ControlReg Reading success val is %x, status%d\n", Data, status); Data |= 0x08; /* setting driver done bit */ @@ -2148,7 +1623,7 @@ static int mos7840_port_probe(struct usb_serial_port *port) mos7840_port->ControlRegOffset, Data); if (status < 0) { dev_dbg(&port->dev, "Writing ControlReg failed(rx_disable) status-0x%x\n", status); - goto out; + goto error; } else dev_dbg(&port->dev, "ControlReg Writing success(rx_disable) status%d\n", status); @@ -2159,7 +1634,7 @@ static int mos7840_port_probe(struct usb_serial_port *port) (__u16) (mos7840_port->DcrRegOffset + 0), Data); if (status < 0) { dev_dbg(&port->dev, "Writing DCR0 failed status-0x%x\n", status); - goto out; + goto error; } else dev_dbg(&port->dev, "DCR0 Writing success status%d\n", status); @@ -2168,7 +1643,7 @@ static int mos7840_port_probe(struct usb_serial_port *port) (__u16) (mos7840_port->DcrRegOffset + 1), Data); if (status < 0) { dev_dbg(&port->dev, "Writing DCR1 failed status-0x%x\n", status); - goto out; + goto error; } else dev_dbg(&port->dev, "DCR1 Writing success status%d\n", status); @@ -2177,7 +1652,7 @@ static int mos7840_port_probe(struct usb_serial_port *port) (__u16) (mos7840_port->DcrRegOffset + 2), Data); if (status < 0) { dev_dbg(&port->dev, "Writing DCR2 failed status-0x%x\n", status); - goto out; + goto error; } else dev_dbg(&port->dev, "DCR2 Writing success status%d\n", status); @@ -2186,7 +1661,7 @@ static int mos7840_port_probe(struct usb_serial_port *port) status = mos7840_set_reg_sync(port, CLK_START_VALUE_REGISTER, Data); if (status < 0) { dev_dbg(&port->dev, "Writing CLK_START_VALUE_REGISTER failed status-0x%x\n", status); - goto out; + goto error; } else dev_dbg(&port->dev, "CLK_START_VALUE_REGISTER Writing success status%d\n", status); @@ -2203,7 +1678,7 @@ static int mos7840_port_probe(struct usb_serial_port *port) status = mos7840_set_uart_reg(port, SCRATCH_PAD_REGISTER, Data); if (status < 0) { dev_dbg(&port->dev, "Writing SCRATCH_PAD_REGISTER failed status-0x%x\n", status); - goto out; + goto error; } else dev_dbg(&port->dev, "SCRATCH_PAD_REGISTER Writing success status%d\n", status); @@ -2217,7 +1692,7 @@ static int mos7840_port_probe(struct usb_serial_port *port) (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num))); if (status < 0) { dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 2, status); - goto out; + goto error; } else dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 2, status); } else { @@ -2229,27 +1704,16 @@ static int mos7840_port_probe(struct usb_serial_port *port) (__u16)(ZLP_REG1 + ((__u16) mos7840_port->port_num) - 0x1)); if (status < 0) { dev_dbg(&port->dev, "Writing ZLP_REG%d failed status-0x%x\n", pnum + 1, status); - goto out; + goto error; } else dev_dbg(&port->dev, "ZLP_REG%d Writing success status%d\n", pnum + 1, status); } - mos7840_port->control_urb = usb_alloc_urb(0, GFP_KERNEL); - mos7840_port->ctrl_buf = kmalloc(16, GFP_KERNEL); - mos7840_port->dr = kmalloc(sizeof(struct usb_ctrlrequest), - GFP_KERNEL); - if (!mos7840_port->control_urb || !mos7840_port->ctrl_buf || - !mos7840_port->dr) { - status = -ENOMEM; - goto error; - } - mos7840_port->has_led = false; + mos7840_port->has_led = device_flags & MCS_LED; /* Initialize LED timers */ - if (device_type == MOSCHIP_DEVICE_ID_7810) { - mos7840_port->has_led = true; - + if (mos7840_port->has_led) { mos7840_port->led_urb = usb_alloc_urb(0, GFP_KERNEL); mos7840_port->led_dr = kmalloc(sizeof(*mos7840_port->led_dr), GFP_KERNEL); @@ -2269,29 +1733,11 @@ static int mos7840_port_probe(struct usb_serial_port *port) /* Turn off LED */ mos7840_set_led_sync(port, MODEM_CONTROL_REGISTER, 0x0300); } -out: - if (pnum == serial->num_ports - 1) { - /* Zero Length flag enable */ - Data = 0x0f; - status = mos7840_set_reg_sync(serial->port[0], ZLP_REG5, Data); - if (status < 0) { - dev_dbg(&port->dev, "Writing ZLP_REG5 failed status-0x%x\n", status); - goto error; - } else - dev_dbg(&port->dev, "ZLP_REG5 Writing success status%d\n", status); - /* setting configuration feature to one */ - usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - 0x03, 0x00, 0x01, 0x00, NULL, 0x00, - MOS_WDR_TIMEOUT); - } return 0; error: kfree(mos7840_port->led_dr); usb_free_urb(mos7840_port->led_urb); - kfree(mos7840_port->dr); - kfree(mos7840_port->ctrl_buf); - usb_free_urb(mos7840_port->control_urb); kfree(mos7840_port); return status; @@ -2299,9 +1745,7 @@ error: static int mos7840_port_remove(struct usb_serial_port *port) { - struct moschip_port *mos7840_port; - - mos7840_port = mos7840_get_port_private(port); + struct moschip_port *mos7840_port = usb_get_serial_port_data(port); if (mos7840_port->has_led) { /* Turn off LED */ @@ -2314,10 +1758,7 @@ static int mos7840_port_remove(struct usb_serial_port *port) usb_free_urb(mos7840_port->led_urb); kfree(mos7840_port->led_dr); } - usb_kill_urb(mos7840_port->control_urb); - usb_free_urb(mos7840_port->control_urb); - kfree(mos7840_port->ctrl_buf); - kfree(mos7840_port->dr); + kfree(mos7840_port); return 0; @@ -2340,18 +1781,17 @@ static struct usb_serial_driver moschip7840_4port_device = { .unthrottle = mos7840_unthrottle, .calc_num_ports = mos7840_calc_num_ports, .probe = mos7840_probe, + .attach = mos7840_attach, .ioctl = mos7840_ioctl, .get_serial = mos7840_get_serial_info, .set_termios = mos7840_set_termios, .break_ctl = mos7840_break, .tiocmget = mos7840_tiocmget, .tiocmset = mos7840_tiocmset, - .tiocmiwait = usb_serial_generic_tiocmiwait, .get_icount = usb_serial_generic_get_icount, .port_probe = mos7840_port_probe, .port_remove = mos7840_port_remove, .read_bulk_callback = mos7840_bulk_in_callback, - .read_int_callback = mos7840_interrupt_callback, }; static struct usb_serial_driver * const serial_drivers[] = { diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c index 06ab016be0b6..e9491d400a24 100644 --- a/drivers/usb/serial/option.c +++ b/drivers/usb/serial/option.c @@ -197,6 +197,7 @@ static void option_instat_callback(struct urb *urb); #define DELL_PRODUCT_5804_MINICARD_ATT 0x819b /* Novatel E371 */ #define DELL_PRODUCT_5821E 0x81d7 +#define DELL_PRODUCT_5821E_ESIM 0x81e0 #define KYOCERA_VENDOR_ID 0x0c88 #define KYOCERA_PRODUCT_KPC650 0x17da @@ -1044,6 +1045,8 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(DELL_VENDOR_ID, DELL_PRODUCT_5804_MINICARD_ATT, 0xff, 0xff, 0xff) }, { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E), .driver_info = RSVD(0) | RSVD(1) | RSVD(6) }, + { USB_DEVICE(DELL_VENDOR_ID, DELL_PRODUCT_5821E_ESIM), + .driver_info = RSVD(0) | RSVD(1) | RSVD(6) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_E100A) }, /* ADU-E100, ADU-310 */ { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_500A) }, { USB_DEVICE(ANYDATA_VENDOR_ID, ANYDATA_PRODUCT_ADU_620UW) }, @@ -1990,6 +1993,10 @@ static const struct usb_device_id option_ids[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x13) }, { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x14) }, { USB_DEVICE_AND_INTERFACE_INFO(0x03f0, 0xa31d, 0xff, 0x06, 0x1b) }, + { USB_DEVICE(0x0489, 0xe0b4), /* Foxconn T77W968 */ + .driver_info = RSVD(0) | RSVD(1) | RSVD(6) }, + { USB_DEVICE(0x0489, 0xe0b5), /* Foxconn T77W968 ESIM */ + .driver_info = RSVD(0) | RSVD(1) | RSVD(6) }, { USB_DEVICE(0x1508, 0x1001), /* Fibocom NL668 */ .driver_info = RSVD(4) | RSVD(5) | RSVD(6) }, { USB_DEVICE(0x2cb7, 0x0104), /* Fibocom NL678 series */ diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 9d27b76c5c6e..aab737e1e7b6 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -47,6 +47,12 @@ static const struct usb_device_id id_table[] = { { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_MOTOROLA) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_ZTEK) }, { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_TB) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GC) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GB) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GT) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GL) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GE) }, + { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_GS) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID) }, { USB_DEVICE(IODATA_VENDOR_ID, IODATA_PRODUCT_ID_RSAQ5) }, { USB_DEVICE(ATEN_VENDOR_ID, ATEN_PRODUCT_ID), @@ -130,9 +136,11 @@ MODULE_DEVICE_TABLE(usb, id_table); #define VENDOR_WRITE_REQUEST_TYPE 0x40 #define VENDOR_WRITE_REQUEST 0x01 +#define VENDOR_WRITE_NREQUEST 0x80 #define VENDOR_READ_REQUEST_TYPE 0xc0 #define VENDOR_READ_REQUEST 0x01 +#define VENDOR_READ_NREQUEST 0x81 #define UART_STATE_INDEX 8 #define UART_STATE_MSR_MASK 0x8b @@ -148,11 +156,24 @@ MODULE_DEVICE_TABLE(usb, id_table); #define PL2303_FLOWCTRL_MASK 0xf0 +#define PL2303_READ_TYPE_HX_STATUS 0x8080 + +#define PL2303_HXN_RESET_REG 0x07 +#define PL2303_HXN_RESET_UPSTREAM_PIPE 0x02 +#define PL2303_HXN_RESET_DOWNSTREAM_PIPE 0x01 + +#define PL2303_HXN_FLOWCTRL_REG 0x0a +#define PL2303_HXN_FLOWCTRL_MASK 0x1c +#define PL2303_HXN_FLOWCTRL_NONE 0x1c +#define PL2303_HXN_FLOWCTRL_RTS_CTS 0x18 +#define PL2303_HXN_FLOWCTRL_XON_XOFF 0x0c + static void pl2303_set_break(struct usb_serial_port *port, bool enable); enum pl2303_type { TYPE_01, /* Type 0 and 1 (difference unknown) */ TYPE_HX, /* HX version of the pl2303 chip */ + TYPE_HXN, /* HXN version of the pl2303 chip */ TYPE_COUNT }; @@ -184,16 +205,26 @@ static const struct pl2303_type_data pl2303_type_data[TYPE_COUNT] = { [TYPE_HX] = { .max_baud_rate = 12000000, }, + [TYPE_HXN] = { + .max_baud_rate = 12000000, + }, }; static int pl2303_vendor_read(struct usb_serial *serial, u16 value, unsigned char buf[1]) { + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); struct device *dev = &serial->interface->dev; + u8 request; int res; + if (spriv->type == &pl2303_type_data[TYPE_HXN]) + request = VENDOR_READ_NREQUEST; + else + request = VENDOR_READ_REQUEST; + res = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), - VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, + request, VENDOR_READ_REQUEST_TYPE, value, 0, buf, 1, 100); if (res != 1) { dev_err(dev, "%s - failed to read [%04x]: %d\n", __func__, @@ -211,13 +242,20 @@ static int pl2303_vendor_read(struct usb_serial *serial, u16 value, static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index) { + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); struct device *dev = &serial->interface->dev; + u8 request; int res; dev_dbg(dev, "%s - [%04x] = %02x\n", __func__, value, index); + if (spriv->type == &pl2303_type_data[TYPE_HXN]) + request = VENDOR_WRITE_NREQUEST; + else + request = VENDOR_WRITE_REQUEST; + res = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), - VENDOR_WRITE_REQUEST, VENDOR_WRITE_REQUEST_TYPE, + request, VENDOR_WRITE_REQUEST_TYPE, value, index, NULL, 0, 100); if (res) { dev_err(dev, "%s - failed to write [%04x]: %d\n", __func__, @@ -230,6 +268,7 @@ static int pl2303_vendor_write(struct usb_serial *serial, u16 value, u16 index) static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val) { + struct pl2303_serial_private *spriv = usb_get_serial_data(serial); int ret = 0; u8 *buf; @@ -237,7 +276,11 @@ static int pl2303_update_reg(struct usb_serial *serial, u8 reg, u8 mask, u8 val) if (!buf) return -ENOMEM; - ret = pl2303_vendor_read(serial, reg | 0x80, buf); + if (spriv->type == &pl2303_type_data[TYPE_HXN]) + ret = pl2303_vendor_read(serial, reg, buf); + else + ret = pl2303_vendor_read(serial, reg | 0x80, buf); + if (ret) goto out_free; @@ -320,6 +363,7 @@ static int pl2303_startup(struct usb_serial *serial) struct pl2303_serial_private *spriv; enum pl2303_type type = TYPE_01; unsigned char *buf; + int res; spriv = kzalloc(sizeof(*spriv), GFP_KERNEL); if (!spriv) @@ -341,26 +385,37 @@ static int pl2303_startup(struct usb_serial *serial) type = TYPE_01; /* type 1 */ dev_dbg(&serial->interface->dev, "device type: %d\n", type); + if (type == TYPE_HX) { + res = usb_control_msg(serial->dev, + usb_rcvctrlpipe(serial->dev, 0), + VENDOR_READ_REQUEST, VENDOR_READ_REQUEST_TYPE, + PL2303_READ_TYPE_HX_STATUS, 0, buf, 1, 100); + if (res != 1) + type = TYPE_HXN; + } + spriv->type = &pl2303_type_data[type]; spriv->quirks = (unsigned long)usb_get_serial_data(serial); spriv->quirks |= spriv->type->quirks; usb_set_serial_data(serial, spriv); - pl2303_vendor_read(serial, 0x8484, buf); - pl2303_vendor_write(serial, 0x0404, 0); - pl2303_vendor_read(serial, 0x8484, buf); - pl2303_vendor_read(serial, 0x8383, buf); - pl2303_vendor_read(serial, 0x8484, buf); - pl2303_vendor_write(serial, 0x0404, 1); - pl2303_vendor_read(serial, 0x8484, buf); - pl2303_vendor_read(serial, 0x8383, buf); - pl2303_vendor_write(serial, 0, 1); - pl2303_vendor_write(serial, 1, 0); - if (spriv->quirks & PL2303_QUIRK_LEGACY) - pl2303_vendor_write(serial, 2, 0x24); - else - pl2303_vendor_write(serial, 2, 0x44); + if (type != TYPE_HXN) { + pl2303_vendor_read(serial, 0x8484, buf); + pl2303_vendor_write(serial, 0x0404, 0); + pl2303_vendor_read(serial, 0x8484, buf); + pl2303_vendor_read(serial, 0x8383, buf); + pl2303_vendor_read(serial, 0x8484, buf); + pl2303_vendor_write(serial, 0x0404, 1); + pl2303_vendor_read(serial, 0x8484, buf); + pl2303_vendor_read(serial, 0x8383, buf); + pl2303_vendor_write(serial, 0, 1); + pl2303_vendor_write(serial, 1, 0); + if (spriv->quirks & PL2303_QUIRK_LEGACY) + pl2303_vendor_write(serial, 2, 0x24); + else + pl2303_vendor_write(serial, 2, 0x44); + } kfree(buf); @@ -719,14 +774,31 @@ static void pl2303_set_termios(struct tty_struct *tty, } if (C_CRTSCTS(tty)) { - if (spriv->quirks & PL2303_QUIRK_LEGACY) + if (spriv->quirks & PL2303_QUIRK_LEGACY) { pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x40); - else + } else if (spriv->type == &pl2303_type_data[TYPE_HXN]) { + pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG, + PL2303_HXN_FLOWCTRL_MASK, + PL2303_HXN_FLOWCTRL_RTS_CTS); + } else { pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0x60); + } } else if (pl2303_enable_xonxoff(tty, spriv->type)) { - pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0); + if (spriv->type == &pl2303_type_data[TYPE_HXN]) { + pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG, + PL2303_HXN_FLOWCTRL_MASK, + PL2303_HXN_FLOWCTRL_XON_XOFF); + } else { + pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0xc0); + } } else { - pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0); + if (spriv->type == &pl2303_type_data[TYPE_HXN]) { + pl2303_update_reg(serial, PL2303_HXN_FLOWCTRL_REG, + PL2303_HXN_FLOWCTRL_MASK, + PL2303_HXN_FLOWCTRL_NONE); + } else { + pl2303_update_reg(serial, 0, PL2303_FLOWCTRL_MASK, 0); + } } kfree(buf); @@ -767,8 +839,14 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port) usb_clear_halt(serial->dev, port->read_urb->pipe); } else { /* reset upstream data pipes */ - pl2303_vendor_write(serial, 8, 0); - pl2303_vendor_write(serial, 9, 0); + if (spriv->type == &pl2303_type_data[TYPE_HXN]) { + pl2303_vendor_write(serial, PL2303_HXN_RESET_REG, + PL2303_HXN_RESET_UPSTREAM_PIPE | + PL2303_HXN_RESET_DOWNSTREAM_PIPE); + } else { + pl2303_vendor_write(serial, 8, 0); + pl2303_vendor_write(serial, 9, 0); + } } /* Setup termios */ diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index b0175f17d1a2..a019ea7e6e0e 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -9,6 +9,12 @@ #define PL2303_VENDOR_ID 0x067b #define PL2303_PRODUCT_ID 0x2303 #define PL2303_PRODUCT_ID_TB 0x2304 +#define PL2303_PRODUCT_ID_GC 0x23a3 +#define PL2303_PRODUCT_ID_GB 0x23b3 +#define PL2303_PRODUCT_ID_GT 0x23c3 +#define PL2303_PRODUCT_ID_GL 0x23d3 +#define PL2303_PRODUCT_ID_GE 0x23e3 +#define PL2303_PRODUCT_ID_GS 0x23f3 #define PL2303_PRODUCT_ID_RSAQ2 0x04bb #define PL2303_PRODUCT_ID_DCU11 0x1234 #define PL2303_PRODUCT_ID_PHAROS 0xaaa0 diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c index dd0ad67aa71e..ef23acc9b9ce 100644 --- a/drivers/usb/serial/ti_usb_3410_5052.c +++ b/drivers/usb/serial/ti_usb_3410_5052.c @@ -776,7 +776,6 @@ static void ti_close(struct usb_serial_port *port) struct ti_port *tport; int port_number; int status; - int do_unlock; unsigned long flags; tdev = usb_get_serial_data(port->serial); @@ -800,16 +799,13 @@ static void ti_close(struct usb_serial_port *port) "%s - cannot send close port command, %d\n" , __func__, status); - /* if mutex_lock is interrupted, continue anyway */ - do_unlock = !mutex_lock_interruptible(&tdev->td_open_close_lock); - --tport->tp_tdev->td_open_port_count; - if (tport->tp_tdev->td_open_port_count <= 0) { + mutex_lock(&tdev->td_open_close_lock); + --tdev->td_open_port_count; + if (tdev->td_open_port_count == 0) { /* last port is closed, shut down interrupt urb */ usb_kill_urb(port->serial->port[0]->interrupt_in_urb); - tport->tp_tdev->td_open_port_count = 0; } - if (do_unlock) - mutex_unlock(&tdev->td_open_close_lock); + mutex_unlock(&tdev->td_open_close_lock); } diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c index 79314d8c94a4..ca3bd58f2025 100644 --- a/drivers/usb/serial/whiteheat.c +++ b/drivers/usb/serial/whiteheat.c @@ -559,6 +559,10 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command, command_port = port->serial->port[COMMAND_PORT]; command_info = usb_get_serial_port_data(command_port); + + if (command_port->bulk_out_size < datasize + 1) + return -EIO; + mutex_lock(&command_info->mutex); command_info->command_finished = false; @@ -632,6 +636,7 @@ static void firm_setup_port(struct tty_struct *tty) struct device *dev = &port->dev; struct whiteheat_port_settings port_settings; unsigned int cflag = tty->termios.c_cflag; + speed_t baud; port_settings.port = port->port_number + 1; @@ -692,11 +697,13 @@ static void firm_setup_port(struct tty_struct *tty) dev_dbg(dev, "%s - XON = %2x, XOFF = %2x\n", __func__, port_settings.xon, port_settings.xoff); /* get the baud rate wanted */ - port_settings.baud = tty_get_baud_rate(tty); - dev_dbg(dev, "%s - baud rate = %d\n", __func__, port_settings.baud); + baud = tty_get_baud_rate(tty); + port_settings.baud = cpu_to_le32(baud); + dev_dbg(dev, "%s - baud rate = %u\n", __func__, baud); /* fixme: should set validated settings */ - tty_encode_baud_rate(tty, port_settings.baud, port_settings.baud); + tty_encode_baud_rate(tty, baud, baud); + /* handle any settings that aren't specified in the tty structure */ port_settings.lloop = 0; diff --git a/drivers/usb/serial/whiteheat.h b/drivers/usb/serial/whiteheat.h index 00398149cd8d..269e727a92f9 100644 --- a/drivers/usb/serial/whiteheat.h +++ b/drivers/usb/serial/whiteheat.h @@ -87,7 +87,7 @@ struct whiteheat_simple { struct whiteheat_port_settings { __u8 port; /* port number (1 to N) */ - __u32 baud; /* any value 7 - 460800, firmware calculates + __le32 baud; /* any value 7 - 460800, firmware calculates best fit; arrives little endian */ __u8 bits; /* 5, 6, 7, or 8 */ __u8 stop; /* 1 or 2, default 1 (2 = 1.5 if bits = 5) */ diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c index 6737fab94959..66a4dcbbb1fc 100644 --- a/drivers/usb/storage/scsiglue.c +++ b/drivers/usb/storage/scsiglue.c @@ -68,7 +68,6 @@ static const char* host_info(struct Scsi_Host *host) static int slave_alloc (struct scsi_device *sdev) { struct us_data *us = host_to_us(sdev->host); - int maxp; /* * Set the INQUIRY transfer length to 36. We don't use any of @@ -78,15 +77,6 @@ static int slave_alloc (struct scsi_device *sdev) sdev->inquiry_len = 36; /* - * USB has unusual scatter-gather requirements: the length of each - * scatterlist element except the last must be divisible by the - * Bulk maxpacket value. Fortunately this value is always a - * power of 2. Inform the block layer about this requirement. - */ - maxp = usb_maxpacket(us->pusb_dev, us->recv_bulk_pipe, 0); - blk_queue_virt_boundary(sdev->request_queue, maxp - 1); - - /* * Some host controllers may have alignment requirements. * We'll play it safe by requiring 512-byte alignment always. */ @@ -379,8 +369,8 @@ static int queuecommand_lck(struct scsi_cmnd *srb, /* check for state-transition errors */ if (us->srb != NULL) { - printk(KERN_ERR "usb-storage: Error in %s: us->srb = %p\n", - __func__, us->srb); + dev_err(&us->pusb_intf->dev, + "Error in %s: us->srb = %p\n", __func__, us->srb); return SCSI_MLQUEUE_HOST_BUSY; } diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index bf80d6f81f58..34538253f12c 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -789,30 +789,10 @@ static int uas_slave_alloc(struct scsi_device *sdev) { struct uas_dev_info *devinfo = (struct uas_dev_info *)sdev->host->hostdata; - int maxp; sdev->hostdata = devinfo; /* - * We have two requirements here. We must satisfy the requirements - * of the physical HC and the demands of the protocol, as we - * definitely want no additional memory allocation in this path - * ruling out using bounce buffers. - * - * For a transmission on USB to continue we must never send - * a package that is smaller than maxpacket. Hence the length of each - * scatterlist element except the last must be divisible by the - * Bulk maxpacket value. - * If the HC does not ensure that through SG, - * the upper layer must do that. We must assume nothing - * about the capabilities off the HC, so we use the most - * pessimistic requirement. - */ - - maxp = usb_maxpacket(devinfo->udev, devinfo->data_in_pipe, 0); - blk_queue_virt_boundary(sdev->request_queue, maxp - 1); - - /* * The protocol has no requirements on alignment in the strict sense. * Controllers may or may not have alignment restrictions. * As this is not exported, we use an extremely conservative guess. diff --git a/drivers/usb/typec/Kconfig b/drivers/usb/typec/Kconfig index 895e2418de53..b4f2aac7ae8a 100644 --- a/drivers/usb/typec/Kconfig +++ b/drivers/usb/typec/Kconfig @@ -50,6 +50,17 @@ source "drivers/usb/typec/tcpm/Kconfig" source "drivers/usb/typec/ucsi/Kconfig" +config TYPEC_HD3SS3220 + tristate "TI HD3SS3220 Type-C DRP Port controller driver" + depends on I2C + depends on USB_ROLE_SWITCH + help + Say Y or M here if your system has TI HD3SS3220 Type-C DRP Port + controller driver. + + If you choose to build this driver as a dynamically linked module, the + module will be called hd3ss3220.ko. + config TYPEC_TPS6598X tristate "TI TPS6598x USB Power Delivery controller driver" depends on I2C diff --git a/drivers/usb/typec/Makefile b/drivers/usb/typec/Makefile index 6696b7263d61..7753a5c3cd46 100644 --- a/drivers/usb/typec/Makefile +++ b/drivers/usb/typec/Makefile @@ -4,5 +4,6 @@ typec-y := class.o mux.o bus.o obj-$(CONFIG_TYPEC) += altmodes/ obj-$(CONFIG_TYPEC_TCPM) += tcpm/ obj-$(CONFIG_TYPEC_UCSI) += ucsi/ +obj-$(CONFIG_TYPEC_HD3SS3220) += hd3ss3220.o obj-$(CONFIG_TYPEC_TPS6598X) += tps6598x.o obj-$(CONFIG_TYPEC) += mux/ diff --git a/drivers/usb/typec/class.c b/drivers/usb/typec/class.c index 94a3eda62add..7ece6ca6e690 100644 --- a/drivers/usb/typec/class.c +++ b/drivers/usb/typec/class.c @@ -53,6 +53,7 @@ struct typec_port { struct typec_mux *mux; const struct typec_capability *cap; + const struct typec_operations *ops; }; #define to_typec_port(_dev_) container_of(_dev_, struct typec_port, dev) @@ -955,7 +956,7 @@ preferred_role_store(struct device *dev, struct device_attribute *attr, return -EOPNOTSUPP; } - if (!port->cap->try_role) { + if (!port->ops || !port->ops->try_role) { dev_dbg(dev, "Setting preferred role not supported\n"); return -EOPNOTSUPP; } @@ -968,7 +969,7 @@ preferred_role_store(struct device *dev, struct device_attribute *attr, return -EINVAL; } - ret = port->cap->try_role(port->cap, role); + ret = port->ops->try_role(port, role); if (ret) return ret; @@ -999,7 +1000,7 @@ static ssize_t data_role_store(struct device *dev, struct typec_port *port = to_typec_port(dev); int ret; - if (!port->cap->dr_set) { + if (!port->ops || !port->ops->dr_set) { dev_dbg(dev, "data role swapping not supported\n"); return -EOPNOTSUPP; } @@ -1014,7 +1015,7 @@ static ssize_t data_role_store(struct device *dev, goto unlock_and_ret; } - ret = port->cap->dr_set(port->cap, ret); + ret = port->ops->dr_set(port, ret); if (ret) goto unlock_and_ret; @@ -1049,7 +1050,7 @@ static ssize_t power_role_store(struct device *dev, return -EOPNOTSUPP; } - if (!port->cap->pr_set) { + if (!port->ops || !port->ops->pr_set) { dev_dbg(dev, "power role swapping not supported\n"); return -EOPNOTSUPP; } @@ -1071,7 +1072,7 @@ static ssize_t power_role_store(struct device *dev, goto unlock_and_ret; } - ret = port->cap->pr_set(port->cap, ret); + ret = port->ops->pr_set(port, ret); if (ret) goto unlock_and_ret; @@ -1102,7 +1103,8 @@ port_type_store(struct device *dev, struct device_attribute *attr, int ret; enum typec_port_type type; - if (!port->cap->port_type_set || port->cap->type != TYPEC_PORT_DRP) { + if (port->cap->type != TYPEC_PORT_DRP || + !port->ops || !port->ops->port_type_set) { dev_dbg(dev, "changing port type not supported\n"); return -EOPNOTSUPP; } @@ -1119,7 +1121,7 @@ port_type_store(struct device *dev, struct device_attribute *attr, goto unlock_and_ret; } - ret = port->cap->port_type_set(port->cap, type); + ret = port->ops->port_type_set(port, type); if (ret) goto unlock_and_ret; @@ -1175,7 +1177,7 @@ static ssize_t vconn_source_store(struct device *dev, return -EOPNOTSUPP; } - if (!port->cap->vconn_set) { + if (!port->ops || !port->ops->vconn_set) { dev_dbg(dev, "VCONN swapping not supported\n"); return -EOPNOTSUPP; } @@ -1184,7 +1186,7 @@ static ssize_t vconn_source_store(struct device *dev, if (ret) return ret; - ret = port->cap->vconn_set(port->cap, (enum typec_role)source); + ret = port->ops->vconn_set(port, (enum typec_role)source); if (ret) return ret; @@ -1278,6 +1280,7 @@ static void typec_release(struct device *dev) ida_destroy(&port->mode_ids); typec_switch_put(port->sw); typec_mux_put(port->mux); + kfree(port->cap); kfree(port); } @@ -1487,6 +1490,16 @@ EXPORT_SYMBOL_GPL(typec_set_mode); /* --------------------------------------- */ /** + * typec_get_drvdata - Return private driver data pointer + * @port: USB Type-C port + */ +void *typec_get_drvdata(struct typec_port *port) +{ + return dev_get_drvdata(&port->dev); +} +EXPORT_SYMBOL_GPL(typec_get_drvdata); + +/** * typec_port_register_altmode - Register USB Type-C Port Alternate Mode * @port: USB Type-C Port that supports the alternate mode * @desc: Description of the alternate mode @@ -1579,7 +1592,7 @@ struct typec_port *typec_register_port(struct device *parent, mutex_init(&port->port_type_lock); port->id = id; - port->cap = cap; + port->ops = cap->ops; port->port_type = cap->type; port->prefer_role = cap->prefer_role; @@ -1589,6 +1602,13 @@ struct typec_port *typec_register_port(struct device *parent, port->dev.fwnode = cap->fwnode; port->dev.type = &typec_port_dev_type; dev_set_name(&port->dev, "port%d", id); + dev_set_drvdata(&port->dev, cap->driver_data); + + port->cap = kmemdup(cap, sizeof(*cap), GFP_KERNEL); + if (!port->cap) { + put_device(&port->dev); + return ERR_PTR(-ENOMEM); + } port->sw = typec_switch_get(&port->dev); if (IS_ERR(port->sw)) { diff --git a/drivers/usb/typec/hd3ss3220.c b/drivers/usb/typec/hd3ss3220.c new file mode 100644 index 000000000000..323dfa8160ab --- /dev/null +++ b/drivers/usb/typec/hd3ss3220.c @@ -0,0 +1,269 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * TI HD3SS3220 Type-C DRP Port Controller Driver + * + * Copyright (C) 2019 Renesas Electronics Corp. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/usb/role.h> +#include <linux/irqreturn.h> +#include <linux/interrupt.h> +#include <linux/regmap.h> +#include <linux/slab.h> +#include <linux/usb/typec.h> +#include <linux/delay.h> + +#define HD3SS3220_REG_CN_STAT_CTRL 0x09 +#define HD3SS3220_REG_GEN_CTRL 0x0A +#define HD3SS3220_REG_DEV_REV 0xA0 + +/* Register HD3SS3220_REG_CN_STAT_CTRL*/ +#define HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK (BIT(7) | BIT(6)) +#define HD3SS3220_REG_CN_STAT_CTRL_AS_DFP BIT(6) +#define HD3SS3220_REG_CN_STAT_CTRL_AS_UFP BIT(7) +#define HD3SS3220_REG_CN_STAT_CTRL_TO_ACCESSORY (BIT(7) | BIT(6)) +#define HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS BIT(4) + +/* Register HD3SS3220_REG_GEN_CTRL*/ +#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK (BIT(2) | BIT(1)) +#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT 0x00 +#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK BIT(1) +#define HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC (BIT(2) | BIT(1)) + +struct hd3ss3220 { + struct device *dev; + struct regmap *regmap; + struct usb_role_switch *role_sw; + struct typec_port *port; +}; + +static int hd3ss3220_set_source_pref(struct hd3ss3220 *hd3ss3220, int src_pref) +{ + return regmap_update_bits(hd3ss3220->regmap, HD3SS3220_REG_GEN_CTRL, + HD3SS3220_REG_GEN_CTRL_SRC_PREF_MASK, + src_pref); +} + +static enum usb_role hd3ss3220_get_attached_state(struct hd3ss3220 *hd3ss3220) +{ + unsigned int reg_val; + enum usb_role attached_state; + int ret; + + ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, + ®_val); + if (ret < 0) + return ret; + + switch (reg_val & HD3SS3220_REG_CN_STAT_CTRL_ATTACHED_STATE_MASK) { + case HD3SS3220_REG_CN_STAT_CTRL_AS_DFP: + attached_state = USB_ROLE_HOST; + break; + case HD3SS3220_REG_CN_STAT_CTRL_AS_UFP: + attached_state = USB_ROLE_DEVICE; + break; + default: + attached_state = USB_ROLE_NONE; + break; + } + + return attached_state; +} + +static int hd3ss3220_dr_set(struct typec_port *port, enum typec_data_role role) +{ + struct hd3ss3220 *hd3ss3220 = typec_get_drvdata(port); + enum usb_role role_val; + int pref, ret = 0; + + if (role == TYPEC_HOST) { + role_val = USB_ROLE_HOST; + pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SRC; + } else { + role_val = USB_ROLE_DEVICE; + pref = HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_TRY_SNK; + } + + ret = hd3ss3220_set_source_pref(hd3ss3220, pref); + usleep_range(10, 100); + + usb_role_switch_set_role(hd3ss3220->role_sw, role_val); + typec_set_data_role(hd3ss3220->port, role); + + return ret; +} + +static const struct typec_operations hd3ss3220_ops = { + .dr_set = hd3ss3220_dr_set +}; + +static void hd3ss3220_set_role(struct hd3ss3220 *hd3ss3220) +{ + enum usb_role role_state = hd3ss3220_get_attached_state(hd3ss3220); + + usb_role_switch_set_role(hd3ss3220->role_sw, role_state); + if (role_state == USB_ROLE_NONE) + hd3ss3220_set_source_pref(hd3ss3220, + HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT); + + switch (role_state) { + case USB_ROLE_HOST: + typec_set_data_role(hd3ss3220->port, TYPEC_HOST); + break; + case USB_ROLE_DEVICE: + typec_set_data_role(hd3ss3220->port, TYPEC_DEVICE); + break; + default: + break; + } +} + +static irqreturn_t hd3ss3220_irq(struct hd3ss3220 *hd3ss3220) +{ + int err; + + hd3ss3220_set_role(hd3ss3220); + err = regmap_update_bits_base(hd3ss3220->regmap, + HD3SS3220_REG_CN_STAT_CTRL, + HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS, + HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS, + NULL, false, true); + if (err < 0) + return IRQ_NONE; + + return IRQ_HANDLED; +} + +static irqreturn_t hd3ss3220_irq_handler(int irq, void *data) +{ + struct i2c_client *client = to_i2c_client(data); + struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client); + + return hd3ss3220_irq(hd3ss3220); +} + +static const struct regmap_config config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x0A, +}; + +static int hd3ss3220_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct typec_capability typec_cap = { }; + struct hd3ss3220 *hd3ss3220; + struct fwnode_handle *connector; + int ret; + unsigned int data; + + hd3ss3220 = devm_kzalloc(&client->dev, sizeof(struct hd3ss3220), + GFP_KERNEL); + if (!hd3ss3220) + return -ENOMEM; + + i2c_set_clientdata(client, hd3ss3220); + + hd3ss3220->dev = &client->dev; + hd3ss3220->regmap = devm_regmap_init_i2c(client, &config); + if (IS_ERR(hd3ss3220->regmap)) + return PTR_ERR(hd3ss3220->regmap); + + hd3ss3220_set_source_pref(hd3ss3220, + HD3SS3220_REG_GEN_CTRL_SRC_PREF_DRP_DEFAULT); + connector = device_get_named_child_node(hd3ss3220->dev, "connector"); + if (!connector) + return -ENODEV; + + hd3ss3220->role_sw = fwnode_usb_role_switch_get(connector); + if (IS_ERR(hd3ss3220->role_sw)) { + ret = PTR_ERR(hd3ss3220->role_sw); + goto err_put_fwnode; + } + + typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; + typec_cap.driver_data = hd3ss3220; + typec_cap.type = TYPEC_PORT_DRP; + typec_cap.data = TYPEC_PORT_DRD; + typec_cap.ops = &hd3ss3220_ops; + typec_cap.fwnode = connector; + + hd3ss3220->port = typec_register_port(&client->dev, &typec_cap); + if (IS_ERR(hd3ss3220->port)) { + ret = PTR_ERR(hd3ss3220->port); + goto err_put_role; + } + + hd3ss3220_set_role(hd3ss3220); + ret = regmap_read(hd3ss3220->regmap, HD3SS3220_REG_CN_STAT_CTRL, &data); + if (ret < 0) + goto err_unreg_port; + + if (data & HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS) { + ret = regmap_write(hd3ss3220->regmap, + HD3SS3220_REG_CN_STAT_CTRL, + data | HD3SS3220_REG_CN_STAT_CTRL_INT_STATUS); + if (ret < 0) + goto err_unreg_port; + } + + if (client->irq > 0) { + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, + hd3ss3220_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "hd3ss3220", &client->dev); + if (ret) + goto err_unreg_port; + } + + ret = i2c_smbus_read_byte_data(client, HD3SS3220_REG_DEV_REV); + if (ret < 0) + goto err_unreg_port; + + fwnode_handle_put(connector); + + dev_info(&client->dev, "probed revision=0x%x\n", ret); + + return 0; +err_unreg_port: + typec_unregister_port(hd3ss3220->port); +err_put_role: + usb_role_switch_put(hd3ss3220->role_sw); +err_put_fwnode: + fwnode_handle_put(connector); + + return ret; +} + +static int hd3ss3220_remove(struct i2c_client *client) +{ + struct hd3ss3220 *hd3ss3220 = i2c_get_clientdata(client); + + typec_unregister_port(hd3ss3220->port); + usb_role_switch_put(hd3ss3220->role_sw); + + return 0; +} + +static const struct of_device_id dev_ids[] = { + { .compatible = "ti,hd3ss3220"}, + {} +}; +MODULE_DEVICE_TABLE(of, dev_ids); + +static struct i2c_driver hd3ss3220_driver = { + .driver = { + .name = "hd3ss3220", + .of_match_table = of_match_ptr(dev_ids), + }, + .probe = hd3ss3220_probe, + .remove = hd3ss3220_remove, +}; + +module_i2c_driver(hd3ss3220_driver); + +MODULE_AUTHOR("Biju Das <biju.das@bp.renesas.com>"); +MODULE_DESCRIPTION("TI HD3SS3220 DRP Port Controller Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index 5f61d9977a15..56fc356bc55c 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -380,9 +380,6 @@ static enum tcpm_state tcpm_default_state(struct tcpm_port *port) return SNK_UNATTACHED; else if (port->try_role == TYPEC_SOURCE) return SRC_UNATTACHED; - else if (port->tcpc->config && - port->tcpc->config->default_role == TYPEC_SINK) - return SNK_UNATTACHED; /* Fall through to return SRC_UNATTACHED */ } else if (port->port_type == TYPEC_PORT_SNK) { return SNK_UNATTACHED; @@ -390,12 +387,6 @@ static enum tcpm_state tcpm_default_state(struct tcpm_port *port) return SRC_UNATTACHED; } -static inline -struct tcpm_port *typec_cap_to_tcpm(const struct typec_capability *cap) -{ - return container_of(cap, struct tcpm_port, typec_caps); -} - static bool tcpm_port_is_disconnected(struct tcpm_port *port) { return (!port->attached && port->cc1 == TYPEC_CC_OPEN && @@ -3970,10 +3961,9 @@ void tcpm_pd_hard_reset(struct tcpm_port *port) } EXPORT_SYMBOL_GPL(tcpm_pd_hard_reset); -static int tcpm_dr_set(const struct typec_capability *cap, - enum typec_data_role data) +static int tcpm_dr_set(struct typec_port *p, enum typec_data_role data) { - struct tcpm_port *port = typec_cap_to_tcpm(cap); + struct tcpm_port *port = typec_get_drvdata(p); int ret; mutex_lock(&port->swap_lock); @@ -4038,10 +4028,9 @@ swap_unlock: return ret; } -static int tcpm_pr_set(const struct typec_capability *cap, - enum typec_role role) +static int tcpm_pr_set(struct typec_port *p, enum typec_role role) { - struct tcpm_port *port = typec_cap_to_tcpm(cap); + struct tcpm_port *port = typec_get_drvdata(p); int ret; mutex_lock(&port->swap_lock); @@ -4082,10 +4071,9 @@ swap_unlock: return ret; } -static int tcpm_vconn_set(const struct typec_capability *cap, - enum typec_role role) +static int tcpm_vconn_set(struct typec_port *p, enum typec_role role) { - struct tcpm_port *port = typec_cap_to_tcpm(cap); + struct tcpm_port *port = typec_get_drvdata(p); int ret; mutex_lock(&port->swap_lock); @@ -4122,16 +4110,16 @@ swap_unlock: return ret; } -static int tcpm_try_role(const struct typec_capability *cap, int role) +static int tcpm_try_role(struct typec_port *p, int role) { - struct tcpm_port *port = typec_cap_to_tcpm(cap); + struct tcpm_port *port = typec_get_drvdata(p); struct tcpc_dev *tcpc = port->tcpc; int ret = 0; mutex_lock(&port->lock); if (tcpc->try_role) ret = tcpc->try_role(tcpc, role); - if (!ret && (!tcpc->config || !tcpc->config->try_role_hw)) + if (!ret) port->try_role = role; port->try_src_count = 0; port->try_snk_count = 0; @@ -4331,10 +4319,9 @@ static void tcpm_init(struct tcpm_port *port) tcpm_set_state(port, PORT_RESET, 0); } -static int tcpm_port_type_set(const struct typec_capability *cap, - enum typec_port_type type) +static int tcpm_port_type_set(struct typec_port *p, enum typec_port_type type) { - struct tcpm_port *port = typec_cap_to_tcpm(cap); + struct tcpm_port *port = typec_get_drvdata(p); mutex_lock(&port->lock); if (type == port->port_type) @@ -4359,6 +4346,14 @@ port_unlock: return 0; } +static const struct typec_operations tcpm_ops = { + .try_role = tcpm_try_role, + .dr_set = tcpm_dr_set, + .pr_set = tcpm_pr_set, + .vconn_set = tcpm_vconn_set, + .port_type_set = tcpm_port_type_set +}; + void tcpm_tcpc_reset(struct tcpm_port *port) { mutex_lock(&port->lock); @@ -4368,34 +4363,6 @@ void tcpm_tcpc_reset(struct tcpm_port *port) } EXPORT_SYMBOL_GPL(tcpm_tcpc_reset); -static int tcpm_copy_pdos(u32 *dest_pdo, const u32 *src_pdo, - unsigned int nr_pdo) -{ - unsigned int i; - - if (nr_pdo > PDO_MAX_OBJECTS) - nr_pdo = PDO_MAX_OBJECTS; - - for (i = 0; i < nr_pdo; i++) - dest_pdo[i] = src_pdo[i]; - - return nr_pdo; -} - -static int tcpm_copy_vdos(u32 *dest_vdo, const u32 *src_vdo, - unsigned int nr_vdo) -{ - unsigned int i; - - if (nr_vdo > VDO_MAX_OBJECTS) - nr_vdo = VDO_MAX_OBJECTS; - - for (i = 0; i < nr_vdo; i++) - dest_vdo[i] = src_vdo[i]; - - return nr_vdo; -} - static int tcpm_fw_get_caps(struct tcpm_port *port, struct fwnode_handle *fwnode) { @@ -4698,35 +4665,10 @@ static int devm_tcpm_psy_register(struct tcpm_port *port) return PTR_ERR_OR_ZERO(port->psy); } -static int tcpm_copy_caps(struct tcpm_port *port, - const struct tcpc_config *tcfg) -{ - if (tcpm_validate_caps(port, tcfg->src_pdo, tcfg->nr_src_pdo) || - tcpm_validate_caps(port, tcfg->snk_pdo, tcfg->nr_snk_pdo)) - return -EINVAL; - - port->nr_src_pdo = tcpm_copy_pdos(port->src_pdo, tcfg->src_pdo, - tcfg->nr_src_pdo); - port->nr_snk_pdo = tcpm_copy_pdos(port->snk_pdo, tcfg->snk_pdo, - tcfg->nr_snk_pdo); - - port->nr_snk_vdo = tcpm_copy_vdos(port->snk_vdo, tcfg->snk_vdo, - tcfg->nr_snk_vdo); - - port->operating_snk_mw = tcfg->operating_snk_mw; - - port->typec_caps.prefer_role = tcfg->default_role; - port->typec_caps.type = tcfg->type; - port->typec_caps.data = tcfg->data; - port->self_powered = tcfg->self_powered; - - return 0; -} - struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) { struct tcpm_port *port; - int i, err; + int err; if (!dev || !tcpc || !tcpc->get_vbus || !tcpc->set_cc || !tcpc->get_cc || @@ -4759,24 +4701,16 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) tcpm_debugfs_init(port); err = tcpm_fw_get_caps(port, tcpc->fwnode); - if ((err < 0) && tcpc->config) - err = tcpm_copy_caps(port, tcpc->config); if (err < 0) goto out_destroy_wq; - if (!tcpc->config || !tcpc->config->try_role_hw) - port->try_role = port->typec_caps.prefer_role; - else - port->try_role = TYPEC_NO_PREFERRED_ROLE; + port->try_role = port->typec_caps.prefer_role; port->typec_caps.fwnode = tcpc->fwnode; port->typec_caps.revision = 0x0120; /* Type-C spec release 1.2 */ port->typec_caps.pd_revision = 0x0300; /* USB-PD spec release 3.0 */ - port->typec_caps.dr_set = tcpm_dr_set; - port->typec_caps.pr_set = tcpm_pr_set; - port->typec_caps.vconn_set = tcpm_vconn_set; - port->typec_caps.try_role = tcpm_try_role; - port->typec_caps.port_type_set = tcpm_port_type_set; + port->typec_caps.driver_data = port; + port->typec_caps.ops = &tcpm_ops; port->partner_desc.identity = &port->partner_ident; port->port_type = port->typec_caps.type; @@ -4797,29 +4731,6 @@ struct tcpm_port *tcpm_register_port(struct device *dev, struct tcpc_dev *tcpc) goto out_role_sw_put; } - if (tcpc->config && tcpc->config->alt_modes) { - const struct typec_altmode_desc *paltmode = tcpc->config->alt_modes; - - i = 0; - while (paltmode->svid && i < ARRAY_SIZE(port->port_altmode)) { - struct typec_altmode *alt; - - alt = typec_port_register_altmode(port->typec_port, - paltmode); - if (IS_ERR(alt)) { - tcpm_log(port, - "%s: failed to register port alternate mode 0x%x", - dev_name(dev), paltmode->svid); - break; - } - typec_altmode_set_drvdata(alt, port); - alt->ops = &tcpm_altmode_ops; - port->port_altmode[i] = alt; - i++; - paltmode++; - } - } - mutex_lock(&port->lock); tcpm_init(port); mutex_unlock(&port->lock); diff --git a/drivers/usb/typec/tps6598x.c b/drivers/usb/typec/tps6598x.c index a38d1409f15b..0698addd1185 100644 --- a/drivers/usb/typec/tps6598x.c +++ b/drivers/usb/typec/tps6598x.c @@ -94,7 +94,6 @@ struct tps6598x { struct typec_port *port; struct typec_partner *partner; struct usb_pd_identity partner_identity; - struct typec_capability typec_cap; }; /* @@ -307,11 +306,10 @@ static int tps6598x_exec_cmd(struct tps6598x *tps, const char *cmd, return 0; } -static int -tps6598x_dr_set(const struct typec_capability *cap, enum typec_data_role role) +static int tps6598x_dr_set(struct typec_port *port, enum typec_data_role role) { - struct tps6598x *tps = container_of(cap, struct tps6598x, typec_cap); const char *cmd = (role == TYPEC_DEVICE) ? "SWUF" : "SWDF"; + struct tps6598x *tps = typec_get_drvdata(port); u32 status; int ret; @@ -338,11 +336,10 @@ out_unlock: return ret; } -static int -tps6598x_pr_set(const struct typec_capability *cap, enum typec_role role) +static int tps6598x_pr_set(struct typec_port *port, enum typec_role role) { - struct tps6598x *tps = container_of(cap, struct tps6598x, typec_cap); const char *cmd = (role == TYPEC_SINK) ? "SWSk" : "SWSr"; + struct tps6598x *tps = typec_get_drvdata(port); u32 status; int ret; @@ -369,6 +366,11 @@ out_unlock: return ret; } +static const struct typec_operations tps6598x_ops = { + .dr_set = tps6598x_dr_set, + .pr_set = tps6598x_pr_set, +}; + static irqreturn_t tps6598x_interrupt(int irq, void *data) { struct tps6598x *tps = data; @@ -448,6 +450,7 @@ static const struct regmap_config tps6598x_regmap_config = { static int tps6598x_probe(struct i2c_client *client) { + struct typec_capability typec_cap = { }; struct tps6598x *tps; u32 status; u32 conf; @@ -492,40 +495,40 @@ static int tps6598x_probe(struct i2c_client *client) if (ret < 0) return ret; - tps->typec_cap.revision = USB_TYPEC_REV_1_2; - tps->typec_cap.pd_revision = 0x200; - tps->typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; - tps->typec_cap.pr_set = tps6598x_pr_set; - tps->typec_cap.dr_set = tps6598x_dr_set; + typec_cap.revision = USB_TYPEC_REV_1_2; + typec_cap.pd_revision = 0x200; + typec_cap.prefer_role = TYPEC_NO_PREFERRED_ROLE; + typec_cap.driver_data = tps; + typec_cap.ops = &tps6598x_ops; switch (TPS_SYSCONF_PORTINFO(conf)) { case TPS_PORTINFO_SINK_ACCESSORY: case TPS_PORTINFO_SINK: - tps->typec_cap.type = TYPEC_PORT_SNK; - tps->typec_cap.data = TYPEC_PORT_UFP; + typec_cap.type = TYPEC_PORT_SNK; + typec_cap.data = TYPEC_PORT_UFP; break; case TPS_PORTINFO_DRP_UFP_DRD: case TPS_PORTINFO_DRP_DFP_DRD: - tps->typec_cap.type = TYPEC_PORT_DRP; - tps->typec_cap.data = TYPEC_PORT_DRD; + typec_cap.type = TYPEC_PORT_DRP; + typec_cap.data = TYPEC_PORT_DRD; break; case TPS_PORTINFO_DRP_UFP: - tps->typec_cap.type = TYPEC_PORT_DRP; - tps->typec_cap.data = TYPEC_PORT_UFP; + typec_cap.type = TYPEC_PORT_DRP; + typec_cap.data = TYPEC_PORT_UFP; break; case TPS_PORTINFO_DRP_DFP: - tps->typec_cap.type = TYPEC_PORT_DRP; - tps->typec_cap.data = TYPEC_PORT_DFP; + typec_cap.type = TYPEC_PORT_DRP; + typec_cap.data = TYPEC_PORT_DFP; break; case TPS_PORTINFO_SOURCE: - tps->typec_cap.type = TYPEC_PORT_SRC; - tps->typec_cap.data = TYPEC_PORT_DFP; + typec_cap.type = TYPEC_PORT_SRC; + typec_cap.data = TYPEC_PORT_DFP; break; default: return -ENODEV; } - tps->port = typec_register_port(&client->dev, &tps->typec_cap); + tps->port = typec_register_port(&client->dev, &typec_cap); if (IS_ERR(tps->port)) return PTR_ERR(tps->port); diff --git a/drivers/usb/typec/ucsi/displayport.c b/drivers/usb/typec/ucsi/displayport.c index d99700cb4dca..d4d5189edfb8 100644 --- a/drivers/usb/typec/ucsi/displayport.c +++ b/drivers/usb/typec/ucsi/displayport.c @@ -48,7 +48,8 @@ struct ucsi_dp { static int ucsi_displayport_enter(struct typec_altmode *alt) { struct ucsi_dp *dp = typec_altmode_get_drvdata(alt); - struct ucsi_control ctrl; + struct ucsi *ucsi = dp->con->ucsi; + u64 command; u8 cur = 0; int ret; @@ -59,25 +60,21 @@ static int ucsi_displayport_enter(struct typec_altmode *alt) dev_warn(&p->dev, "firmware doesn't support alternate mode overriding\n"); - mutex_unlock(&dp->con->lock); - return -EOPNOTSUPP; + ret = -EOPNOTSUPP; + goto err_unlock; } - UCSI_CMD_GET_CURRENT_CAM(ctrl, dp->con->num); - ret = ucsi_send_command(dp->con->ucsi, &ctrl, &cur, sizeof(cur)); + command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(dp->con->num); + ret = ucsi_send_command(ucsi, command, &cur, sizeof(cur)); if (ret < 0) { - if (dp->con->ucsi->ppm->data->version > 0x0100) { - mutex_unlock(&dp->con->lock); - return ret; - } + if (ucsi->version > 0x0100) + goto err_unlock; cur = 0xff; } if (cur != 0xff) { - mutex_unlock(&dp->con->lock); - if (dp->con->port_altmode[cur] == alt) - return 0; - return -EBUSY; + ret = dp->con->port_altmode[cur] == alt ? 0 : -EBUSY; + goto err_unlock; } /* @@ -94,16 +91,17 @@ static int ucsi_displayport_enter(struct typec_altmode *alt) dp->vdo_size = 1; schedule_work(&dp->work); - + ret = 0; +err_unlock: mutex_unlock(&dp->con->lock); - return 0; + return ret; } static int ucsi_displayport_exit(struct typec_altmode *alt) { struct ucsi_dp *dp = typec_altmode_get_drvdata(alt); - struct ucsi_control ctrl; + u64 command; int ret = 0; mutex_lock(&dp->con->lock); @@ -117,8 +115,8 @@ static int ucsi_displayport_exit(struct typec_altmode *alt) goto out_unlock; } - ctrl.raw_cmd = UCSI_CMD_SET_NEW_CAM(dp->con->num, 0, dp->offset, 0); - ret = ucsi_send_command(dp->con->ucsi, &ctrl, NULL, 0); + command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 0, dp->offset, 0); + ret = ucsi_send_command(dp->con->ucsi, command, NULL, 0); if (ret < 0) goto out_unlock; @@ -172,14 +170,14 @@ static int ucsi_displayport_status_update(struct ucsi_dp *dp) static int ucsi_displayport_configure(struct ucsi_dp *dp) { u32 pins = DP_CONF_GET_PIN_ASSIGN(dp->data.conf); - struct ucsi_control ctrl; + u64 command; if (!dp->override) return 0; - ctrl.raw_cmd = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins); + command = UCSI_CMD_SET_NEW_CAM(dp->con->num, 1, dp->offset, pins); - return ucsi_send_command(dp->con->ucsi, &ctrl, NULL, 0); + return ucsi_send_command(dp->con->ucsi, command, NULL, 0); } static int ucsi_displayport_vdm(struct typec_altmode *alt, diff --git a/drivers/usb/typec/ucsi/trace.c b/drivers/usb/typec/ucsi/trace.c index 1dabafb74320..48ad1dc1b1b2 100644 --- a/drivers/usb/typec/ucsi/trace.c +++ b/drivers/usb/typec/ucsi/trace.c @@ -33,17 +33,6 @@ const char *ucsi_cmd_str(u64 raw_cmd) return ucsi_cmd_strs[(cmd >= ARRAY_SIZE(ucsi_cmd_strs)) ? 0 : cmd]; } -static const char * const ucsi_ack_strs[] = { - [0] = "", - [UCSI_ACK_EVENT] = "event", - [UCSI_ACK_CMD] = "command", -}; - -const char *ucsi_ack_str(u8 ack) -{ - return ucsi_ack_strs[(ack >= ARRAY_SIZE(ucsi_ack_strs)) ? 0 : ack]; -} - const char *ucsi_cci_str(u32 cci) { if (cci & GENMASK(7, 0)) { diff --git a/drivers/usb/typec/ucsi/trace.h b/drivers/usb/typec/ucsi/trace.h index 783ec9c72055..a0d3a934d3d9 100644 --- a/drivers/usb/typec/ucsi/trace.h +++ b/drivers/usb/typec/ucsi/trace.h @@ -10,54 +10,18 @@ #include <linux/usb/typec_altmode.h> const char *ucsi_cmd_str(u64 raw_cmd); -const char *ucsi_ack_str(u8 ack); const char *ucsi_cci_str(u32 cci); const char *ucsi_recipient_str(u8 recipient); -DECLARE_EVENT_CLASS(ucsi_log_ack, - TP_PROTO(u8 ack), - TP_ARGS(ack), - TP_STRUCT__entry( - __field(u8, ack) - ), - TP_fast_assign( - __entry->ack = ack; - ), - TP_printk("ACK %s", ucsi_ack_str(__entry->ack)) -); - -DEFINE_EVENT(ucsi_log_ack, ucsi_ack, - TP_PROTO(u8 ack), - TP_ARGS(ack) -); - -DECLARE_EVENT_CLASS(ucsi_log_control, - TP_PROTO(struct ucsi_control *ctrl), - TP_ARGS(ctrl), - TP_STRUCT__entry( - __field(u64, ctrl) - ), - TP_fast_assign( - __entry->ctrl = ctrl->raw_cmd; - ), - TP_printk("control=%08llx (%s)", __entry->ctrl, - ucsi_cmd_str(__entry->ctrl)) -); - -DEFINE_EVENT(ucsi_log_control, ucsi_command, - TP_PROTO(struct ucsi_control *ctrl), - TP_ARGS(ctrl) -); - DECLARE_EVENT_CLASS(ucsi_log_command, - TP_PROTO(struct ucsi_control *ctrl, int ret), - TP_ARGS(ctrl, ret), + TP_PROTO(u64 command, int ret), + TP_ARGS(command, ret), TP_STRUCT__entry( __field(u64, ctrl) __field(int, ret) ), TP_fast_assign( - __entry->ctrl = ctrl->raw_cmd; + __entry->ctrl = command; __entry->ret = ret; ), TP_printk("%s -> %s (err=%d)", ucsi_cmd_str(__entry->ctrl), @@ -66,30 +30,13 @@ DECLARE_EVENT_CLASS(ucsi_log_command, ); DEFINE_EVENT(ucsi_log_command, ucsi_run_command, - TP_PROTO(struct ucsi_control *ctrl, int ret), - TP_ARGS(ctrl, ret) + TP_PROTO(u64 command, int ret), + TP_ARGS(command, ret) ); DEFINE_EVENT(ucsi_log_command, ucsi_reset_ppm, - TP_PROTO(struct ucsi_control *ctrl, int ret), - TP_ARGS(ctrl, ret) -); - -DECLARE_EVENT_CLASS(ucsi_log_cci, - TP_PROTO(u32 cci), - TP_ARGS(cci), - TP_STRUCT__entry( - __field(u32, cci) - ), - TP_fast_assign( - __entry->cci = cci; - ), - TP_printk("CCI=%08x %s", __entry->cci, ucsi_cci_str(__entry->cci)) -); - -DEFINE_EVENT(ucsi_log_cci, ucsi_notify, - TP_PROTO(u32 cci), - TP_ARGS(cci) + TP_PROTO(u64 command, int ret), + TP_ARGS(command, ret) ); DECLARE_EVENT_CLASS(ucsi_log_connector_status, @@ -109,13 +56,13 @@ DECLARE_EVENT_CLASS(ucsi_log_connector_status, TP_fast_assign( __entry->port = port - 1; __entry->change = status->change; - __entry->opmode = status->pwr_op_mode; - __entry->connected = status->connected; - __entry->pwr_dir = status->pwr_dir; - __entry->partner_flags = status->partner_flags; - __entry->partner_type = status->partner_type; + __entry->opmode = UCSI_CONSTAT_PWR_OPMODE(status->flags); + __entry->connected = !!(status->flags & UCSI_CONSTAT_CONNECTED); + __entry->pwr_dir = !!(status->flags & UCSI_CONSTAT_PWR_DIR); + __entry->partner_flags = UCSI_CONSTAT_PARTNER_FLAGS(status->flags); + __entry->partner_type = UCSI_CONSTAT_PARTNER_TYPE(status->flags); __entry->request_data_obj = status->request_data_obj; - __entry->bc_status = status->bc_status; + __entry->bc_status = UCSI_CONSTAT_BC_STATUS(status->pwr_status); ), TP_printk("port%d status: change=%04x, opmode=%x, connected=%d, " "sourcing=%d, partner_flags=%x, partner_type=%x, " diff --git a/drivers/usb/typec/ucsi/ucsi.c b/drivers/usb/typec/ucsi/ucsi.c index ba288b964dc8..4459bc68aa33 100644 --- a/drivers/usb/typec/ucsi/ucsi.c +++ b/drivers/usb/typec/ucsi/ucsi.c @@ -17,9 +17,6 @@ #include "ucsi.h" #include "trace.h" -#define to_ucsi_connector(_cap_) container_of(_cap_, struct ucsi_connector, \ - typec_cap) - /* * UCSI_TIMEOUT_MS - PPM communication timeout * @@ -39,169 +36,148 @@ */ #define UCSI_SWAP_TIMEOUT_MS 5000 -static inline int ucsi_sync(struct ucsi *ucsi) +static int ucsi_acknowledge_command(struct ucsi *ucsi) { - if (ucsi->ppm && ucsi->ppm->sync) - return ucsi->ppm->sync(ucsi->ppm); - return 0; + u64 ctrl; + + ctrl = UCSI_ACK_CC_CI; + ctrl |= UCSI_ACK_COMMAND_COMPLETE; + + return ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl)); +} + +static int ucsi_acknowledge_connector_change(struct ucsi *ucsi) +{ + u64 ctrl; + + ctrl = UCSI_ACK_CC_CI; + ctrl |= UCSI_ACK_CONNECTOR_CHANGE; + + return ucsi->ops->async_write(ucsi, UCSI_CONTROL, &ctrl, sizeof(ctrl)); } -static int ucsi_command(struct ucsi *ucsi, struct ucsi_control *ctrl) +static int ucsi_exec_command(struct ucsi *ucsi, u64 command); + +static int ucsi_read_error(struct ucsi *ucsi) { + u16 error; int ret; - trace_ucsi_command(ctrl); + /* Acknowlege the command that failed */ + ret = ucsi_acknowledge_command(ucsi); + if (ret) + return ret; - set_bit(COMMAND_PENDING, &ucsi->flags); + ret = ucsi_exec_command(ucsi, UCSI_GET_ERROR_STATUS); + if (ret < 0) + return ret; - ret = ucsi->ppm->cmd(ucsi->ppm, ctrl); + ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, &error, sizeof(error)); if (ret) - goto err_clear_flag; + return ret; - if (!wait_for_completion_timeout(&ucsi->complete, - msecs_to_jiffies(UCSI_TIMEOUT_MS))) { - dev_warn(ucsi->dev, "PPM NOT RESPONDING\n"); - ret = -ETIMEDOUT; + switch (error) { + case UCSI_ERROR_INCOMPATIBLE_PARTNER: + return -EOPNOTSUPP; + case UCSI_ERROR_CC_COMMUNICATION_ERR: + return -ECOMM; + case UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL: + return -EPROTO; + case UCSI_ERROR_DEAD_BATTERY: + dev_warn(ucsi->dev, "Dead battery condition!\n"); + return -EPERM; + case UCSI_ERROR_INVALID_CON_NUM: + case UCSI_ERROR_UNREGONIZED_CMD: + case UCSI_ERROR_INVALID_CMD_ARGUMENT: + dev_err(ucsi->dev, "possible UCSI driver bug %u\n", error); + return -EINVAL; + case UCSI_ERROR_OVERCURRENT: + dev_warn(ucsi->dev, "Overcurrent condition\n"); + break; + case UCSI_ERROR_PARTNER_REJECTED_SWAP: + dev_warn(ucsi->dev, "Partner rejected swap\n"); + break; + case UCSI_ERROR_HARD_RESET: + dev_warn(ucsi->dev, "Hard reset occurred\n"); + break; + case UCSI_ERROR_PPM_POLICY_CONFLICT: + dev_warn(ucsi->dev, "PPM Policy conflict\n"); + break; + case UCSI_ERROR_SWAP_REJECTED: + dev_warn(ucsi->dev, "Swap rejected\n"); + break; + case UCSI_ERROR_UNDEFINED: + default: + dev_err(ucsi->dev, "unknown error %u\n", error); + break; } -err_clear_flag: - clear_bit(COMMAND_PENDING, &ucsi->flags); - - return ret; + return -EIO; } -static int ucsi_ack(struct ucsi *ucsi, u8 ack) +static int ucsi_exec_command(struct ucsi *ucsi, u64 cmd) { - struct ucsi_control ctrl; + u32 cci; int ret; - trace_ucsi_ack(ack); - - set_bit(ACK_PENDING, &ucsi->flags); + ret = ucsi->ops->sync_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); + if (ret) + return ret; - UCSI_CMD_ACK(ctrl, ack); - ret = ucsi->ppm->cmd(ucsi->ppm, &ctrl); + ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); if (ret) - goto out_clear_bit; + return ret; - /* Waiting for ACK with ACK CMD, but not with EVENT for now */ - if (ack == UCSI_ACK_EVENT) - goto out_clear_bit; + if (cci & UCSI_CCI_BUSY) + return -EBUSY; - if (!wait_for_completion_timeout(&ucsi->complete, - msecs_to_jiffies(UCSI_TIMEOUT_MS))) - ret = -ETIMEDOUT; + if (!(cci & UCSI_CCI_COMMAND_COMPLETE)) + return -EIO; -out_clear_bit: - clear_bit(ACK_PENDING, &ucsi->flags); + if (cci & UCSI_CCI_NOT_SUPPORTED) + return -EOPNOTSUPP; - if (ret) - dev_err(ucsi->dev, "%s: failed\n", __func__); + if (cci & UCSI_CCI_ERROR) { + if (cmd == UCSI_GET_ERROR_STATUS) + return -EIO; + return ucsi_read_error(ucsi); + } - return ret; + return UCSI_CCI_LENGTH(cci); } -static int ucsi_run_command(struct ucsi *ucsi, struct ucsi_control *ctrl, +static int ucsi_run_command(struct ucsi *ucsi, u64 command, void *data, size_t size) { - struct ucsi_control _ctrl; - u8 data_length; - u16 error; + u8 length; int ret; - ret = ucsi_command(ucsi, ctrl); - if (ret) - goto err; - - switch (ucsi->status) { - case UCSI_IDLE: - ret = ucsi_sync(ucsi); - if (ret) - dev_warn(ucsi->dev, "%s: sync failed\n", __func__); - - if (data) - memcpy(data, ucsi->ppm->data->message_in, size); - - data_length = ucsi->ppm->data->cci.data_length; - - ret = ucsi_ack(ucsi, UCSI_ACK_CMD); - if (!ret) - ret = data_length; - break; - case UCSI_BUSY: - /* The caller decides whether to cancel or not */ - ret = -EBUSY; - break; - case UCSI_ERROR: - ret = ucsi_ack(ucsi, UCSI_ACK_CMD); - if (ret) - break; - - _ctrl.raw_cmd = 0; - _ctrl.cmd.cmd = UCSI_GET_ERROR_STATUS; - ret = ucsi_command(ucsi, &_ctrl); - if (ret) { - dev_err(ucsi->dev, "reading error failed!\n"); - break; - } + ret = ucsi_exec_command(ucsi, command); + if (ret < 0) + return ret; - memcpy(&error, ucsi->ppm->data->message_in, sizeof(error)); + length = ret; - /* Something has really gone wrong */ - if (WARN_ON(ucsi->status == UCSI_ERROR)) { - ret = -ENODEV; - break; - } - - ret = ucsi_ack(ucsi, UCSI_ACK_CMD); + if (data) { + ret = ucsi->ops->read(ucsi, UCSI_MESSAGE_IN, data, size); if (ret) - break; - - switch (error) { - case UCSI_ERROR_INCOMPATIBLE_PARTNER: - ret = -EOPNOTSUPP; - break; - case UCSI_ERROR_CC_COMMUNICATION_ERR: - ret = -ECOMM; - break; - case UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL: - ret = -EPROTO; - break; - case UCSI_ERROR_DEAD_BATTERY: - dev_warn(ucsi->dev, "Dead battery condition!\n"); - ret = -EPERM; - break; - /* The following mean a bug in this driver */ - case UCSI_ERROR_INVALID_CON_NUM: - case UCSI_ERROR_UNREGONIZED_CMD: - case UCSI_ERROR_INVALID_CMD_ARGUMENT: - dev_warn(ucsi->dev, - "%s: possible UCSI driver bug - error 0x%x\n", - __func__, error); - ret = -EINVAL; - break; - default: - dev_warn(ucsi->dev, - "%s: error without status\n", __func__); - ret = -EIO; - break; - } - break; + return ret; } -err: - trace_ucsi_run_command(ctrl, ret); + ret = ucsi_acknowledge_command(ucsi); + if (ret) + return ret; - return ret; + return length; } -int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl, +int ucsi_send_command(struct ucsi *ucsi, u64 command, void *retval, size_t size) { int ret; mutex_lock(&ucsi->ppm_lock); - ret = ucsi_run_command(ucsi, ctrl, retval, size); + ret = ucsi_run_command(ucsi, command, retval, size); mutex_unlock(&ucsi->ppm_lock); return ret; @@ -210,11 +186,12 @@ EXPORT_SYMBOL_GPL(ucsi_send_command); int ucsi_resume(struct ucsi *ucsi) { - struct ucsi_control ctrl; + u64 command; /* Restore UCSI notification enable mask after system resume */ - UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL); - return ucsi_send_command(ucsi, &ctrl, NULL, 0); + command = UCSI_SET_NOTIFICATION_ENABLE | UCSI_ENABLE_NTFY_ALL; + + return ucsi_send_command(ucsi, command, NULL, 0); } EXPORT_SYMBOL_GPL(ucsi_resume); /* -------------------------------------------------------------------------- */ @@ -222,15 +199,15 @@ EXPORT_SYMBOL_GPL(ucsi_resume); void ucsi_altmode_update_active(struct ucsi_connector *con) { const struct typec_altmode *altmode = NULL; - struct ucsi_control ctrl; + u64 command; int ret; u8 cur; int i; - UCSI_CMD_GET_CURRENT_CAM(ctrl, con->num); - ret = ucsi_run_command(con->ucsi, &ctrl, &cur, sizeof(cur)); + command = UCSI_GET_CURRENT_CAM | UCSI_CONNECTOR_NUMBER(con->num); + ret = ucsi_run_command(con->ucsi, command, &cur, sizeof(cur)); if (ret < 0) { - if (con->ucsi->ppm->data->version > 0x0100) { + if (con->ucsi->version > 0x0100) { dev_err(con->ucsi->dev, "GET_CURRENT_CAM command failed\n"); return; @@ -346,7 +323,7 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient) int max_altmodes = UCSI_MAX_ALTMODES; struct typec_altmode_desc desc; struct ucsi_altmode alt[2]; - struct ucsi_control ctrl; + u64 command; int num = 1; int ret; int len; @@ -364,8 +341,11 @@ static int ucsi_register_altmodes(struct ucsi_connector *con, u8 recipient) for (i = 0; i < max_altmodes;) { memset(alt, 0, sizeof(alt)); - UCSI_CMD_GET_ALTERNATE_MODES(ctrl, recipient, con->num, i, 1); - len = ucsi_run_command(con->ucsi, &ctrl, alt, sizeof(alt)); + command = UCSI_GET_ALTERNATE_MODES; + command |= UCSI_GET_ALTMODE_RECIPIENT(recipient); + command |= UCSI_GET_ALTMODE_CONNECTOR_NUMBER(con->num); + command |= UCSI_GET_ALTMODE_OFFSET(i); + len = ucsi_run_command(con->ucsi, command, alt, sizeof(alt)); if (len <= 0) return len; @@ -427,7 +407,7 @@ static void ucsi_unregister_altmodes(struct ucsi_connector *con, u8 recipient) static void ucsi_pwr_opmode_change(struct ucsi_connector *con) { - switch (con->status.pwr_op_mode) { + switch (UCSI_CONSTAT_PWR_OPMODE(con->status.flags)) { case UCSI_CONSTAT_PWR_OPMODE_PD: typec_set_pwr_opmode(con->port, TYPEC_PWR_MODE_PD); break; @@ -445,6 +425,7 @@ static void ucsi_pwr_opmode_change(struct ucsi_connector *con) static int ucsi_register_partner(struct ucsi_connector *con) { + u8 pwr_opmode = UCSI_CONSTAT_PWR_OPMODE(con->status.flags); struct typec_partner_desc desc; struct typec_partner *partner; @@ -453,7 +434,7 @@ static int ucsi_register_partner(struct ucsi_connector *con) memset(&desc, 0, sizeof(desc)); - switch (con->status.partner_type) { + switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_DEBUG: desc.accessory = TYPEC_ACCESSORY_DEBUG; break; @@ -464,7 +445,7 @@ static int ucsi_register_partner(struct ucsi_connector *con) break; } - desc.usb_pd = con->status.pwr_op_mode == UCSI_CONSTAT_PWR_OPMODE_PD; + desc.usb_pd = pwr_opmode == UCSI_CONSTAT_PWR_OPMODE_PD; partner = typec_register_partner(con->port, &desc); if (IS_ERR(partner)) { @@ -496,7 +477,7 @@ static void ucsi_partner_change(struct ucsi_connector *con) if (!con->partner) return; - switch (con->status.partner_type) { + switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: typec_set_data_role(con->port, TYPEC_HOST); break; @@ -521,29 +502,33 @@ static void ucsi_partner_change(struct ucsi_connector *con) ucsi_altmode_update_active(con); } -static void ucsi_connector_change(struct work_struct *work) +static void ucsi_handle_connector_change(struct work_struct *work) { struct ucsi_connector *con = container_of(work, struct ucsi_connector, work); struct ucsi *ucsi = con->ucsi; - struct ucsi_control ctrl; + enum typec_role role; + u64 command; int ret; mutex_lock(&con->lock); - UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num); - ret = ucsi_send_command(ucsi, &ctrl, &con->status, sizeof(con->status)); + command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); + ret = ucsi_send_command(ucsi, command, &con->status, + sizeof(con->status)); if (ret < 0) { dev_err(ucsi->dev, "%s: GET_CONNECTOR_STATUS failed (%d)\n", __func__, ret); goto out_unlock; } + role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); + if (con->status.change & UCSI_CONSTAT_POWER_OPMODE_CHANGE) ucsi_pwr_opmode_change(con); if (con->status.change & UCSI_CONSTAT_POWER_DIR_CHANGE) { - typec_set_pwr_role(con->port, con->status.pwr_dir); + typec_set_pwr_role(con->port, role); /* Complete pending power role swap */ if (!completion_done(&con->complete)) @@ -551,9 +536,9 @@ static void ucsi_connector_change(struct work_struct *work) } if (con->status.change & UCSI_CONSTAT_CONNECT_CHANGE) { - typec_set_pwr_role(con->port, con->status.pwr_dir); + typec_set_pwr_role(con->port, role); - switch (con->status.partner_type) { + switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: typec_set_data_role(con->port, TYPEC_HOST); break; @@ -564,7 +549,7 @@ static void ucsi_connector_change(struct work_struct *work) break; } - if (con->status.connected) + if (con->status.flags & UCSI_CONSTAT_CONNECTED) ucsi_register_partner(con); else ucsi_unregister_partner(con); @@ -576,14 +561,15 @@ static void ucsi_connector_change(struct work_struct *work) * Running GET_CAM_SUPPORTED command just to make sure the PPM * does not get stuck in case it assumes we do so. */ - UCSI_CMD_GET_CAM_SUPPORTED(ctrl, con->num); - ucsi_run_command(con->ucsi, &ctrl, NULL, 0); + command = UCSI_GET_CAM_SUPPORTED; + command |= UCSI_CONNECTOR_NUMBER(con->num); + ucsi_run_command(con->ucsi, command, NULL, 0); } if (con->status.change & UCSI_CONSTAT_PARTNER_CHANGE) ucsi_partner_change(con); - ret = ucsi_ack(ucsi, UCSI_ACK_EVENT); + ret = ucsi_acknowledge_connector_change(ucsi); if (ret) dev_err(ucsi->dev, "%s: ACK failed (%d)", __func__, ret); @@ -595,117 +581,83 @@ out_unlock: } /** - * ucsi_notify - PPM notification handler - * @ucsi: Source UCSI Interface for the notifications - * - * Handle notifications from PPM of @ucsi. + * ucsi_connector_change - Process Connector Change Event + * @ucsi: UCSI Interface + * @num: Connector number */ -void ucsi_notify(struct ucsi *ucsi) +void ucsi_connector_change(struct ucsi *ucsi, u8 num) { - struct ucsi_cci *cci; - - /* There is no requirement to sync here, but no harm either. */ - ucsi_sync(ucsi); - - cci = &ucsi->ppm->data->cci; - - if (cci->error) - ucsi->status = UCSI_ERROR; - else if (cci->busy) - ucsi->status = UCSI_BUSY; - else - ucsi->status = UCSI_IDLE; + struct ucsi_connector *con = &ucsi->connector[num - 1]; - if (cci->cmd_complete && test_bit(COMMAND_PENDING, &ucsi->flags)) { - complete(&ucsi->complete); - } else if (cci->ack_complete && test_bit(ACK_PENDING, &ucsi->flags)) { - complete(&ucsi->complete); - } else if (cci->connector_change) { - struct ucsi_connector *con; - - con = &ucsi->connector[cci->connector_change - 1]; - - if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags)) - schedule_work(&con->work); - } - - trace_ucsi_notify(ucsi->ppm->data->raw_cci); + if (!test_and_set_bit(EVENT_PENDING, &ucsi->flags)) + schedule_work(&con->work); } -EXPORT_SYMBOL_GPL(ucsi_notify); +EXPORT_SYMBOL_GPL(ucsi_connector_change); /* -------------------------------------------------------------------------- */ static int ucsi_reset_connector(struct ucsi_connector *con, bool hard) { - struct ucsi_control ctrl; + u64 command; - UCSI_CMD_CONNECTOR_RESET(ctrl, con, hard); + command = UCSI_CONNECTOR_RESET | UCSI_CONNECTOR_NUMBER(con->num); + command |= hard ? UCSI_CONNECTOR_RESET_HARD : 0; - return ucsi_send_command(con->ucsi, &ctrl, NULL, 0); + return ucsi_send_command(con->ucsi, command, NULL, 0); } static int ucsi_reset_ppm(struct ucsi *ucsi) { - struct ucsi_control ctrl; + u64 command = UCSI_PPM_RESET; unsigned long tmo; + u32 cci; int ret; - ctrl.raw_cmd = 0; - ctrl.cmd.cmd = UCSI_PPM_RESET; - trace_ucsi_command(&ctrl); - ret = ucsi->ppm->cmd(ucsi->ppm, &ctrl); - if (ret) - goto err; + ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, &command, + sizeof(command)); + if (ret < 0) + return ret; tmo = jiffies + msecs_to_jiffies(UCSI_TIMEOUT_MS); do { - /* Here sync is critical. */ - ret = ucsi_sync(ucsi); - if (ret) - goto err; + if (time_is_before_jiffies(tmo)) + return -ETIMEDOUT; - if (ucsi->ppm->data->cci.reset_complete) - break; + ret = ucsi->ops->read(ucsi, UCSI_CCI, &cci, sizeof(cci)); + if (ret) + return ret; /* If the PPM is still doing something else, reset it again. */ - if (ucsi->ppm->data->raw_cci) { - dev_warn_ratelimited(ucsi->dev, - "Failed to reset PPM! Trying again..\n"); - - trace_ucsi_command(&ctrl); - ret = ucsi->ppm->cmd(ucsi->ppm, &ctrl); - if (ret) - goto err; + if (cci & ~UCSI_CCI_RESET_COMPLETE) { + ret = ucsi->ops->async_write(ucsi, UCSI_CONTROL, + &command, + sizeof(command)); + if (ret < 0) + return ret; } - /* Letting the PPM settle down. */ msleep(20); + } while (!(cci & UCSI_CCI_RESET_COMPLETE)); - ret = -ETIMEDOUT; - } while (time_is_after_jiffies(tmo)); - -err: - trace_ucsi_reset_ppm(&ctrl, ret); - - return ret; + return 0; } -static int ucsi_role_cmd(struct ucsi_connector *con, struct ucsi_control *ctrl) +static int ucsi_role_cmd(struct ucsi_connector *con, u64 command) { int ret; - ret = ucsi_send_command(con->ucsi, ctrl, NULL, 0); + ret = ucsi_send_command(con->ucsi, command, NULL, 0); if (ret == -ETIMEDOUT) { - struct ucsi_control c; + u64 c; /* PPM most likely stopped responding. Resetting everything. */ mutex_lock(&con->ucsi->ppm_lock); ucsi_reset_ppm(con->ucsi); mutex_unlock(&con->ucsi->ppm_lock); - UCSI_CMD_SET_NTFY_ENABLE(c, UCSI_ENABLE_NTFY_ALL); - ucsi_send_command(con->ucsi, &c, NULL, 0); + c = UCSI_SET_NOTIFICATION_ENABLE | UCSI_ENABLE_NTFY_ALL; + ucsi_send_command(con->ucsi, c, NULL, 0); ucsi_reset_connector(con, true); } @@ -713,11 +665,11 @@ static int ucsi_role_cmd(struct ucsi_connector *con, struct ucsi_control *ctrl) return ret; } -static int -ucsi_dr_swap(const struct typec_capability *cap, enum typec_data_role role) +static int ucsi_dr_swap(struct typec_port *port, enum typec_data_role role) { - struct ucsi_connector *con = to_ucsi_connector(cap); - struct ucsi_control ctrl; + struct ucsi_connector *con = typec_get_drvdata(port); + u8 partner_type; + u64 command; int ret = 0; mutex_lock(&con->lock); @@ -727,14 +679,17 @@ ucsi_dr_swap(const struct typec_capability *cap, enum typec_data_role role) goto out_unlock; } - if ((con->status.partner_type == UCSI_CONSTAT_PARTNER_TYPE_DFP && + partner_type = UCSI_CONSTAT_PARTNER_TYPE(con->status.flags); + if ((partner_type == UCSI_CONSTAT_PARTNER_TYPE_DFP && role == TYPEC_DEVICE) || - (con->status.partner_type == UCSI_CONSTAT_PARTNER_TYPE_UFP && + (partner_type == UCSI_CONSTAT_PARTNER_TYPE_UFP && role == TYPEC_HOST)) goto out_unlock; - UCSI_CMD_SET_UOR(ctrl, con, role); - ret = ucsi_role_cmd(con, &ctrl); + command = UCSI_SET_UOR | UCSI_CONNECTOR_NUMBER(con->num); + command |= UCSI_SET_UOR_ROLE(role); + command |= UCSI_SET_UOR_ACCEPT_ROLE_SWAPS; + ret = ucsi_role_cmd(con, command); if (ret < 0) goto out_unlock; @@ -748,11 +703,11 @@ out_unlock: return ret < 0 ? ret : 0; } -static int -ucsi_pr_swap(const struct typec_capability *cap, enum typec_role role) +static int ucsi_pr_swap(struct typec_port *port, enum typec_role role) { - struct ucsi_connector *con = to_ucsi_connector(cap); - struct ucsi_control ctrl; + struct ucsi_connector *con = typec_get_drvdata(port); + enum typec_role cur_role; + u64 command; int ret = 0; mutex_lock(&con->lock); @@ -762,11 +717,15 @@ ucsi_pr_swap(const struct typec_capability *cap, enum typec_role role) goto out_unlock; } - if (con->status.pwr_dir == role) + cur_role = !!(con->status.flags & UCSI_CONSTAT_PWR_DIR); + + if (cur_role == role) goto out_unlock; - UCSI_CMD_SET_PDR(ctrl, con, role); - ret = ucsi_role_cmd(con, &ctrl); + command = UCSI_SET_PDR | UCSI_CONNECTOR_NUMBER(con->num); + command |= UCSI_SET_PDR_ROLE(role); + command |= UCSI_SET_PDR_ACCEPT_ROLE_SWAPS; + ret = ucsi_role_cmd(con, command); if (ret < 0) goto out_unlock; @@ -777,7 +736,8 @@ ucsi_pr_swap(const struct typec_capability *cap, enum typec_role role) } /* Something has gone wrong while swapping the role */ - if (con->status.pwr_op_mode != UCSI_CONSTAT_PWR_OPMODE_PD) { + if (UCSI_CONSTAT_PWR_OPMODE(con->status.flags) != + UCSI_CONSTAT_PWR_OPMODE_PD) { ucsi_reset_connector(con, true); ret = -EPROTO; } @@ -788,6 +748,11 @@ out_unlock: return ret; } +static const struct typec_operations ucsi_ops = { + .dr_set = ucsi_dr_swap, + .pr_set = ucsi_pr_swap +}; + static struct fwnode_handle *ucsi_find_fwnode(struct ucsi_connector *con) { struct fwnode_handle *fwnode; @@ -804,18 +769,19 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) struct ucsi_connector *con = &ucsi->connector[index]; struct typec_capability *cap = &con->typec_cap; enum typec_accessory *accessory = cap->accessory; - struct ucsi_control ctrl; + u64 command; int ret; - INIT_WORK(&con->work, ucsi_connector_change); + INIT_WORK(&con->work, ucsi_handle_connector_change); init_completion(&con->complete); mutex_init(&con->lock); con->num = index + 1; con->ucsi = ucsi; /* Get connector capability */ - UCSI_CMD_GET_CONNECTOR_CAPABILITY(ctrl, con->num); - ret = ucsi_run_command(ucsi, &ctrl, &con->cap, sizeof(con->cap)); + command = UCSI_GET_CONNECTOR_CAPABILITY; + command |= UCSI_CONNECTOR_NUMBER(con->num); + ret = ucsi_run_command(ucsi, command, &con->cap, sizeof(con->cap)); if (ret < 0) return ret; @@ -826,11 +792,12 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) else if (con->cap.op_mode & UCSI_CONCAP_OPMODE_UFP) cap->data = TYPEC_PORT_UFP; - if (con->cap.provider && con->cap.consumer) + if ((con->cap.flags & UCSI_CONCAP_FLAG_PROVIDER) && + (con->cap.flags & UCSI_CONCAP_FLAG_CONSUMER)) cap->type = TYPEC_PORT_DRP; - else if (con->cap.provider) + else if (con->cap.flags & UCSI_CONCAP_FLAG_PROVIDER) cap->type = TYPEC_PORT_SRC; - else if (con->cap.consumer) + else if (con->cap.flags & UCSI_CONCAP_FLAG_CONSUMER) cap->type = TYPEC_PORT_SNK; cap->revision = ucsi->cap.typec_version; @@ -843,8 +810,8 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) *accessory = TYPEC_ACCESSORY_DEBUG; cap->fwnode = ucsi_find_fwnode(con); - cap->dr_set = ucsi_dr_swap; - cap->pr_set = ucsi_pr_swap; + cap->driver_data = con; + cap->ops = &ucsi_ops; /* Register the connector */ con->port = typec_register_port(ucsi->dev, cap); @@ -858,17 +825,15 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) con->num); /* Get the status */ - UCSI_CMD_GET_CONNECTOR_STATUS(ctrl, con->num); - ret = ucsi_run_command(ucsi, &ctrl, &con->status, sizeof(con->status)); + command = UCSI_GET_CONNECTOR_STATUS | UCSI_CONNECTOR_NUMBER(con->num); + ret = ucsi_run_command(ucsi, command, &con->status, + sizeof(con->status)); if (ret < 0) { dev_err(ucsi->dev, "con%d: failed to get status\n", con->num); return 0; } - ucsi_pwr_opmode_change(con); - typec_set_pwr_role(con->port, con->status.pwr_dir); - - switch (con->status.partner_type) { + switch (UCSI_CONSTAT_PARTNER_TYPE(con->status.flags)) { case UCSI_CONSTAT_PARTNER_TYPE_UFP: typec_set_data_role(con->port, TYPEC_HOST); break; @@ -880,8 +845,12 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) } /* Check if there is already something connected */ - if (con->status.connected) + if (con->status.flags & UCSI_CONSTAT_CONNECTED) { + typec_set_pwr_role(con->port, + !!(con->status.flags & UCSI_CONSTAT_PWR_DIR)); + ucsi_pwr_opmode_change(con); ucsi_register_partner(con); + } if (con->partner) { ret = ucsi_register_altmodes(con, UCSI_RECIPIENT_SOP); @@ -898,11 +867,16 @@ static int ucsi_register_port(struct ucsi *ucsi, int index) return 0; } -static void ucsi_init(struct work_struct *work) +/** + * ucsi_init - Initialize UCSI interface + * @ucsi: UCSI to be initialized + * + * Registers all ports @ucsi has and enables all notification events. + */ +int ucsi_init(struct ucsi *ucsi) { - struct ucsi *ucsi = container_of(work, struct ucsi, work); struct ucsi_connector *con; - struct ucsi_control ctrl; + u64 command; int ret; int i; @@ -916,15 +890,15 @@ static void ucsi_init(struct work_struct *work) } /* Enable basic notifications */ - UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_CMD_COMPLETE | - UCSI_ENABLE_NTFY_ERROR); - ret = ucsi_run_command(ucsi, &ctrl, NULL, 0); + command = UCSI_SET_NOTIFICATION_ENABLE; + command |= UCSI_ENABLE_NTFY_CMD_COMPLETE | UCSI_ENABLE_NTFY_ERROR; + ret = ucsi_run_command(ucsi, command, NULL, 0); if (ret < 0) goto err_reset; /* Get PPM capabilities */ - UCSI_CMD_GET_CAPABILITY(ctrl); - ret = ucsi_run_command(ucsi, &ctrl, &ucsi->cap, sizeof(ucsi->cap)); + command = UCSI_GET_CAPABILITY; + ret = ucsi_run_command(ucsi, command, &ucsi->cap, sizeof(ucsi->cap)); if (ret < 0) goto err_reset; @@ -949,14 +923,14 @@ static void ucsi_init(struct work_struct *work) } /* Enable all notifications */ - UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_ALL); - ret = ucsi_run_command(ucsi, &ctrl, NULL, 0); + command = UCSI_SET_NOTIFICATION_ENABLE | UCSI_ENABLE_NTFY_ALL; + ret = ucsi_run_command(ucsi, command, NULL, 0); if (ret < 0) goto err_unregister; mutex_unlock(&ucsi->ppm_lock); - return; + return 0; err_unregister: for (con = ucsi->connector; con->port; con++) { @@ -970,59 +944,115 @@ err_reset: ucsi_reset_ppm(ucsi); err: mutex_unlock(&ucsi->ppm_lock); - dev_err(ucsi->dev, "PPM init failed (%d)\n", ret); + + return ret; +} +EXPORT_SYMBOL_GPL(ucsi_init); + +static void ucsi_init_work(struct work_struct *work) +{ + struct ucsi *ucsi = container_of(work, struct ucsi, work); + int ret; + + ret = ucsi_init(ucsi); + if (ret) + dev_err(ucsi->dev, "PPM init failed (%d)\n", ret); } /** - * ucsi_register_ppm - Register UCSI PPM Interface - * @dev: Device interface to the PPM - * @ppm: The PPM interface - * - * Allocates UCSI instance, associates it with @ppm and returns it to the - * caller, and schedules initialization of the interface. + * ucsi_get_drvdata - Return private driver data pointer + * @ucsi: UCSI interface + */ +void *ucsi_get_drvdata(struct ucsi *ucsi) +{ + return ucsi->driver_data; +} +EXPORT_SYMBOL_GPL(ucsi_get_drvdata); + +/** + * ucsi_get_drvdata - Assign private driver data pointer + * @ucsi: UCSI interface + * @data: Private data pointer */ -struct ucsi *ucsi_register_ppm(struct device *dev, struct ucsi_ppm *ppm) +void ucsi_set_drvdata(struct ucsi *ucsi, void *data) +{ + ucsi->driver_data = data; +} +EXPORT_SYMBOL_GPL(ucsi_set_drvdata); + +/** + * ucsi_create - Allocate UCSI instance + * @dev: Device interface to the PPM (Platform Policy Manager) + * @ops: I/O routines + */ +struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops) { struct ucsi *ucsi; + if (!ops || !ops->read || !ops->sync_write || !ops->async_write) + return ERR_PTR(-EINVAL); + ucsi = kzalloc(sizeof(*ucsi), GFP_KERNEL); if (!ucsi) return ERR_PTR(-ENOMEM); - INIT_WORK(&ucsi->work, ucsi_init); - init_completion(&ucsi->complete); + INIT_WORK(&ucsi->work, ucsi_init_work); mutex_init(&ucsi->ppm_lock); - ucsi->dev = dev; - ucsi->ppm = ppm; + ucsi->ops = ops; + + return ucsi; +} +EXPORT_SYMBOL_GPL(ucsi_create); + +/** + * ucsi_destroy - Free UCSI instance + * @ucsi: UCSI instance to be freed + */ +void ucsi_destroy(struct ucsi *ucsi) +{ + kfree(ucsi); +} +EXPORT_SYMBOL_GPL(ucsi_destroy); + +/** + * ucsi_register - Register UCSI interface + * @ucsi: UCSI instance + */ +int ucsi_register(struct ucsi *ucsi) +{ + int ret; + + ret = ucsi->ops->read(ucsi, UCSI_VERSION, &ucsi->version, + sizeof(ucsi->version)); + if (ret) + return ret; + + if (!ucsi->version) + return -ENODEV; - /* - * Communication with the PPM takes a lot of time. It is not reasonable - * to initialize the driver here. Using a work for now. - */ queue_work(system_long_wq, &ucsi->work); - return ucsi; + return 0; } -EXPORT_SYMBOL_GPL(ucsi_register_ppm); +EXPORT_SYMBOL_GPL(ucsi_register); /** - * ucsi_unregister_ppm - Unregister UCSI PPM Interface - * @ucsi: struct ucsi associated with the PPM + * ucsi_unregister - Unregister UCSI interface + * @ucsi: UCSI interface to be unregistered * - * Unregister UCSI PPM that was created with ucsi_register(). + * Unregister UCSI interface that was created with ucsi_register(). */ -void ucsi_unregister_ppm(struct ucsi *ucsi) +void ucsi_unregister(struct ucsi *ucsi) { - struct ucsi_control ctrl; + u64 cmd = UCSI_SET_NOTIFICATION_ENABLE; int i; /* Make sure that we are not in the middle of driver initialization */ cancel_work_sync(&ucsi->work); - /* Disable everything except command complete notification */ - UCSI_CMD_SET_NTFY_ENABLE(ctrl, UCSI_ENABLE_NTFY_CMD_COMPLETE) - ucsi_send_command(ucsi, &ctrl, NULL, 0); + /* Disable notifications */ + ucsi->ops->async_write(ucsi, UCSI_CONTROL, &cmd, sizeof(cmd)); for (i = 0; i < ucsi->cap.num_connectors; i++) { cancel_work_sync(&ucsi->connector[i].work); @@ -1032,12 +1062,9 @@ void ucsi_unregister_ppm(struct ucsi *ucsi) typec_unregister_port(ucsi->connector[i].port); } - ucsi_reset_ppm(ucsi); - kfree(ucsi->connector); - kfree(ucsi); } -EXPORT_SYMBOL_GPL(ucsi_unregister_ppm); +EXPORT_SYMBOL_GPL(ucsi_unregister); MODULE_AUTHOR("Heikki Krogerus <heikki.krogerus@linux.intel.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/usb/typec/ucsi/ucsi.h b/drivers/usb/typec/ucsi/ucsi.h index de87d0b8319d..8569bbd3762f 100644 --- a/drivers/usb/typec/ucsi/ucsi.h +++ b/drivers/usb/typec/ucsi/ucsi.h @@ -10,177 +10,55 @@ /* -------------------------------------------------------------------------- */ -/* Command Status and Connector Change Indication (CCI) data structure */ -struct ucsi_cci { - u8:1; /* reserved */ - u8 connector_change:7; - u8 data_length; - u16:9; /* reserved */ - u16 not_supported:1; - u16 cancel_complete:1; - u16 reset_complete:1; - u16 busy:1; - u16 ack_complete:1; - u16 error:1; - u16 cmd_complete:1; -} __packed; - -/* Default fields in CONTROL data structure */ -struct ucsi_command { - u8 cmd; - u8 length; - u64 data:48; -} __packed; - -/* ACK Command structure */ -struct ucsi_ack_cmd { - u8 cmd; - u8 length; - u8 cci_ack:1; - u8 cmd_ack:1; - u8:6; /* reserved */ -} __packed; - -/* Connector Reset Command structure */ -struct ucsi_con_rst { - u8 cmd; - u8 length; - u8 con_num:7; - u8 hard_reset:1; -} __packed; - -/* Set USB Operation Mode Command structure */ -struct ucsi_uor_cmd { - u8 cmd; - u8 length; - u16 con_num:7; - u16 role:3; -#define UCSI_UOR_ROLE_DFP BIT(0) -#define UCSI_UOR_ROLE_UFP BIT(1) -#define UCSI_UOR_ROLE_DRP BIT(2) - u16:6; /* reserved */ -} __packed; - -/* Get Alternate Modes Command structure */ -struct ucsi_altmode_cmd { - u8 cmd; - u8 length; - u8 recipient; -#define UCSI_RECIPIENT_CON 0 -#define UCSI_RECIPIENT_SOP 1 -#define UCSI_RECIPIENT_SOP_P 2 -#define UCSI_RECIPIENT_SOP_PP 3 - u8 con_num; - u8 offset; - u8 num_altmodes; -} __packed; +struct ucsi; -struct ucsi_control { - union { - u64 raw_cmd; - struct ucsi_command cmd; - struct ucsi_uor_cmd uor; - struct ucsi_ack_cmd ack; - struct ucsi_con_rst con_rst; - struct ucsi_altmode_cmd alt; - }; +/* UCSI offsets (Bytes) */ +#define UCSI_VERSION 0 +#define UCSI_CCI 4 +#define UCSI_CONTROL 8 +#define UCSI_MESSAGE_IN 16 +#define UCSI_MESSAGE_OUT 32 + +/* Command Status and Connector Change Indication (CCI) bits */ +#define UCSI_CCI_CONNECTOR(_c_) (((_c_) & GENMASK(7, 0)) >> 1) +#define UCSI_CCI_LENGTH(_c_) (((_c_) & GENMASK(15, 8)) >> 8) +#define UCSI_CCI_NOT_SUPPORTED BIT(25) +#define UCSI_CCI_CANCEL_COMPLETE BIT(26) +#define UCSI_CCI_RESET_COMPLETE BIT(27) +#define UCSI_CCI_BUSY BIT(28) +#define UCSI_CCI_ACK_COMPLETE BIT(29) +#define UCSI_CCI_ERROR BIT(30) +#define UCSI_CCI_COMMAND_COMPLETE BIT(31) + +/** + * struct ucsi_operations - UCSI I/O operations + * @read: Read operation + * @sync_write: Blocking write operation + * @async_write: Non-blocking write operation + * + * Read and write routines for UCSI interface. @sync_write must wait for the + * Command Completion Event from the PPM before returning, and @async_write must + * return immediately after sending the data to the PPM. + */ +struct ucsi_operations { + int (*read)(struct ucsi *ucsi, unsigned int offset, + void *val, size_t val_len); + int (*sync_write)(struct ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len); + int (*async_write)(struct ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len); }; -#define __UCSI_CMD(_ctrl_, _cmd_) \ -{ \ - (_ctrl_).raw_cmd = 0; \ - (_ctrl_).cmd.cmd = _cmd_; \ -} - -/* Helper for preparing ucsi_control for CONNECTOR_RESET command. */ -#define UCSI_CMD_CONNECTOR_RESET(_ctrl_, _con_, _hard_) \ -{ \ - __UCSI_CMD(_ctrl_, UCSI_CONNECTOR_RESET) \ - (_ctrl_).con_rst.con_num = (_con_)->num; \ - (_ctrl_).con_rst.hard_reset = _hard_; \ -} - -/* Helper for preparing ucsi_control for ACK_CC_CI command. */ -#define UCSI_CMD_ACK(_ctrl_, _ack_) \ -{ \ - __UCSI_CMD(_ctrl_, UCSI_ACK_CC_CI) \ - (_ctrl_).ack.cci_ack = ((_ack_) == UCSI_ACK_EVENT); \ - (_ctrl_).ack.cmd_ack = ((_ack_) == UCSI_ACK_CMD); \ -} - -/* Helper for preparing ucsi_control for SET_NOTIFY_ENABLE command. */ -#define UCSI_CMD_SET_NTFY_ENABLE(_ctrl_, _ntfys_) \ -{ \ - __UCSI_CMD(_ctrl_, UCSI_SET_NOTIFICATION_ENABLE) \ - (_ctrl_).cmd.data = _ntfys_; \ -} - -/* Helper for preparing ucsi_control for GET_CAPABILITY command. */ -#define UCSI_CMD_GET_CAPABILITY(_ctrl_) \ -{ \ - __UCSI_CMD(_ctrl_, UCSI_GET_CAPABILITY) \ -} - -/* Helper for preparing ucsi_control for GET_CONNECTOR_CAPABILITY command. */ -#define UCSI_CMD_GET_CONNECTOR_CAPABILITY(_ctrl_, _con_) \ -{ \ - __UCSI_CMD(_ctrl_, UCSI_GET_CONNECTOR_CAPABILITY) \ - (_ctrl_).cmd.data = _con_; \ -} +struct ucsi *ucsi_create(struct device *dev, const struct ucsi_operations *ops); +void ucsi_destroy(struct ucsi *ucsi); +int ucsi_register(struct ucsi *ucsi); +void ucsi_unregister(struct ucsi *ucsi); +void *ucsi_get_drvdata(struct ucsi *ucsi); +void ucsi_set_drvdata(struct ucsi *ucsi, void *data); -/* Helper for preparing ucsi_control for GET_ALTERNATE_MODES command. */ -#define UCSI_CMD_GET_ALTERNATE_MODES(_ctrl_, _r_, _con_num_, _o_, _num_)\ -{ \ - __UCSI_CMD((_ctrl_), UCSI_GET_ALTERNATE_MODES) \ - _ctrl_.alt.recipient = (_r_); \ - _ctrl_.alt.con_num = (_con_num_); \ - _ctrl_.alt.offset = (_o_); \ - _ctrl_.alt.num_altmodes = (_num_) - 1; \ -} +void ucsi_connector_change(struct ucsi *ucsi, u8 num); -/* Helper for preparing ucsi_control for GET_CAM_SUPPORTED command. */ -#define UCSI_CMD_GET_CAM_SUPPORTED(_ctrl_, _con_) \ -{ \ - __UCSI_CMD((_ctrl_), UCSI_GET_CAM_SUPPORTED) \ - _ctrl_.cmd.data = (_con_); \ -} - -/* Helper for preparing ucsi_control for GET_CAM_SUPPORTED command. */ -#define UCSI_CMD_GET_CURRENT_CAM(_ctrl_, _con_) \ -{ \ - __UCSI_CMD((_ctrl_), UCSI_GET_CURRENT_CAM) \ - _ctrl_.cmd.data = (_con_); \ -} - -/* Helper for preparing ucsi_control for GET_CONNECTOR_STATUS command. */ -#define UCSI_CMD_GET_CONNECTOR_STATUS(_ctrl_, _con_) \ -{ \ - __UCSI_CMD(_ctrl_, UCSI_GET_CONNECTOR_STATUS) \ - (_ctrl_).cmd.data = _con_; \ -} - -#define __UCSI_ROLE(_ctrl_, _cmd_, _con_num_) \ -{ \ - __UCSI_CMD(_ctrl_, _cmd_) \ - (_ctrl_).uor.con_num = _con_num_; \ - (_ctrl_).uor.role = UCSI_UOR_ROLE_DRP; \ -} - -/* Helper for preparing ucsi_control for SET_UOR command. */ -#define UCSI_CMD_SET_UOR(_ctrl_, _con_, _role_) \ -{ \ - __UCSI_ROLE(_ctrl_, UCSI_SET_UOR, (_con_)->num) \ - (_ctrl_).uor.role |= (_role_) == TYPEC_HOST ? UCSI_UOR_ROLE_DFP : \ - UCSI_UOR_ROLE_UFP; \ -} - -/* Helper for preparing ucsi_control for SET_PDR command. */ -#define UCSI_CMD_SET_PDR(_ctrl_, _con_, _role_) \ -{ \ - __UCSI_ROLE(_ctrl_, UCSI_SET_PDR, (_con_)->num) \ - (_ctrl_).uor.role |= (_role_) == TYPEC_SOURCE ? UCSI_UOR_ROLE_DFP : \ - UCSI_UOR_ROLE_UFP; \ -} +/* -------------------------------------------------------------------------- */ /* Commands */ #define UCSI_PPM_RESET 0x01 @@ -203,24 +81,49 @@ struct ucsi_control { #define UCSI_GET_CONNECTOR_STATUS 0x12 #define UCSI_GET_ERROR_STATUS 0x13 -/* ACK_CC_CI commands */ -#define UCSI_ACK_EVENT 1 -#define UCSI_ACK_CMD 2 - -/* Bits for SET_NOTIFICATION_ENABLE command */ -#define UCSI_ENABLE_NTFY_CMD_COMPLETE BIT(0) -#define UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE BIT(1) -#define UCSI_ENABLE_NTFY_PWR_OPMODE_CHANGE BIT(2) -#define UCSI_ENABLE_NTFY_CAP_CHANGE BIT(5) -#define UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE BIT(6) -#define UCSI_ENABLE_NTFY_PD_RESET_COMPLETE BIT(7) -#define UCSI_ENABLE_NTFY_CAM_CHANGE BIT(8) -#define UCSI_ENABLE_NTFY_BAT_STATUS_CHANGE BIT(9) -#define UCSI_ENABLE_NTFY_PARTNER_CHANGE BIT(11) -#define UCSI_ENABLE_NTFY_PWR_DIR_CHANGE BIT(12) -#define UCSI_ENABLE_NTFY_CONNECTOR_CHANGE BIT(14) -#define UCSI_ENABLE_NTFY_ERROR BIT(15) -#define UCSI_ENABLE_NTFY_ALL 0xdbe7 +#define UCSI_CONNECTOR_NUMBER(_num_) ((u64)(_num_) << 16) + +/* CONNECTOR_RESET command bits */ +#define UCSI_CONNECTOR_RESET_HARD BIT(23) /* Deprecated in v1.1 */ + +/* ACK_CC_CI bits */ +#define UCSI_ACK_CONNECTOR_CHANGE BIT(16) +#define UCSI_ACK_COMMAND_COMPLETE BIT(17) + +/* SET_NOTIFICATION_ENABLE command bits */ +#define UCSI_ENABLE_NTFY_CMD_COMPLETE BIT(16) +#define UCSI_ENABLE_NTFY_EXT_PWR_SRC_CHANGE BIT(17) +#define UCSI_ENABLE_NTFY_PWR_OPMODE_CHANGE BIT(18) +#define UCSI_ENABLE_NTFY_CAP_CHANGE BIT(19) +#define UCSI_ENABLE_NTFY_PWR_LEVEL_CHANGE BIT(20) +#define UCSI_ENABLE_NTFY_PD_RESET_COMPLETE BIT(21) +#define UCSI_ENABLE_NTFY_CAM_CHANGE BIT(22) +#define UCSI_ENABLE_NTFY_BAT_STATUS_CHANGE BIT(23) +#define UCSI_ENABLE_NTFY_PARTNER_CHANGE BIT(24) +#define UCSI_ENABLE_NTFY_PWR_DIR_CHANGE BIT(25) +#define UCSI_ENABLE_NTFY_CONNECTOR_CHANGE BIT(26) +#define UCSI_ENABLE_NTFY_ERROR BIT(27) +#define UCSI_ENABLE_NTFY_ALL 0xdbe70000 + +/* SET_UOR command bits */ +#define UCSI_SET_UOR_ROLE(_r_) (((_r_) == TYPEC_HOST ? 1 : 2) << 23) +#define UCSI_SET_UOR_ACCEPT_ROLE_SWAPS BIT(25) + +/* SET_PDF command bits */ +#define UCSI_SET_PDR_ROLE(_r_) (((_r_) == TYPEC_SOURCE ? 1 : 2) << 23) +#define UCSI_SET_PDR_ACCEPT_ROLE_SWAPS BIT(25) + +/* GET_ALTERNATE_MODES command bits */ +#define UCSI_GET_ALTMODE_RECIPIENT(_r_) ((u64)(_r_) << 16) +#define UCSI_RECIPIENT_CON 0 +#define UCSI_RECIPIENT_SOP 1 +#define UCSI_RECIPIENT_SOP_P 2 +#define UCSI_RECIPIENT_SOP_PP 3 +#define UCSI_GET_ALTMODE_CONNECTOR_NUMBER(_r_) ((u64)(_r_) << 24) +#define UCSI_GET_ALTMODE_OFFSET(_r_) ((u64)(_r_) << 32) +#define UCSI_GET_ALTMODE_NUM_ALTMODES(_r_) ((u64)(_r_) << 40) + +/* -------------------------------------------------------------------------- */ /* Error information returned by PPM in response to GET_ERROR_STATUS command. */ #define UCSI_ERROR_UNREGONIZED_CMD BIT(0) @@ -230,6 +133,12 @@ struct ucsi_control { #define UCSI_ERROR_CC_COMMUNICATION_ERR BIT(4) #define UCSI_ERROR_DEAD_BATTERY BIT(5) #define UCSI_ERROR_CONTRACT_NEGOTIATION_FAIL BIT(6) +#define UCSI_ERROR_OVERCURRENT BIT(7) +#define UCSI_ERROR_UNDEFINED BIT(8) +#define UCSI_ERROR_PARTNER_REJECTED_SWAP BIT(9) +#define UCSI_ERROR_HARD_RESET BIT(10) +#define UCSI_ERROR_PPM_POLICY_CONFLICT BIT(11) +#define UCSI_ERROR_SWAP_REJECTED BIT(12) /* Data structure filled by PPM in response to GET_CAPABILITY command. */ struct ucsi_capability { @@ -241,8 +150,8 @@ struct ucsi_capability { #define UCSI_CAP_ATTR_POWER_AC_SUPPLY BIT(8) #define UCSI_CAP_ATTR_POWER_OTHER BIT(10) #define UCSI_CAP_ATTR_POWER_VBUS BIT(14) - u32 num_connectors:8; - u32 features:24; + u8 num_connectors; + u8 features; #define UCSI_CAP_SET_UOM BIT(0) #define UCSI_CAP_SET_PDM BIT(1) #define UCSI_CAP_ALT_MODE_DETAILS BIT(2) @@ -251,8 +160,9 @@ struct ucsi_capability { #define UCSI_CAP_CABLE_DETAILS BIT(5) #define UCSI_CAP_EXT_SUPPLY_NOTIFICATIONS BIT(6) #define UCSI_CAP_PD_RESET BIT(7) + u16 reserved_1; u8 num_alt_modes; - u8 reserved; + u8 reserved_2; u16 bc_version; u16 pd_version; u16 typec_version; @@ -269,9 +179,9 @@ struct ucsi_connector_capability { #define UCSI_CONCAP_OPMODE_USB2 BIT(5) #define UCSI_CONCAP_OPMODE_USB3 BIT(6) #define UCSI_CONCAP_OPMODE_ALT_MODE BIT(7) - u8 provider:1; - u8 consumer:1; - u8:6; /* reserved */ + u8 flags; +#define UCSI_CONCAP_FLAG_PROVIDER BIT(0) +#define UCSI_CONCAP_FLAG_CONSUMER BIT(1) } __packed; struct ucsi_altmode { @@ -283,18 +193,17 @@ struct ucsi_altmode { struct ucsi_cable_property { u16 speed_supported; u8 current_capability; - u8 vbus_in_cable:1; - u8 active_cable:1; - u8 directionality:1; - u8 plug_type:2; -#define UCSI_CABLE_PROPERTY_PLUG_TYPE_A 0 -#define UCSI_CABLE_PROPERTY_PLUG_TYPE_B 1 -#define UCSI_CABLE_PROPERTY_PLUG_TYPE_C 2 -#define UCSI_CABLE_PROPERTY_PLUG_OTHER 3 - u8 mode_support:1; - u8:2; /* reserved */ - u8 latency:4; - u8:4; /* reserved */ + u8 flags; +#define UCSI_CABLE_PROP_FLAG_VBUS_IN_CABLE BIT(0) +#define UCSI_CABLE_PROP_FLAG_ACTIVE_CABLE BIT(1) +#define UCSI_CABLE_PROP_FLAG_DIRECTIONALITY BIT(2) +#define UCSI_CABLE_PROP_FLAG_PLUG_TYPE(_f_) ((_f_) & GENMASK(3, 0)) +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_A 0 +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_B 1 +#define UCSI_CABLE_PROPERTY_PLUG_TYPE_C 2 +#define UCSI_CABLE_PROPERTY_PLUG_OTHER 3 +#define UCSI_CABLE_PROP_MODE_SUPPORT BIT(5) + u8 latency; } __packed; /* Data structure filled by PPM in response to GET_CONNECTOR_STATUS command. */ @@ -311,83 +220,47 @@ struct ucsi_connector_status { #define UCSI_CONSTAT_POWER_DIR_CHANGE BIT(12) #define UCSI_CONSTAT_CONNECT_CHANGE BIT(14) #define UCSI_CONSTAT_ERROR BIT(15) - u16 pwr_op_mode:3; -#define UCSI_CONSTAT_PWR_OPMODE_NONE 0 -#define UCSI_CONSTAT_PWR_OPMODE_DEFAULT 1 -#define UCSI_CONSTAT_PWR_OPMODE_BC 2 -#define UCSI_CONSTAT_PWR_OPMODE_PD 3 -#define UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5 4 -#define UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0 5 - u16 connected:1; - u16 pwr_dir:1; - u16 partner_flags:8; -#define UCSI_CONSTAT_PARTNER_FLAG_USB BIT(0) -#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE BIT(1) - u16 partner_type:3; -#define UCSI_CONSTAT_PARTNER_TYPE_DFP 1 -#define UCSI_CONSTAT_PARTNER_TYPE_UFP 2 -#define UCSI_CONSTAT_PARTNER_TYPE_CABLE 3 /* Powered Cable */ -#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */ -#define UCSI_CONSTAT_PARTNER_TYPE_DEBUG 5 -#define UCSI_CONSTAT_PARTNER_TYPE_AUDIO 6 + u16 flags; +#define UCSI_CONSTAT_PWR_OPMODE(_f_) ((_f_) & GENMASK(2, 0)) +#define UCSI_CONSTAT_PWR_OPMODE_NONE 0 +#define UCSI_CONSTAT_PWR_OPMODE_DEFAULT 1 +#define UCSI_CONSTAT_PWR_OPMODE_BC 2 +#define UCSI_CONSTAT_PWR_OPMODE_PD 3 +#define UCSI_CONSTAT_PWR_OPMODE_TYPEC1_5 4 +#define UCSI_CONSTAT_PWR_OPMODE_TYPEC3_0 5 +#define UCSI_CONSTAT_CONNECTED BIT(3) +#define UCSI_CONSTAT_PWR_DIR BIT(4) +#define UCSI_CONSTAT_PARTNER_FLAGS(_f_) (((_f_) & GENMASK(12, 5)) >> 5) +#define UCSI_CONSTAT_PARTNER_FLAG_USB 1 +#define UCSI_CONSTAT_PARTNER_FLAG_ALT_MODE 2 +#define UCSI_CONSTAT_PARTNER_TYPE(_f_) (((_f_) & GENMASK(15, 13)) >> 13) +#define UCSI_CONSTAT_PARTNER_TYPE_DFP 1 +#define UCSI_CONSTAT_PARTNER_TYPE_UFP 2 +#define UCSI_CONSTAT_PARTNER_TYPE_CABLE 3 /* Powered Cable */ +#define UCSI_CONSTAT_PARTNER_TYPE_CABLE_AND_UFP 4 /* Powered Cable */ +#define UCSI_CONSTAT_PARTNER_TYPE_DEBUG 5 +#define UCSI_CONSTAT_PARTNER_TYPE_AUDIO 6 u32 request_data_obj; - u8 bc_status:2; -#define UCSI_CONSTAT_BC_NOT_CHARGING 0 -#define UCSI_CONSTAT_BC_NOMINAL_CHARGING 1 -#define UCSI_CONSTAT_BC_SLOW_CHARGING 2 -#define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3 - u8 provider_cap_limit_reason:4; -#define UCSI_CONSTAT_CAP_PWR_LOWERED 0 -#define UCSI_CONSTAT_CAP_PWR_BUDGET_LIMIT 1 - u8:2; /* reserved */ + u8 pwr_status; +#define UCSI_CONSTAT_BC_STATUS(_p_) ((_p_) & GENMASK(2, 0)) +#define UCSI_CONSTAT_BC_NOT_CHARGING 0 +#define UCSI_CONSTAT_BC_NOMINAL_CHARGING 1 +#define UCSI_CONSTAT_BC_SLOW_CHARGING 2 +#define UCSI_CONSTAT_BC_TRICKLE_CHARGING 3 +#define UCSI_CONSTAT_PROVIDER_CAP_LIMIT(_p_) (((_p_) & GENMASK(6, 3)) >> 3) +#define UCSI_CONSTAT_CAP_PWR_LOWERED 0 +#define UCSI_CONSTAT_CAP_PWR_BUDGET_LIMIT 1 } __packed; /* -------------------------------------------------------------------------- */ -struct ucsi; - -struct ucsi_data { - u16 version; - u16 reserved; - union { - u32 raw_cci; - struct ucsi_cci cci; - }; - struct ucsi_control ctrl; - u32 message_in[4]; - u32 message_out[4]; -} __packed; - -/* - * struct ucsi_ppm - Interface to UCSI Platform Policy Manager - * @data: memory location to the UCSI data structures - * @cmd: UCSI command execution routine - * @sync: Refresh UCSI mailbox (the data structures) - */ -struct ucsi_ppm { - struct ucsi_data *data; - int (*cmd)(struct ucsi_ppm *, struct ucsi_control *); - int (*sync)(struct ucsi_ppm *); -}; - -struct ucsi *ucsi_register_ppm(struct device *dev, struct ucsi_ppm *ppm); -void ucsi_unregister_ppm(struct ucsi *ucsi); -void ucsi_notify(struct ucsi *ucsi); - -/* -------------------------------------------------------------------------- */ - -enum ucsi_status { - UCSI_IDLE = 0, - UCSI_BUSY, - UCSI_ERROR, -}; - struct ucsi { + u16 version; struct device *dev; - struct ucsi_ppm *ppm; + struct driver_data *driver_data; + + const struct ucsi_operations *ops; - enum ucsi_status status; - struct completion complete; struct ucsi_capability cap; struct ucsi_connector *connector; @@ -426,7 +299,7 @@ struct ucsi_connector { struct ucsi_connector_capability cap; }; -int ucsi_send_command(struct ucsi *ucsi, struct ucsi_control *ctrl, +int ucsi_send_command(struct ucsi *ucsi, u64 command, void *retval, size_t size); void ucsi_altmode_update_active(struct ucsi_connector *con); diff --git a/drivers/usb/typec/ucsi/ucsi_acpi.c b/drivers/usb/typec/ucsi/ucsi_acpi.c index a18112a83fae..3f1786170098 100644 --- a/drivers/usb/typec/ucsi/ucsi_acpi.c +++ b/drivers/usb/typec/ucsi/ucsi_acpi.c @@ -19,7 +19,9 @@ struct ucsi_acpi { struct device *dev; struct ucsi *ucsi; - struct ucsi_ppm ppm; + void __iomem *base; + struct completion complete; + unsigned long flags; guid_t guid; }; @@ -39,27 +41,73 @@ static int ucsi_acpi_dsm(struct ucsi_acpi *ua, int func) return 0; } -static int ucsi_acpi_cmd(struct ucsi_ppm *ppm, struct ucsi_control *ctrl) +static int ucsi_acpi_read(struct ucsi *ucsi, unsigned int offset, + void *val, size_t val_len) { - struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm); + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); + int ret; + + ret = ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); + if (ret) + return ret; + + memcpy(val, (const void __force *)(ua->base + offset), val_len); + + return 0; +} + +static int ucsi_acpi_async_write(struct ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len) +{ + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); - ppm->data->ctrl.raw_cmd = ctrl->raw_cmd; + memcpy((void __force *)(ua->base + offset), val, val_len); return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_WRITE); } -static int ucsi_acpi_sync(struct ucsi_ppm *ppm) +static int ucsi_acpi_sync_write(struct ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len) { - struct ucsi_acpi *ua = container_of(ppm, struct ucsi_acpi, ppm); + struct ucsi_acpi *ua = ucsi_get_drvdata(ucsi); + int ret; + + set_bit(COMMAND_PENDING, &ua->flags); + + ret = ucsi_acpi_async_write(ucsi, offset, val, val_len); + if (ret) + goto out_clear_bit; - return ucsi_acpi_dsm(ua, UCSI_DSM_FUNC_READ); + if (!wait_for_completion_timeout(&ua->complete, msecs_to_jiffies(5000))) + ret = -ETIMEDOUT; + +out_clear_bit: + clear_bit(COMMAND_PENDING, &ua->flags); + + return ret; } +static const struct ucsi_operations ucsi_acpi_ops = { + .read = ucsi_acpi_read, + .sync_write = ucsi_acpi_sync_write, + .async_write = ucsi_acpi_async_write +}; + 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)); + if (ret) + return; - ucsi_notify(ua->ucsi); + if (test_bit(COMMAND_PENDING, &ua->flags) && + cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE)) + complete(&ua->complete); + else if (UCSI_CCI_CONNECTOR(cci)) + ucsi_connector_change(ua->ucsi, UCSI_CCI_CONNECTOR(cci)); } static int ucsi_acpi_probe(struct platform_device *pdev) @@ -90,35 +138,39 @@ static int ucsi_acpi_probe(struct platform_device *pdev) * it can not be requested here, and we can not use * devm_ioremap_resource(). */ - ua->ppm.data = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!ua->ppm.data) + ua->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); + if (!ua->base) return -ENOMEM; - if (!ua->ppm.data->version) - return -ENODEV; - ret = guid_parse(UCSI_DSM_UUID, &ua->guid); if (ret) return ret; - ua->ppm.cmd = ucsi_acpi_cmd; - ua->ppm.sync = ucsi_acpi_sync; + init_completion(&ua->complete); ua->dev = &pdev->dev; + ua->ucsi = ucsi_create(&pdev->dev, &ucsi_acpi_ops); + if (IS_ERR(ua->ucsi)) + return PTR_ERR(ua->ucsi); + + ucsi_set_drvdata(ua->ucsi, ua); + status = acpi_install_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY, ucsi_acpi_notify, ua); if (ACPI_FAILURE(status)) { dev_err(&pdev->dev, "failed to install notify handler\n"); + ucsi_destroy(ua->ucsi); return -ENODEV; } - ua->ucsi = ucsi_register_ppm(&pdev->dev, &ua->ppm); - if (IS_ERR(ua->ucsi)) { + ret = ucsi_register(ua->ucsi); + if (ret) { acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY, ucsi_acpi_notify); - return PTR_ERR(ua->ucsi); + ucsi_destroy(ua->ucsi); + return ret; } platform_set_drvdata(pdev, ua); @@ -130,7 +182,8 @@ static int ucsi_acpi_remove(struct platform_device *pdev) { struct ucsi_acpi *ua = platform_get_drvdata(pdev); - ucsi_unregister_ppm(ua->ucsi); + ucsi_unregister(ua->ucsi); + ucsi_destroy(ua->ucsi); acpi_remove_notify_handler(ACPI_HANDLE(&pdev->dev), ACPI_DEVICE_NOTIFY, ucsi_acpi_notify); diff --git a/drivers/usb/typec/ucsi/ucsi_ccg.c b/drivers/usb/typec/ucsi/ucsi_ccg.c index d772fce51905..3370b3fc37b1 100644 --- a/drivers/usb/typec/ucsi/ucsi_ccg.c +++ b/drivers/usb/typec/ucsi/ucsi_ccg.c @@ -176,8 +176,8 @@ struct ccg_resp { struct ucsi_ccg { struct device *dev; struct ucsi *ucsi; - struct ucsi_ppm ppm; struct i2c_client *client; + struct ccg_dev_info info; /* version info for boot, primary and secondary */ struct version_info version[FW2 + 1]; @@ -196,6 +196,8 @@ struct ucsi_ccg { /* fw build with vendor information */ u16 fw_build; struct work_struct pm_work; + + struct completion complete; }; static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) @@ -243,7 +245,7 @@ static int ccg_read(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) return 0; } -static int ccg_write(struct ucsi_ccg *uc, u16 rab, u8 *data, u32 len) +static int ccg_write(struct ucsi_ccg *uc, u16 rab, const u8 *data, u32 len) { struct i2c_client *client = uc->client; unsigned char *buf; @@ -317,88 +319,85 @@ static int ucsi_ccg_init(struct ucsi_ccg *uc) return -ETIMEDOUT; } -static int ucsi_ccg_send_data(struct ucsi_ccg *uc) +static int ucsi_ccg_read(struct ucsi *ucsi, unsigned int offset, + void *val, size_t val_len) { - u8 *ppm = (u8 *)uc->ppm.data; - int status; - u16 rab; + u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset); - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, message_out)); - status = ccg_write(uc, rab, ppm + - offsetof(struct ucsi_data, message_out), - sizeof(uc->ppm.data->message_out)); - if (status < 0) - return status; - - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, ctrl)); - return ccg_write(uc, rab, ppm + offsetof(struct ucsi_data, ctrl), - sizeof(uc->ppm.data->ctrl)); + return ccg_read(ucsi_get_drvdata(ucsi), reg, val, val_len); } -static int ucsi_ccg_recv_data(struct ucsi_ccg *uc) +static int ucsi_ccg_async_write(struct ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len) { - u8 *ppm = (u8 *)uc->ppm.data; - int status; - u16 rab; + u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(offset); - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, cci)); - status = ccg_read(uc, rab, ppm + offsetof(struct ucsi_data, cci), - sizeof(uc->ppm.data->cci)); - if (status < 0) - return status; - - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, message_in)); - return ccg_read(uc, rab, ppm + offsetof(struct ucsi_data, message_in), - sizeof(uc->ppm.data->message_in)); + return ccg_write(ucsi_get_drvdata(ucsi), reg, val, val_len); } -static int ucsi_ccg_ack_interrupt(struct ucsi_ccg *uc) +static int ucsi_ccg_sync_write(struct ucsi *ucsi, unsigned int offset, + const void *val, size_t val_len) { - int status; - unsigned char data; + struct ucsi_ccg *uc = ucsi_get_drvdata(ucsi); + int ret; - status = ccg_read(uc, CCGX_RAB_INTR_REG, &data, sizeof(data)); - if (status < 0) - return status; + mutex_lock(&uc->lock); + pm_runtime_get_sync(uc->dev); + set_bit(DEV_CMD_PENDING, &uc->flags); - return ccg_write(uc, CCGX_RAB_INTR_REG, &data, sizeof(data)); -} + ret = ucsi_ccg_async_write(ucsi, offset, val, val_len); + if (ret) + goto err_clear_bit; -static int ucsi_ccg_sync(struct ucsi_ppm *ppm) -{ - struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm); - int status; + if (!wait_for_completion_timeout(&uc->complete, msecs_to_jiffies(5000))) + ret = -ETIMEDOUT; - status = ucsi_ccg_recv_data(uc); - if (status < 0) - return status; +err_clear_bit: + clear_bit(DEV_CMD_PENDING, &uc->flags); + pm_runtime_put_sync(uc->dev); + mutex_unlock(&uc->lock); - /* ack interrupt to allow next command to run */ - return ucsi_ccg_ack_interrupt(uc); + return ret; } -static int ucsi_ccg_cmd(struct ucsi_ppm *ppm, struct ucsi_control *ctrl) -{ - struct ucsi_ccg *uc = container_of(ppm, struct ucsi_ccg, ppm); - - ppm->data->ctrl.raw_cmd = ctrl->raw_cmd; - return ucsi_ccg_send_data(uc); -} +static const struct ucsi_operations ucsi_ccg_ops = { + .read = ucsi_ccg_read, + .sync_write = ucsi_ccg_sync_write, + .async_write = ucsi_ccg_async_write +}; static irqreturn_t ccg_irq_handler(int irq, void *data) { + u16 reg = CCGX_RAB_UCSI_DATA_BLOCK(UCSI_CCI); struct ucsi_ccg *uc = data; + u8 intr_reg; + u32 cci; + int ret; + + ret = ccg_read(uc, CCGX_RAB_INTR_REG, &intr_reg, sizeof(intr_reg)); + if (ret) + return ret; + + ret = ccg_read(uc, reg, (void *)&cci, sizeof(cci)); + if (ret) + goto err_clear_irq; + + if (UCSI_CCI_CONNECTOR(cci)) + ucsi_connector_change(uc->ucsi, UCSI_CCI_CONNECTOR(cci)); + + if (test_bit(DEV_CMD_PENDING, &uc->flags) && + cci & (UCSI_CCI_ACK_COMPLETE | UCSI_CCI_COMMAND_COMPLETE)) + complete(&uc->complete); - ucsi_notify(uc->ucsi); +err_clear_irq: + ccg_write(uc, CCGX_RAB_INTR_REG, &intr_reg, sizeof(intr_reg)); return IRQ_HANDLED; } static void ccg_pm_workaround_work(struct work_struct *pm_work) { - struct ucsi_ccg *uc = container_of(pm_work, struct ucsi_ccg, pm_work); - - ucsi_notify(uc->ucsi); + ccg_irq_handler(0, container_of(pm_work, struct ucsi_ccg, pm_work)); } static int get_fw_info(struct ucsi_ccg *uc) @@ -1027,10 +1026,10 @@ static int ccg_restart(struct ucsi_ccg *uc) return status; } - uc->ucsi = ucsi_register_ppm(dev, &uc->ppm); - if (IS_ERR(uc->ucsi)) { - dev_err(uc->dev, "ucsi_register_ppm failed\n"); - return PTR_ERR(uc->ucsi); + status = ucsi_register(uc->ucsi); + if (status) { + dev_err(uc->dev, "failed to register the interface\n"); + return status; } return 0; @@ -1047,7 +1046,7 @@ static void ccg_update_firmware(struct work_struct *work) return; if (flash_mode != FLASH_NOT_NEEDED) { - ucsi_unregister_ppm(uc->ucsi); + ucsi_unregister(uc->ucsi); free_irq(uc->irq, uc); ccg_fw_update(uc, flash_mode); @@ -1091,21 +1090,15 @@ static int ucsi_ccg_probe(struct i2c_client *client, struct device *dev = &client->dev; struct ucsi_ccg *uc; int status; - u16 rab; uc = devm_kzalloc(dev, sizeof(*uc), GFP_KERNEL); if (!uc) return -ENOMEM; - uc->ppm.data = devm_kzalloc(dev, sizeof(struct ucsi_data), GFP_KERNEL); - if (!uc->ppm.data) - return -ENOMEM; - - uc->ppm.cmd = ucsi_ccg_cmd; - uc->ppm.sync = ucsi_ccg_sync; uc->dev = dev; uc->client = client; mutex_init(&uc->lock); + init_completion(&uc->complete); INIT_WORK(&uc->work, ccg_update_firmware); INIT_WORK(&uc->pm_work, ccg_pm_workaround_work); @@ -1133,30 +1126,25 @@ static int ucsi_ccg_probe(struct i2c_client *client, if (uc->info.mode & CCG_DEVINFO_PDPORTS_MASK) uc->port_num++; + uc->ucsi = ucsi_create(dev, &ucsi_ccg_ops); + if (IS_ERR(uc->ucsi)) + return PTR_ERR(uc->ucsi); + + ucsi_set_drvdata(uc->ucsi, uc); + status = request_threaded_irq(client->irq, NULL, ccg_irq_handler, IRQF_ONESHOT | IRQF_TRIGGER_HIGH, dev_name(dev), uc); if (status < 0) { dev_err(uc->dev, "request_threaded_irq failed - %d\n", status); - return status; + goto out_ucsi_destroy; } uc->irq = client->irq; - uc->ucsi = ucsi_register_ppm(dev, &uc->ppm); - if (IS_ERR(uc->ucsi)) { - dev_err(uc->dev, "ucsi_register_ppm failed\n"); - return PTR_ERR(uc->ucsi); - } - - rab = CCGX_RAB_UCSI_DATA_BLOCK(offsetof(struct ucsi_data, version)); - status = ccg_read(uc, rab, (u8 *)(uc->ppm.data) + - offsetof(struct ucsi_data, version), - sizeof(uc->ppm.data->version)); - if (status < 0) { - ucsi_unregister_ppm(uc->ucsi); - return status; - } + status = ucsi_register(uc->ucsi); + if (status) + goto out_free_irq; i2c_set_clientdata(client, uc); @@ -1167,6 +1155,13 @@ static int ucsi_ccg_probe(struct i2c_client *client, pm_runtime_idle(uc->dev); return 0; + +out_free_irq: + free_irq(uc->irq, uc); +out_ucsi_destroy: + ucsi_destroy(uc->ucsi); + + return status; } static int ucsi_ccg_remove(struct i2c_client *client) @@ -1175,8 +1170,9 @@ static int ucsi_ccg_remove(struct i2c_client *client) cancel_work_sync(&uc->pm_work); cancel_work_sync(&uc->work); - ucsi_unregister_ppm(uc->ucsi); pm_runtime_disable(uc->dev); + ucsi_unregister(uc->ucsi); + ucsi_destroy(uc->ucsi); free_irq(uc->irq, uc); return 0; diff --git a/drivers/usb/usbip/Kconfig b/drivers/usb/usbip/Kconfig index 2f86b28fa3da..7bbae7a08642 100644 --- a/drivers/usb/usbip/Kconfig +++ b/drivers/usb/usbip/Kconfig @@ -4,6 +4,7 @@ config USBIP_CORE tristate "USB/IP support" depends on NET select USB_COMMON + select SGL_ALLOC ---help--- This enables pushing USB packets over IP to allow remote machines direct access to USB devices. It provides the diff --git a/drivers/usb/usbip/stub_rx.c b/drivers/usb/usbip/stub_rx.c index 66edfeea68fe..e2b019532234 100644 --- a/drivers/usb/usbip/stub_rx.c +++ b/drivers/usb/usbip/stub_rx.c @@ -470,18 +470,50 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, if (pipe == -1) return; + /* + * Smatch reported the error case where use_sg is true and buf_len is 0. + * In this case, It adds SDEV_EVENT_ERROR_MALLOC and stub_priv will be + * released by stub event handler and connection will be shut down. + */ priv = stub_priv_alloc(sdev, pdu); if (!priv) return; buf_len = (unsigned long long)pdu->u.cmd_submit.transfer_buffer_length; + if (use_sg && !buf_len) { + dev_err(&udev->dev, "sg buffer with zero length\n"); + goto err_malloc; + } + /* allocate urb transfer buffer, if needed */ if (buf_len) { if (use_sg) { sgl = sgl_alloc(buf_len, GFP_KERNEL, &nents); if (!sgl) goto err_malloc; + + /* Check if the server's HCD supports SG */ + if (!udev->bus->sg_tablesize) { + /* + * If the server's HCD doesn't support SG, break + * a single SG request into several URBs and map + * each SG list entry to corresponding URB + * buffer. The previously allocated SG list is + * stored in priv->sgl (If the server's HCD + * support SG, SG list is stored only in + * urb->sg) and it is used as an indicator that + * the server split single SG request into + * several URBs. Later, priv->sgl is used by + * stub_complete() and stub_send_ret_submit() to + * reassemble the divied URBs. + */ + support_sg = 0; + num_urbs = nents; + priv->completed_urbs = 0; + pdu->u.cmd_submit.transfer_flags &= + ~URB_DMA_MAP_SG; + } } else { buffer = kzalloc(buf_len, GFP_KERNEL); if (!buffer) @@ -489,24 +521,6 @@ static void stub_recv_cmd_submit(struct stub_device *sdev, } } - /* Check if the server's HCD supports SG */ - if (use_sg && !udev->bus->sg_tablesize) { - /* - * If the server's HCD doesn't support SG, break a single SG - * request into several URBs and map each SG list entry to - * corresponding URB buffer. The previously allocated SG - * list is stored in priv->sgl (If the server's HCD support SG, - * SG list is stored only in urb->sg) and it is used as an - * indicator that the server split single SG request into - * several URBs. Later, priv->sgl is used by stub_complete() and - * stub_send_ret_submit() to reassemble the divied URBs. - */ - support_sg = 0; - num_urbs = nents; - priv->completed_urbs = 0; - pdu->u.cmd_submit.transfer_flags &= ~URB_DMA_MAP_SG; - } - /* allocate urb array */ priv->num_urbs = num_urbs; priv->urbs = kmalloc_array(num_urbs, sizeof(*priv->urbs), GFP_KERNEL); diff --git a/drivers/usb/usbip/stub_tx.c b/drivers/usb/usbip/stub_tx.c index 36010a82b359..b1c2f6781cb3 100644 --- a/drivers/usb/usbip/stub_tx.c +++ b/drivers/usb/usbip/stub_tx.c @@ -291,7 +291,7 @@ static int stub_send_ret_submit(struct stub_device *sdev) kfree(iov); usbip_event_add(&sdev->ud, SDEV_EVENT_ERROR_TCP); - return -1; + return -1; } } diff --git a/drivers/usb/usbip/vhci_tx.c b/drivers/usb/usbip/vhci_tx.c index c3803785f6ef..0ae40a13a9fe 100644 --- a/drivers/usb/usbip/vhci_tx.c +++ b/drivers/usb/usbip/vhci_tx.c @@ -147,7 +147,10 @@ static int vhci_send_cmd_submit(struct vhci_device *vdev) } kfree(iov); + /* This is only for isochronous case */ kfree(iso_buffer); + iso_buffer = NULL; + usbip_dbg_vhci_tx("send txdata\n"); total_size += txsize; |