usb/uas: only bind if the hcd supports SG
The UAS driver requires SG support by the HCD operating the device. This patch stops UAS from operating on a HCD without sg support and prints a message to let him know. The spec says: |For [USB2] backward compatibility, the device shall present [BOT] as |alternate interface zero (primary) and [UAS] as alternate interface one |(secondary). A device which does not need backward compatibility with |[BOT] shall present [UAS] as alternate interface zero. In [USB2] |systems, the [BOT] driver or an associated filter driver may need to |issue a SET INTERFACE request for alternate interface one and then allow |the [UAS] driver to load. If the user used usb_modeswitch to switch to UAS then he can go back to BOT or use a different HCD. In case UAS is the only interface then there is currently no way out. In future usb_sg_wait() should be extended to provide a non-blocking interface so it can work with the UAS driver. Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
This commit is contained in:
committed by
Sarah Sharp
parent
b603669842
commit
c898add51c
@@ -13,6 +13,7 @@
|
|||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
|
#include <linux/usb/hcd.h>
|
||||||
#include <linux/usb/storage.h>
|
#include <linux/usb/storage.h>
|
||||||
|
|
||||||
#include <scsi/scsi.h>
|
#include <scsi/scsi.h>
|
||||||
@@ -621,22 +622,34 @@ static int uas_is_interface(struct usb_host_interface *intf)
|
|||||||
intf->desc.bInterfaceProtocol == USB_PR_UAS);
|
intf->desc.bInterfaceProtocol == USB_PR_UAS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int uas_isnt_supported(struct usb_device *udev)
|
||||||
|
{
|
||||||
|
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
|
||||||
|
|
||||||
|
dev_warn(&udev->dev, "The driver for the USB controller %s does not "
|
||||||
|
"support scatter-gather which is\n",
|
||||||
|
hcd->driver->description);
|
||||||
|
dev_warn(&udev->dev, "required by the UAS driver. Please try an"
|
||||||
|
"alternative USB controller if you wish to use UAS.\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
static int uas_switch_interface(struct usb_device *udev,
|
static int uas_switch_interface(struct usb_device *udev,
|
||||||
struct usb_interface *intf)
|
struct usb_interface *intf)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
int sg_supported = udev->bus->sg_tablesize != 0;
|
||||||
if (uas_is_interface(intf->cur_altsetting))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (i = 0; i < intf->num_altsetting; i++) {
|
for (i = 0; i < intf->num_altsetting; i++) {
|
||||||
struct usb_host_interface *alt = &intf->altsetting[i];
|
struct usb_host_interface *alt = &intf->altsetting[i];
|
||||||
if (alt == intf->cur_altsetting)
|
|
||||||
continue;
|
if (uas_is_interface(alt)) {
|
||||||
if (uas_is_interface(alt))
|
if (!sg_supported)
|
||||||
|
return uas_isnt_supported(udev);
|
||||||
return usb_set_interface(udev,
|
return usb_set_interface(udev,
|
||||||
alt->desc.bInterfaceNumber,
|
alt->desc.bInterfaceNumber,
|
||||||
alt->desc.bAlternateSetting);
|
alt->desc.bAlternateSetting);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
Reference in New Issue
Block a user