Commit cee853e8 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'usb-5.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

Pull USB/Thunderbolt fixes from Greg KH:
 "Here are a number of small USB driver fixes for 5.6-rc3.

  Included in here are:
  - MAINTAINER file updates
  - USB gadget driver fixes
  - usb core quirk additions and fixes for regressions
  - xhci driver fixes
  - usb serial driver id additions and fixes
  - thunderbolt bugfix

  Thunderbolt patches come in through here now that USB4 is really
  thunderbolt.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'usb-5.6-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (34 commits)
  USB: misc: iowarrior: add support for the 100 device
  thunderbolt: Prevent crash if non-active NVMem file is read
  usb: gadget: udc-xilinx: Fix xudc_stop() kernel-doc format
  USB: misc: iowarrior: add support for the 28 and 28L devices
  USB: misc: iowarrior: add support for 2 OEMed devices
  USB: Fix novation SourceControl XL after suspend
  xhci: Fix memory leak when caching protocol extended capability PSI tables - take 2
  Revert "xhci: Fix memory leak when caching protocol extended capability PSI tables"
  MAINTAINERS: Sort entries in database for THUNDERBOLT
  usb: dwc3: debug: fix string position formatting mixup with ret and len
  usb: gadget: serial: fix Tx stall after buffer overflow
  usb: gadget: ffs: ffs_aio_cancel(): Save/restore IRQ flags
  usb: dwc2: Fix SET/CLEAR_FEATURE and GET_STATUS flows
  usb: dwc2: Fix in ISOC request length checking
  usb: gadget: composite: Support more than 500mA MaxPower
  usb: gadget: composite: Fix bMaxPower for SuperSpeedPlus
  usb: gadget: u_audio: Fix high-speed max packet size
  usb: dwc3: gadget: Check for IOC/LST bit in TRB->ctrl fields
  USB: core: clean up endpoint-descriptor parsing
  USB: quirks: blacklist duplicate ep on Sound Devices USBPre2
  ...
parents 88f8bbfa 8b978be8
...@@ -16552,8 +16552,8 @@ M: Michael Jamet <michael.jamet@intel.com> ...@@ -16552,8 +16552,8 @@ M: Michael Jamet <michael.jamet@intel.com>
M: Mika Westerberg <mika.westerberg@linux.intel.com> M: Mika Westerberg <mika.westerberg@linux.intel.com>
M: Yehezkel Bernat <YehezkelShB@gmail.com> M: Yehezkel Bernat <YehezkelShB@gmail.com>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git
S: Maintained S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/westeri/thunderbolt.git
F: Documentation/admin-guide/thunderbolt.rst F: Documentation/admin-guide/thunderbolt.rst
F: drivers/thunderbolt/ F: drivers/thunderbolt/
F: include/linux/thunderbolt.h F: include/linux/thunderbolt.h
...@@ -17392,11 +17392,14 @@ F: drivers/usb/ ...@@ -17392,11 +17392,14 @@ F: drivers/usb/
F: include/linux/usb.h F: include/linux/usb.h
F: include/linux/usb/ F: include/linux/usb/
USB TYPEC PI3USB30532 MUX DRIVER USB TYPEC BUS FOR ALTERNATE MODES
M: Hans de Goede <hdegoede@redhat.com> M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
S: Maintained S: Maintained
F: drivers/usb/typec/mux/pi3usb30532.c F: Documentation/ABI/testing/sysfs-bus-typec
F: Documentation/driver-api/usb/typec_bus.rst
F: drivers/usb/typec/altmodes/
F: include/linux/usb/typec_altmode.h
USB TYPEC CLASS USB TYPEC CLASS
M: Heikki Krogerus <heikki.krogerus@linux.intel.com> M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
...@@ -17407,14 +17410,11 @@ F: Documentation/driver-api/usb/typec.rst ...@@ -17407,14 +17410,11 @@ F: Documentation/driver-api/usb/typec.rst
F: drivers/usb/typec/ F: drivers/usb/typec/
F: include/linux/usb/typec.h F: include/linux/usb/typec.h
USB TYPEC BUS FOR ALTERNATE MODES USB TYPEC PI3USB30532 MUX DRIVER
M: Heikki Krogerus <heikki.krogerus@linux.intel.com> M: Hans de Goede <hdegoede@redhat.com>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
S: Maintained S: Maintained
F: Documentation/ABI/testing/sysfs-bus-typec F: drivers/usb/typec/mux/pi3usb30532.c
F: Documentation/driver-api/usb/typec_bus.rst
F: drivers/usb/typec/altmodes/
F: include/linux/usb/typec_altmode.h
USB TYPEC PORT CONTROLLER DRIVERS USB TYPEC PORT CONTROLLER DRIVERS
M: Guenter Roeck <linux@roeck-us.net> M: Guenter Roeck <linux@roeck-us.net>
......
...@@ -348,6 +348,12 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val, ...@@ -348,6 +348,12 @@ static int tb_switch_nvm_read(void *priv, unsigned int offset, void *val,
return ret; return ret;
} }
static int tb_switch_nvm_no_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
return -EPERM;
}
static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val, static int tb_switch_nvm_write(void *priv, unsigned int offset, void *val,
size_t bytes) size_t bytes)
{ {
...@@ -393,6 +399,7 @@ static struct nvmem_device *register_nvmem(struct tb_switch *sw, int id, ...@@ -393,6 +399,7 @@ static struct nvmem_device *register_nvmem(struct tb_switch *sw, int id,
config.read_only = true; config.read_only = true;
} else { } else {
config.name = "nvm_non_active"; config.name = "nvm_non_active";
config.reg_read = tb_switch_nvm_no_read;
config.reg_write = tb_switch_nvm_write; config.reg_write = tb_switch_nvm_write;
config.root_only = true; config.root_only = true;
} }
......
...@@ -256,6 +256,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -256,6 +256,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
struct usb_host_interface *ifp, int num_ep, struct usb_host_interface *ifp, int num_ep,
unsigned char *buffer, int size) unsigned char *buffer, int size)
{ {
struct usb_device *udev = to_usb_device(ddev);
unsigned char *buffer0 = buffer; unsigned char *buffer0 = buffer;
struct usb_endpoint_descriptor *d; struct usb_endpoint_descriptor *d;
struct usb_host_endpoint *endpoint; struct usb_host_endpoint *endpoint;
...@@ -297,6 +298,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -297,6 +298,16 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
goto skip_to_next_endpoint_or_interface_descriptor; goto skip_to_next_endpoint_or_interface_descriptor;
} }
/* Ignore blacklisted endpoints */
if (udev->quirks & USB_QUIRK_ENDPOINT_BLACKLIST) {
if (usb_endpoint_is_blacklisted(udev, ifp, d)) {
dev_warn(ddev, "config %d interface %d altsetting %d has a blacklisted endpoint with address 0x%X, skipping\n",
cfgno, inum, asnum,
d->bEndpointAddress);
goto skip_to_next_endpoint_or_interface_descriptor;
}
}
endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints]; endpoint = &ifp->endpoint[ifp->desc.bNumEndpoints];
++ifp->desc.bNumEndpoints; ++ifp->desc.bNumEndpoints;
...@@ -311,7 +322,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -311,7 +322,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
j = 255; j = 255;
if (usb_endpoint_xfer_int(d)) { if (usb_endpoint_xfer_int(d)) {
i = 1; i = 1;
switch (to_usb_device(ddev)->speed) { switch (udev->speed) {
case USB_SPEED_SUPER_PLUS: case USB_SPEED_SUPER_PLUS:
case USB_SPEED_SUPER: case USB_SPEED_SUPER:
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
...@@ -332,8 +343,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -332,8 +343,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
/* /*
* This quirk fixes bIntervals reported in ms. * This quirk fixes bIntervals reported in ms.
*/ */
if (to_usb_device(ddev)->quirks & if (udev->quirks & USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) {
USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL) {
n = clamp(fls(d->bInterval) + 3, i, j); n = clamp(fls(d->bInterval) + 3, i, j);
i = j = n; i = j = n;
} }
...@@ -341,8 +351,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -341,8 +351,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
* This quirk fixes bIntervals reported in * This quirk fixes bIntervals reported in
* linear microframes. * linear microframes.
*/ */
if (to_usb_device(ddev)->quirks & if (udev->quirks & USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) {
USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL) {
n = clamp(fls(d->bInterval), i, j); n = clamp(fls(d->bInterval), i, j);
i = j = n; i = j = n;
} }
...@@ -359,7 +368,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -359,7 +368,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
} else if (usb_endpoint_xfer_isoc(d)) { } else if (usb_endpoint_xfer_isoc(d)) {
i = 1; i = 1;
j = 16; j = 16;
switch (to_usb_device(ddev)->speed) { switch (udev->speed) {
case USB_SPEED_HIGH: case USB_SPEED_HIGH:
n = 7; /* 8 ms = 2^(7-1) uframes */ n = 7; /* 8 ms = 2^(7-1) uframes */
break; break;
...@@ -381,8 +390,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -381,8 +390,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
* explicitly forbidden by the USB spec. In an attempt to make * explicitly forbidden by the USB spec. In an attempt to make
* them usable, we will try treating them as Interrupt endpoints. * them usable, we will try treating them as Interrupt endpoints.
*/ */
if (to_usb_device(ddev)->speed == USB_SPEED_LOW && if (udev->speed == USB_SPEED_LOW && usb_endpoint_xfer_bulk(d)) {
usb_endpoint_xfer_bulk(d)) {
dev_warn(ddev, "config %d interface %d altsetting %d " dev_warn(ddev, "config %d interface %d altsetting %d "
"endpoint 0x%X is Bulk; changing to Interrupt\n", "endpoint 0x%X is Bulk; changing to Interrupt\n",
cfgno, inum, asnum, d->bEndpointAddress); cfgno, inum, asnum, d->bEndpointAddress);
...@@ -406,7 +414,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -406,7 +414,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
/* Find the highest legal maxpacket size for this endpoint */ /* Find the highest legal maxpacket size for this endpoint */
i = 0; /* additional transactions per microframe */ i = 0; /* additional transactions per microframe */
switch (to_usb_device(ddev)->speed) { switch (udev->speed) {
case USB_SPEED_LOW: case USB_SPEED_LOW:
maxpacket_maxes = low_speed_maxpacket_maxes; maxpacket_maxes = low_speed_maxpacket_maxes;
break; break;
...@@ -442,8 +450,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -442,8 +450,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
* maxpacket sizes other than 512. High speed HCDs may not * maxpacket sizes other than 512. High speed HCDs may not
* be able to handle that particular bug, so let's warn... * be able to handle that particular bug, so let's warn...
*/ */
if (to_usb_device(ddev)->speed == USB_SPEED_HIGH if (udev->speed == USB_SPEED_HIGH && usb_endpoint_xfer_bulk(d)) {
&& usb_endpoint_xfer_bulk(d)) {
if (maxp != 512) if (maxp != 512)
dev_warn(ddev, "config %d interface %d altsetting %d " dev_warn(ddev, "config %d interface %d altsetting %d "
"bulk endpoint 0x%X has invalid maxpacket %d\n", "bulk endpoint 0x%X has invalid maxpacket %d\n",
...@@ -452,7 +459,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, ...@@ -452,7 +459,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno,
} }
/* Parse a possible SuperSpeed endpoint companion descriptor */ /* Parse a possible SuperSpeed endpoint companion descriptor */
if (to_usb_device(ddev)->speed >= USB_SPEED_SUPER) if (udev->speed >= USB_SPEED_SUPER)
usb_parse_ss_endpoint_companion(ddev, cfgno, usb_parse_ss_endpoint_companion(ddev, cfgno,
inum, asnum, endpoint, buffer, size); inum, asnum, endpoint, buffer, size);
......
...@@ -38,7 +38,9 @@ ...@@ -38,7 +38,9 @@
#include "otg_whitelist.h" #include "otg_whitelist.h"
#define USB_VENDOR_GENESYS_LOGIC 0x05e3 #define USB_VENDOR_GENESYS_LOGIC 0x05e3
#define USB_VENDOR_SMSC 0x0424
#define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01
#define HUB_QUIRK_DISABLE_AUTOSUSPEND 0x02
#define USB_TP_TRANSMISSION_DELAY 40 /* ns */ #define USB_TP_TRANSMISSION_DELAY 40 /* ns */
#define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */ #define USB_TP_TRANSMISSION_DELAY_MAX 65535 /* ns */
...@@ -1217,11 +1219,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) ...@@ -1217,11 +1219,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
#ifdef CONFIG_PM #ifdef CONFIG_PM
udev->reset_resume = 1; udev->reset_resume = 1;
#endif #endif
/* Don't set the change_bits when the device
* was powered off.
*/
if (test_bit(port1, hub->power_bits))
set_bit(port1, hub->change_bits);
} else { } else {
/* The power session is gone; tell hub_wq */ /* The power session is gone; tell hub_wq */
...@@ -1731,6 +1728,10 @@ static void hub_disconnect(struct usb_interface *intf) ...@@ -1731,6 +1728,10 @@ static void hub_disconnect(struct usb_interface *intf)
kfree(hub->buffer); kfree(hub->buffer);
pm_suspend_ignore_children(&intf->dev, false); pm_suspend_ignore_children(&intf->dev, false);
if (hub->quirk_disable_autosuspend)
usb_autopm_put_interface(intf);
kref_put(&hub->kref, hub_release); kref_put(&hub->kref, hub_release);
} }
...@@ -1863,6 +1864,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -1863,6 +1864,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND) if (id->driver_info & HUB_QUIRK_CHECK_PORT_AUTOSUSPEND)
hub->quirk_check_port_auto_suspend = 1; hub->quirk_check_port_auto_suspend = 1;
if (id->driver_info & HUB_QUIRK_DISABLE_AUTOSUSPEND) {
hub->quirk_disable_autosuspend = 1;
usb_autopm_get_interface(intf);
}
if (hub_configure(hub, &desc->endpoint[0].desc) >= 0) if (hub_configure(hub, &desc->endpoint[0].desc) >= 0)
return 0; return 0;
...@@ -5599,6 +5605,10 @@ static void hub_event(struct work_struct *work) ...@@ -5599,6 +5605,10 @@ static void hub_event(struct work_struct *work)
} }
static const struct usb_device_id hub_id_table[] = { static const struct usb_device_id hub_id_table[] = {
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS,
.idVendor = USB_VENDOR_SMSC,
.bInterfaceClass = USB_CLASS_HUB,
.driver_info = HUB_QUIRK_DISABLE_AUTOSUSPEND},
{ .match_flags = USB_DEVICE_ID_MATCH_VENDOR { .match_flags = USB_DEVICE_ID_MATCH_VENDOR
| USB_DEVICE_ID_MATCH_INT_CLASS, | USB_DEVICE_ID_MATCH_INT_CLASS,
.idVendor = USB_VENDOR_GENESYS_LOGIC, .idVendor = USB_VENDOR_GENESYS_LOGIC,
......
...@@ -61,6 +61,7 @@ struct usb_hub { ...@@ -61,6 +61,7 @@ struct usb_hub {
unsigned quiescing:1; unsigned quiescing:1;
unsigned disconnected:1; unsigned disconnected:1;
unsigned in_reset:1; unsigned in_reset:1;
unsigned quirk_disable_autosuspend:1;
unsigned quirk_check_port_auto_suspend:1; unsigned quirk_check_port_auto_suspend:1;
......
...@@ -354,6 +354,10 @@ static const struct usb_device_id usb_quirk_list[] = { ...@@ -354,6 +354,10 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0904, 0x6103), .driver_info = { USB_DEVICE(0x0904, 0x6103), .driver_info =
USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL }, USB_QUIRK_LINEAR_FRAME_INTR_BINTERVAL },
/* Sound Devices USBPre2 */
{ USB_DEVICE(0x0926, 0x0202), .driver_info =
USB_QUIRK_ENDPOINT_BLACKLIST },
/* Keytouch QWERTY Panel keyboard */ /* Keytouch QWERTY Panel keyboard */
{ USB_DEVICE(0x0926, 0x3333), .driver_info = { USB_DEVICE(0x0926, 0x3333), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS }, USB_QUIRK_CONFIG_INTF_STRINGS },
...@@ -445,6 +449,9 @@ static const struct usb_device_id usb_quirk_list[] = { ...@@ -445,6 +449,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* INTEL VALUE SSD */ /* INTEL VALUE SSD */
{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
/* novation SoundControl XL */
{ USB_DEVICE(0x1235, 0x0061), .driver_info = USB_QUIRK_RESET_RESUME },
{ } /* terminating entry must be last */ { } /* terminating entry must be last */
}; };
...@@ -472,6 +479,39 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = { ...@@ -472,6 +479,39 @@ static const struct usb_device_id usb_amd_resume_quirk_list[] = {
{ } /* terminating entry must be last */ { } /* terminating entry must be last */
}; };
/*
* Entries for blacklisted endpoints that should be ignored when parsing
* configuration descriptors.
*
* Matched for devices with USB_QUIRK_ENDPOINT_BLACKLIST.
*/
static const struct usb_device_id usb_endpoint_blacklist[] = {
{ USB_DEVICE_INTERFACE_NUMBER(0x0926, 0x0202, 1), .driver_info = 0x85 },
{ }
};
bool usb_endpoint_is_blacklisted(struct usb_device *udev,
struct usb_host_interface *intf,
struct usb_endpoint_descriptor *epd)
{
const struct usb_device_id *id;
unsigned int address;
for (id = usb_endpoint_blacklist; id->match_flags; ++id) {
if (!usb_match_device(udev, id))
continue;
if (!usb_match_one_id_intf(udev, intf, id))
continue;
address = id->driver_info;
if (address == epd->bEndpointAddress)
return true;
}
return false;
}
static bool usb_match_any_interface(struct usb_device *udev, static bool usb_match_any_interface(struct usb_device *udev,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
......
...@@ -37,6 +37,9 @@ extern void usb_authorize_interface(struct usb_interface *); ...@@ -37,6 +37,9 @@ extern void usb_authorize_interface(struct usb_interface *);
extern void usb_detect_quirks(struct usb_device *udev); extern void usb_detect_quirks(struct usb_device *udev);
extern void usb_detect_interface_quirks(struct usb_device *udev); extern void usb_detect_interface_quirks(struct usb_device *udev);
extern void usb_release_quirk_list(void); extern void usb_release_quirk_list(void);
extern bool usb_endpoint_is_blacklisted(struct usb_device *udev,
struct usb_host_interface *intf,
struct usb_endpoint_descriptor *epd);
extern int usb_remove_device(struct usb_device *udev); extern int usb_remove_device(struct usb_device *udev);
extern int usb_get_device_descriptor(struct usb_device *dev, extern int usb_get_device_descriptor(struct usb_device *dev,
......
...@@ -1083,11 +1083,6 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg, ...@@ -1083,11 +1083,6 @@ static void dwc2_hsotg_start_req(struct dwc2_hsotg *hsotg,
else else
packets = 1; /* send one packet if length is zero. */ packets = 1; /* send one packet if length is zero. */
if (hs_ep->isochronous && length > (hs_ep->mc * hs_ep->ep.maxpacket)) {
dev_err(hsotg->dev, "req length > maxpacket*mc\n");
return;
}
if (dir_in && index != 0) if (dir_in && index != 0)
if (hs_ep->isochronous) if (hs_ep->isochronous)
epsize = DXEPTSIZ_MC(packets); epsize = DXEPTSIZ_MC(packets);
...@@ -1391,6 +1386,13 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req, ...@@ -1391,6 +1386,13 @@ static int dwc2_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
req->actual = 0; req->actual = 0;
req->status = -EINPROGRESS; req->status = -EINPROGRESS;
/* Don't queue ISOC request if length greater than mps*mc */
if (hs_ep->isochronous &&
req->length > (hs_ep->mc * hs_ep->ep.maxpacket)) {
dev_err(hs->dev, "req length > maxpacket*mc\n");
return -EINVAL;
}
/* In DDMA mode for ISOC's don't queue request if length greater /* In DDMA mode for ISOC's don't queue request if length greater
* than descriptor limits. * than descriptor limits.
*/ */
...@@ -1632,6 +1634,7 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, ...@@ -1632,6 +1634,7 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0]; struct dwc2_hsotg_ep *ep0 = hsotg->eps_out[0];
struct dwc2_hsotg_ep *ep; struct dwc2_hsotg_ep *ep;
__le16 reply; __le16 reply;
u16 status;
int ret; int ret;
dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__); dev_dbg(hsotg->dev, "%s: USB_REQ_GET_STATUS\n", __func__);
...@@ -1643,11 +1646,10 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg, ...@@ -1643,11 +1646,10 @@ static int dwc2_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
switch (ctrl->bRequestType & USB_RECIP_MASK) { switch (ctrl->bRequestType & USB_RECIP_MASK) {
case USB_RECIP_DEVICE: case USB_RECIP_DEVICE:
/* status = 1 << USB_DEVICE_SELF_POWERED;
* bit 0 => self powered status |= hsotg->remote_wakeup_allowed <<
* bit 1 => remote wakeup USB_DEVICE_REMOTE_WAKEUP;
*/ reply = cpu_to_le16(status);
reply = cpu_to_le16(0);
break; break;
case USB_RECIP_INTERFACE: case USB_RECIP_INTERFACE:
...@@ -1758,7 +1760,10 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, ...@@ -1758,7 +1760,10 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
case USB_RECIP_DEVICE: case USB_RECIP_DEVICE:
switch (wValue) { switch (wValue) {
case USB_DEVICE_REMOTE_WAKEUP: case USB_DEVICE_REMOTE_WAKEUP:
if (set)
hsotg->remote_wakeup_allowed = 1; hsotg->remote_wakeup_allowed = 1;
else
hsotg->remote_wakeup_allowed = 0;
break; break;
case USB_DEVICE_TEST_MODE: case USB_DEVICE_TEST_MODE:
...@@ -1768,6 +1773,11 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, ...@@ -1768,6 +1773,11 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
return -EINVAL; return -EINVAL;
hsotg->test_mode = wIndex >> 8; hsotg->test_mode = wIndex >> 8;
break;
default:
return -ENOENT;
}
ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0); ret = dwc2_hsotg_send_reply(hsotg, ep0, NULL, 0);
if (ret) { if (ret) {
dev_err(hsotg->dev, dev_err(hsotg->dev,
...@@ -1775,10 +1785,6 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg, ...@@ -1775,10 +1785,6 @@ static int dwc2_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
return ret; return ret;
} }
break; break;
default:
return -ENOENT;
}
break;
case USB_RECIP_ENDPOINT: case USB_RECIP_ENDPOINT:
ep = ep_from_windex(hsotg, wIndex); ep = ep_from_windex(hsotg, wIndex);
......
...@@ -256,86 +256,77 @@ static inline const char *dwc3_ep_event_string(char *str, size_t size, ...@@ -256,86 +256,77 @@ static inline const char *dwc3_ep_event_string(char *str, size_t size,
u8 epnum = event->endpoint_number; u8 epnum = event->endpoint_number;
size_t len; size_t len;
int status; int status;
int ret;
ret = snprintf(str, size, "ep%d%s: ", epnum >> 1, len = scnprintf(str, size, "ep%d%s: ", epnum >> 1,
(epnum & 1) ? "in" : "out"); (epnum & 1) ? "in" : "out");
if (ret < 0)
return "UNKNOWN";
status = event->status; status = event->status;
switch (event->endpoint_event) { switch (event->endpoint_event) {
case DWC3_DEPEVT_XFERCOMPLETE: case DWC3_DEPEVT_XFERCOMPLETE:
len = strlen(str); len += scnprintf(str + len, size - len,
snprintf(str + len, size - len, "Transfer Complete (%c%c%c)", "Transfer Complete (%c%c%c)",
status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_SHORT ? 'S' : 's',
status & DEPEVT_STATUS_IOC ? 'I' : 'i', status & DEPEVT_STATUS_IOC ? 'I' : 'i',
status & DEPEVT_STATUS_LST ? 'L' : 'l'); status & DEPEVT_STATUS_LST ? 'L' : 'l');
len = strlen(str);
if (epnum <= 1) if (epnum <= 1)
snprintf(str + len, size - len, " [%s]", scnprintf(str + len, size - len, " [%s]",
dwc3_ep0_state_string(ep0state)); dwc3_ep0_state_string(ep0state));
break; break;
case DWC3_DEPEVT_XFERINPROGRESS: case DWC3_DEPEVT_XFERINPROGRESS:
len = strlen(str); scnprintf(str + len, size - len,
"Transfer In Progress [%d] (%c%c%c)",
snprintf(str + len, size - len, "Transfer In Progress [%d] (%c%c%c)",
event->parameters, event->parameters,
status & DEPEVT_STATUS_SHORT ? 'S' : 's', status & DEPEVT_STATUS_SHORT ? 'S' : 's',
status & DEPEVT_STATUS_IOC ? 'I' : 'i', status & DEPEVT_STATUS_IOC ? 'I' : 'i',
status & DEPEVT_STATUS_LST ? 'M' : 'm'); status & DEPEVT_STATUS_LST ? 'M' : 'm');
break; break;
case DWC3_DEPEVT_XFERNOTREADY: case DWC3_DEPEVT_XFERNOTREADY:
len = strlen(str); len += scnprintf(str + len, size - len,
"Transfer Not Ready [%d]%s",
snprintf(str + len, size - len, "Transfer Not Ready [%d]%s",
event->parameters, event->parameters,
status & DEPEVT_STATUS_TRANSFER_ACTIVE ? status & DEPEVT_STATUS_TRANSFER_ACTIVE ?
" (Active)" : " (Not Active)"); " (Active)" : " (Not Active)");
len = strlen(str);
/* Control Endpoints */ /* Control Endpoints */
if (epnum <= 1) { if (epnum <= 1) {
int phase = DEPEVT_STATUS_CONTROL_PHASE(event->status); int phase = DEPEVT_STATUS_CONTROL_PHASE(event->status);
switch (phase) { switch (phase) {
case DEPEVT_STATUS_CONTROL_DATA: case DEPEVT_STATUS_CONTROL_DATA:
snprintf(str + ret, size - ret, scnprintf(str + len, size - len,
" [Data Phase]"); " [Data Phase]");
break; break;
case DEPEVT_STATUS_CONTROL_STATUS: case DEPEVT_STATUS_CONTROL_STATUS:
snprintf(str + ret, size - ret, scnprintf(str + len, size - len,
" [Status Phase]"); " [Status Phase]");
} }
} }
break; break;
case DWC3_DEPEVT_RXTXFIFOEVT: case DWC3_DEPEVT_RXTXFIFOEVT:
snprintf(str + ret, size - ret, "FIFO"); scnprintf(str + len, size - len, "FIFO");
break; break;
case DWC3_DEPEVT_STREAMEVT: case DWC3_DEPEVT_STREAMEVT:
status = event->status; status = event->status;
switch (status) { switch (status) {
case DEPEVT_STREAMEVT_FOUND: case DEPEVT_STREAMEVT_FOUND:
snprintf(str + ret, size - ret, " Stream %d Found", scnprintf(str + len, size - len, " Stream %d Found",
event->parameters); event->parameters);
break; break;
case DEPEVT_STREAMEVT_NOTFOUND: case DEPEVT_STREAMEVT_NOTFOUND:
default: default:
snprintf(str + ret, size - ret, " Stream Not Found"); scnprintf(str + len, size - len, " Stream Not Found");
break; break;
} }
break; break;
case DWC3_DEPEVT_EPCMDCMPLT: case DWC3_DEPEVT_EPCMDCMPLT:
snprintf(str + ret, size - ret, "Endpoint Command Complete"); scnprintf(str + len, size - len, "Endpoint Command Complete");
break; break;
default: default:
snprintf(str, size, "UNKNOWN"); scnprintf(str + len, size - len, "UNKNOWN");
} }
return str; return str;
......
...@@ -2429,7 +2429,8 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep, ...@@ -2429,7 +2429,8 @@ static int dwc3_gadget_ep_reclaim_completed_trb(struct dwc3_ep *dep,
if (event->status & DEPEVT_STATUS_SHORT && !chain) if (event->status & DEPEVT_STATUS_SHORT && !chain)
return 1; return 1;
if (event->status & DEPEVT_STATUS_IOC) if ((trb->ctrl & DWC3_TRB_CTRL_IOC) ||
(trb->ctrl & DWC3_TRB_CTRL_LST))
return 1; return 1;
return 0; return 0;
......
...@@ -437,12 +437,14 @@ static u8 encode_bMaxPower(enum usb_device_speed speed, ...@@ -437,12 +437,14 @@ static u8 encode_bMaxPower(enum usb_device_speed speed,
val = CONFIG_USB_GADGET_VBUS_DRAW; val = CONFIG_USB_GADGET_VBUS_DRAW;
if (!val) if (!val)
return 0; return 0;
switch (speed) { if (speed < USB_SPEED_SUPER)
case USB_SPEED_SUPER: return min(val, 500U) / 2;
return DIV_ROUND_UP(val, 8); else
default: /*
return DIV_ROUND_UP(val, 2); * USB 3.x supports up to 900mA, but since 900 isn't divisible
} * by 8 the integral division will effectively cap to 896mA.
*/
return min(val, 900U) / 8;
} }
static int config_buf(struct usb_configuration *config, static int config_buf(struct usb_configuration *config,
...@@ -854,6 +856,10 @@ static int set_config(struct usb_composite_dev *cdev, ...@@ -854,6 +856,10 @@ static int set_config(struct usb_composite_dev *cdev,
/* when we return, be sure our power usage is valid */ /* when we return, be sure our power usage is valid */
power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW; power = c->MaxPower ? c->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW;
if (gadget->speed < USB_SPEED_SUPER)
power = min(power, 500U);
else
power = min(power, 900U);
done: done:
usb_gadget_vbus_draw(gadget, power); usb_gadget_vbus_draw(gadget, power);
if (result >= 0 && cdev->delayed_status) if (result >= 0 && cdev->delayed_status)
...@@ -2280,7 +2286,7 @@ void composite_resume(struct usb_gadget *gadget) ...@@ -2280,7 +2286,7 @@ void composite_resume(struct usb_gadget *gadget)
{ {
struct usb_composite_dev *cdev = get_gadget_data(gadget); struct usb_composite_dev *cdev = get_gadget_data(gadget);
struct usb_function *f; struct usb_function *f;
u16 maxpower; unsigned maxpower;
/* REVISIT: should we have config level /* REVISIT: should we have config level
* suspend/resume callbacks? * suspend/resume callbacks?
...@@ -2294,10 +2300,14 @@ void composite_resume(struct usb_gadget *gadget) ...@@ -2294,10 +2300,14 @@ void composite_resume(struct usb_gadget *gadget)
f->resume(f); f->resume(f);
} }
maxpower = cdev->config->MaxPower; maxpower = cdev->config->MaxPower ?
cdev->config->MaxPower : CONFIG_USB_GADGET_VBUS_DRAW;
if (gadget->speed < USB_SPEED_SUPER)
maxpower = min(maxpower, 500U);
else
maxpower = min(maxpower, 900U);
usb_gadget_vbus_draw(gadget, maxpower ? usb_gadget_vbus_draw(gadget, maxpower);
maxpower : CONFIG_USB_GADGET_VBUS_DRAW);
} }
cdev->suspended = 0; cdev->suspended = 0;
......
...@@ -1162,18 +1162,19 @@ static int ffs_aio_cancel(struct kiocb *kiocb) ...@@ -1162,18 +1162,19 @@ static int ffs_aio_cancel(struct kiocb *kiocb)
{ {
struct ffs_io_data *io_data = kiocb->private; struct ffs_io_data *io_data = kiocb->private;
struct ffs_epfile *epfile = kiocb->ki_filp->private_data; struct ffs_epfile *epfile = kiocb->ki_filp->private_data;
unsigned long flags;
int value; int value;
ENTER(); ENTER();
spin_lock_irq(&epfile->ffs->eps_lock); spin_lock_irqsave(&epfile->ffs->eps_lock, flags);
if (likely(io_data && io_data->ep && io_data->req)) if (likely(io_data && io_data->ep && io_data->req))
value = usb_ep_dequeue(io_data->ep, io_data->req); value = usb_ep_dequeue(io_data->ep, io_data->req);
else else
value = -EINVAL; value = -EINVAL;
spin_unlock_irq(&epfile->ffs->eps_lock); spin_unlock_irqrestore(&epfile->ffs->eps_lock, flags);
return value; return value;
} }
......
...@@ -361,7 +361,7 @@ int u_audio_start_capture(struct g_audio *audio_dev) ...@@ -361,7 +361,7 @@ int u_audio_start_capture(struct g_audio *audio_dev)
ep = audio_dev->out_ep; ep = audio_dev->out_ep;
prm = &uac->c_prm; prm = &uac->c_prm;
config_ep_by_speed(gadget, &audio_dev->func, ep); config_ep_by_speed(gadget, &audio_dev->func, ep);
req_len = prm->max_psize; req_len = ep->maxpacket;
prm->ep_enabled = true; prm->ep_enabled = true;
usb_ep_enable(ep); usb_ep_enable(ep);
...@@ -379,7 +379,7 @@ int u_audio_start_capture(struct g_audio *audio_dev) ...@@ -379,7 +379,7 @@ int u_audio_start_capture(struct g_audio *audio_dev)
req->context = &prm->ureq[i]; req->context = &prm->ureq[i];
req->length = req_len; req->length = req_len;
req->complete = u_audio_iso_complete; req->complete = u_audio_iso_complete;
req->buf = prm->rbuf + i * prm->max_psize; req->buf = prm->rbuf + i * ep->maxpacket;
} }
if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC)) if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC))
...@@ -430,9 +430,9 @@ int u_audio_start_playback(struct g_audio *audio_dev) ...@@ -430,9 +430,9 @@ int u_audio_start_playback(struct g_audio *audio_dev)
uac->p_pktsize = min_t(unsigned int, uac->p_pktsize = min_t(unsigned int,
uac->p_framesize * uac->p_framesize *
(params->p_srate / uac->p_interval), (params->p_srate / uac->p_interval),
prm->max_psize); ep->maxpacket);
if (uac->p_pktsize < prm->max_psize) if (uac->p_pktsize < ep->maxpacket)
uac->p_pktsize_residue = uac->p_framesize * uac->p_pktsize_residue = uac->p_framesize *
(params->p_srate % uac->p_interval); (params->p_srate % uac->p_interval);
else else
...@@ -457,7 +457,7 @@ int u_audio_start_playback(struct g_audio *audio_dev) ...@@ -457,7 +457,7 @@ int u_audio_start_playback(struct g_audio *audio_dev)
req->context = &prm->ureq[i]; req->context = &prm->ureq[i];
req->length = req_len; req->length = req_len;
req->complete = u_audio_iso_complete; req->complete = u_audio_iso_complete;
req->buf = prm->rbuf + i * prm->max_psize; req->buf = prm->rbuf + i * ep->maxpacket;
} }
if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC)) if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC))
......
...@@ -561,8 +561,10 @@ static int gs_start_io(struct gs_port *port) ...@@ -561,8 +561,10 @@ static int gs_start_io(struct gs_port *port)
port->n_read = 0; port->n_read = 0;
started = gs_start_rx(port); started = gs_start_rx(port);
/* unblock any pending writes into our circular buffer */
if (started) { if (started) {
gs_start_tx(port);
/* Unblock any pending writes into our circular buffer, in case
* we didn't in gs_start_tx() */
tty_wakeup(port->port.tty); tty_wakeup(port->port.tty);
} else { } else {
gs_free_requests(ep, head, &port->read_allocated); gs_free_requests(ep, head, &port->read_allocated);
......
...@@ -1399,7 +1399,6 @@ static int xudc_start(struct usb_gadget *gadget, ...@@ -1399,7 +1399,6 @@ static int xudc_start(struct usb_gadget *gadget,
/** /**
* xudc_stop - stops the device. * xudc_stop - stops the device.
* @gadget: pointer to the usb gadget structure * @gadget: pointer to the usb gadget structure
* @driver: pointer to usb gadget driver structure
* *
* Return: zero always * Return: zero always
*/ */
......
...@@ -55,6 +55,7 @@ static u8 usb_bos_descriptor [] = { ...@@ -55,6 +55,7 @@ static u8 usb_bos_descriptor [] = {
static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf, static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
u16 wLength) u16 wLength)
{ {
struct xhci_port_cap *port_cap = NULL;
int i, ssa_count; int i, ssa_count;
u32 temp; u32 temp;
u16 desc_size, ssp_cap_size, ssa_size = 0; u16 desc_size, ssp_cap_size, ssa_size = 0;
...@@ -64,16 +65,24 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf, ...@@ -64,16 +65,24 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
ssp_cap_size = sizeof(usb_bos_descriptor) - desc_size; ssp_cap_size = sizeof(usb_bos_descriptor) - desc_size;
/* does xhci support USB 3.1 Enhanced SuperSpeed */ /* does xhci support USB 3.1 Enhanced SuperSpeed */
if (xhci->usb3_rhub.min_rev >= 0x01) { for (i = 0; i < xhci->num_port_caps; i++) {
if (xhci->port_caps[i].maj_rev == 0x03 &&
xhci->port_caps[i].min_rev >= 0x01) {
usb3_1 = true;
port_cap = &xhci->port_caps[i];
break;
}
}
if (usb3_1) {
/* does xhci provide a PSI table for SSA speed attributes? */ /* does xhci provide a PSI table for SSA speed attributes? */
if (xhci->usb3_rhub.psi_count) { if (port_cap->psi_count) {
/* two SSA entries for each unique PSI ID, RX and TX */ /* two SSA entries for each unique PSI ID, RX and TX */
ssa_count = xhci->usb3_rhub.psi_uid_count * 2; ssa_count = port_cap->psi_uid_count * 2;
ssa_size = ssa_count * sizeof(u32); ssa_size = ssa_count * sizeof(u32);
ssp_cap_size -= 16; /* skip copying the default SSA */ ssp_cap_size -= 16; /* skip copying the default SSA */
} }
desc_size += ssp_cap_size; desc_size += ssp_cap_size;
usb3_1 = true;
} }
memcpy(buf, &usb_bos_descriptor, min(desc_size, wLength)); memcpy(buf, &usb_bos_descriptor, min(desc_size, wLength));
...@@ -99,7 +108,7 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf, ...@@ -99,7 +108,7 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
} }
/* If PSI table exists, add the custom speed attributes from it */ /* If PSI table exists, add the custom speed attributes from it */
if (usb3_1 && xhci->usb3_rhub.psi_count) { if (usb3_1 && port_cap->psi_count) {
u32 ssp_cap_base, bm_attrib, psi, psi_mant, psi_exp; u32 ssp_cap_base, bm_attrib, psi, psi_mant, psi_exp;
int offset; int offset;
...@@ -111,7 +120,7 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf, ...@@ -111,7 +120,7 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
/* attribute count SSAC bits 4:0 and ID count SSIC bits 8:5 */ /* attribute count SSAC bits 4:0 and ID count SSIC bits 8:5 */
bm_attrib = (ssa_count - 1) & 0x1f; bm_attrib = (ssa_count - 1) & 0x1f;
bm_attrib |= (xhci->usb3_rhub.psi_uid_count - 1) << 5; bm_attrib |= (port_cap->psi_uid_count - 1) << 5;
put_unaligned_le32(bm_attrib, &buf[ssp_cap_base + 4]); put_unaligned_le32(bm_attrib, &buf[ssp_cap_base + 4]);
if (wLength < desc_size + ssa_size) if (wLength < desc_size + ssa_size)
...@@ -124,8 +133,8 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf, ...@@ -124,8 +133,8 @@ static int xhci_create_usb3_bos_desc(struct xhci_hcd *xhci, char *buf,
* USB 3.1 requires two SSA entries (RX and TX) for every link * USB 3.1 requires two SSA entries (RX and TX) for every link
*/ */
offset = desc_size; offset = desc_size;
for (i = 0; i < xhci->usb3_rhub.psi_count; i++) { for (i = 0; i < port_cap->psi_count; i++) {
psi = xhci->usb3_rhub.psi[i]; psi = port_cap->psi[i];
psi &= ~USB_SSP_SUBLINK_SPEED_RSVD; psi &= ~USB_SSP_SUBLINK_SPEED_RSVD;
psi_exp = XHCI_EXT_PORT_PSIE(psi); psi_exp = XHCI_EXT_PORT_PSIE(psi);
psi_mant = XHCI_EXT_PORT_PSIM(psi); psi_mant = XHCI_EXT_PORT_PSIM(psi);
......
...@@ -1475,9 +1475,15 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, ...@@ -1475,9 +1475,15 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
/* Allow 3 retries for everything but isoc, set CErr = 3 */ /* Allow 3 retries for everything but isoc, set CErr = 3 */
if (!usb_endpoint_xfer_isoc(&ep->desc)) if (!usb_endpoint_xfer_isoc(&ep->desc))
err_count = 3; err_count = 3;
/* Some devices get this wrong */ /* HS bulk max packet should be 512, FS bulk supports 8, 16, 32 or 64 */
if (usb_endpoint_xfer_bulk(&ep->desc) && udev->speed == USB_SPEED_HIGH) if (usb_endpoint_xfer_bulk(&ep->desc)) {
if (udev->speed == USB_SPEED_HIGH)
max_packet = 512; max_packet = 512;
if (udev->speed == USB_SPEED_FULL) {
max_packet = rounddown_pow_of_two(max_packet);
max_packet = clamp_val(max_packet, 8, 64);
}
}
/* xHCI 1.0 and 1.1 indicates that ctrl ep avg TRB Length should be 8 */ /* xHCI 1.0 and 1.1 indicates that ctrl ep avg TRB Length should be 8 */
if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100) if (usb_endpoint_xfer_control(&ep->desc) && xhci->hci_version >= 0x100)
avg_trb_len = 8; avg_trb_len = 8;
...@@ -1909,17 +1915,17 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) ...@@ -1909,17 +1915,17 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->usb3_rhub.num_ports = 0; xhci->usb3_rhub.num_ports = 0;
xhci->num_active_eps = 0; xhci->num_active_eps = 0;
kfree(xhci->usb2_rhub.ports); kfree(xhci->usb2_rhub.ports);
kfree(xhci->usb2_rhub.psi);
kfree(xhci->usb3_rhub.ports); kfree(xhci->usb3_rhub.ports);
kfree(xhci->usb3_rhub.psi);
kfree(xhci->hw_ports); kfree(xhci->hw_ports);
kfree(xhci->rh_bw); kfree(xhci->rh_bw);
kfree(xhci->ext_caps); kfree(xhci->ext_caps);
for (i = 0; i < xhci->num_port_caps; i++)
kfree(xhci->port_caps[i].psi);
kfree(xhci->port_caps);
xhci->num_port_caps = 0;
xhci->usb2_rhub.ports = NULL; xhci->usb2_rhub.ports = NULL;
xhci->usb2_rhub.psi = NULL;
xhci->usb3_rhub.ports = NULL; xhci->usb3_rhub.ports = NULL;
xhci->usb3_rhub.psi = NULL;
xhci->hw_ports = NULL; xhci->hw_ports = NULL;
xhci->rh_bw = NULL; xhci->rh_bw = NULL;
xhci->ext_caps = NULL; xhci->ext_caps = NULL;
...@@ -2120,6 +2126,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, ...@@ -2120,6 +2126,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
u8 major_revision, minor_revision; u8 major_revision, minor_revision;
struct xhci_hub *rhub; struct xhci_hub *rhub;
struct device *dev = xhci_to_hcd(xhci)->self.sysdev; struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
struct xhci_port_cap *port_cap;
temp = readl(addr); temp = readl(addr);
major_revision = XHCI_EXT_PORT_MAJOR(temp); major_revision = XHCI_EXT_PORT_MAJOR(temp);
...@@ -2154,31 +2161,39 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, ...@@ -2154,31 +2161,39 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
/* WTF? "Valid values are ‘1’ to MaxPorts" */ /* WTF? "Valid values are ‘1’ to MaxPorts" */
return; return;
rhub->psi_count = XHCI_EXT_PORT_PSIC(temp); port_cap = &xhci->port_caps[xhci->num_port_caps++];
if (rhub->psi_count) { if (xhci->num_port_caps > max_caps)
rhub->psi = kcalloc_node(rhub->psi_count, sizeof(*rhub->psi), return;
port_cap->maj_rev = major_revision;
port_cap->min_rev = minor_revision;
port_cap->psi_count = XHCI_EXT_PORT_PSIC(temp);
if (port_cap->psi_count) {
port_cap->psi = kcalloc_node(port_cap->psi_count,
sizeof(*port_cap->psi),
GFP_KERNEL, dev_to_node(dev)); GFP_KERNEL, dev_to_node(dev));
if (!rhub->psi) if (!port_cap->psi)
rhub->psi_count = 0; port_cap->psi_count = 0;
rhub->psi_uid_count++; port_cap->psi_uid_count++;
for (i = 0; i < rhub->psi_count; i++) { for (i = 0; i < port_cap->psi_count; i++) {
rhub->psi[i] = readl(addr + 4 + i); port_cap->psi[i] = readl(addr + 4 + i);
/* count unique ID values, two consecutive entries can /* count unique ID values, two consecutive entries can
* have the same ID if link is assymetric * have the same ID if link is assymetric
*/ */
if (i && (XHCI_EXT_PORT_PSIV(rhub->psi[i]) != if (i && (XHCI_EXT_PORT_PSIV(port_cap->psi[i]) !=
XHCI_EXT_PORT_PSIV(rhub->psi[i - 1]))) XHCI_EXT_PORT_PSIV(port_cap->psi[i - 1])))
rhub->psi_uid_count++; port_cap->psi_uid_count++;
xhci_dbg(xhci, "PSIV:%d PSIE:%d PLT:%d PFD:%d LP:%d PSIM:%d\n", xhci_dbg(xhci, "PSIV:%d PSIE:%d PLT:%d PFD:%d LP:%d PSIM:%d\n",
XHCI_EXT_PORT_PSIV(rhub->psi[i]), XHCI_EXT_PORT_PSIV(port_cap->psi[i]),
XHCI_EXT_PORT_PSIE(rhub->psi[i]), XHCI_EXT_PORT_PSIE(port_cap->psi[i]),
XHCI_EXT_PORT_PLT(rhub->psi[i]), XHCI_EXT_PORT_PLT(port_cap->psi[i]),
XHCI_EXT_PORT_PFD(rhub->psi[i]), XHCI_EXT_PORT_PFD(port_cap->psi[i]),
XHCI_EXT_PORT_LP(rhub->psi[i]), XHCI_EXT_PORT_LP(port_cap->psi[i]),
XHCI_EXT_PORT_PSIM(rhub->psi[i])); XHCI_EXT_PORT_PSIM(port_cap->psi[i]));
} }
} }
/* cache usb2 port capabilities */ /* cache usb2 port capabilities */
...@@ -2213,6 +2228,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports, ...@@ -2213,6 +2228,7 @@ static void xhci_add_in_port(struct xhci_hcd *xhci, unsigned int num_ports,
continue; continue;
} }
hw_port->rhub = rhub; hw_port->rhub = rhub;
hw_port->port_cap = port_cap;
rhub->num_ports++; rhub->num_ports++;
} }
/* FIXME: Should we disable ports not in the Extended Capabilities? */ /* FIXME: Should we disable ports not in the Extended Capabilities? */
...@@ -2303,6 +2319,11 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) ...@@ -2303,6 +2319,11 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
if (!xhci->ext_caps) if (!xhci->ext_caps)
return -ENOMEM; return -ENOMEM;
xhci->port_caps = kcalloc_node(cap_count, sizeof(*xhci->port_caps),
flags, dev_to_node(dev));
if (!xhci->port_caps)
return -ENOMEM;
offset = cap_start; offset = cap_start;
while (offset) { while (offset) {
......
...@@ -49,6 +49,7 @@ ...@@ -49,6 +49,7 @@
#define PCI_DEVICE_ID_INTEL_TITAN_RIDGE_4C_XHCI 0x15ec #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_TITAN_RIDGE_DD_XHCI 0x15f0
#define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13 #define PCI_DEVICE_ID_INTEL_ICE_LAKE_XHCI 0x8a13
#define PCI_DEVICE_ID_INTEL_CML_XHCI 0xa3af
#define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9 #define PCI_DEVICE_ID_AMD_PROMONTORYA_4 0x43b9
#define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba #define PCI_DEVICE_ID_AMD_PROMONTORYA_3 0x43ba
...@@ -187,7 +188,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci) ...@@ -187,7 +188,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_M_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_BROXTON_B_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI || pdev->device == PCI_DEVICE_ID_INTEL_APL_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI)) { pdev->device == PCI_DEVICE_ID_INTEL_DNV_XHCI ||
pdev->device == PCI_DEVICE_ID_INTEL_CML_XHCI)) {
xhci->quirks |= XHCI_PME_STUCK_QUIRK; xhci->quirks |= XHCI_PME_STUCK_QUIRK;
} }
if (pdev->vendor == PCI_VENDOR_ID_INTEL && if (pdev->vendor == PCI_VENDOR_ID_INTEL &&
...@@ -302,6 +304,9 @@ static int xhci_pci_setup(struct usb_hcd *hcd) ...@@ -302,6 +304,9 @@ static int xhci_pci_setup(struct usb_hcd *hcd)
if (!usb_hcd_is_primary_hcd(hcd)) if (!usb_hcd_is_primary_hcd(hcd))
return 0; return 0;
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
xhci_pme_acpi_rtd3_enable(pdev);
xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
/* Find any debug ports */ /* Find any debug ports */
...@@ -359,9 +364,6 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) ...@@ -359,9 +364,6 @@ static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
HCC_MAX_PSA(xhci->hcc_params) >= 4) HCC_MAX_PSA(xhci->hcc_params) >= 4)
xhci->shared_hcd->can_do_streams = 1; xhci->shared_hcd->can_do_streams = 1;
if (xhci->quirks & XHCI_PME_STUCK_QUIRK)
xhci_pme_acpi_rtd3_enable(dev);
/* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */ /* USB-2 and USB-3 roothubs initialized, allow runtime pm suspend */
pm_runtime_put_noidle(&dev->dev); pm_runtime_put_noidle(&dev->dev);
......
...@@ -1702,12 +1702,20 @@ struct xhci_bus_state { ...@@ -1702,12 +1702,20 @@ struct xhci_bus_state {
* Intel Lynx Point LP xHCI host. * Intel Lynx Point LP xHCI host.
*/ */
#define XHCI_MAX_REXIT_TIMEOUT_MS 20 #define XHCI_MAX_REXIT_TIMEOUT_MS 20
struct xhci_port_cap {
u32 *psi; /* array of protocol speed ID entries */
u8 psi_count;
u8 psi_uid_count;
u8 maj_rev;
u8 min_rev;
};
struct xhci_port { struct xhci_port {
__le32 __iomem *addr; __le32 __iomem *addr;
int hw_portnum; int hw_portnum;
int hcd_portnum; int hcd_portnum;
struct xhci_hub *rhub; struct xhci_hub *rhub;
struct xhci_port_cap *port_cap;
}; };
struct xhci_hub { struct xhci_hub {
...@@ -1719,9 +1727,6 @@ struct xhci_hub { ...@@ -1719,9 +1727,6 @@ struct xhci_hub {
/* supported prococol extended capabiliy values */ /* supported prococol extended capabiliy values */
u8 maj_rev; u8 maj_rev;
u8 min_rev; u8 min_rev;
u32 *psi; /* array of protocol speed ID entries */
u8 psi_count;
u8 psi_uid_count;
}; };
/* There is one xhci_hcd structure per controller */ /* There is one xhci_hcd structure per controller */
...@@ -1880,6 +1885,9 @@ struct xhci_hcd { ...@@ -1880,6 +1885,9 @@ struct xhci_hcd {
/* cached usb2 extened protocol capabilites */ /* cached usb2 extened protocol capabilites */
u32 *ext_caps; u32 *ext_caps;
unsigned int num_ext_caps; unsigned int num_ext_caps;
/* cached extended protocol port capabilities */
struct xhci_port_cap *port_caps;
unsigned int num_port_caps;
/* Compliance Mode Recovery Data */ /* Compliance Mode Recovery Data */
struct timer_list comp_mode_recovery_timer; struct timer_list comp_mode_recovery_timer;
u32 port_status_u0; u32 port_status_u0;
......
...@@ -33,6 +33,14 @@ ...@@ -33,6 +33,14 @@
#define USB_DEVICE_ID_CODEMERCS_IOWPV2 0x1512 #define USB_DEVICE_ID_CODEMERCS_IOWPV2 0x1512
/* full speed iowarrior */ /* full speed iowarrior */
#define USB_DEVICE_ID_CODEMERCS_IOW56 0x1503 #define USB_DEVICE_ID_CODEMERCS_IOW56 0x1503
/* fuller speed iowarrior */
#define USB_DEVICE_ID_CODEMERCS_IOW28 0x1504
#define USB_DEVICE_ID_CODEMERCS_IOW28L 0x1505
#define USB_DEVICE_ID_CODEMERCS_IOW100 0x1506
/* OEMed devices */
#define USB_DEVICE_ID_CODEMERCS_IOW24SAG 0x158a
#define USB_DEVICE_ID_CODEMERCS_IOW56AM 0x158b
/* Get a minor range for your devices from the usb maintainer */ /* Get a minor range for your devices from the usb maintainer */
#ifdef CONFIG_USB_DYNAMIC_MINORS #ifdef CONFIG_USB_DYNAMIC_MINORS
...@@ -133,6 +141,11 @@ static const struct usb_device_id iowarrior_ids[] = { ...@@ -133,6 +141,11 @@ static const struct usb_device_id iowarrior_ids[] = {
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)}, {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)},
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV2)}, {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV2)},
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56)}, {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56)},
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24SAG)},
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW56AM)},
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28)},
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW28L)},
{USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW100)},
{} /* Terminating entry */ {} /* Terminating entry */
}; };
MODULE_DEVICE_TABLE(usb, iowarrior_ids); MODULE_DEVICE_TABLE(usb, iowarrior_ids);
...@@ -357,6 +370,7 @@ static ssize_t iowarrior_write(struct file *file, ...@@ -357,6 +370,7 @@ static ssize_t iowarrior_write(struct file *file,
} }
switch (dev->product_id) { switch (dev->product_id) {
case USB_DEVICE_ID_CODEMERCS_IOW24: case USB_DEVICE_ID_CODEMERCS_IOW24:
case USB_DEVICE_ID_CODEMERCS_IOW24SAG:
case USB_DEVICE_ID_CODEMERCS_IOWPV1: case USB_DEVICE_ID_CODEMERCS_IOWPV1:
case USB_DEVICE_ID_CODEMERCS_IOWPV2: case USB_DEVICE_ID_CODEMERCS_IOWPV2:
case USB_DEVICE_ID_CODEMERCS_IOW40: case USB_DEVICE_ID_CODEMERCS_IOW40:
...@@ -371,6 +385,10 @@ static ssize_t iowarrior_write(struct file *file, ...@@ -371,6 +385,10 @@ static ssize_t iowarrior_write(struct file *file,
goto exit; goto exit;
break; break;
case USB_DEVICE_ID_CODEMERCS_IOW56: case USB_DEVICE_ID_CODEMERCS_IOW56:
case USB_DEVICE_ID_CODEMERCS_IOW56AM:
case USB_DEVICE_ID_CODEMERCS_IOW28:
case USB_DEVICE_ID_CODEMERCS_IOW28L:
case USB_DEVICE_ID_CODEMERCS_IOW100:
/* The IOW56 uses asynchronous IO and more urbs */ /* The IOW56 uses asynchronous IO and more urbs */
if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) { if (atomic_read(&dev->write_busy) == MAX_WRITES_IN_FLIGHT) {
/* Wait until we are below the limit for submitted urbs */ /* Wait until we are below the limit for submitted urbs */
...@@ -493,6 +511,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd, ...@@ -493,6 +511,7 @@ static long iowarrior_ioctl(struct file *file, unsigned int cmd,
switch (cmd) { switch (cmd) {
case IOW_WRITE: case IOW_WRITE:
if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 || if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24 ||
dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW24SAG ||
dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV1 ||
dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 || dev->product_id == USB_DEVICE_ID_CODEMERCS_IOWPV2 ||
dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) { dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW40) {
...@@ -767,7 +786,11 @@ static int iowarrior_probe(struct usb_interface *interface, ...@@ -767,7 +786,11 @@ static int iowarrior_probe(struct usb_interface *interface,
goto error; goto error;
} }
if (dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) { if ((dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) ||
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56AM) ||
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28) ||
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28L) ||
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW100)) {
res = usb_find_last_int_out_endpoint(iface_desc, res = usb_find_last_int_out_endpoint(iface_desc,
&dev->int_out_endpoint); &dev->int_out_endpoint);
if (res) { if (res) {
...@@ -780,7 +803,11 @@ static int iowarrior_probe(struct usb_interface *interface, ...@@ -780,7 +803,11 @@ static int iowarrior_probe(struct usb_interface *interface,
/* we have to check the report_size often, so remember it in the endianness suitable for our machine */ /* we have to check the report_size often, so remember it in the endianness suitable for our machine */
dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint); dev->report_size = usb_endpoint_maxp(dev->int_in_endpoint);
if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) && if ((dev->interface->cur_altsetting->desc.bInterfaceNumber == 0) &&
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56)) ((dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56) ||
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW56AM) ||
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28) ||
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW28L) ||
(dev->product_id == USB_DEVICE_ID_CODEMERCS_IOW100)))
/* IOWarrior56 has wMaxPacketSize different from report size */ /* IOWarrior56 has wMaxPacketSize different from report size */
dev->report_size = 7; dev->report_size = 7;
......
...@@ -969,6 +969,10 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy, ...@@ -969,6 +969,10 @@ static int utmi_phy_probe(struct tegra_usb_phy *tegra_phy,
return -ENXIO; return -ENXIO;
} }
/*
* Note that UTMI pad registers are shared by all PHYs, therefore
* devm_platform_ioremap_resource() can't be used here.
*/
tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start, tegra_phy->pad_regs = devm_ioremap(&pdev->dev, res->start,
resource_size(res)); resource_size(res));
if (!tegra_phy->pad_regs) { if (!tegra_phy->pad_regs) {
...@@ -1087,6 +1091,10 @@ static int tegra_usb_phy_probe(struct platform_device *pdev) ...@@ -1087,6 +1091,10 @@ static int tegra_usb_phy_probe(struct platform_device *pdev)
return -ENXIO; return -ENXIO;
} }
/*
* Note that PHY and USB controller are using shared registers,
* therefore devm_platform_ioremap_resource() can't be used here.
*/
tegra_phy->regs = devm_ioremap(&pdev->dev, res->start, tegra_phy->regs = devm_ioremap(&pdev->dev, res->start,
resource_size(res)); resource_size(res));
if (!tegra_phy->regs) { if (!tegra_phy->regs) {
......
...@@ -205,6 +205,16 @@ static int ch341_get_divisor(speed_t speed) ...@@ -205,6 +205,16 @@ static int ch341_get_divisor(speed_t speed)
16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1))) 16 * speed - 16 * CH341_CLKRATE / (clk_div * (div + 1)))
div++; div++;
/*
* Prefer lower base clock (fact = 0) if even divisor.
*
* Note that this makes the receiver more tolerant to errors.
*/
if (fact == 1 && div % 2 == 0) {
div /= 2;
fact = 0;
}
return (0x100 - div) << 8 | fact << 2 | ps; return (0x100 - div) << 8 | fact << 2 | ps;
} }
......
...@@ -448,7 +448,7 @@ static void ir_set_termios(struct tty_struct *tty, ...@@ -448,7 +448,7 @@ static void ir_set_termios(struct tty_struct *tty,
usb_sndbulkpipe(udev, port->bulk_out_endpointAddress), usb_sndbulkpipe(udev, port->bulk_out_endpointAddress),
transfer_buffer, 1, &actual_length, 5000); transfer_buffer, 1, &actual_length, 5000);
if (ret || actual_length != 1) { if (ret || actual_length != 1) {
if (actual_length != 1) if (!ret)
ret = -EIO; ret = -EIO;
dev_err(&port->dev, "failed to change line speed: %d\n", ret); dev_err(&port->dev, "failed to change line speed: %d\n", ret);
} }
......
...@@ -45,6 +45,7 @@ struct uas_dev_info { ...@@ -45,6 +45,7 @@ struct uas_dev_info {
struct scsi_cmnd *cmnd[MAX_CMNDS]; struct scsi_cmnd *cmnd[MAX_CMNDS];
spinlock_t lock; spinlock_t lock;
struct work_struct work; struct work_struct work;
struct work_struct scan_work; /* for async scanning */
}; };
enum { enum {
...@@ -114,6 +115,17 @@ static void uas_do_work(struct work_struct *work) ...@@ -114,6 +115,17 @@ static void uas_do_work(struct work_struct *work)
spin_unlock_irqrestore(&devinfo->lock, flags); spin_unlock_irqrestore(&devinfo->lock, flags);
} }
static void uas_scan_work(struct work_struct *work)
{
struct uas_dev_info *devinfo =
container_of(work, struct uas_dev_info, scan_work);
struct Scsi_Host *shost = usb_get_intfdata(devinfo->intf);
dev_dbg(&devinfo->intf->dev, "starting scan\n");
scsi_scan_host(shost);
dev_dbg(&devinfo->intf->dev, "scan complete\n");
}
static void uas_add_work(struct uas_cmd_info *cmdinfo) static void uas_add_work(struct uas_cmd_info *cmdinfo)
{ {
struct scsi_pointer *scp = (void *)cmdinfo; struct scsi_pointer *scp = (void *)cmdinfo;
...@@ -982,6 +994,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -982,6 +994,7 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
init_usb_anchor(&devinfo->data_urbs); init_usb_anchor(&devinfo->data_urbs);
spin_lock_init(&devinfo->lock); spin_lock_init(&devinfo->lock);
INIT_WORK(&devinfo->work, uas_do_work); INIT_WORK(&devinfo->work, uas_do_work);
INIT_WORK(&devinfo->scan_work, uas_scan_work);
result = uas_configure_endpoints(devinfo); result = uas_configure_endpoints(devinfo);
if (result) if (result)
...@@ -998,7 +1011,9 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -998,7 +1011,9 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (result) if (result)
goto free_streams; goto free_streams;
scsi_scan_host(shost); /* Submit the delayed_work for SCSI-device scanning */
schedule_work(&devinfo->scan_work);
return result; return result;
free_streams: free_streams:
...@@ -1166,6 +1181,12 @@ static void uas_disconnect(struct usb_interface *intf) ...@@ -1166,6 +1181,12 @@ static void uas_disconnect(struct usb_interface *intf)
usb_kill_anchored_urbs(&devinfo->data_urbs); usb_kill_anchored_urbs(&devinfo->data_urbs);
uas_zap_pending(devinfo, DID_NO_CONNECT); uas_zap_pending(devinfo, DID_NO_CONNECT);
/*
* Prevent SCSI scanning (if it hasn't started yet)
* or wait for the SCSI-scanning routine to stop.
*/
cancel_work_sync(&devinfo->scan_work);
scsi_remove_host(shost); scsi_remove_host(shost);
uas_free_streams(devinfo); uas_free_streams(devinfo);
scsi_host_put(shost); scsi_host_put(shost);
......
...@@ -69,4 +69,7 @@ ...@@ -69,4 +69,7 @@
/* Hub needs extra delay after resetting its port. */ /* Hub needs extra delay after resetting its port. */
#define USB_QUIRK_HUB_SLOW_RESET BIT(14) #define USB_QUIRK_HUB_SLOW_RESET BIT(14)
/* device has blacklisted endpoints */
#define USB_QUIRK_ENDPOINT_BLACKLIST BIT(15)
#endif /* __LINUX_USB_QUIRKS_H */ #endif /* __LINUX_USB_QUIRKS_H */
...@@ -14,18 +14,18 @@ ...@@ -14,18 +14,18 @@
* ACA (Accessory Charger Adapters) * ACA (Accessory Charger Adapters)
*/ */
enum usb_charger_type { enum usb_charger_type {
UNKNOWN_TYPE, UNKNOWN_TYPE = 0,
SDP_TYPE, SDP_TYPE = 1,
DCP_TYPE, DCP_TYPE = 2,
CDP_TYPE, CDP_TYPE = 3,
ACA_TYPE, ACA_TYPE = 4,
}; };
/* USB charger state */ /* USB charger state */
enum usb_charger_state { enum usb_charger_state {
USB_CHARGER_DEFAULT, USB_CHARGER_DEFAULT = 0,
USB_CHARGER_PRESENT, USB_CHARGER_PRESENT = 1,
USB_CHARGER_ABSENT, USB_CHARGER_ABSENT = 2,
}; };
#endif /* _UAPI__LINUX_USB_CHARGER_H */ #endif /* _UAPI__LINUX_USB_CHARGER_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment