Merge branch 'usb-3.3-rc4' into usb-next
This is to pull in the xhci changes and the other fixes and device id updates that were done in Linus's tree. Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
commit
c69263c66e
56 changed files with 1051 additions and 352 deletions
|
@ -182,3 +182,14 @@ Description:
|
|||
USB2 hardware LPM is enabled for the device. Developer can
|
||||
write y/Y/1 or n/N/0 to the file to enable/disable the
|
||||
feature.
|
||||
|
||||
What: /sys/bus/usb/devices/.../removable
|
||||
Date: February 2012
|
||||
Contact: Matthew Garrett <mjg@redhat.com>
|
||||
Description:
|
||||
Some information about whether a given USB device is
|
||||
physically fixed to the platform can be inferred from a
|
||||
combination of hub decriptor bits and platform-specific data
|
||||
such as ACPI. This file will read either "removable" or
|
||||
"fixed" if the information is available, and "unknown"
|
||||
otherwise.
|
|
@ -1295,6 +1295,7 @@ EXPORT_SYMBOL(int_to_scsilun);
|
|||
* LUNs even if it's older than SCSI-3.
|
||||
* If BLIST_NOREPORTLUN is set, return 1 always.
|
||||
* If BLIST_NOLUN is set, return 0 always.
|
||||
* If starget->no_report_luns is set, return 1 always.
|
||||
*
|
||||
* Return:
|
||||
* 0: scan completed (or no memory, so further scanning is futile)
|
||||
|
@ -1321,6 +1322,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
|
|||
* Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
|
||||
* Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does
|
||||
* support more than 8 LUNs.
|
||||
* Don't attempt if the target doesn't support REPORT LUNS.
|
||||
*/
|
||||
if (bflags & BLIST_NOREPORTLUN)
|
||||
return 1;
|
||||
|
@ -1332,6 +1334,8 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
|
|||
return 1;
|
||||
if (bflags & BLIST_NOLUN)
|
||||
return 0;
|
||||
if (starget->no_report_luns)
|
||||
return 1;
|
||||
|
||||
if (!(sdev = scsi_device_lookup_by_target(starget, 0))) {
|
||||
sdev = scsi_alloc_sdev(starget, 0, NULL);
|
||||
|
|
|
@ -2349,7 +2349,7 @@ static int sd_try_extended_inquiry(struct scsi_device *sdp)
|
|||
* some USB ones crash on receiving them, and the pages
|
||||
* we currently ask for are for SPC-3 and beyond
|
||||
*/
|
||||
if (sdp->scsi_level > SCSI_SPC_2)
|
||||
if (sdp->scsi_level > SCSI_SPC_2 && !sdp->skip_vpd_pages)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -76,6 +76,7 @@ config USB_ARCH_HAS_EHCI
|
|||
default y if MICROBLAZE
|
||||
default y if SPARC_LEON
|
||||
default y if ARCH_MMP
|
||||
default y if MACH_LOONGSON1
|
||||
default PCI
|
||||
|
||||
# some non-PCI HCDs implement xHCI
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#define DRIVER_AUTHOR "Oliver Neukum"
|
||||
#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
|
||||
|
||||
#define HUAWEI_VENDOR_ID 0x12D1
|
||||
|
||||
static const struct usb_device_id wdm_ids[] = {
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
|
||||
|
@ -38,6 +40,20 @@ static const struct usb_device_id wdm_ids[] = {
|
|||
.bInterfaceClass = USB_CLASS_COMM,
|
||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Huawei E392, E398 and possibly other Qualcomm based modems
|
||||
* embed the Qualcomm QMI protocol inside CDC on CDC ECM like
|
||||
* control interfaces. Userspace access to this is required
|
||||
* to configure the accompanying data interface
|
||||
*/
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_INFO,
|
||||
.idVendor = HUAWEI_VENDOR_ID,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.bInterfaceSubClass = 1,
|
||||
.bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -54,6 +70,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
|
|||
#define WDM_POLL_RUNNING 6
|
||||
#define WDM_RESPONDING 7
|
||||
#define WDM_SUSPENDING 8
|
||||
#define WDM_RESETTING 9
|
||||
|
||||
#define WDM_MAX 16
|
||||
|
||||
|
@ -82,7 +99,6 @@ struct wdm_device {
|
|||
u16 bufsize;
|
||||
u16 wMaxCommand;
|
||||
u16 wMaxPacketSize;
|
||||
u16 bMaxPacketSize0;
|
||||
__le16 inum;
|
||||
int reslength;
|
||||
int length;
|
||||
|
@ -162,11 +178,9 @@ static void wdm_int_callback(struct urb *urb)
|
|||
int rv = 0;
|
||||
int status = urb->status;
|
||||
struct wdm_device *desc;
|
||||
struct usb_ctrlrequest *req;
|
||||
struct usb_cdc_notification *dr;
|
||||
|
||||
desc = urb->context;
|
||||
req = desc->irq;
|
||||
dr = (struct usb_cdc_notification *)desc->sbuf;
|
||||
|
||||
if (status) {
|
||||
|
@ -213,24 +227,6 @@ static void wdm_int_callback(struct urb *urb)
|
|||
goto exit;
|
||||
}
|
||||
|
||||
req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
|
||||
req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
|
||||
req->wValue = 0;
|
||||
req->wIndex = desc->inum;
|
||||
req->wLength = cpu_to_le16(desc->wMaxCommand);
|
||||
|
||||
usb_fill_control_urb(
|
||||
desc->response,
|
||||
interface_to_usbdev(desc->intf),
|
||||
/* using common endpoint 0 */
|
||||
usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
|
||||
(unsigned char *)req,
|
||||
desc->inbuf,
|
||||
desc->wMaxCommand,
|
||||
wdm_in_callback,
|
||||
desc
|
||||
);
|
||||
desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
spin_lock(&desc->iuspin);
|
||||
clear_bit(WDM_READ, &desc->flags);
|
||||
set_bit(WDM_RESPONDING, &desc->flags);
|
||||
|
@ -279,14 +275,8 @@ static void free_urbs(struct wdm_device *desc)
|
|||
|
||||
static void cleanup(struct wdm_device *desc)
|
||||
{
|
||||
usb_free_coherent(interface_to_usbdev(desc->intf),
|
||||
desc->wMaxPacketSize,
|
||||
desc->sbuf,
|
||||
desc->validity->transfer_dma);
|
||||
usb_free_coherent(interface_to_usbdev(desc->intf),
|
||||
desc->bMaxPacketSize0,
|
||||
desc->inbuf,
|
||||
desc->response->transfer_dma);
|
||||
kfree(desc->sbuf);
|
||||
kfree(desc->inbuf);
|
||||
kfree(desc->orq);
|
||||
kfree(desc->irq);
|
||||
kfree(desc->ubuf);
|
||||
|
@ -351,6 +341,10 @@ static ssize_t wdm_write
|
|||
else
|
||||
if (test_bit(WDM_IN_USE, &desc->flags))
|
||||
r = -EAGAIN;
|
||||
|
||||
if (test_bit(WDM_RESETTING, &desc->flags))
|
||||
r = -EIO;
|
||||
|
||||
if (r < 0) {
|
||||
kfree(buf);
|
||||
goto out;
|
||||
|
@ -430,6 +424,10 @@ static ssize_t wdm_read
|
|||
rv = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
if (test_bit(WDM_RESETTING, &desc->flags)) {
|
||||
rv = -EIO;
|
||||
goto err;
|
||||
}
|
||||
usb_mark_last_busy(interface_to_usbdev(desc->intf));
|
||||
if (rv < 0) {
|
||||
rv = -ERESTARTSYS;
|
||||
|
@ -631,7 +629,6 @@ static void wdm_rxwork(struct work_struct *work)
|
|||
static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
||||
{
|
||||
int rv = -EINVAL;
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct wdm_device *desc;
|
||||
struct usb_host_interface *iface;
|
||||
struct usb_endpoint_descriptor *ep;
|
||||
|
@ -692,7 +689,6 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
goto err;
|
||||
|
||||
desc->wMaxPacketSize = usb_endpoint_maxp(ep);
|
||||
desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
|
||||
|
||||
desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
|
||||
if (!desc->orq)
|
||||
|
@ -717,19 +713,13 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
if (!desc->ubuf)
|
||||
goto err;
|
||||
|
||||
desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf),
|
||||
desc->wMaxPacketSize,
|
||||
GFP_KERNEL,
|
||||
&desc->validity->transfer_dma);
|
||||
desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL);
|
||||
if (!desc->sbuf)
|
||||
goto err;
|
||||
|
||||
desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
|
||||
desc->wMaxCommand,
|
||||
GFP_KERNEL,
|
||||
&desc->response->transfer_dma);
|
||||
desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
|
||||
if (!desc->inbuf)
|
||||
goto err2;
|
||||
goto err;
|
||||
|
||||
usb_fill_int_urb(
|
||||
desc->validity,
|
||||
|
@ -741,30 +731,39 @@ static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
desc,
|
||||
ep->bInterval
|
||||
);
|
||||
desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
|
||||
|
||||
desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
|
||||
desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
|
||||
desc->irq->wValue = 0;
|
||||
desc->irq->wIndex = desc->inum;
|
||||
desc->irq->wLength = cpu_to_le16(desc->wMaxCommand);
|
||||
|
||||
usb_fill_control_urb(
|
||||
desc->response,
|
||||
interface_to_usbdev(intf),
|
||||
/* using common endpoint 0 */
|
||||
usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
|
||||
(unsigned char *)desc->irq,
|
||||
desc->inbuf,
|
||||
desc->wMaxCommand,
|
||||
wdm_in_callback,
|
||||
desc
|
||||
);
|
||||
|
||||
usb_set_intfdata(intf, desc);
|
||||
rv = usb_register_dev(intf, &wdm_class);
|
||||
if (rv < 0)
|
||||
goto err3;
|
||||
goto err2;
|
||||
else
|
||||
dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n",
|
||||
intf->minor - WDM_MINOR_BASE);
|
||||
dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
|
||||
out:
|
||||
return rv;
|
||||
err3:
|
||||
usb_set_intfdata(intf, NULL);
|
||||
usb_free_coherent(interface_to_usbdev(desc->intf),
|
||||
desc->bMaxPacketSize0,
|
||||
desc->inbuf,
|
||||
desc->response->transfer_dma);
|
||||
err2:
|
||||
usb_free_coherent(interface_to_usbdev(desc->intf),
|
||||
desc->wMaxPacketSize,
|
||||
desc->sbuf,
|
||||
desc->validity->transfer_dma);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
err:
|
||||
free_urbs(desc);
|
||||
kfree(desc->inbuf);
|
||||
kfree(desc->sbuf);
|
||||
kfree(desc->ubuf);
|
||||
kfree(desc->orq);
|
||||
kfree(desc->irq);
|
||||
|
@ -869,10 +868,6 @@ static int wdm_pre_reset(struct usb_interface *intf)
|
|||
{
|
||||
struct wdm_device *desc = usb_get_intfdata(intf);
|
||||
|
||||
mutex_lock(&desc->rlock);
|
||||
mutex_lock(&desc->wlock);
|
||||
kill_urbs(desc);
|
||||
|
||||
/*
|
||||
* we notify everybody using poll of
|
||||
* an exceptional situation
|
||||
|
@ -880,9 +875,16 @@ static int wdm_pre_reset(struct usb_interface *intf)
|
|||
* message from the device is lost
|
||||
*/
|
||||
spin_lock_irq(&desc->iuspin);
|
||||
set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */
|
||||
set_bit(WDM_READ, &desc->flags); /* unblock read */
|
||||
clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */
|
||||
desc->rerr = -EINTR;
|
||||
spin_unlock_irq(&desc->iuspin);
|
||||
wake_up_all(&desc->wait);
|
||||
mutex_lock(&desc->rlock);
|
||||
mutex_lock(&desc->wlock);
|
||||
kill_urbs(desc);
|
||||
cancel_work_sync(&desc->rxwork);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -891,6 +893,7 @@ static int wdm_post_reset(struct usb_interface *intf)
|
|||
struct wdm_device *desc = usb_get_intfdata(intf);
|
||||
int rv;
|
||||
|
||||
clear_bit(WDM_RESETTING, &desc->flags);
|
||||
rv = recover_from_urb_loss(desc);
|
||||
mutex_unlock(&desc->wlock);
|
||||
mutex_unlock(&desc->rlock);
|
||||
|
|
|
@ -958,13 +958,8 @@ void usb_rebind_intf(struct usb_interface *intf)
|
|||
int rc;
|
||||
|
||||
/* Delayed unbind of an existing driver */
|
||||
if (intf->dev.driver) {
|
||||
struct usb_driver *driver =
|
||||
to_usb_driver(intf->dev.driver);
|
||||
|
||||
dev_dbg(&intf->dev, "forced unbind\n");
|
||||
usb_driver_release_interface(driver, intf);
|
||||
}
|
||||
if (intf->dev.driver)
|
||||
usb_forced_unbind_intf(intf);
|
||||
|
||||
/* Try to rebind the interface */
|
||||
if (!intf->dev.power.is_prepared) {
|
||||
|
@ -977,15 +972,13 @@ void usb_rebind_intf(struct usb_interface *intf)
|
|||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
#define DO_UNBIND 0
|
||||
#define DO_REBIND 1
|
||||
|
||||
/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
|
||||
* or rebind interfaces that have been unbound, according to @action.
|
||||
/* Unbind drivers for @udev's interfaces that don't support suspend/resume
|
||||
* There is no check for reset_resume here because it can be determined
|
||||
* only during resume whether reset_resume is needed.
|
||||
*
|
||||
* The caller must hold @udev's device lock.
|
||||
*/
|
||||
static void do_unbind_rebind(struct usb_device *udev, int action)
|
||||
static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
|
||||
{
|
||||
struct usb_host_config *config;
|
||||
int i;
|
||||
|
@ -996,23 +989,53 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
|
|||
if (config) {
|
||||
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
|
||||
intf = config->interface[i];
|
||||
switch (action) {
|
||||
case DO_UNBIND:
|
||||
if (intf->dev.driver) {
|
||||
drv = to_usb_driver(intf->dev.driver);
|
||||
if (!drv->suspend || !drv->resume)
|
||||
usb_forced_unbind_intf(intf);
|
||||
}
|
||||
break;
|
||||
case DO_REBIND:
|
||||
if (intf->needs_binding)
|
||||
usb_rebind_intf(intf);
|
||||
break;
|
||||
|
||||
if (intf->dev.driver) {
|
||||
drv = to_usb_driver(intf->dev.driver);
|
||||
if (!drv->suspend || !drv->resume)
|
||||
usb_forced_unbind_intf(intf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
|
||||
* These interfaces have the needs_binding flag set by usb_resume_interface().
|
||||
*
|
||||
* The caller must hold @udev's device lock.
|
||||
*/
|
||||
static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
|
||||
{
|
||||
struct usb_host_config *config;
|
||||
int i;
|
||||
struct usb_interface *intf;
|
||||
|
||||
config = udev->actconfig;
|
||||
if (config) {
|
||||
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
|
||||
intf = config->interface[i];
|
||||
if (intf->dev.driver && intf->needs_binding)
|
||||
usb_forced_unbind_intf(intf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void do_rebind_interfaces(struct usb_device *udev)
|
||||
{
|
||||
struct usb_host_config *config;
|
||||
int i;
|
||||
struct usb_interface *intf;
|
||||
|
||||
config = udev->actconfig;
|
||||
if (config) {
|
||||
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
|
||||
intf = config->interface[i];
|
||||
if (intf->needs_binding)
|
||||
usb_rebind_intf(intf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
|
||||
{
|
||||
struct usb_device_driver *udriver;
|
||||
|
@ -1302,35 +1325,48 @@ int usb_suspend(struct device *dev, pm_message_t msg)
|
|||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
|
||||
do_unbind_rebind(udev, DO_UNBIND);
|
||||
unbind_no_pm_drivers_interfaces(udev);
|
||||
|
||||
/* From now on we are sure all drivers support suspend/resume
|
||||
* but not necessarily reset_resume()
|
||||
* so we may still need to unbind and rebind upon resume
|
||||
*/
|
||||
choose_wakeup(udev, msg);
|
||||
return usb_suspend_both(udev, msg);
|
||||
}
|
||||
|
||||
/* The device lock is held by the PM core */
|
||||
int usb_resume_complete(struct device *dev)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
|
||||
/* For PM complete calls, all we do is rebind interfaces
|
||||
* whose needs_binding flag is set
|
||||
*/
|
||||
if (udev->state != USB_STATE_NOTATTACHED)
|
||||
do_rebind_interfaces(udev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* The device lock is held by the PM core */
|
||||
int usb_resume(struct device *dev, pm_message_t msg)
|
||||
{
|
||||
struct usb_device *udev = to_usb_device(dev);
|
||||
int status;
|
||||
|
||||
/* For PM complete calls, all we do is rebind interfaces */
|
||||
if (msg.event == PM_EVENT_ON) {
|
||||
if (udev->state != USB_STATE_NOTATTACHED)
|
||||
do_unbind_rebind(udev, DO_REBIND);
|
||||
status = 0;
|
||||
|
||||
/* For all other calls, take the device back to full power and
|
||||
/* For all calls, take the device back to full power and
|
||||
* tell the PM core in case it was autosuspended previously.
|
||||
* Unbind the interfaces that will need rebinding later.
|
||||
* Unbind the interfaces that will need rebinding later,
|
||||
* because they fail to support reset_resume.
|
||||
* (This can't be done in usb_resume_interface()
|
||||
* above because it doesn't own the right set of locks.)
|
||||
*/
|
||||
} else {
|
||||
status = usb_resume_both(udev, msg);
|
||||
if (status == 0) {
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
do_unbind_rebind(udev, DO_REBIND);
|
||||
}
|
||||
status = usb_resume_both(udev, msg);
|
||||
if (status == 0) {
|
||||
pm_runtime_disable(dev);
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
unbind_no_reset_resume_drivers_interfaces(udev);
|
||||
}
|
||||
|
||||
/* Avoid PM error messages for devices disconnected while suspended
|
||||
|
|
|
@ -62,6 +62,8 @@ struct usb_hub {
|
|||
resumed */
|
||||
unsigned long removed_bits[1]; /* ports with a "removed"
|
||||
device present */
|
||||
unsigned long wakeup_bits[1]; /* ports that have signaled
|
||||
remote wakeup */
|
||||
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
|
||||
#error event_bits[] is too short!
|
||||
#endif
|
||||
|
@ -411,6 +413,29 @@ void usb_kick_khubd(struct usb_device *hdev)
|
|||
kick_khubd(hub);
|
||||
}
|
||||
|
||||
/*
|
||||
* Let the USB core know that a USB 3.0 device has sent a Function Wake Device
|
||||
* Notification, which indicates it had initiated remote wakeup.
|
||||
*
|
||||
* USB 3.0 hubs do not report the port link state change from U3 to U0 when the
|
||||
* device initiates resume, so the USB core will not receive notice of the
|
||||
* resume through the normal hub interrupt URB.
|
||||
*/
|
||||
void usb_wakeup_notification(struct usb_device *hdev,
|
||||
unsigned int portnum)
|
||||
{
|
||||
struct usb_hub *hub;
|
||||
|
||||
if (!hdev)
|
||||
return;
|
||||
|
||||
hub = hdev_to_hub(hdev);
|
||||
if (hub) {
|
||||
set_bit(portnum, hub->wakeup_bits);
|
||||
kick_khubd(hub);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_wakeup_notification);
|
||||
|
||||
/* completion function, fires on port status changes and various faults */
|
||||
static void hub_irq(struct urb *urb)
|
||||
|
@ -823,12 +848,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||
clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_ENABLE);
|
||||
}
|
||||
if (portchange & USB_PORT_STAT_C_LINK_STATE) {
|
||||
need_debounce_delay = true;
|
||||
clear_port_feature(hub->hdev, port1,
|
||||
USB_PORT_FEAT_C_PORT_LINK_STATE);
|
||||
}
|
||||
|
||||
if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
|
||||
hub_is_superspeed(hub->hdev)) {
|
||||
need_debounce_delay = true;
|
||||
|
@ -850,12 +869,19 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
|
|||
set_bit(port1, hub->change_bits);
|
||||
|
||||
} else if (portstatus & USB_PORT_STAT_ENABLE) {
|
||||
bool port_resumed = (portstatus &
|
||||
USB_PORT_STAT_LINK_STATE) ==
|
||||
USB_SS_PORT_LS_U0;
|
||||
/* The power session apparently survived the resume.
|
||||
* If there was an overcurrent or suspend change
|
||||
* (i.e., remote wakeup request), have khubd
|
||||
* take care of it.
|
||||
* take care of it. Look at the port link state
|
||||
* for USB 3.0 hubs, since they don't have a suspend
|
||||
* change bit, and they don't set the port link change
|
||||
* bit on device-initiated resume.
|
||||
*/
|
||||
if (portchange)
|
||||
if (portchange || (hub_is_superspeed(hub->hdev) &&
|
||||
port_resumed))
|
||||
set_bit(port1, hub->change_bits);
|
||||
|
||||
} else if (udev->persist_enabled) {
|
||||
|
@ -1293,14 +1319,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
desc = intf->cur_altsetting;
|
||||
hdev = interface_to_usbdev(intf);
|
||||
|
||||
/* Hubs have proper suspend/resume support. USB 3.0 device suspend is
|
||||
* different from USB 2.0/1.1 device suspend, and unfortunately we
|
||||
* don't support it yet. So leave autosuspend disabled for USB 3.0
|
||||
* external hubs for now. Enable autosuspend for USB 3.0 roothubs,
|
||||
* since that isn't a "real" hub.
|
||||
*/
|
||||
if (!hub_is_superspeed(hdev) || !hdev->parent)
|
||||
usb_enable_autosuspend(hdev);
|
||||
/* Hubs have proper suspend/resume support. */
|
||||
usb_enable_autosuspend(hdev);
|
||||
|
||||
if (hdev->level == MAX_TOPO_LEVEL) {
|
||||
dev_err(&intf->dev,
|
||||
|
@ -1842,6 +1862,37 @@ static int usb_enumerate_device(struct usb_device *udev)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void set_usb_port_removable(struct usb_device *udev)
|
||||
{
|
||||
struct usb_device *hdev = udev->parent;
|
||||
struct usb_hub *hub;
|
||||
u8 port = udev->portnum;
|
||||
u16 wHubCharacteristics;
|
||||
bool removable = true;
|
||||
|
||||
if (!hdev)
|
||||
return;
|
||||
|
||||
hub = hdev_to_hub(udev->parent);
|
||||
|
||||
wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
|
||||
|
||||
if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
|
||||
return;
|
||||
|
||||
if (hub_is_superspeed(hdev)) {
|
||||
if (hub->descriptor->u.ss.DeviceRemovable & (1 << port))
|
||||
removable = false;
|
||||
} else {
|
||||
if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
|
||||
removable = false;
|
||||
}
|
||||
|
||||
if (removable)
|
||||
udev->removable = USB_DEVICE_REMOVABLE;
|
||||
else
|
||||
udev->removable = USB_DEVICE_FIXED;
|
||||
}
|
||||
|
||||
/**
|
||||
* usb_new_device - perform initial device setup (usbcore-internal)
|
||||
|
@ -1900,6 +1951,15 @@ int usb_new_device(struct usb_device *udev)
|
|||
announce_device(udev);
|
||||
|
||||
device_enable_async_suspend(&udev->dev);
|
||||
|
||||
/*
|
||||
* check whether the hub marks this port as non-removable. Do it
|
||||
* now so that platform-specific data can override it in
|
||||
* device_add()
|
||||
*/
|
||||
if (udev->parent)
|
||||
set_usb_port_removable(udev);
|
||||
|
||||
/* Register the device. The device driver is responsible
|
||||
* for configuring the device and invoking the add-device
|
||||
* notifier chain (used by usbfs and possibly others).
|
||||
|
@ -2385,11 +2445,27 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
|
|||
* we don't explicitly enable it here.
|
||||
*/
|
||||
if (udev->do_remote_wakeup) {
|
||||
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
|
||||
USB_DEVICE_REMOTE_WAKEUP, 0,
|
||||
NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
if (!hub_is_superspeed(hub->hdev)) {
|
||||
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
|
||||
USB_DEVICE_REMOTE_WAKEUP, 0,
|
||||
NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
} else {
|
||||
/* Assume there's only one function on the USB 3.0
|
||||
* device and enable remote wake for the first
|
||||
* interface. FIXME if the interface association
|
||||
* descriptor shows there's more than one function.
|
||||
*/
|
||||
status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
|
||||
USB_REQ_SET_FEATURE,
|
||||
USB_RECIP_INTERFACE,
|
||||
USB_INTRF_FUNC_SUSPEND,
|
||||
USB_INTRF_FUNC_SUSPEND_RW |
|
||||
USB_INTRF_FUNC_SUSPEND_LP,
|
||||
NULL, 0,
|
||||
USB_CTRL_SET_TIMEOUT);
|
||||
}
|
||||
if (status) {
|
||||
dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
|
||||
status);
|
||||
|
@ -2679,6 +2755,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
|
|||
struct usb_hub *hub = usb_get_intfdata (intf);
|
||||
struct usb_device *hdev = hub->hdev;
|
||||
unsigned port1;
|
||||
int status;
|
||||
|
||||
/* Warn if children aren't already suspended */
|
||||
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
|
||||
|
@ -2691,6 +2768,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
|
|||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
|
||||
/* Enable hub to send remote wakeup for all ports. */
|
||||
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
|
||||
status = set_port_feature(hdev,
|
||||
port1 |
|
||||
USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
|
||||
USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
|
||||
USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
|
||||
USB_PORT_FEAT_REMOTE_WAKE_MASK);
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(&intf->dev, "%s\n", __func__);
|
||||
|
||||
|
@ -3424,6 +3512,46 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
|
|||
hcd->driver->relinquish_port(hcd, port1);
|
||||
}
|
||||
|
||||
/* Returns 1 if there was a remote wakeup and a connect status change. */
|
||||
static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
|
||||
u16 portstatus, u16 portchange)
|
||||
{
|
||||
struct usb_device *hdev;
|
||||
struct usb_device *udev;
|
||||
int connect_change = 0;
|
||||
int ret;
|
||||
|
||||
hdev = hub->hdev;
|
||||
udev = hdev->children[port-1];
|
||||
if (!hub_is_superspeed(hdev)) {
|
||||
if (!(portchange & USB_PORT_STAT_C_SUSPEND))
|
||||
return 0;
|
||||
clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
|
||||
} else {
|
||||
if (!udev || udev->state != USB_STATE_SUSPENDED ||
|
||||
(portstatus & USB_PORT_STAT_LINK_STATE) !=
|
||||
USB_SS_PORT_LS_U0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (udev) {
|
||||
/* TRSMRCY = 10 msec */
|
||||
msleep(10);
|
||||
|
||||
usb_lock_device(udev);
|
||||
ret = usb_remote_wakeup(udev);
|
||||
usb_unlock_device(udev);
|
||||
if (ret < 0)
|
||||
connect_change = 1;
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
hub_port_disable(hub, port, 1);
|
||||
}
|
||||
dev_dbg(hub->intfdev, "resume on port %d, status %d\n",
|
||||
port, ret);
|
||||
return connect_change;
|
||||
}
|
||||
|
||||
static void hub_events(void)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
|
@ -3436,7 +3564,7 @@ static void hub_events(void)
|
|||
u16 portstatus;
|
||||
u16 portchange;
|
||||
int i, ret;
|
||||
int connect_change;
|
||||
int connect_change, wakeup_change;
|
||||
|
||||
/*
|
||||
* We restart the list every time to avoid a deadlock with
|
||||
|
@ -3515,8 +3643,9 @@ static void hub_events(void)
|
|||
if (test_bit(i, hub->busy_bits))
|
||||
continue;
|
||||
connect_change = test_bit(i, hub->change_bits);
|
||||
wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
|
||||
if (!test_and_clear_bit(i, hub->event_bits) &&
|
||||
!connect_change)
|
||||
!connect_change && !wakeup_change)
|
||||
continue;
|
||||
|
||||
ret = hub_port_status(hub, i,
|
||||
|
@ -3557,31 +3686,10 @@ static void hub_events(void)
|
|||
}
|
||||
}
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_SUSPEND) {
|
||||
struct usb_device *udev;
|
||||
if (hub_handle_remote_wakeup(hub, i,
|
||||
portstatus, portchange))
|
||||
connect_change = 1;
|
||||
|
||||
clear_port_feature(hdev, i,
|
||||
USB_PORT_FEAT_C_SUSPEND);
|
||||
udev = hdev->children[i-1];
|
||||
if (udev) {
|
||||
/* TRSMRCY = 10 msec */
|
||||
msleep(10);
|
||||
|
||||
usb_lock_device(udev);
|
||||
ret = usb_remote_wakeup(hdev->
|
||||
children[i-1]);
|
||||
usb_unlock_device(udev);
|
||||
if (ret < 0)
|
||||
connect_change = 1;
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
hub_port_disable(hub, i, 1);
|
||||
}
|
||||
dev_dbg (hub_dev,
|
||||
"resume on port %d, status %d\n",
|
||||
i, ret);
|
||||
}
|
||||
|
||||
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
|
||||
u16 status = 0;
|
||||
u16 unused;
|
||||
|
|
|
@ -230,6 +230,28 @@ show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
|
|||
}
|
||||
static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
|
||||
|
||||
static ssize_t
|
||||
show_removable(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_device *udev;
|
||||
char *state;
|
||||
|
||||
udev = to_usb_device(dev);
|
||||
|
||||
switch (udev->removable) {
|
||||
case USB_DEVICE_REMOVABLE:
|
||||
state = "removable";
|
||||
break;
|
||||
case USB_DEVICE_FIXED:
|
||||
state = "fixed";
|
||||
break;
|
||||
default:
|
||||
state = "unknown";
|
||||
}
|
||||
|
||||
return sprintf(buf, "%s\n", state);
|
||||
}
|
||||
static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
|
@ -626,6 +648,7 @@ static struct attribute *dev_attrs[] = {
|
|||
&dev_attr_avoid_reset_quirk.attr,
|
||||
&dev_attr_authorized.attr,
|
||||
&dev_attr_remove.attr,
|
||||
&dev_attr_removable.attr,
|
||||
NULL,
|
||||
};
|
||||
static struct attribute_group dev_attr_grp = {
|
||||
|
|
|
@ -403,20 +403,17 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
|||
* cause problems in HCDs if they get it wrong.
|
||||
*/
|
||||
{
|
||||
unsigned int orig_flags = urb->transfer_flags;
|
||||
unsigned int allowed;
|
||||
static int pipetypes[4] = {
|
||||
PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
|
||||
};
|
||||
|
||||
/* Check that the pipe's type matches the endpoint's type */
|
||||
if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) {
|
||||
dev_err(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
|
||||
if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
|
||||
dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
|
||||
usb_pipetype(urb->pipe), pipetypes[xfertype]);
|
||||
return -EPIPE; /* The most suitable error code :-) */
|
||||
}
|
||||
|
||||
/* enforce simple/standard policy */
|
||||
/* Check against a simple/standard policy */
|
||||
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
|
||||
URB_FREE_BUFFER);
|
||||
switch (xfertype) {
|
||||
|
@ -435,14 +432,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
|||
allowed |= URB_ISO_ASAP;
|
||||
break;
|
||||
}
|
||||
urb->transfer_flags &= allowed;
|
||||
allowed &= urb->transfer_flags;
|
||||
|
||||
/* fail if submitter gave bogus flags */
|
||||
if (urb->transfer_flags != orig_flags) {
|
||||
dev_err(&dev->dev, "BOGUS urb flags, %x --> %x\n",
|
||||
orig_flags, urb->transfer_flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* warn if submitter gave bogus flags */
|
||||
if (allowed != urb->transfer_flags)
|
||||
dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
|
||||
urb->transfer_flags, allowed);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
|
|
|
@ -274,7 +274,7 @@ static int usb_dev_prepare(struct device *dev)
|
|||
static void usb_dev_complete(struct device *dev)
|
||||
{
|
||||
/* Currently used only for rebinding interfaces */
|
||||
usb_resume(dev, PMSG_ON); /* FIXME: change to PMSG_COMPLETE */
|
||||
usb_resume_complete(dev);
|
||||
}
|
||||
|
||||
static int usb_dev_suspend(struct device *dev)
|
||||
|
|
|
@ -56,6 +56,7 @@ extern void usb_major_cleanup(void);
|
|||
|
||||
extern int usb_suspend(struct device *dev, pm_message_t msg);
|
||||
extern int usb_resume(struct device *dev, pm_message_t msg);
|
||||
extern int usb_resume_complete(struct device *dev);
|
||||
|
||||
extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
|
||||
extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
|
||||
|
|
|
@ -323,7 +323,9 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
|
|||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int retval;
|
||||
struct fsl_usb2_platform_data *pdata;
|
||||
struct device *dev;
|
||||
|
||||
dev = hcd->self.controller;
|
||||
pdata = hcd->self.controller->platform_data;
|
||||
ehci->big_endian_desc = pdata->big_endian_desc;
|
||||
ehci->big_endian_mmio = pdata->big_endian_mmio;
|
||||
|
@ -353,6 +355,16 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
|
|||
|
||||
ehci_reset(ehci);
|
||||
|
||||
if (of_device_is_compatible(dev->parent->of_node,
|
||||
"fsl,mpc5121-usb2-dr")) {
|
||||
/*
|
||||
* set SBUSCFG:AHBBRST so that control msgs don't
|
||||
* fail when doing heavy PATA writes.
|
||||
*/
|
||||
ehci_writel(ehci, SBUSCFG_INCR8,
|
||||
hcd->regs + FSL_SOC_USB_SBUSCFG);
|
||||
}
|
||||
|
||||
retval = ehci_fsl_reinit(ehci);
|
||||
return retval;
|
||||
}
|
||||
|
@ -476,6 +488,8 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
|
|||
ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
|
||||
hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
|
||||
|
||||
ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);
|
||||
|
||||
/* restore EHCI registers */
|
||||
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
|
||||
ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#define _EHCI_FSL_H
|
||||
|
||||
/* offsets for the non-ehci registers in the FSL SOC USB controller */
|
||||
#define FSL_SOC_USB_SBUSCFG 0x90
|
||||
#define SBUSCFG_INCR8 0x02 /* INCR8, specified */
|
||||
#define FSL_SOC_USB_ULPIVP 0x170
|
||||
#define FSL_SOC_USB_PORTSC1 0x184
|
||||
#define PORT_PTS_MSK (3<<30)
|
||||
|
|
|
@ -1376,6 +1376,11 @@ MODULE_LICENSE ("GPL");
|
|||
#define PLATFORM_DRIVER ehci_mv_driver
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_MACH_LOONGSON1
|
||||
#include "ehci-ls1x.c"
|
||||
#define PLATFORM_DRIVER ehci_ls1x_driver
|
||||
#endif
|
||||
|
||||
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
|
||||
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
|
||||
!defined(XILINX_OF_PLATFORM_DRIVER)
|
||||
|
|
|
@ -107,7 +107,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
|
|||
ehci->owned_ports = 0;
|
||||
}
|
||||
|
||||
static int ehci_port_change(struct ehci_hcd *ehci)
|
||||
static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
|
||||
{
|
||||
int i = HCS_N_PORTS(ehci->hcs_params);
|
||||
|
||||
|
@ -1076,7 +1076,8 @@ static int ehci_hub_control (
|
|||
return retval;
|
||||
}
|
||||
|
||||
static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
|
||||
static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd,
|
||||
int portnum)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
|
||||
|
@ -1085,7 +1086,8 @@ static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
|
|||
set_owner(ehci, --portnum, PORT_OWNER);
|
||||
}
|
||||
|
||||
static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
|
||||
static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd,
|
||||
int portnum)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
u32 __iomem *reg;
|
||||
|
|
159
drivers/usb/host/ehci-ls1x.c
Normal file
159
drivers/usb/host/ehci-ls1x.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Bus Glue for Loongson LS1X built-in EHCI controller.
|
||||
*
|
||||
* Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static int ehci_ls1x_reset(struct usb_hcd *hcd)
|
||||
{
|
||||
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
|
||||
int ret;
|
||||
|
||||
ehci->caps = hcd->regs;
|
||||
|
||||
ret = ehci_setup(hcd);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ehci_port_power(ehci, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct hc_driver ehci_ls1x_hc_driver = {
|
||||
.description = hcd_name,
|
||||
.product_desc = "LOONGSON1 EHCI",
|
||||
.hcd_priv_size = sizeof(struct ehci_hcd),
|
||||
|
||||
/*
|
||||
* generic hardware linkage
|
||||
*/
|
||||
.irq = ehci_irq,
|
||||
.flags = HCD_MEMORY | HCD_USB2,
|
||||
|
||||
/*
|
||||
* basic lifecycle operations
|
||||
*/
|
||||
.reset = ehci_ls1x_reset,
|
||||
.start = ehci_run,
|
||||
.stop = ehci_stop,
|
||||
.shutdown = ehci_shutdown,
|
||||
|
||||
/*
|
||||
* managing i/o requests and associated device resources
|
||||
*/
|
||||
.urb_enqueue = ehci_urb_enqueue,
|
||||
.urb_dequeue = ehci_urb_dequeue,
|
||||
.endpoint_disable = ehci_endpoint_disable,
|
||||
.endpoint_reset = ehci_endpoint_reset,
|
||||
|
||||
/*
|
||||
* scheduling support
|
||||
*/
|
||||
.get_frame_number = ehci_get_frame,
|
||||
|
||||
/*
|
||||
* root hub support
|
||||
*/
|
||||
.hub_status_data = ehci_hub_status_data,
|
||||
.hub_control = ehci_hub_control,
|
||||
.relinquish_port = ehci_relinquish_port,
|
||||
.port_handed_over = ehci_port_handed_over,
|
||||
|
||||
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
|
||||
};
|
||||
|
||||
static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd;
|
||||
struct resource *res;
|
||||
int irq;
|
||||
int ret;
|
||||
|
||||
pr_debug("initializing loongson1 ehci USB Controller\n");
|
||||
|
||||
if (usb_disabled())
|
||||
return -ENODEV;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no IRQ. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
irq = res->start;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res) {
|
||||
dev_err(&pdev->dev,
|
||||
"Found HC with no register addr. Check %s setup!\n",
|
||||
dev_name(&pdev->dev));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev,
|
||||
dev_name(&pdev->dev));
|
||||
if (!hcd)
|
||||
return -ENOMEM;
|
||||
hcd->rsrc_start = res->start;
|
||||
hcd->rsrc_len = resource_size(res);
|
||||
|
||||
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
|
||||
dev_dbg(&pdev->dev, "controller already in use\n");
|
||||
ret = -EBUSY;
|
||||
goto err_put_hcd;
|
||||
}
|
||||
|
||||
hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
|
||||
if (hcd->regs == NULL) {
|
||||
dev_dbg(&pdev->dev, "error mapping memory\n");
|
||||
ret = -EFAULT;
|
||||
goto err_release_region;
|
||||
}
|
||||
|
||||
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
|
||||
if (ret)
|
||||
goto err_iounmap;
|
||||
|
||||
return ret;
|
||||
|
||||
err_iounmap:
|
||||
iounmap(hcd->regs);
|
||||
err_release_region:
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
err_put_hcd:
|
||||
usb_put_hcd(hcd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct usb_hcd *hcd = platform_get_drvdata(pdev);
|
||||
|
||||
usb_remove_hcd(hcd);
|
||||
iounmap(hcd->regs);
|
||||
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
|
||||
usb_put_hcd(hcd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ehci_ls1x_driver = {
|
||||
.probe = ehci_hcd_ls1x_probe,
|
||||
.remove = ehci_hcd_ls1x_remove,
|
||||
.shutdown = usb_hcd_platform_shutdown,
|
||||
.driver = {
|
||||
.name = "ls1x-ehci",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci");
|
|
@ -239,7 +239,7 @@ static int debug_status_show(struct seq_file *s, void *v)
|
|||
"ETDs allocated: %d/%d (max=%d)\n"
|
||||
"ETDs in use sw: %d\n"
|
||||
"ETDs in use hw: %d\n"
|
||||
"DMEM alocated: %d/%d (max=%d)\n"
|
||||
"DMEM allocated: %d/%d (max=%d)\n"
|
||||
"DMEM blocks: %d\n"
|
||||
"Queued waiting for ETD: %d\n"
|
||||
"Queued waiting for DMEM: %d\n",
|
||||
|
|
|
@ -565,6 +565,9 @@ static int uhci_start(struct usb_hcd *hcd)
|
|||
struct dentry __maybe_unused *dentry;
|
||||
|
||||
hcd->uses_new_polling = 1;
|
||||
/* Accept arbitrarily long scatter-gather lists */
|
||||
if (!(hcd->driver->flags & HCD_LOCAL_MEM))
|
||||
hcd->self.sg_tablesize = ~0;
|
||||
|
||||
spin_lock_init(&uhci->lock);
|
||||
setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout,
|
||||
|
|
|
@ -422,6 +422,32 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
|||
xhci_writel(xhci, temp, port_array[port_id]);
|
||||
}
|
||||
|
||||
void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
|
||||
__le32 __iomem **port_array, int port_id, u16 wake_mask)
|
||||
{
|
||||
u32 temp;
|
||||
|
||||
temp = xhci_readl(xhci, port_array[port_id]);
|
||||
temp = xhci_port_state_to_neutral(temp);
|
||||
|
||||
if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT)
|
||||
temp |= PORT_WKCONN_E;
|
||||
else
|
||||
temp &= ~PORT_WKCONN_E;
|
||||
|
||||
if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT)
|
||||
temp |= PORT_WKDISC_E;
|
||||
else
|
||||
temp &= ~PORT_WKDISC_E;
|
||||
|
||||
if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT)
|
||||
temp |= PORT_WKOC_E;
|
||||
else
|
||||
temp &= ~PORT_WKOC_E;
|
||||
|
||||
xhci_writel(xhci, temp, port_array[port_id]);
|
||||
}
|
||||
|
||||
/* Test and clear port RWC bit */
|
||||
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
||||
int port_id, u32 port_bit)
|
||||
|
@ -448,6 +474,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
int slot_id;
|
||||
struct xhci_bus_state *bus_state;
|
||||
u16 link_state = 0;
|
||||
u16 wake_mask = 0;
|
||||
|
||||
max_ports = xhci_get_ports(hcd, &port_array);
|
||||
bus_state = &xhci->bus_state[hcd_index(hcd)];
|
||||
|
@ -593,6 +620,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
case SetPortFeature:
|
||||
if (wValue == USB_PORT_FEAT_LINK_STATE)
|
||||
link_state = (wIndex & 0xff00) >> 3;
|
||||
if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
|
||||
wake_mask = wIndex & 0xff00;
|
||||
wIndex &= 0xff;
|
||||
if (!wIndex || wIndex > max_ports)
|
||||
goto error;
|
||||
|
@ -703,6 +732,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
|
||||
break;
|
||||
case USB_PORT_FEAT_REMOTE_WAKE_MASK:
|
||||
xhci_set_remote_wake_mask(xhci, port_array,
|
||||
wIndex, wake_mask);
|
||||
temp = xhci_readl(xhci, port_array[wIndex]);
|
||||
xhci_dbg(xhci, "set port remote wake mask, "
|
||||
"actual port %d status = 0x%x\n",
|
||||
wIndex, temp);
|
||||
break;
|
||||
case USB_PORT_FEAT_BH_PORT_RESET:
|
||||
temp |= PORT_WR;
|
||||
xhci_writel(xhci, temp, port_array[wIndex]);
|
||||
|
@ -883,6 +920,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
|
|||
t2 |= PORT_LINK_STROBE | XDEV_U3;
|
||||
set_bit(port_index, &bus_state->bus_suspended);
|
||||
}
|
||||
/* USB core sets remote wake mask for USB 3.0 hubs,
|
||||
* including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND
|
||||
* is enabled, so also enable remote wake here.
|
||||
*/
|
||||
if (hcd->self.root_hub->do_remote_wakeup) {
|
||||
if (t1 & PORT_CONNECT) {
|
||||
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
|
||||
|
|
|
@ -2157,7 +2157,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|||
unsigned int val, val2;
|
||||
u64 val_64;
|
||||
struct xhci_segment *seg;
|
||||
u32 page_size;
|
||||
u32 page_size, temp;
|
||||
int i;
|
||||
|
||||
page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
|
||||
|
@ -2340,6 +2340,15 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
|
|||
|
||||
INIT_LIST_HEAD(&xhci->lpm_failed_devs);
|
||||
|
||||
/* Enable USB 3.0 device notifications for function remote wake, which
|
||||
* is necessary for allowing USB 3.0 devices to do remote wakeup from
|
||||
* U3 (device suspend).
|
||||
*/
|
||||
temp = xhci_readl(xhci, &xhci->op_regs->dev_notification);
|
||||
temp &= ~DEV_NOTE_MASK;
|
||||
temp |= DEV_NOTE_FWAKE;
|
||||
xhci_writel(xhci, temp, &xhci->op_regs->dev_notification);
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
|
|
|
@ -1237,6 +1237,26 @@ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
|
|||
return num_similar_speed_ports;
|
||||
}
|
||||
|
||||
static void handle_device_notification(struct xhci_hcd *xhci,
|
||||
union xhci_trb *event)
|
||||
{
|
||||
u32 slot_id;
|
||||
struct usb_device *udev;
|
||||
|
||||
slot_id = TRB_TO_SLOT_ID(event->generic.field[3]);
|
||||
if (!xhci->devs[slot_id]) {
|
||||
xhci_warn(xhci, "Device Notification event for "
|
||||
"unused slot %u\n", slot_id);
|
||||
return;
|
||||
}
|
||||
|
||||
xhci_dbg(xhci, "Device Wake Notification event for slot ID %u\n",
|
||||
slot_id);
|
||||
udev = xhci->devs[slot_id]->udev;
|
||||
if (udev && udev->parent)
|
||||
usb_wakeup_notification(udev->parent, udev->portnum);
|
||||
}
|
||||
|
||||
static void handle_port_status(struct xhci_hcd *xhci,
|
||||
union xhci_trb *event)
|
||||
{
|
||||
|
@ -1321,20 +1341,21 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
}
|
||||
|
||||
if (DEV_SUPERSPEED(temp)) {
|
||||
xhci_dbg(xhci, "resume SS port %d\n", port_id);
|
||||
xhci_dbg(xhci, "remote wake SS port %d\n", port_id);
|
||||
/* Set a flag to say the port signaled remote wakeup,
|
||||
* so we can tell the difference between the end of
|
||||
* device and host initiated resume.
|
||||
*/
|
||||
bus_state->port_remote_wakeup |= 1 << faked_port_index;
|
||||
xhci_test_and_clear_bit(xhci, port_array,
|
||||
faked_port_index, PORT_PLC);
|
||||
xhci_set_link_state(xhci, port_array, faked_port_index,
|
||||
XDEV_U0);
|
||||
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
||||
faked_port_index + 1);
|
||||
if (!slot_id) {
|
||||
xhci_dbg(xhci, "slot_id is zero\n");
|
||||
goto cleanup;
|
||||
}
|
||||
xhci_ring_device(xhci, slot_id);
|
||||
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
|
||||
/* Clear PORT_PLC */
|
||||
xhci_test_and_clear_bit(xhci, port_array,
|
||||
faked_port_index, PORT_PLC);
|
||||
/* Need to wait until the next link state change
|
||||
* indicates the device is actually in U0.
|
||||
*/
|
||||
bogus_port_status = true;
|
||||
goto cleanup;
|
||||
} else {
|
||||
xhci_dbg(xhci, "resume HS port %d\n", port_id);
|
||||
bus_state->resume_done[faked_port_index] = jiffies +
|
||||
|
@ -1345,6 +1366,32 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
}
|
||||
}
|
||||
|
||||
if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 &&
|
||||
DEV_SUPERSPEED(temp)) {
|
||||
xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
|
||||
/* We've just brought the device into U0 through either the
|
||||
* Resume state after a device remote wakeup, or through the
|
||||
* U3Exit state after a host-initiated resume. If it's a device
|
||||
* initiated remote wake, don't pass up the link state change,
|
||||
* so the roothub behavior is consistent with external
|
||||
* USB 3.0 hub behavior.
|
||||
*/
|
||||
slot_id = xhci_find_slot_id_by_port(hcd, xhci,
|
||||
faked_port_index + 1);
|
||||
if (slot_id && xhci->devs[slot_id])
|
||||
xhci_ring_device(xhci, slot_id);
|
||||
if (bus_state->port_remote_wakeup && (1 << faked_port_index)) {
|
||||
bus_state->port_remote_wakeup &=
|
||||
~(1 << faked_port_index);
|
||||
xhci_test_and_clear_bit(xhci, port_array,
|
||||
faked_port_index, PORT_PLC);
|
||||
usb_wakeup_notification(hcd->self.root_hub,
|
||||
faked_port_index + 1);
|
||||
bogus_port_status = true;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (hcd->speed != HCD_USB3)
|
||||
xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
|
||||
PORT_PLC);
|
||||
|
@ -2277,6 +2324,9 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
|
|||
else
|
||||
update_ptrs = 0;
|
||||
break;
|
||||
case TRB_TYPE(TRB_DEV_NOTE):
|
||||
handle_device_notification(xhci, event);
|
||||
break;
|
||||
default:
|
||||
if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=
|
||||
TRB_TYPE(48))
|
||||
|
|
|
@ -1344,6 +1344,7 @@ struct xhci_bus_state {
|
|||
/* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */
|
||||
u32 port_c_suspend;
|
||||
u32 suspended_ports;
|
||||
u32 port_remote_wakeup;
|
||||
unsigned long resume_done[USB_MAXCHILDREN];
|
||||
};
|
||||
|
||||
|
|
|
@ -286,7 +286,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
|
|||
|
||||
if (result != size) {
|
||||
dbg("%s - Unable to send config request, "
|
||||
"request=0x%x size=%d result=%d\n",
|
||||
"request=0x%x size=%d result=%d",
|
||||
__func__, request, size, result);
|
||||
if (result > 0)
|
||||
result = -EPROTO;
|
||||
|
@ -340,7 +340,7 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
|
|||
|
||||
if ((size > 2 && result != size) || result < 0) {
|
||||
dbg("%s - Unable to send request, "
|
||||
"request=0x%x size=%d result=%d\n",
|
||||
"request=0x%x size=%d result=%d",
|
||||
__func__, request, size, result);
|
||||
if (result > 0)
|
||||
result = -EPROTO;
|
||||
|
@ -683,13 +683,13 @@ static void cp210x_set_termios(struct tty_struct *tty,
|
|||
default:
|
||||
dbg("cp210x driver does not "
|
||||
"support the number of bits requested,"
|
||||
" using 8 bit mode\n");
|
||||
" using 8 bit mode");
|
||||
bits |= BITS_DATA_8;
|
||||
break;
|
||||
}
|
||||
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
|
||||
dbg("Number of data bits requested "
|
||||
"not supported by device\n");
|
||||
"not supported by device");
|
||||
}
|
||||
|
||||
if ((cflag & (PARENB|PARODD|CMSPAR)) !=
|
||||
|
@ -716,8 +716,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
|
|||
}
|
||||
}
|
||||
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
|
||||
dbg("Parity mode not supported "
|
||||
"by device\n");
|
||||
dbg("Parity mode not supported by device");
|
||||
}
|
||||
|
||||
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
|
||||
|
@ -732,7 +731,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
|
|||
}
|
||||
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
|
||||
dbg("Number of stop bits requested "
|
||||
"not supported by device\n");
|
||||
"not supported by device");
|
||||
}
|
||||
|
||||
if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
|
||||
|
|
|
@ -800,7 +800,7 @@ static void cypress_send(struct usb_serial_port *port)
|
|||
cypress_write_int_callback, port, priv->write_urb_interval);
|
||||
result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
dev_err(&port->dev,
|
||||
dev_err_console(port,
|
||||
"%s - failed submitting write urb, error %d\n",
|
||||
__func__, result);
|
||||
priv->write_urb_in_use = 0;
|
||||
|
|
|
@ -995,7 +995,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
/* return length of new data written, or error */
|
||||
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
|
||||
if (ret < 0)
|
||||
dev_err(&port->dev,
|
||||
dev_err_console(port,
|
||||
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
|
||||
__func__, ret, priv->dp_port_num);
|
||||
dbg("digi_write: returning %d", ret);
|
||||
|
@ -1065,7 +1065,7 @@ static void digi_write_bulk_callback(struct urb *urb)
|
|||
|
||||
spin_unlock(&priv->dp_port_lock);
|
||||
if (ret && ret != -EPERM)
|
||||
dev_err(&port->dev,
|
||||
dev_err_console(port,
|
||||
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
|
||||
__func__, ret, priv->dp_port_num);
|
||||
}
|
||||
|
|
|
@ -217,7 +217,7 @@ static int usb_serial_generic_write_start(struct usb_serial_port *port)
|
|||
clear_bit(i, &port->write_urbs_free);
|
||||
result = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
dev_err(&port->dev, "%s - error submitting urb: %d\n",
|
||||
dev_err_console(port, "%s - error submitting urb: %d\n",
|
||||
__func__, result);
|
||||
set_bit(i, &port->write_urbs_free);
|
||||
spin_lock_irqsave(&port->lock, flags);
|
||||
|
|
|
@ -1286,7 +1286,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
|
|||
count = fifo->count;
|
||||
buffer = kmalloc(count+2, GFP_ATOMIC);
|
||||
if (buffer == NULL) {
|
||||
dev_err(&edge_port->port->dev,
|
||||
dev_err_console(edge_port->port,
|
||||
"%s - no more kernel memory...\n", __func__);
|
||||
edge_port->write_in_progress = false;
|
||||
goto exit_send;
|
||||
|
@ -1331,7 +1331,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
|
|||
status = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (status) {
|
||||
/* something went wrong */
|
||||
dev_err(&edge_port->port->dev,
|
||||
dev_err_console(edge_port->port,
|
||||
"%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n",
|
||||
__func__, status);
|
||||
edge_port->write_in_progress = false;
|
||||
|
|
|
@ -1817,7 +1817,7 @@ static void edge_bulk_out_callback(struct urb *urb)
|
|||
__func__, status);
|
||||
return;
|
||||
default:
|
||||
dev_err(&urb->dev->dev, "%s - nonzero write bulk status "
|
||||
dev_err_console(port, "%s - nonzero write bulk status "
|
||||
"received: %d\n", __func__, status);
|
||||
}
|
||||
|
||||
|
@ -2111,7 +2111,7 @@ static void edge_send(struct tty_struct *tty)
|
|||
/* send the data out the bulk port */
|
||||
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
dev_err(&port->dev,
|
||||
dev_err_console(port,
|
||||
"%s - failed submitting write urb, error %d\n",
|
||||
__func__, result);
|
||||
edge_port->ep_write_urb_in_use = 0;
|
||||
|
|
|
@ -1294,7 +1294,7 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
|
||||
GFP_KERNEL);
|
||||
if (urb->transfer_buffer == NULL) {
|
||||
dev_err(&port->dev, "%s no more kernel memory...\n",
|
||||
dev_err_console(port, "%s no more kernel memory...\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
|
@ -1315,7 +1315,7 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
/* send it down the pipe */
|
||||
status = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (status) {
|
||||
dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
|
||||
dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
|
||||
"with status = %d\n", __func__, status);
|
||||
bytes_sent = status;
|
||||
goto exit;
|
||||
|
|
|
@ -1509,7 +1509,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
|
||||
|
||||
if (urb->transfer_buffer == NULL) {
|
||||
dev_err(&port->dev, "%s no more kernel memory...\n",
|
||||
dev_err_console(port, "%s no more kernel memory...\n",
|
||||
__func__);
|
||||
goto exit;
|
||||
}
|
||||
|
@ -1535,7 +1535,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
|
||||
if (status) {
|
||||
mos7840_port->busy[i] = 0;
|
||||
dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
|
||||
dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
|
||||
"with status = %d\n", __func__, status);
|
||||
bytes_sent = status;
|
||||
goto exit;
|
||||
|
|
|
@ -254,7 +254,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
|
|||
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
set_bit(0, &wport->write_urbs_free);
|
||||
dev_err(&port->dev,
|
||||
dev_err_console(port,
|
||||
"%s - failed submitting write urb, error %d\n",
|
||||
__func__, result);
|
||||
} else
|
||||
|
|
|
@ -302,7 +302,7 @@ static void send_data(struct work_struct *work)
|
|||
if (count != 0) {
|
||||
allow = kmalloc(1, GFP_KERNEL);
|
||||
if (!allow) {
|
||||
dev_err(&port->dev, "%s(): kmalloc failed\n",
|
||||
dev_err_console(port, "%s(): kmalloc failed\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
@ -334,7 +334,7 @@ static void send_data(struct work_struct *work)
|
|||
port->write_urb->transfer_buffer_length = count;
|
||||
result = usb_submit_urb(port->write_urb, GFP_NOIO);
|
||||
if (result != 0) {
|
||||
dev_err(&port->dev, "%s(): usb_submit_urb() failed"
|
||||
dev_err_console(port, "%s(): usb_submit_urb() failed"
|
||||
" with error %d\n", __func__, result);
|
||||
priv->flags.write_urb_in_use = 0;
|
||||
}
|
||||
|
@ -938,7 +938,7 @@ static void oti6858_write_bulk_callback(struct urb *urb)
|
|||
port->write_urb->transfer_buffer_length = 1;
|
||||
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
|
||||
dev_err_console(port, "%s(): usb_submit_urb() failed,"
|
||||
" error %d\n", __func__, result);
|
||||
} else {
|
||||
return;
|
||||
|
|
|
@ -1250,7 +1250,6 @@ static void ti_bulk_out_callback(struct urb *urb)
|
|||
{
|
||||
struct ti_port *tport = urb->context;
|
||||
struct usb_serial_port *port = tport->tp_port;
|
||||
struct device *dev = &urb->dev->dev;
|
||||
int status = urb->status;
|
||||
|
||||
dbg("%s - port %d", __func__, port->number);
|
||||
|
@ -1268,7 +1267,7 @@ static void ti_bulk_out_callback(struct urb *urb)
|
|||
wake_up_interruptible(&tport->tp_write_wait);
|
||||
return;
|
||||
default:
|
||||
dev_err(dev, "%s - nonzero urb status, %d\n",
|
||||
dev_err_console(port, "%s - nonzero urb status, %d\n",
|
||||
__func__, status);
|
||||
tport->tp_tdev->td_urb_error = 1;
|
||||
wake_up_interruptible(&tport->tp_write_wait);
|
||||
|
@ -1337,7 +1336,7 @@ static void ti_send(struct ti_port *tport)
|
|||
|
||||
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
dev_err(&port->dev, "%s - submit write urb failed, %d\n",
|
||||
dev_err_console(port, "%s - submit write urb failed, %d\n",
|
||||
__func__, result);
|
||||
tport->tp_write_urb_in_use = 0;
|
||||
/* TODO: reschedule ti_send */
|
||||
|
|
|
@ -740,7 +740,7 @@ static int whiteheat_write(struct tty_struct *tty,
|
|||
urb->transfer_buffer_length = bytes;
|
||||
result = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (result) {
|
||||
dev_err(&port->dev,
|
||||
dev_err_console(port,
|
||||
"%s - failed submitting write urb, error %d\n",
|
||||
__func__, result);
|
||||
sent = result;
|
||||
|
|
|
@ -1276,6 +1276,7 @@ static struct usb_driver alauda_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = alauda_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(alauda_driver);
|
||||
|
|
|
@ -272,6 +272,7 @@ static struct usb_driver cypress_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = cypress_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(cypress_driver);
|
||||
|
|
|
@ -751,6 +751,7 @@ static struct usb_driver datafab_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = datafab_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(datafab_driver);
|
||||
|
|
|
@ -2407,6 +2407,7 @@ static struct usb_driver ene_ub6250_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = ene_ub6250_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(ene_ub6250_driver);
|
||||
|
|
|
@ -553,6 +553,7 @@ static struct usb_driver freecom_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = freecom_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(freecom_driver);
|
||||
|
|
|
@ -1566,6 +1566,7 @@ static struct usb_driver isd200_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = isd200_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(isd200_driver);
|
||||
|
|
|
@ -677,6 +677,7 @@ static struct usb_driver jumpshot_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = jumpshot_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(jumpshot_driver);
|
||||
|
|
|
@ -230,6 +230,7 @@ static struct usb_driver karma_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = karma_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(karma_driver);
|
||||
|
|
|
@ -312,6 +312,7 @@ static struct usb_driver onetouch_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = onetouch_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(onetouch_driver);
|
||||
|
|
|
@ -1100,6 +1100,7 @@ static struct usb_driver realtek_cr_driver = {
|
|||
.id_table = realtek_cr_ids,
|
||||
.soft_unbind = 1,
|
||||
.supports_autosuspend = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(realtek_cr_driver);
|
||||
|
|
|
@ -78,8 +78,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);
|
||||
|
||||
/*
|
||||
* Set the INQUIRY transfer length to 36. We don't use any of
|
||||
* the extra data and many devices choke if asked for more or
|
||||
|
@ -104,18 +102,6 @@ static int slave_alloc (struct scsi_device *sdev)
|
|||
*/
|
||||
blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
|
||||
|
||||
/*
|
||||
* The UFI spec treates the Peripheral Qualifier bits in an
|
||||
* INQUIRY result as reserved and requires devices to set them
|
||||
* to 0. However the SCSI spec requires these bits to be set
|
||||
* to 3 to indicate when a LUN is not present.
|
||||
*
|
||||
* Let the scanning code know if this target merely sets
|
||||
* Peripheral Device Type to 0x1f to indicate no LUN.
|
||||
*/
|
||||
if (us->subclass == USB_SC_UFI)
|
||||
sdev->sdev_target->pdt_1f_for_no_lun = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -197,6 +183,9 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
* page x08, so we will skip it. */
|
||||
sdev->skip_ms_page_8 = 1;
|
||||
|
||||
/* Some devices don't handle VPD pages correctly */
|
||||
sdev->skip_vpd_pages = 1;
|
||||
|
||||
/* Some disks return the total number of blocks in response
|
||||
* to READ CAPACITY rather than the highest block number.
|
||||
* If this device makes that mistake, tell the sd driver. */
|
||||
|
@ -217,16 +206,6 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
if (sdev->scsi_level > SCSI_SPC_2)
|
||||
us->fflags |= US_FL_SANE_SENSE;
|
||||
|
||||
/* Some devices report a SCSI revision level above 2 but are
|
||||
* unable to handle the REPORT LUNS command (for which
|
||||
* support is mandatory at level 3). Since we already have
|
||||
* a Get-Max-LUN request, we won't lose much by setting the
|
||||
* revision level down to 2. The only devices that would be
|
||||
* affected are those with sparse LUNs. */
|
||||
if (sdev->scsi_level > SCSI_2)
|
||||
sdev->sdev_target->scsi_level =
|
||||
sdev->scsi_level = SCSI_2;
|
||||
|
||||
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
|
||||
* Hardware Error) when any low-level error occurs,
|
||||
* recoverable or not. Setting this flag tells the SCSI
|
||||
|
@ -283,6 +262,33 @@ static int slave_configure(struct scsi_device *sdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int target_alloc(struct scsi_target *starget)
|
||||
{
|
||||
struct us_data *us = host_to_us(dev_to_shost(starget->dev.parent));
|
||||
|
||||
/*
|
||||
* Some USB drives don't support REPORT LUNS, even though they
|
||||
* report a SCSI revision level above 2. Tell the SCSI layer
|
||||
* not to issue that command; it will perform a normal sequential
|
||||
* scan instead.
|
||||
*/
|
||||
starget->no_report_luns = 1;
|
||||
|
||||
/*
|
||||
* The UFI spec treats the Peripheral Qualifier bits in an
|
||||
* INQUIRY result as reserved and requires devices to set them
|
||||
* to 0. However the SCSI spec requires these bits to be set
|
||||
* to 3 to indicate when a LUN is not present.
|
||||
*
|
||||
* Let the scanning code know if this target merely sets
|
||||
* Peripheral Device Type to 0x1f to indicate no LUN.
|
||||
*/
|
||||
if (us->subclass == USB_SC_UFI)
|
||||
starget->pdt_1f_for_no_lun = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* queue a command */
|
||||
/* This is always called with scsi_lock(host) held */
|
||||
static int queuecommand_lck(struct scsi_cmnd *srb,
|
||||
|
@ -546,6 +552,7 @@ struct scsi_host_template usb_stor_host_template = {
|
|||
|
||||
.slave_alloc = slave_alloc,
|
||||
.slave_configure = slave_configure,
|
||||
.target_alloc = target_alloc,
|
||||
|
||||
/* lots of sg segments can be handled */
|
||||
.sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
|
||||
|
|
|
@ -1787,6 +1787,7 @@ static struct usb_driver sddr09_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = sddr09_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(sddr09_driver);
|
||||
|
|
|
@ -1006,6 +1006,7 @@ static struct usb_driver sddr55_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = sddr55_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(sddr55_driver);
|
||||
|
|
|
@ -1863,6 +1863,7 @@ static struct usb_driver usbat_driver = {
|
|||
.post_reset = usb_stor_post_reset,
|
||||
.id_table = usbat_usb_ids,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
module_usb_driver(usbat_driver);
|
||||
|
|
|
@ -13,7 +13,9 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/hcd.h>
|
||||
#include <linux/usb/storage.h>
|
||||
#include <linux/usb/uas.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_dbg.h>
|
||||
|
@ -22,49 +24,6 @@
|
|||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_tcq.h>
|
||||
|
||||
/* Common header for all IUs */
|
||||
struct iu {
|
||||
__u8 iu_id;
|
||||
__u8 rsvd1;
|
||||
__be16 tag;
|
||||
};
|
||||
|
||||
enum {
|
||||
IU_ID_COMMAND = 0x01,
|
||||
IU_ID_STATUS = 0x03,
|
||||
IU_ID_RESPONSE = 0x04,
|
||||
IU_ID_TASK_MGMT = 0x05,
|
||||
IU_ID_READ_READY = 0x06,
|
||||
IU_ID_WRITE_READY = 0x07,
|
||||
};
|
||||
|
||||
struct command_iu {
|
||||
__u8 iu_id;
|
||||
__u8 rsvd1;
|
||||
__be16 tag;
|
||||
__u8 prio_attr;
|
||||
__u8 rsvd5;
|
||||
__u8 len;
|
||||
__u8 rsvd7;
|
||||
struct scsi_lun lun;
|
||||
__u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
|
||||
};
|
||||
|
||||
/*
|
||||
* Also used for the Read Ready and Write Ready IUs since they have the
|
||||
* same first four bytes
|
||||
*/
|
||||
struct sense_iu {
|
||||
__u8 iu_id;
|
||||
__u8 rsvd1;
|
||||
__be16 tag;
|
||||
__be16 status_qual;
|
||||
__u8 status;
|
||||
__u8 rsvd7[7];
|
||||
__be16 len;
|
||||
__u8 sense[SCSI_SENSE_BUFFERSIZE];
|
||||
};
|
||||
|
||||
/*
|
||||
* The r00-r01c specs define this version of the SENSE IU data structure.
|
||||
* It's still in use by several different firmware releases.
|
||||
|
@ -79,18 +38,6 @@ struct sense_iu_old {
|
|||
__u8 sense[SCSI_SENSE_BUFFERSIZE];
|
||||
};
|
||||
|
||||
enum {
|
||||
CMD_PIPE_ID = 1,
|
||||
STATUS_PIPE_ID = 2,
|
||||
DATA_IN_PIPE_ID = 3,
|
||||
DATA_OUT_PIPE_ID = 4,
|
||||
|
||||
UAS_SIMPLE_TAG = 0,
|
||||
UAS_HEAD_TAG = 1,
|
||||
UAS_ORDERED_TAG = 2,
|
||||
UAS_ACA = 4,
|
||||
};
|
||||
|
||||
struct uas_dev_info {
|
||||
struct usb_interface *intf;
|
||||
struct usb_device *udev;
|
||||
|
@ -98,6 +45,8 @@ struct uas_dev_info {
|
|||
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
|
||||
unsigned use_streams:1;
|
||||
unsigned uas_sense_old:1;
|
||||
struct scsi_cmnd *cmnd;
|
||||
struct urb *status_urb; /* used only if stream support is available */
|
||||
};
|
||||
|
||||
enum {
|
||||
|
@ -109,6 +58,9 @@ enum {
|
|||
SUBMIT_DATA_OUT_URB = (1 << 5),
|
||||
ALLOC_CMD_URB = (1 << 6),
|
||||
SUBMIT_CMD_URB = (1 << 7),
|
||||
COMPLETED_DATA_IN = (1 << 8),
|
||||
COMPLETED_DATA_OUT = (1 << 9),
|
||||
DATA_COMPLETES_CMD = (1 << 10),
|
||||
};
|
||||
|
||||
/* Overrides scsi_pointer */
|
||||
|
@ -116,6 +68,7 @@ struct uas_cmd_info {
|
|||
unsigned int state;
|
||||
unsigned int stream;
|
||||
struct urb *cmd_urb;
|
||||
/* status_urb is used only if stream support isn't available */
|
||||
struct urb *status_urb;
|
||||
struct urb *data_in_urb;
|
||||
struct urb *data_out_urb;
|
||||
|
@ -125,33 +78,43 @@ struct uas_cmd_info {
|
|||
/* I hate forward declarations, but I actually have a loop */
|
||||
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
|
||||
struct uas_dev_info *devinfo, gfp_t gfp);
|
||||
static void uas_do_work(struct work_struct *work);
|
||||
|
||||
static DECLARE_WORK(uas_work, uas_do_work);
|
||||
static DEFINE_SPINLOCK(uas_work_lock);
|
||||
static LIST_HEAD(uas_work_list);
|
||||
|
||||
static void uas_do_work(struct work_struct *work)
|
||||
{
|
||||
struct uas_cmd_info *cmdinfo;
|
||||
struct uas_cmd_info *temp;
|
||||
struct list_head list;
|
||||
int err;
|
||||
|
||||
spin_lock_irq(&uas_work_lock);
|
||||
list_replace_init(&uas_work_list, &list);
|
||||
spin_unlock_irq(&uas_work_lock);
|
||||
|
||||
list_for_each_entry(cmdinfo, &list, list) {
|
||||
list_for_each_entry_safe(cmdinfo, temp, &list, list) {
|
||||
struct scsi_pointer *scp = (void *)cmdinfo;
|
||||
struct scsi_cmnd *cmnd = container_of(scp,
|
||||
struct scsi_cmnd, SCp);
|
||||
uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
|
||||
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
|
||||
if (err) {
|
||||
list_del(&cmdinfo->list);
|
||||
spin_lock_irq(&uas_work_lock);
|
||||
list_add_tail(&cmdinfo->list, &uas_work_list);
|
||||
spin_unlock_irq(&uas_work_lock);
|
||||
schedule_work(&uas_work);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static DECLARE_WORK(uas_work, uas_do_work);
|
||||
|
||||
static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
|
||||
{
|
||||
struct sense_iu *sense_iu = urb->transfer_buffer;
|
||||
struct scsi_device *sdev = cmnd->device;
|
||||
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
|
||||
|
||||
if (urb->actual_length > 16) {
|
||||
unsigned len = be16_to_cpup(&sense_iu->len);
|
||||
|
@ -169,16 +132,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
|
|||
}
|
||||
|
||||
cmnd->result = sense_iu->status;
|
||||
if (sdev->current_cmnd)
|
||||
sdev->current_cmnd = NULL;
|
||||
cmnd->scsi_done(cmnd);
|
||||
usb_free_urb(urb);
|
||||
if (!(cmdinfo->state & DATA_COMPLETES_CMD))
|
||||
cmnd->scsi_done(cmnd);
|
||||
}
|
||||
|
||||
static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
|
||||
{
|
||||
struct sense_iu_old *sense_iu = urb->transfer_buffer;
|
||||
struct scsi_device *sdev = cmnd->device;
|
||||
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
|
||||
|
||||
if (urb->actual_length > 8) {
|
||||
unsigned len = be16_to_cpup(&sense_iu->len) - 2;
|
||||
|
@ -196,10 +158,8 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
|
|||
}
|
||||
|
||||
cmnd->result = sense_iu->status;
|
||||
if (sdev->current_cmnd)
|
||||
sdev->current_cmnd = NULL;
|
||||
cmnd->scsi_done(cmnd);
|
||||
usb_free_urb(urb);
|
||||
if (!(cmdinfo->state & DATA_COMPLETES_CMD))
|
||||
cmnd->scsi_done(cmnd);
|
||||
}
|
||||
|
||||
static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
|
||||
|
@ -208,7 +168,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
|
|||
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
|
||||
int err;
|
||||
|
||||
cmdinfo->state = direction | SUBMIT_STATUS_URB;
|
||||
cmdinfo->state = direction;
|
||||
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
|
||||
if (err) {
|
||||
spin_lock(&uas_work_lock);
|
||||
|
@ -221,27 +181,61 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
|
|||
static void uas_stat_cmplt(struct urb *urb)
|
||||
{
|
||||
struct iu *iu = urb->transfer_buffer;
|
||||
struct scsi_device *sdev = urb->context;
|
||||
struct uas_dev_info *devinfo = sdev->hostdata;
|
||||
struct Scsi_Host *shost = urb->context;
|
||||
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
|
||||
struct scsi_cmnd *cmnd;
|
||||
struct uas_cmd_info *cmdinfo;
|
||||
u16 tag;
|
||||
int ret;
|
||||
|
||||
if (urb->status) {
|
||||
dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
|
||||
usb_free_urb(urb);
|
||||
if (devinfo->use_streams)
|
||||
usb_free_urb(urb);
|
||||
return;
|
||||
}
|
||||
|
||||
tag = be16_to_cpup(&iu->tag) - 1;
|
||||
if (sdev->current_cmnd)
|
||||
cmnd = sdev->current_cmnd;
|
||||
if (tag == 0)
|
||||
cmnd = devinfo->cmnd;
|
||||
else
|
||||
cmnd = scsi_find_tag(sdev, tag);
|
||||
if (!cmnd)
|
||||
cmnd = scsi_host_find_tag(shost, tag - 1);
|
||||
if (!cmnd) {
|
||||
if (devinfo->use_streams) {
|
||||
usb_free_urb(urb);
|
||||
return;
|
||||
}
|
||||
ret = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (ret)
|
||||
dev_err(&urb->dev->dev, "failed submit status urb\n");
|
||||
return;
|
||||
}
|
||||
cmdinfo = (void *)&cmnd->SCp;
|
||||
|
||||
switch (iu->iu_id) {
|
||||
case IU_ID_STATUS:
|
||||
if (devinfo->cmnd == cmnd)
|
||||
devinfo->cmnd = NULL;
|
||||
|
||||
if (!(cmdinfo->state & COMPLETED_DATA_IN) &&
|
||||
cmdinfo->data_in_urb) {
|
||||
if (devinfo->use_streams) {
|
||||
cmdinfo->state |= DATA_COMPLETES_CMD;
|
||||
usb_unlink_urb(cmdinfo->data_in_urb);
|
||||
} else {
|
||||
usb_free_urb(cmdinfo->data_in_urb);
|
||||
}
|
||||
}
|
||||
if (!(cmdinfo->state & COMPLETED_DATA_OUT) &&
|
||||
cmdinfo->data_out_urb) {
|
||||
if (devinfo->use_streams) {
|
||||
cmdinfo->state |= DATA_COMPLETES_CMD;
|
||||
usb_unlink_urb(cmdinfo->data_in_urb);
|
||||
} else {
|
||||
usb_free_urb(cmdinfo->data_out_urb);
|
||||
}
|
||||
}
|
||||
|
||||
if (urb->actual_length < 16)
|
||||
devinfo->uas_sense_old = 1;
|
||||
if (devinfo->uas_sense_old)
|
||||
|
@ -259,29 +253,70 @@ static void uas_stat_cmplt(struct urb *urb)
|
|||
scmd_printk(KERN_ERR, cmnd,
|
||||
"Bogus IU (%d) received on status pipe\n", iu->iu_id);
|
||||
}
|
||||
|
||||
if (devinfo->use_streams) {
|
||||
usb_free_urb(urb);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = usb_submit_urb(urb, GFP_ATOMIC);
|
||||
if (ret)
|
||||
dev_err(&urb->dev->dev, "failed submit status urb\n");
|
||||
}
|
||||
|
||||
static void uas_data_cmplt(struct urb *urb)
|
||||
static void uas_data_out_cmplt(struct urb *urb)
|
||||
{
|
||||
struct scsi_data_buffer *sdb = urb->context;
|
||||
struct scsi_cmnd *cmnd = urb->context;
|
||||
struct scsi_data_buffer *sdb = scsi_out(cmnd);
|
||||
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
|
||||
|
||||
cmdinfo->state |= COMPLETED_DATA_OUT;
|
||||
|
||||
sdb->resid = sdb->length - urb->actual_length;
|
||||
usb_free_urb(urb);
|
||||
|
||||
if (cmdinfo->state & DATA_COMPLETES_CMD)
|
||||
cmnd->scsi_done(cmnd);
|
||||
}
|
||||
|
||||
static void uas_data_in_cmplt(struct urb *urb)
|
||||
{
|
||||
struct scsi_cmnd *cmnd = urb->context;
|
||||
struct scsi_data_buffer *sdb = scsi_in(cmnd);
|
||||
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
|
||||
|
||||
cmdinfo->state |= COMPLETED_DATA_IN;
|
||||
|
||||
sdb->resid = sdb->length - urb->actual_length;
|
||||
usb_free_urb(urb);
|
||||
|
||||
if (cmdinfo->state & DATA_COMPLETES_CMD)
|
||||
cmnd->scsi_done(cmnd);
|
||||
}
|
||||
|
||||
static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
|
||||
unsigned int pipe, u16 stream_id,
|
||||
struct scsi_data_buffer *sdb,
|
||||
enum dma_data_direction dir)
|
||||
unsigned int pipe, struct scsi_cmnd *cmnd,
|
||||
enum dma_data_direction dir)
|
||||
{
|
||||
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
|
||||
struct usb_device *udev = devinfo->udev;
|
||||
struct urb *urb = usb_alloc_urb(0, gfp);
|
||||
struct scsi_data_buffer *sdb;
|
||||
usb_complete_t complete_fn;
|
||||
u16 stream_id = cmdinfo->stream;
|
||||
|
||||
if (!urb)
|
||||
goto out;
|
||||
usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt,
|
||||
sdb);
|
||||
if (devinfo->use_streams)
|
||||
urb->stream_id = stream_id;
|
||||
if (dir == DMA_FROM_DEVICE) {
|
||||
sdb = scsi_in(cmnd);
|
||||
complete_fn = uas_data_in_cmplt;
|
||||
} else {
|
||||
sdb = scsi_out(cmnd);
|
||||
complete_fn = uas_data_out_cmplt;
|
||||
}
|
||||
usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
|
||||
complete_fn, cmnd);
|
||||
urb->stream_id = stream_id;
|
||||
urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
|
||||
urb->sg = sdb->table.sgl;
|
||||
out:
|
||||
|
@ -289,7 +324,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
|
|||
}
|
||||
|
||||
static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
|
||||
struct scsi_cmnd *cmnd, u16 stream_id)
|
||||
struct Scsi_Host *shost, u16 stream_id)
|
||||
{
|
||||
struct usb_device *udev = devinfo->udev;
|
||||
struct urb *urb = usb_alloc_urb(0, gfp);
|
||||
|
@ -303,7 +338,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
|
|||
goto free;
|
||||
|
||||
usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
|
||||
uas_stat_cmplt, cmnd->device);
|
||||
uas_stat_cmplt, shost);
|
||||
urb->stream_id = stream_id;
|
||||
urb->transfer_flags |= URB_FREE_BUFFER;
|
||||
out:
|
||||
|
@ -334,7 +369,10 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
|
|||
goto free;
|
||||
|
||||
iu->iu_id = IU_ID_COMMAND;
|
||||
iu->tag = cpu_to_be16(stream_id);
|
||||
if (blk_rq_tagged(cmnd->request))
|
||||
iu->tag = cpu_to_be16(cmnd->request->tag + 2);
|
||||
else
|
||||
iu->tag = cpu_to_be16(1);
|
||||
iu->prio_attr = UAS_SIMPLE_TAG;
|
||||
iu->len = len;
|
||||
int_to_scsilun(sdev->lun, &iu->lun);
|
||||
|
@ -362,8 +400,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
|
|||
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
|
||||
|
||||
if (cmdinfo->state & ALLOC_STATUS_URB) {
|
||||
cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
|
||||
cmdinfo->stream);
|
||||
cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
|
||||
cmnd->device->host, cmdinfo->stream);
|
||||
if (!cmdinfo->status_urb)
|
||||
return SCSI_MLQUEUE_DEVICE_BUSY;
|
||||
cmdinfo->state &= ~ALLOC_STATUS_URB;
|
||||
|
@ -380,8 +418,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
|
|||
|
||||
if (cmdinfo->state & ALLOC_DATA_IN_URB) {
|
||||
cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
|
||||
devinfo->data_in_pipe, cmdinfo->stream,
|
||||
scsi_in(cmnd), DMA_FROM_DEVICE);
|
||||
devinfo->data_in_pipe, cmnd,
|
||||
DMA_FROM_DEVICE);
|
||||
if (!cmdinfo->data_in_urb)
|
||||
return SCSI_MLQUEUE_DEVICE_BUSY;
|
||||
cmdinfo->state &= ~ALLOC_DATA_IN_URB;
|
||||
|
@ -398,8 +436,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
|
|||
|
||||
if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
|
||||
cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
|
||||
devinfo->data_out_pipe, cmdinfo->stream,
|
||||
scsi_out(cmnd), DMA_TO_DEVICE);
|
||||
devinfo->data_out_pipe, cmnd,
|
||||
DMA_TO_DEVICE);
|
||||
if (!cmdinfo->data_out_urb)
|
||||
return SCSI_MLQUEUE_DEVICE_BUSY;
|
||||
cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
|
||||
|
@ -444,13 +482,13 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
|
|||
|
||||
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
|
||||
|
||||
if (!cmdinfo->status_urb && sdev->current_cmnd)
|
||||
if (devinfo->cmnd)
|
||||
return SCSI_MLQUEUE_DEVICE_BUSY;
|
||||
|
||||
if (blk_rq_tagged(cmnd->request)) {
|
||||
cmdinfo->stream = cmnd->request->tag + 1;
|
||||
cmdinfo->stream = cmnd->request->tag + 2;
|
||||
} else {
|
||||
sdev->current_cmnd = cmnd;
|
||||
devinfo->cmnd = cmnd;
|
||||
cmdinfo->stream = 1;
|
||||
}
|
||||
|
||||
|
@ -472,7 +510,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
|
|||
}
|
||||
|
||||
if (!devinfo->use_streams) {
|
||||
cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
|
||||
cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB |
|
||||
ALLOC_STATUS_URB | SUBMIT_STATUS_URB);
|
||||
cmdinfo->stream = 0;
|
||||
}
|
||||
|
||||
|
@ -551,7 +590,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
|
|||
{
|
||||
struct uas_dev_info *devinfo = sdev->hostdata;
|
||||
scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
|
||||
scsi_activate_tcq(sdev, devinfo->qdepth - 1);
|
||||
scsi_activate_tcq(sdev, devinfo->qdepth - 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -589,22 +628,34 @@ static int uas_is_interface(struct usb_host_interface *intf)
|
|||
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,
|
||||
struct usb_interface *intf)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (uas_is_interface(intf->cur_altsetting))
|
||||
return 0;
|
||||
int sg_supported = udev->bus->sg_tablesize != 0;
|
||||
|
||||
for (i = 0; i < intf->num_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,
|
||||
alt->desc.bInterfaceNumber,
|
||||
alt->desc.bAlternateSetting);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
|
@ -619,6 +670,7 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
|
|||
unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;
|
||||
|
||||
devinfo->uas_sense_old = 0;
|
||||
devinfo->cmnd = NULL;
|
||||
|
||||
for (i = 0; i < n_endpoints; i++) {
|
||||
unsigned char *extra = endpoint[i].extra;
|
||||
|
@ -670,6 +722,40 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
|
|||
}
|
||||
}
|
||||
|
||||
static int uas_alloc_status_urb(struct uas_dev_info *devinfo,
|
||||
struct Scsi_Host *shost)
|
||||
{
|
||||
if (devinfo->use_streams) {
|
||||
devinfo->status_urb = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL,
|
||||
shost, 0);
|
||||
if (!devinfo->status_urb)
|
||||
goto err_s_urb;
|
||||
|
||||
if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL))
|
||||
goto err_submit_urb;
|
||||
|
||||
return 0;
|
||||
err_submit_urb:
|
||||
usb_free_urb(devinfo->status_urb);
|
||||
err_s_urb:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void uas_free_streams(struct uas_dev_info *devinfo)
|
||||
{
|
||||
struct usb_device *udev = devinfo->udev;
|
||||
struct usb_host_endpoint *eps[3];
|
||||
|
||||
eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
|
||||
eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
|
||||
eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
|
||||
usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX: What I'd like to do here is register a SCSI host for each USB host in
|
||||
* the system. Follow usb-storage's design of registering a SCSI host for
|
||||
|
@ -699,18 +785,33 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
|
|||
shost->max_id = 1;
|
||||
shost->sg_tablesize = udev->bus->sg_tablesize;
|
||||
|
||||
result = scsi_add_host(shost, &intf->dev);
|
||||
if (result)
|
||||
goto free;
|
||||
shost->hostdata[0] = (unsigned long)devinfo;
|
||||
|
||||
devinfo->intf = intf;
|
||||
devinfo->udev = udev;
|
||||
uas_configure_endpoints(devinfo);
|
||||
|
||||
result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
|
||||
if (result)
|
||||
goto free;
|
||||
|
||||
result = scsi_add_host(shost, &intf->dev);
|
||||
if (result)
|
||||
goto deconfig_eps;
|
||||
|
||||
shost->hostdata[0] = (unsigned long)devinfo;
|
||||
|
||||
result = uas_alloc_status_urb(devinfo, shost);
|
||||
if (result)
|
||||
goto err_alloc_status;
|
||||
|
||||
scsi_scan_host(shost);
|
||||
usb_set_intfdata(intf, shost);
|
||||
return result;
|
||||
|
||||
err_alloc_status:
|
||||
scsi_remove_host(shost);
|
||||
shost = NULL;
|
||||
deconfig_eps:
|
||||
uas_free_streams(devinfo);
|
||||
free:
|
||||
kfree(devinfo);
|
||||
if (shost)
|
||||
|
@ -732,18 +833,13 @@ static int uas_post_reset(struct usb_interface *intf)
|
|||
|
||||
static void uas_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
struct usb_host_endpoint *eps[3];
|
||||
struct Scsi_Host *shost = usb_get_intfdata(intf);
|
||||
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
|
||||
|
||||
scsi_remove_host(shost);
|
||||
|
||||
eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
|
||||
eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
|
||||
eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
|
||||
usb_free_streams(intf, eps, 3, GFP_KERNEL);
|
||||
|
||||
usb_kill_urb(devinfo->status_urb);
|
||||
usb_free_urb(devinfo->status_urb);
|
||||
uas_free_streams(devinfo);
|
||||
kfree(devinfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,9 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
|
|||
{ } /* Terminating entry */
|
||||
};
|
||||
|
||||
static struct us_unusual_dev for_dynamic_ids =
|
||||
USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0);
|
||||
|
||||
#undef UNUSUAL_DEV
|
||||
#undef COMPLIANT_DEV
|
||||
#undef USUAL_DEV
|
||||
|
@ -999,8 +1002,10 @@ EXPORT_SYMBOL_GPL(usb_stor_disconnect);
|
|||
static int storage_probe(struct usb_interface *intf,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct us_unusual_dev *unusual_dev;
|
||||
struct us_data *us;
|
||||
int result;
|
||||
int size;
|
||||
|
||||
/*
|
||||
* If libusual is configured, let it decide whether a standard
|
||||
|
@ -1019,8 +1024,19 @@ static int storage_probe(struct usb_interface *intf,
|
|||
* table, so we use the index of the id entry to find the
|
||||
* corresponding unusual_devs entry.
|
||||
*/
|
||||
result = usb_stor_probe1(&us, intf, id,
|
||||
(id - usb_storage_usb_ids) + us_unusual_dev_list);
|
||||
|
||||
size = ARRAY_SIZE(us_unusual_dev_list);
|
||||
if (id >= usb_storage_usb_ids && id < usb_storage_usb_ids + size) {
|
||||
unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list;
|
||||
} else {
|
||||
unusual_dev = &for_dynamic_ids;
|
||||
|
||||
US_DEBUGP("%s %s 0x%04x 0x%04x\n", "Use Bulk-Only transport",
|
||||
"with the Transparent SCSI protocol for dynamic id:",
|
||||
id->idVendor, id->idProduct);
|
||||
}
|
||||
|
||||
result = usb_stor_probe1(&us, intf, id, unusual_dev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
|
@ -1046,7 +1062,6 @@ static struct usb_driver usb_storage_driver = {
|
|||
.id_table = usb_storage_usb_ids,
|
||||
.supports_autosuspend = 1,
|
||||
.soft_unbind = 1,
|
||||
.no_dynamic_id = 1,
|
||||
};
|
||||
|
||||
static int __init usb_stor_init(void)
|
||||
|
|
|
@ -376,6 +376,12 @@ struct usb_bus {
|
|||
|
||||
struct usb_tt;
|
||||
|
||||
enum usb_device_removable {
|
||||
USB_DEVICE_REMOVABLE_UNKNOWN = 0,
|
||||
USB_DEVICE_REMOVABLE,
|
||||
USB_DEVICE_FIXED,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct usb_device - kernel's representation of a USB device
|
||||
* @devnum: device number; address on a USB bus
|
||||
|
@ -432,6 +438,7 @@ struct usb_tt;
|
|||
* @wusb_dev: if this is a Wireless USB device, link to the WUSB
|
||||
* specific data for the device.
|
||||
* @slot_id: Slot ID assigned by xHCI
|
||||
* @removable: Device can be physically removed from this port
|
||||
*
|
||||
* Notes:
|
||||
* Usbcore drivers should not set usbdev->state directly. Instead use
|
||||
|
@ -509,6 +516,7 @@ struct usb_device {
|
|||
#endif
|
||||
struct wusb_dev *wusb_dev;
|
||||
int slot_id;
|
||||
enum usb_device_removable removable;
|
||||
};
|
||||
#define to_usb_device(d) container_of(d, struct usb_device, dev)
|
||||
|
||||
|
|
|
@ -76,6 +76,11 @@
|
|||
#define USB_PORT_FEAT_C_BH_PORT_RESET 29
|
||||
#define USB_PORT_FEAT_FORCE_LINKPM_ACCEPT 30
|
||||
|
||||
/* USB 3.0 hub remote wake mask bits, see table 10-14 */
|
||||
#define USB_PORT_FEAT_REMOTE_WAKE_CONNECT (1 << 8)
|
||||
#define USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT (1 << 9)
|
||||
#define USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT (1 << 10)
|
||||
|
||||
/*
|
||||
* Hub Status and Hub Change results
|
||||
* See USB 2.0 spec Table 11-19 and Table 11-20
|
||||
|
|
|
@ -412,6 +412,8 @@ extern irqreturn_t usb_hcd_irq(int irq, void *__hcd);
|
|||
|
||||
extern void usb_hc_died(struct usb_hcd *hcd);
|
||||
extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
|
||||
extern void usb_wakeup_notification(struct usb_device *hdev,
|
||||
unsigned int portnum);
|
||||
|
||||
/* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
|
||||
#define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
|
||||
|
|
|
@ -389,5 +389,20 @@ do { \
|
|||
printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Macro for reporting errors in write path to avoid inifinite loop
|
||||
* when port is used as a console.
|
||||
*/
|
||||
#define dev_err_console(usport, fmt, ...) \
|
||||
do { \
|
||||
static bool __print_once; \
|
||||
struct usb_serial_port *__port = (usport); \
|
||||
\
|
||||
if (!__port->port.console || !__print_once) { \
|
||||
__print_once = true; \
|
||||
dev_err(&__port->dev, fmt, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* __LINUX_USB_SERIAL_H */
|
||||
|
||||
|
|
69
include/linux/usb/uas.h
Normal file
69
include/linux/usb/uas.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef __USB_UAS_H__
|
||||
#define __USB_UAS_H__
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
|
||||
/* Common header for all IUs */
|
||||
struct iu {
|
||||
__u8 iu_id;
|
||||
__u8 rsvd1;
|
||||
__be16 tag;
|
||||
};
|
||||
|
||||
enum {
|
||||
IU_ID_COMMAND = 0x01,
|
||||
IU_ID_STATUS = 0x03,
|
||||
IU_ID_RESPONSE = 0x04,
|
||||
IU_ID_TASK_MGMT = 0x05,
|
||||
IU_ID_READ_READY = 0x06,
|
||||
IU_ID_WRITE_READY = 0x07,
|
||||
};
|
||||
|
||||
struct command_iu {
|
||||
__u8 iu_id;
|
||||
__u8 rsvd1;
|
||||
__be16 tag;
|
||||
__u8 prio_attr;
|
||||
__u8 rsvd5;
|
||||
__u8 len;
|
||||
__u8 rsvd7;
|
||||
struct scsi_lun lun;
|
||||
__u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
|
||||
};
|
||||
|
||||
/*
|
||||
* Also used for the Read Ready and Write Ready IUs since they have the
|
||||
* same first four bytes
|
||||
*/
|
||||
struct sense_iu {
|
||||
__u8 iu_id;
|
||||
__u8 rsvd1;
|
||||
__be16 tag;
|
||||
__be16 status_qual;
|
||||
__u8 status;
|
||||
__u8 rsvd7[7];
|
||||
__be16 len;
|
||||
__u8 sense[SCSI_SENSE_BUFFERSIZE];
|
||||
};
|
||||
|
||||
struct usb_pipe_usage_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
|
||||
__u8 bPipeID;
|
||||
__u8 Reserved;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
enum {
|
||||
CMD_PIPE_ID = 1,
|
||||
STATUS_PIPE_ID = 2,
|
||||
DATA_IN_PIPE_ID = 3,
|
||||
DATA_OUT_PIPE_ID = 4,
|
||||
|
||||
UAS_SIMPLE_TAG = 0,
|
||||
UAS_HEAD_TAG = 1,
|
||||
UAS_ORDERED_TAG = 2,
|
||||
UAS_ACA = 4,
|
||||
};
|
||||
#endif
|
|
@ -136,6 +136,7 @@ struct scsi_device {
|
|||
unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */
|
||||
unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */
|
||||
unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */
|
||||
unsigned skip_vpd_pages:1; /* do not read VPD pages */
|
||||
unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */
|
||||
unsigned no_start_on_add:1; /* do not issue start on add */
|
||||
unsigned allow_restart:1; /* issue START_UNIT in error handler */
|
||||
|
@ -246,8 +247,10 @@ struct scsi_target {
|
|||
unsigned int single_lun:1; /* Indicates we should only
|
||||
* allow I/O to one of the luns
|
||||
* for the device at a time. */
|
||||
unsigned int pdt_1f_for_no_lun; /* PDT = 0x1f */
|
||||
/* means no lun present */
|
||||
unsigned int pdt_1f_for_no_lun:1; /* PDT = 0x1f
|
||||
* means no lun present. */
|
||||
unsigned int no_report_luns:1; /* Don't use
|
||||
* REPORT LUNS for scanning. */
|
||||
/* commands actually active on LLD. protected by host lock. */
|
||||
unsigned int target_busy;
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue