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:
Greg Kroah-Hartman 2012-02-23 08:20:44 -08:00
commit c69263c66e
56 changed files with 1051 additions and 352 deletions

View file

@ -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.

View file

@ -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);

View file

@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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;

View file

@ -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 = {

View file

@ -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
/*

View file

@ -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)

View file

@ -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);

View file

@ -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);

View file

@ -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)

View file

@ -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)

View file

@ -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;

View 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");

View file

@ -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",

View file

@ -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,

View file

@ -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;

View file

@ -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:

View file

@ -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))

View file

@ -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];
};

View file

@ -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)) {

View file

@ -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;

View file

@ -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);
}

View file

@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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 */

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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,

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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);
}

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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
View 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

View file

@ -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;
/*