Commit e1f015ee authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

Merge kroah.com:/home/greg/linux/BK/bleed-2.5

into kroah.com:/home/greg/linux/BK/gregkh-2.5
parents 201be7ab b75f41cf
......@@ -578,7 +578,9 @@ static int proc_control(struct dev_state *ps, void *arg)
}
free_page((unsigned long)tbuf);
if (i<0) {
printk(KERN_DEBUG "usbfs: USBDEVFS_CONTROL failed dev %d rqt %u rq %u len %u ret %d\n",
printk(KERN_DEBUG "usbfs: USBDEVFS_CONTROL failed "
"cmd %s dev %d rqt %u rq %u len %u ret %d\n",
current->comm,
dev->devnum, ctrl.bRequestType, ctrl.bRequest, ctrl.wLength, i);
}
return i;
......
......@@ -64,17 +64,17 @@ static inline struct device *hubdev (struct usb_device *dev)
}
/* USB 2.0 spec Section 11.24.4.5 */
static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
static int get_hub_descriptor(struct usb_device *dev, void *data, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN | USB_RT_HUB,
USB_DT_HUB << 8, 0, data, size, HZ);
USB_DT_HUB << 8, 0, data, size, HZ * USB_CTRL_GET_TIMEOUT);
}
/*
* USB 2.0 spec Section 11.24.2.1
*/
static int usb_clear_hub_feature(struct usb_device *dev, int feature)
static int clear_hub_feature(struct usb_device *dev, int feature)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RT_HUB, feature, 0, NULL, 0, HZ);
......@@ -84,7 +84,7 @@ static int usb_clear_hub_feature(struct usb_device *dev, int feature)
* USB 2.0 spec Section 11.24.2.2
* BUG: doesn't handle port indicator selector in high byte of wIndex
*/
static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
static int clear_port_feature(struct usb_device *dev, int port, int feature)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_CLEAR_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
......@@ -94,7 +94,7 @@ static int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
* USB 2.0 spec Section 11.24.2.13
* BUG: doesn't handle port indicator selector in high byte of wIndex
*/
static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
static int set_port_feature(struct usb_device *dev, int port, int feature)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_FEATURE, USB_RT_PORT, feature, port, NULL, 0, HZ);
......@@ -103,21 +103,23 @@ static int usb_set_port_feature(struct usb_device *dev, int port, int feature)
/*
* USB 2.0 spec Section 11.24.2.6
*/
static int usb_get_hub_status(struct usb_device *dev, void *data)
static int get_hub_status(struct usb_device *dev,
struct usb_hub_status *data)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_HUB, 0, 0,
data, sizeof(struct usb_hub_status), HZ);
data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
}
/*
* USB 2.0 spec Section 11.24.2.7
*/
static int usb_get_port_status(struct usb_device *dev, int port, void *data)
static int get_port_status(struct usb_device *dev, int port,
struct usb_port_status *data)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
data, sizeof(struct usb_hub_status), HZ);
data, sizeof(*data), HZ * USB_CTRL_GET_TIMEOUT);
}
/* completion function, fires on port status changes and various faults */
......@@ -256,7 +258,7 @@ void usb_hub_tt_clear_buffer (struct usb_device *dev, int pipe)
spin_unlock_irqrestore (&tt->lock, flags);
}
static void usb_hub_power_on(struct usb_hub *hub)
static void hub_power_on(struct usb_hub *hub)
{
struct usb_device *dev;
int i;
......@@ -266,22 +268,55 @@ static void usb_hub_power_on(struct usb_hub *hub)
"enabling power on all ports\n");
dev = interface_to_usbdev(hub->intf);
for (i = 0; i < hub->descriptor->bNbrPorts; i++)
usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
/* Wait for power to be enabled */
wait_ms(hub->descriptor->bPwrOn2PwrGood * 2);
}
static int usb_hub_configure(struct usb_hub *hub,
static int hub_hub_status(struct usb_hub *hub,
u16 *status, u16 *change)
{
struct usb_device *dev = interface_to_usbdev (hub->intf);
int ret;
ret = get_hub_status(dev, &hub->status->hub);
if (ret < 0)
dev_err (hubdev (dev),
"%s failed (err = %d)\n", __FUNCTION__, ret);
else {
*status = le16_to_cpu(hub->status->hub.wHubStatus);
*change = le16_to_cpu(hub->status->hub.wHubChange);
ret = 0;
}
return ret;
}
static int hub_configure(struct usb_hub *hub,
struct usb_endpoint_descriptor *endpoint)
{
struct usb_device *dev = interface_to_usbdev (hub->intf);
struct device *hub_dev;
struct usb_hub_status hubstatus;
u16 hubstatus, hubchange;
unsigned int pipe;
int maxp, ret;
char *message;
hub->buffer = usb_buffer_alloc(dev, sizeof(*hub->buffer), GFP_KERNEL,
&hub->buffer_dma);
if (!hub->buffer) {
message = "can't allocate hub irq buffer";
ret = -ENOMEM;
goto fail;
}
hub->status = kmalloc(sizeof(*hub->status), GFP_KERNEL);
if (!hub->status) {
message = "can't kmalloc hub status buffer";
ret = -ENOMEM;
goto fail;
}
hub->descriptor = kmalloc(sizeof(*hub->descriptor), GFP_KERNEL);
if (!hub->descriptor) {
message = "can't kmalloc hub descriptor";
......@@ -293,7 +328,7 @@ static int usb_hub_configure(struct usb_hub *hub,
* hub->descriptor can handle USB_MAXCHILDREN ports,
* but the hub can/will return fewer bytes here.
*/
ret = usb_get_hub_descriptor(dev, hub->descriptor,
ret = get_hub_descriptor(dev, hub->descriptor,
sizeof(*hub->descriptor));
if (ret < 0) {
message = "can't read hub descriptor";
......@@ -396,27 +431,25 @@ static int usb_hub_configure(struct usb_hub *hub,
dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
hub->descriptor->bHubContrCurrent);
ret = usb_get_hub_status(dev, &hubstatus);
ret = hub_hub_status(hub, &hubstatus, &hubchange);
if (ret < 0) {
message = "can't get hub status";
goto fail;
}
le16_to_cpus(&hubstatus.wHubStatus);
dev_dbg(hub_dev, "local power source is %s\n",
(hubstatus.wHubStatus & HUB_STATUS_LOCAL_POWER)
(hubstatus & HUB_STATUS_LOCAL_POWER)
? "lost (inactive)" : "good");
dev_dbg(hub_dev, "%sover-current condition exists\n",
(hubstatus.wHubStatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
/* Start the interrupt endpoint */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
if (maxp > sizeof(hub->buffer))
maxp = sizeof(hub->buffer);
if (maxp > sizeof(*hub->buffer))
maxp = sizeof(*hub->buffer);
hub->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!hub->urb) {
......@@ -425,8 +458,10 @@ static int usb_hub_configure(struct usb_hub *hub,
goto fail;
}
usb_fill_int_urb(hub->urb, dev, pipe, hub->buffer, maxp, hub_irq,
usb_fill_int_urb(hub->urb, dev, pipe, *hub->buffer, maxp, hub_irq,
hub, endpoint->bInterval);
hub->urb->transfer_dma = hub->buffer_dma;
hub->urb->transfer_flags |= URB_NO_DMA_MAP;
ret = usb_submit_urb(hub->urb, GFP_KERNEL);
if (ret) {
message = "couldn't submit status urb";
......@@ -436,7 +471,7 @@ static int usb_hub_configure(struct usb_hub *hub,
/* Wake up khubd */
wake_up(&khubd_wait);
usb_hub_power_on(hub);
hub_power_on(hub);
return 0;
......@@ -484,6 +519,18 @@ static void hub_disconnect(struct usb_interface *intf)
hub->descriptor = NULL;
}
if (hub->status) {
kfree(hub->status);
hub->status = NULL;
}
if (hub->buffer) {
usb_buffer_free(interface_to_usbdev(intf),
sizeof(*hub->buffer), hub->buffer,
hub->buffer_dma);
hub->buffer = NULL;
}
/* Free the memory */
kfree(hub);
}
......@@ -550,7 +597,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
usb_set_intfdata (intf, hub);
if (usb_hub_configure(hub, endpoint) >= 0) {
if (hub_configure(hub, endpoint) >= 0) {
strcpy (intf->dev.name, "Hub");
return 0;
}
......@@ -594,7 +641,7 @@ hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
}
}
static int usb_hub_reset(struct usb_hub *hub)
static int hub_reset(struct usb_hub *hub)
{
struct usb_device *dev = interface_to_usbdev(hub->intf);
int i;
......@@ -618,12 +665,12 @@ static int usb_hub_reset(struct usb_hub *hub)
if (usb_submit_urb(hub->urb, GFP_KERNEL))
return -1;
usb_hub_power_on(hub);
hub_power_on(hub);
return 0;
}
static void usb_hub_disconnect(struct usb_device *dev)
static void hub_start_disconnect(struct usb_device *dev)
{
struct usb_device *parent = dev->parent;
int i;
......@@ -641,26 +688,21 @@ static void usb_hub_disconnect(struct usb_device *dev)
err("cannot disconnect hub %s", dev->devpath);
}
static int usb_hub_port_status(struct usb_device *hub, int port,
static int hub_port_status(struct usb_device *dev, int port,
u16 *status, u16 *change)
{
struct usb_port_status *portsts;
int ret = -ENOMEM;
struct usb_hub *hub = usb_get_intfdata (dev->actconfig->interface);
int ret;
portsts = kmalloc(sizeof(*portsts), GFP_NOIO);
if (portsts) {
ret = usb_get_port_status(hub, port + 1, portsts);
ret = get_port_status(dev, port + 1, &hub->status->port);
if (ret < 0)
dev_err (hubdev (hub),
"%s failed (err = %d)\n", __FUNCTION__,
ret);
dev_err (hubdev (dev),
"%s failed (err = %d)\n", __FUNCTION__, ret);
else {
*status = le16_to_cpu(portsts->wPortStatus);
*change = le16_to_cpu(portsts->wPortChange);
*status = le16_to_cpu(hub->status->port.wPortStatus);
*change = le16_to_cpu(hub->status->port.wPortChange);
ret = 0;
}
kfree(portsts);
}
return ret;
}
......@@ -671,7 +713,7 @@ static int usb_hub_port_status(struct usb_device *hub, int port,
#define HUB_RESET_TIMEOUT 500
/* return: -1 on error, 0 on success, 1 on disconnect. */
static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
static int hub_port_wait_reset(struct usb_device *hub, int port,
struct usb_device *dev, unsigned int delay)
{
int delay_time, ret;
......@@ -685,7 +727,7 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
wait_ms(delay);
/* read and decode port status */
ret = usb_hub_port_status(hub, port, &portstatus, &portchange);
ret = hub_port_status(hub, port, &portstatus, &portchange);
if (ret < 0) {
return -1;
}
......@@ -723,19 +765,19 @@ static int usb_hub_port_wait_reset(struct usb_device *hub, int port,
}
/* return: -1 on error, 0 on success, 1 on disconnect. */
static int usb_hub_port_reset(struct usb_device *hub, int port,
static int hub_port_reset(struct usb_device *hub, int port,
struct usb_device *dev, unsigned int delay)
{
int i, status;
/* Reset the port */
for (i = 0; i < HUB_RESET_TRIES; i++) {
usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
/* return on disconnect or reset */
status = usb_hub_port_wait_reset(hub, port, dev, delay);
status = hub_port_wait_reset(hub, port, dev, delay);
if (status != -1) {
usb_clear_port_feature(hub,
clear_port_feature(hub,
port + 1, USB_PORT_FEAT_C_RESET);
dev->state = status
? USB_STATE_NOTATTACHED
......@@ -756,11 +798,11 @@ static int usb_hub_port_reset(struct usb_device *hub, int port,
return -1;
}
int usb_hub_port_disable(struct usb_device *hub, int port)
int hub_port_disable(struct usb_device *hub, int port)
{
int ret;
ret = usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
ret = clear_port_feature(hub, port + 1, USB_PORT_FEAT_ENABLE);
if (ret)
dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n",
port + 1, ret);
......@@ -787,7 +829,7 @@ int usb_hub_port_disable(struct usb_device *hub, int port)
#define HUB_DEBOUNCE_STABLE 4
/* return: -1 on error, 0 on success, 1 on disconnect. */
static int usb_hub_port_debounce(struct usb_device *hub, int port)
static int hub_port_debounce(struct usb_device *hub, int port)
{
int ret;
int delay_time, stable_count;
......@@ -799,7 +841,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port)
for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {
wait_ms(HUB_DEBOUNCE_STEP);
ret = usb_hub_port_status(hub, port, &portstatus, &portchange);
ret = hub_port_status(hub, port, &portstatus, &portchange);
if (ret < 0)
return -1;
......@@ -814,7 +856,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port)
connection = portstatus & USB_PORT_STAT_CONNECTION;
if ((portchange & USB_PORT_STAT_C_CONNECTION)) {
usb_clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION);
clear_port_feature(hub, port+1, USB_PORT_FEAT_C_CONNECTION);
}
}
......@@ -826,7 +868,7 @@ static int usb_hub_port_debounce(struct usb_device *hub, int port)
return ((portstatus&USB_PORT_STAT_CONNECTION)) ? 0 : 1;
}
static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
static void hub_port_connect_change(struct usb_hub *hubstate, int port,
u16 portstatus, u16 portchange)
{
struct usb_device *hub = interface_to_usbdev(hubstate->intf);
......@@ -839,7 +881,7 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
port + 1, portstatus, portchange, portspeed (portstatus));
/* Clear the connection change status */
usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_CONNECTION);
/* Disconnect any existing devices under this port */
if (hub->children[port])
......@@ -848,16 +890,16 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
/* Return now if nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
if (portstatus & USB_PORT_STAT_ENABLE)
usb_hub_port_disable(hub, port);
hub_port_disable(hub, port);
return;
}
if (usb_hub_port_debounce(hub, port)) {
if (hub_port_debounce(hub, port)) {
dev_err (&hubstate->intf->dev,
"connect-debounce failed, port %d disabled\n",
port+1);
usb_hub_port_disable(hub, port);
hub_port_disable(hub, port);
return;
}
......@@ -884,7 +926,7 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
dev->state = USB_STATE_POWERED;
/* Reset the device, and detect its speed */
if (usb_hub_port_reset(hub, port, dev, delay)) {
if (hub_port_reset(hub, port, dev, delay)) {
usb_put_dev(dev);
break;
}
......@@ -944,18 +986,17 @@ static void usb_hub_port_connect_change(struct usb_hub *hubstate, int port,
}
hub->children[port] = NULL;
usb_hub_port_disable(hub, port);
hub_port_disable(hub, port);
done:
up(&usb_address0_sem);
}
static void usb_hub_events(void)
static void hub_events(void)
{
unsigned long flags;
struct list_head *tmp;
struct usb_device *dev;
struct usb_hub *hub;
struct usb_hub_status hubsts;
u16 hubstatus;
u16 hubchange;
u16 portstatus;
......@@ -991,11 +1032,11 @@ static void usb_hub_events(void)
dev_dbg (&hub->intf->dev, "resetting for error %d\n",
hub->error);
if (usb_hub_reset(hub)) {
if (hub_reset(hub)) {
dev_dbg (&hub->intf->dev,
"can't reset; disconnecting\n");
up(&hub->khubd_sem);
usb_hub_disconnect(dev);
hub_start_disconnect(dev);
continue;
}
......@@ -1004,18 +1045,18 @@ static void usb_hub_events(void)
}
for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
ret = usb_hub_port_status(dev, i, &portstatus, &portchange);
ret = hub_port_status(dev, i, &portstatus, &portchange);
if (ret < 0) {
continue;
}
if (portchange & USB_PORT_STAT_C_CONNECTION) {
usb_hub_port_connect_change(hub, i, portstatus, portchange);
hub_port_connect_change(hub, i, portstatus, portchange);
} else if (portchange & USB_PORT_STAT_C_ENABLE) {
dev_dbg (hubdev (dev),
"port %d enable change, status %x\n",
i + 1, portstatus);
usb_clear_port_feature(dev,
clear_port_feature(dev,
i + 1, USB_PORT_FEAT_C_ENABLE);
/*
......@@ -1032,7 +1073,7 @@ static void usb_hub_events(void)
"disabled by hub (EMI?), "
"re-enabling...",
i + 1);
usb_hub_port_connect_change(hub,
hub_port_connect_change(hub,
i, portstatus, portchange);
}
}
......@@ -1041,7 +1082,7 @@ static void usb_hub_events(void)
dev_dbg (&hub->intf->dev,
"suspend change on port %d\n",
i + 1);
usb_clear_port_feature(dev,
clear_port_feature(dev,
i + 1, USB_PORT_FEAT_C_SUSPEND);
}
......@@ -1049,35 +1090,33 @@ static void usb_hub_events(void)
dev_err (&hub->intf->dev,
"over-current change on port %d\n",
i + 1);
usb_clear_port_feature(dev,
clear_port_feature(dev,
i + 1, USB_PORT_FEAT_C_OVER_CURRENT);
usb_hub_power_on(hub);
hub_power_on(hub);
}
if (portchange & USB_PORT_STAT_C_RESET) {
dev_dbg (&hub->intf->dev,
"reset change on port %d\n",
i + 1);
usb_clear_port_feature(dev,
clear_port_feature(dev,
i + 1, USB_PORT_FEAT_C_RESET);
}
} /* end for i */
/* deal with hub status changes */
if (usb_get_hub_status(dev, &hubsts) < 0)
if (hub_hub_status(hub, &hubstatus, &hubchange) < 0)
dev_err (&hub->intf->dev, "get_hub_status failed\n");
else {
hubstatus = le16_to_cpup(&hubsts.wHubStatus);
hubchange = le16_to_cpup(&hubsts.wHubChange);
if (hubchange & HUB_CHANGE_LOCAL_POWER) {
dev_dbg (&hub->intf->dev, "power change\n");
usb_clear_hub_feature(dev, C_HUB_LOCAL_POWER);
clear_hub_feature(dev, C_HUB_LOCAL_POWER);
}
if (hubchange & HUB_CHANGE_OVERCURRENT) {
dev_dbg (&hub->intf->dev, "overcurrent change\n");
wait_ms(500); /* Cool down */
usb_clear_hub_feature(dev, C_HUB_OVER_CURRENT);
usb_hub_power_on(hub);
clear_hub_feature(dev, C_HUB_OVER_CURRENT);
hub_power_on(hub);
}
}
up(&hub->khubd_sem);
......@@ -1086,7 +1125,7 @@ static void usb_hub_events(void)
spin_unlock_irqrestore(&hub_event_lock, flags);
}
static int usb_hub_thread(void *__hub)
static int hub_thread(void *__hub)
{
/*
* This thread doesn't need any user-level access,
......@@ -1098,13 +1137,13 @@ static int usb_hub_thread(void *__hub)
/* Send me a signal to get me die (for debugging) */
do {
usb_hub_events();
hub_events();
wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list));
if (current->flags & PF_FREEZE)
refrigerator(PF_IOTHREAD);
} while (!signal_pending(current));
dbg("usb_hub_thread exiting");
dbg("hub_thread exiting");
complete_and_exit(&khubd_exited, 0);
}
......@@ -1139,7 +1178,7 @@ int usb_hub_init(void)
return -1;
}
pid = kernel_thread(usb_hub_thread, NULL,
pid = kernel_thread(hub_thread, NULL,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
if (pid >= 0) {
khubd_pid = pid;
......@@ -1149,7 +1188,7 @@ int usb_hub_init(void)
/* Fall through if kernel_thread failed */
usb_deregister(&hub_driver);
err("failed to start usb_hub_thread");
err("failed to start hub_thread");
return -1;
}
......@@ -1212,8 +1251,8 @@ int usb_physical_reset_device(struct usb_device *dev)
down(&usb_address0_sem);
/* Send a reset to the device */
if (usb_hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) {
usb_hub_port_disable(parent, port);
if (hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) {
hub_port_disable(parent, port);
up(&usb_address0_sem);
kfree(descriptor);
return(-ENODEV);
......@@ -1223,7 +1262,7 @@ int usb_physical_reset_device(struct usb_device *dev)
ret = usb_set_address(dev);
if (ret < 0) {
err("USB device not accepting new address (error=%d)", ret);
usb_hub_port_disable(parent, port);
hub_port_disable(parent, port);
up(&usb_address0_sem);
kfree(descriptor);
return ret;
......
......@@ -174,7 +174,12 @@ struct usb_hub {
struct urb *urb; /* for interrupt polling pipe */
/* buffer for urb ... 1 bit each for hub and children, rounded up */
char buffer[(USB_MAXCHILDREN + 1 + 7) / 8];
char (*buffer)[(USB_MAXCHILDREN + 1 + 7) / 8];
dma_addr_t buffer_dma; /* DMA address for buffer */
union {
struct usb_hub_status hub;
struct usb_port_status port;
} *status; /* buffer for status reports */
int error; /* last reported error */
int nerrors; /* track consecutive errors */
......
......@@ -20,10 +20,12 @@
* short OUT transfers happen.) Drivers can use the req->no_interrupt
* hint to completely eliminate some IRQs, if a later IRQ is guaranteed
* and DMA chaining is enabled.
*
* Note that almost all the errata workarounds here are only needed for
* rev1 chips. Rev1a silicon (0110) fixes almost all of them.
*/
// #define NET2280_DMA_OUT_WORKAROUND
// #define USE_DMA_CHAINING
#define USE_DMA_CHAINING
/*
......@@ -180,6 +182,13 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
* kicking in the "toggle-irrelevant" mode.
*/
tmp = USB_ENDPOINT_XFER_BULK;
} else if (tmp == USB_ENDPOINT_XFER_BULK) {
/* catch some particularly blatant driver bugs */
if ((dev->gadget.speed == USB_SPEED_HIGH
&& max != 512)
|| (dev->gadget.speed == USB_SPEED_FULL
&& max > 64))
return -ERANGE;
}
ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0;
tmp <<= ENDPOINT_TYPE;
......@@ -252,9 +261,6 @@ static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
udelay (1);
usec--;
} while (usec > 0);
#ifdef DEBUG
if (done == 0) dump_stack (); /* ignore out_flush timeout */
#endif
return -ETIMEDOUT;
}
......@@ -917,6 +923,8 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
*/
if (read_fifo (ep, req)) {
done (ep, req, 0);
if (ep->num == 0)
allow_status (ep);
/* don't queue it */
req = 0;
} else
......@@ -1194,9 +1202,12 @@ net2280_set_halt (struct usb_ep *_ep, int value)
VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
/* set/clear, then synch memory views with the device */
if (value)
set_halt (ep);
if (value) {
if (ep->num == 0)
ep->dev->protocol_stall = 1;
else
set_halt (ep);
} else
clear_halt (ep);
(void) readl (&ep->regs->ep_rsp);
......@@ -2042,6 +2053,7 @@ static void handle_ep_small (struct net2280_ep *ep)
* can decide to stall ep0 after that done() returns,
* from non-irq context
*/
if (!ep->stopped)
allow_status (ep);
req = 0;
} else {
......
......@@ -377,12 +377,8 @@ static struct ed *ed_get (
ed->type = type;
}
/* FIXME: Don't do this without knowing it's safe to clobber this
* state/mode info. Currently the upper layers don't support such
* guarantees; we're lucky changing config/altsetting is rare.
* The state/mode info also changes during enumeration: set_address
* uses the 'wrong' device address, and ep0 maxpacketsize will often
* improve on the initial value.
/* NOTE: only ep0 currently needs this "re"init logic, during
* enumeration (after set_address, or if ep0 maxpacket >8).
*/
if (ed->state == ED_IDLE) {
u32 info;
......
......@@ -45,7 +45,7 @@ hpusbscsi_usb_probe(struct usb_interface *intf,
struct usb_host_interface *altsetting = intf->altsetting;
struct hpusbscsi *new;
int error = -ENOMEM;
int i, result;
int i;
if (altsetting->desc.bNumEndpoints != 3) {
printk (KERN_ERR "Wrong number of endpoints\n");
......
......@@ -1101,6 +1101,52 @@ static int vicam_read_proc_gain(char *page, char **start, off_t off,
((struct vicam_camera *)data)->gain);
}
static int
vicam_write_proc_shutter(struct file *file, const char *buffer,
unsigned long count, void *data)
{
u16 stmp;
char kbuf[8];
struct vicam_camera *cam = (struct vicam_camera *) data;
if (count > 6)
return -EINVAL;
if (copy_from_user(kbuf, buffer, count))
return -EFAULT;
stmp = (u16) simple_strtoul(kbuf, NULL, 10);
if (stmp < 4 || stmp > 32000)
return -EINVAL;
cam->shutter_speed = stmp;
return count;
}
static int
vicam_write_proc_gain(struct file *file, const char *buffer,
unsigned long count, void *data)
{
u16 gtmp;
char kbuf[8];
struct vicam_camera *cam = (struct vicam_camera *) data;
if (count > 4)
return -EINVAL;
if (copy_from_user(kbuf, buffer, count))
return -EFAULT;
gtmp = (u16) simple_strtoul(kbuf, NULL, 10);
if (gtmp > 255)
return -EINVAL;
cam->gain = gtmp;
return count;
}
static void
vicam_create_proc_root(void)
{
......@@ -1142,18 +1188,21 @@ vicam_create_proc_entry(struct vicam_camera *cam)
if ( !cam->proc_dir )
return; // FIXME: We should probably return an error here
ent =
create_proc_entry("shutter", S_IFREG | S_IRUGO, cam->proc_dir);
ent = create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
cam->proc_dir);
if (ent) {
ent->data = cam;
ent->read_proc = vicam_read_proc_shutter;
ent->write_proc = vicam_write_proc_shutter;
ent->size = 64;
}
ent = create_proc_entry("gain", S_IFREG | S_IRUGO , cam->proc_dir);
if ( ent ) {
ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
cam->proc_dir);
if (ent) {
ent->data = cam;
ent->read_proc = vicam_read_proc_gain;
ent->write_proc = vicam_write_proc_gain;
ent->size = 64;
}
}
......
......@@ -63,6 +63,8 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
static const char driver_name[] = "catc";
/*
* Some defines.
*/
......@@ -677,7 +679,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
/* get driver info */
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strncpy(info.driver, SHORT_DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
strncpy(info.driver, driver_name, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
usb_make_path (catc->usbdev, info.bus_info, sizeof info.bus_info);
if (copy_to_user(useraddr, &info, sizeof(info)))
......@@ -978,7 +980,7 @@ MODULE_DEVICE_TABLE(usb, catc_id_table);
static struct usb_driver catc_driver = {
.owner = THIS_MODULE,
.name = "catc",
.name = driver_name,
.probe = catc_probe,
.disconnect = catc_disconnect,
.id_table = catc_id_table,
......
......@@ -114,6 +114,8 @@ MODULE_AUTHOR("Michael Zappe <zapman@interlan.net>, Stephane Alnet <stephane@u-p
MODULE_DESCRIPTION("KL5USB101 USB Ethernet driver");
MODULE_LICENSE("GPL");
static const char driver_name[] = "kaweth";
static int kaweth_probe(
struct usb_interface *intf,
const struct usb_device_id *id /* from id_table */
......@@ -169,7 +171,7 @@ MODULE_DEVICE_TABLE (usb, usb_klsi_table);
****************************************************************/
static struct usb_driver kaweth_driver = {
.owner = THIS_MODULE,
.name = "kaweth",
.name = driver_name,
.probe = kaweth_probe,
.disconnect = kaweth_disconnect,
.id_table = usb_klsi_table,
......@@ -670,7 +672,7 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
switch (ethcmd) {
case ETHTOOL_GDRVINFO: {
struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
strlcpy(info.driver, "kaweth", sizeof(info.driver));
strlcpy(info.driver, driver_name, sizeof(info.driver));
if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT;
return 0;
......
/*
* Copyright (c) 1999-2002 Petko Manolov (petkan@users.sourceforge.net)
* Copyright (c) 1999-2003 Petko Manolov (petkan@users.sourceforge.net)
*
* 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
......@@ -45,7 +45,7 @@
/*
* Version Information
*/
#define DRIVER_VERSION "v0.5.10 (2003/04/01)"
#define DRIVER_VERSION "v0.5.12 (2003/06/06)"
#define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
#define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver"
......@@ -564,7 +564,14 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
dbg("%s: reset MAC", net->name);
pegasus->flags &= ~PEGASUS_RX_BUSY;
break;
case -EPIPE: /* stall, or disconnect from TT */
/* FIXME schedule work to clear the halt */
warn("%s: no rx stall recovery", net->name);
return;
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
dbg("%s: rx unlink, %d", net->name, urb->status);
return;
default:
dbg("%s: RX status %d", net->name, urb->status);
......@@ -604,6 +611,9 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
pegasus->stats.rx_packets++;
pegasus->stats.rx_bytes += pkt_len;
if (pegasus->flags & PEGASUS_UNPLUG)
return;
spin_lock(&pegasus->rx_pool_lock);
pegasus->rx_skb = pull_skb(pegasus);
spin_unlock(&pegasus->rx_pool_lock);
......@@ -631,24 +641,24 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
static void rx_fixup(unsigned long data)
{
pegasus_t *pegasus;
unsigned long flags;
pegasus = (pegasus_t *) data;
if (pegasus->flags & PEGASUS_UNPLUG)
return;
spin_lock_irq(&pegasus->rx_pool_lock);
spin_lock_irqsave(&pegasus->rx_pool_lock, flags);
fill_skb_pool(pegasus);
spin_unlock_irq(&pegasus->rx_pool_lock);
if (pegasus->flags & PEGASUS_RX_URB_FAIL)
if (pegasus->rx_skb)
goto try_again;
if (pegasus->rx_skb == NULL) {
spin_lock_irq(&pegasus->rx_pool_lock);
pegasus->rx_skb = pull_skb(pegasus);
spin_unlock_irq(&pegasus->rx_pool_lock);
}
if (pegasus->rx_skb == NULL) {
warn("wow, low on memory");
tasklet_schedule(&pegasus->rx_tl);
return;
goto done;
}
usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb,
usb_rcvbulkpipe(pegasus->usb, 1),
......@@ -661,23 +671,41 @@ static void rx_fixup(unsigned long data)
} else {
pegasus->flags &= ~PEGASUS_RX_URB_FAIL;
}
done:
spin_unlock_irqrestore(&pegasus->rx_pool_lock, flags);
}
static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
{
pegasus_t *pegasus = urb->context;
struct net_device *net = pegasus->net;
if (!pegasus || !(pegasus->flags & PEGASUS_RUNNING))
return;
if (!netif_device_present(pegasus->net))
if (!netif_device_present(net))
return;
if (urb->status)
info("%s: TX status %d", pegasus->net->name, urb->status);
switch (urb->status) {
case -EPIPE:
/* FIXME schedule_work() to clear the tx halt */
netif_stop_queue(net);
warn("%s: no tx stall recovery", net->name);
return;
case -ENOENT:
case -ECONNRESET:
case -ESHUTDOWN:
dbg("%s: tx unlink, %d", net->name, urb->status);
return;
default:
info("%s: TX status %d", net->name, urb->status);
/* FALL THROUGH */
case 0:
break;
}
pegasus->net->trans_start = jiffies;
netif_wake_queue(pegasus->net);
net->trans_start = jiffies;
netif_wake_queue(net);
}
static void intr_callback(struct urb *urb, struct pt_regs *regs)
......@@ -754,8 +782,16 @@ static int pegasus_start_xmit(struct sk_buff *skb, struct net_device *net)
write_bulk_callback, pegasus);
if ((res = usb_submit_urb(pegasus->tx_urb, GFP_ATOMIC))) {
warn("failed tx_urb %d", res);
switch (res) {
case -EPIPE: /* stall, or disconnect from TT */
/* cleanup should already have been scheduled */
break;
case -ENODEV: /* disconnect() upcoming */
break;
default:
pegasus->stats.tx_errors++;
netif_start_queue(net);
}
} else {
pegasus->stats.tx_packets++;
pegasus->stats.tx_bytes += skb->len;
......@@ -903,6 +939,7 @@ static int pegasus_close(struct net_device *net)
netif_stop_queue(net);
if (!(pegasus->flags & PEGASUS_UNPLUG))
disable_net_traffic(pegasus);
tasklet_kill(&pegasus->rx_tl);
unlink_all_urbs(pegasus);
return 0;
......@@ -920,11 +957,15 @@ static int pegasus_ethtool_ioctl(struct net_device *dev, void *useraddr)
switch (ethcmd) {
/* get driver-specific version/etc. info */
case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strlcpy(info.driver, driver_name,
sizeof (info.driver));
strlcpy(info.version, DRIVER_VERSION,
sizeof (info.version));
struct ethtool_drvinfo info;
memset (&info, 0, sizeof (info));
info.cmd = ETHTOOL_GDRVINFO;
strncpy(info.driver, driver_name,
sizeof (info.driver) - 1);
strncpy(info.version, DRIVER_VERSION,
sizeof (info.version) - 1);
usb_make_path(pegasus->usb, info.bus_info,
sizeof (info.bus_info));
if (copy_to_user(useraddr, &info, sizeof (info)))
return -EFAULT;
return 0;
......@@ -993,12 +1034,15 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
return -EFAULT;
switch (cmd) {
case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strncpy(info.driver, driver_name, sizeof info.driver);
struct ethtool_drvinfo info;
memset (&info, 0, sizeof (info));
info.cmd = ETHTOOL_GDRVINFO;
strncpy(info.driver, driver_name,
sizeof (info.driver) - 1);
strncpy(info.version, DRIVER_VERSION,
ETHTOOL_BUSINFO_LEN);
sizeof (info.version) - 1);
usb_make_path(pegasus->usb, info.bus_info,
sizeof info.bus_info);
sizeof (info.bus_info));
if (copy_to_user(uaddr, &info, sizeof (info)))
return -EFAULT;
return 0;
......@@ -1006,14 +1050,19 @@ static int pegasus_ethtool_ioctl(struct net_device *net, void *uaddr)
case ETHTOOL_GSET:{
struct ethtool_cmd ecmd;
short lpa, bmcr;
u8 port;
memset(&ecmd, 0, sizeof ecmd);
memset(&ecmd, 0, sizeof (ecmd));
ecmd.supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
SUPPORTED_100baseT_Half |
SUPPORTED_100baseT_Full |
SUPPORTED_Autoneg |
SUPPORTED_TP | SUPPORTED_MII);
get_registers(pegasus, Reg7b, 1, &port);
if (port == 0)
ecmd.port = PORT_MII;
else
ecmd.port = PORT_TP;
ecmd.transceiver = XCVR_INTERNAL;
ecmd.phy_address = pegasus->phy;
......@@ -1132,6 +1181,9 @@ static inline void setup_pegasus_II(pegasus_t * pegasus)
set_register(pegasus, Reg1d, 0);
set_register(pegasus, Reg7b, 1);
mdelay(100);
if ((pegasus->features & HAS_HOME_PNA) && mii_mode)
set_register(pegasus, Reg7b, 0);
else
set_register(pegasus, Reg7b, 2);
set_register(pegasus, 0x83, data);
......@@ -1253,7 +1305,6 @@ static void pegasus_disconnect(struct usb_interface *intf)
pegasus->flags |= PEGASUS_UNPLUG;
unregister_netdev(pegasus->net);
usb_put_dev(interface_to_usbdev(intf));
unlink_all_urbs(pegasus);
free_all_urbs(pegasus);
free_skb_pool(pegasus);
if (pegasus->rx_skb)
......@@ -1263,7 +1314,6 @@ static void pegasus_disconnect(struct usb_interface *intf)
}
static struct usb_driver pegasus_driver = {
.owner = THIS_MODULE,
.name = driver_name,
.probe = pegasus_probe,
.disconnect = pegasus_disconnect,
......
/*
* Copyright (c) 1999-2002 Petko Manolov - Petkan (petkan@users.sourceforge.net)
* Copyright (c) 1999-2003 Petko Manolov - Petkan (petkan@users.sourceforge.net)
*
* 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
......@@ -129,6 +129,7 @@ struct usb_eth_dev {
#define VENDOR_ELCON 0x0db7
#define VENDOR_ELSA 0x05cc
#define VENDOR_HAWKING 0x0e66
#define VENDOR_HP 0x03f0
#define VENDOR_IODATA 0x04bb
#define VENDOR_KINGSTON 0x0951
#define VENDOR_LANEED 0x056e
......@@ -223,6 +224,8 @@ PEGASUS_DEV( "Elsa Micolink USB2Ethernet", VENDOR_ELSA, 0x3000,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "Hawking UF100 10/100 Ethernet", VENDOR_HAWKING, 0x400c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "HP hn210c Ethernet USB", VENDOR_HP, 0x811c,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "IO DATA USB ET/TX", VENDOR_IODATA, 0x0904,
DEFAULT_GPIO_RESET )
PEGASUS_DEV( "IO DATA USB ET/TX-S", VENDOR_IODATA, 0x0913,
......
......@@ -113,9 +113,11 @@ static void rtl8150_disconnect(struct usb_interface *intf);
static int rtl8150_probe(struct usb_interface *intf,
const struct usb_device_id *id);
static const char driver_name [] = "rtl8150";
static struct usb_driver rtl8150_driver = {
.owner = THIS_MODULE,
.name = "rtl8150",
.name = driver_name,
.probe = rtl8150_probe,
.disconnect = rtl8150_disconnect,
.id_table = rtl8150_table,
......@@ -684,7 +686,7 @@ static int rtl8150_ethtool_ioctl(struct net_device *netdev, void *uaddr)
case ETHTOOL_GDRVINFO:{
struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
strncpy(info.driver, DRIVER_DESC, ETHTOOL_BUSINFO_LEN);
strncpy(info.driver, driver_name, ETHTOOL_BUSINFO_LEN);
strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
usb_make_path(dev->udev, info.bus_info, sizeof info.bus_info);
if (copy_to_user(uaddr, &info, sizeof(info)))
......
......@@ -48,6 +48,7 @@
#include <linux/config.h>
#include "transport.h"
#include "protocol.h"
#include "scsiglue.h"
#include "usb.h"
#include "debug.h"
......@@ -303,6 +304,11 @@ static int interpret_urb_result(struct us_data *us, unsigned int pipe,
US_DEBUGP("-- device NAKed\n");
return USB_STOR_XFER_ERROR;
/* babble - the device tried to send more than we wanted to read */
case -EOVERFLOW:
US_DEBUGP("-- Babble\n");
return USB_STOR_XFER_LONG;
/* the transfer was cancelled, presumably by an abort */
case -ECONNRESET:
US_DEBUGP("-- transfer cancelled\n");
......@@ -525,6 +531,12 @@ void usb_stor_invoke_transport(Scsi_Cmnd *srb, struct us_data *us)
return;
}
/* if the transport provided its own sense data, don't auto-sense */
if (result == USB_STOR_TRANSPORT_NO_SENSE) {
srb->result = SAM_STAT_CHECK_CONDITION;
return;
}
/* Determine if we need to auto-sense
*
* I normally don't use a flag like this, but it's almost impossible
......@@ -764,7 +776,7 @@ int usb_stor_CBI_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->request_buffer, transfer_length,
srb->use_sg, &srb->resid);
US_DEBUGP("CBI data stage result is 0x%x\n", result);
if (result == USB_STOR_XFER_ERROR)
if (result > USB_STOR_XFER_STALLED)
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -854,7 +866,7 @@ int usb_stor_CB_transport(Scsi_Cmnd *srb, struct us_data *us)
srb->request_buffer, transfer_length,
srb->use_sg, &srb->resid);
US_DEBUGP("CB data stage result is 0x%x\n", result);
if (result == USB_STOR_XFER_ERROR)
if (result > USB_STOR_XFER_STALLED)
return USB_STOR_TRANSPORT_ERROR;
}
......@@ -899,6 +911,7 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
struct bulk_cs_wrap bcs;
unsigned int transfer_length = srb->request_bufflen;
int result;
int fake_sense = 0;
/* set up the command wrapper */
bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
......@@ -936,6 +949,15 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP("Bulk data transfer result 0x%x\n", result);
if (result == USB_STOR_XFER_ERROR)
return USB_STOR_TRANSPORT_ERROR;
/* If the device tried to send back more data than the
* amount requested, the spec requires us to transfer
* the CSW anyway. Since there's no point retrying the
* the command, we'll return fake sense data indicating
* Illegal Request, Invalid Field in CDB.
*/
if (result == USB_STOR_XFER_LONG)
fake_sense = 1;
}
/* See flow chart on pg 15 of the Bulk Only Transport spec for
......@@ -975,6 +997,14 @@ int usb_stor_Bulk_transport(Scsi_Cmnd *srb, struct us_data *us)
/* based on the status code, we report good or bad */
switch (bcs.Status) {
case US_BULK_STAT_OK:
/* device babbled -- return fake sense data */
if (fake_sense) {
memcpy(srb->sense_buffer,
usb_stor_sense_invalidCDB,
sizeof(usb_stor_sense_invalidCDB));
return USB_STOR_TRANSPORT_NO_SENSE;
}
/* command good -- note that data could be short */
return USB_STOR_TRANSPORT_GOOD;
......
......@@ -122,7 +122,8 @@ struct bulk_cs_wrap {
#define USB_STOR_XFER_GOOD 0 /* good transfer */
#define USB_STOR_XFER_SHORT 1 /* transferred less than expected */
#define USB_STOR_XFER_STALLED 2 /* endpoint stalled */
#define USB_STOR_XFER_ERROR 3 /* transfer died in the middle */
#define USB_STOR_XFER_LONG 3 /* device tried to send too much */
#define USB_STOR_XFER_ERROR 4 /* transfer died in the middle */
/*
* Transport return codes
......@@ -130,7 +131,8 @@ struct bulk_cs_wrap {
#define USB_STOR_TRANSPORT_GOOD 0 /* Transport good, command good */
#define USB_STOR_TRANSPORT_FAILED 1 /* Transport good, command failed */
#define USB_STOR_TRANSPORT_ERROR 2 /* Transport bad (i.e. device dead) */
#define USB_STOR_TRANSPORT_NO_SENSE 2 /* Command failed, no auto-sense */
#define USB_STOR_TRANSPORT_ERROR 3 /* Transport bad (i.e. device dead) */
/*
* We used to have USB_STOR_XFER_ABORTED and USB_STOR_TRANSPORT_ABORTED
......
......@@ -3,10 +3,11 @@
* $Id: usb.c,v 1.75 2002/04/22 03:39:43 mdharm Exp $
*
* Current development and maintenance by:
* (c) 1999-2002 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
* (c) 1999-2003 Matthew Dharm (mdharm-usb@one-eyed-alien.net)
*
* Developed with the assistance of:
* (c) 2000 David L. Brown, Jr. (usb-storage@davidb.org)
* (c) 2003 Alan Stern (stern@rowland.harvard.edu)
*
* Initial work by:
* (c) 1999 Michael Gee (michael@linuxspecific.com)
......@@ -297,7 +298,7 @@ static int usb_stor_control_thread(void * __us)
/*
* This thread doesn't need any user-level access,
* so get rid of all our resources..
* so get rid of all our resources.
*/
daemonize("usb-storage");
......@@ -305,9 +306,6 @@ static int usb_stor_control_thread(void * __us)
unlock_kernel();
/* set up for wakeups by new commands */
init_MUTEX_LOCKED(&us->sema);
/* signal that we've started the thread */
complete(&(us->notify));
......@@ -366,17 +364,6 @@ static int usb_stor_control_thread(void * __us)
us->srb->result = DID_BAD_TARGET << 16;
}
/* handle requests for EVPD, which most USB devices do
* not support */
else if((us->srb->cmnd[0] == INQUIRY) &&
(us->srb->cmnd[1] & 0x1)) {
US_DEBUGP("Faking INQUIRY command for EVPD\n");
memcpy(us->srb->sense_buffer,
usb_stor_sense_invalidCDB,
sizeof(usb_stor_sense_invalidCDB));
us->srb->result = SAM_STAT_CHECK_CONDITION;
}
/* Handle those devices which need us to fake
* their inquiry data */
else if ((us->srb->cmnd[0] == INQUIRY) &&
......@@ -432,272 +419,60 @@ static int usb_stor_control_thread(void * __us)
return 0;
}
/* Set up the URB and the usb_ctrlrequest.
* us->dev_semaphore must already be locked.
* Note that this function assumes that all the data in the us_data
* structure is current.
* Returns non-zero on failure, zero on success
*/
static int usb_stor_allocate_urbs(struct us_data *us)
{
/* calculate and store the pipe values */
us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev, us->ep_out);
us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev, us->ep_in);
us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev, us->ep_int);
/* allocate the usb_ctrlrequest for control packets */
US_DEBUGP("Allocating usb_ctrlrequest\n");
us->dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_NOIO);
if (!us->dr) {
US_DEBUGP("allocation failed\n");
return 1;
}
/* allocate the URB we're going to use */
US_DEBUGP("Allocating URB\n");
us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!us->current_urb) {
US_DEBUGP("allocation failed\n");
return 2;
}
US_DEBUGP("Allocating scatter-gather request block\n");
us->current_sg = kmalloc(sizeof(*us->current_sg), GFP_KERNEL);
if (!us->current_sg) {
US_DEBUGP("allocation failed\n");
return 5;
}
return 0; /* success */
}
/***********************************************************************
* Device probing and disconnecting
***********************************************************************/
/* Deallocate the URB, the usb_ctrlrequest, and the IRQ pipe.
* us->dev_semaphore must already be locked.
*/
static void usb_stor_deallocate_urbs(struct us_data *us)
/* Get the unusual_devs entries and the string descriptors */
static void get_device_info(struct us_data *us,
struct us_unusual_dev *unusual_dev)
{
/* free the scatter-gather request block */
if (us->current_sg) {
kfree(us->current_sg);
us->current_sg = NULL;
}
/* free up the main URB for this device */
if (us->current_urb) {
US_DEBUGP("-- releasing main URB\n");
usb_free_urb(us->current_urb);
us->current_urb = NULL;
}
struct usb_device *dev = us->pusb_dev;
/* free the usb_ctrlrequest buffer */
if (us->dr) {
kfree(us->dr);
us->dr = NULL;
}
/* mark the device as gone */
usb_put_dev(us->pusb_dev);
us->pusb_dev = NULL;
}
/* Probe to see if a new device is actually a SCSI device */
static int storage_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
int ifnum = intf->altsetting->desc.bInterfaceNumber;
int i;
const int id_index = id - storage_usb_ids;
char mf[USB_STOR_STRING_LEN]; /* manufacturer */
char prod[USB_STOR_STRING_LEN]; /* product */
char serial[USB_STOR_STRING_LEN]; /* serial number */
unsigned int flags;
struct us_unusual_dev *unusual_dev;
struct us_data *us = NULL;
int result;
/* these are temporary copies -- we test on these, then put them
* in the us-data structure
*/
struct usb_endpoint_descriptor *ep_in = NULL;
struct usb_endpoint_descriptor *ep_out = NULL;
struct usb_endpoint_descriptor *ep_int = NULL;
u8 subclass = 0;
u8 protocol = 0;
/* the altsetting on the interface we're probing that matched our
* usb_match_id table
*/
struct usb_host_interface *altsetting =
intf[ifnum].altsetting + intf[ifnum].act_altsetting;
US_DEBUGP("act_altsetting is %d\n", intf[ifnum].act_altsetting);
/* clear the temporary strings */
memset(mf, 0, sizeof(mf));
memset(prod, 0, sizeof(prod));
memset(serial, 0, sizeof(serial));
/*
* Can we support this device, either because we know about it
* from our unusual device list, or because it advertises that it's
* compliant to the specification?
*
* id_index is calculated in the declaration to be the index number
* of the match from the usb_device_id table, so we can find the
* corresponding entry in the private table.
*/
US_DEBUGP("id_index calculated to be: %d\n", id_index);
US_DEBUGP("Array length appears to be: %d\n", sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0]));
if (id_index <
sizeof(us_unusual_dev_list) / sizeof(us_unusual_dev_list[0])) {
unusual_dev = &us_unusual_dev_list[id_index];
if (unusual_dev->vendorName)
US_DEBUGP("Vendor: %s\n", unusual_dev->vendorName);
if (unusual_dev->productName)
US_DEBUGP("Product: %s\n", unusual_dev->productName);
} else
/* no, we can't support it */
return -EIO;
/* At this point, we know we've got a live one */
US_DEBUGP("USB Mass Storage device detected\n");
/* Determine subclass and protocol, or copy from the interface */
subclass = unusual_dev->useProtocol;
protocol = unusual_dev->useTransport;
flags = unusual_dev->flags;
/*
* Find the endpoints we need
* We are expecting a minimum of 2 endpoints - in and out (bulk).
* An optional interrupt is OK (necessary for CBI protocol).
* We will ignore any others.
*/
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
struct usb_endpoint_descriptor *ep;
ep = &altsetting->endpoint[i].desc;
/* is it an BULK endpoint? */
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK) {
/* BULK in or out? */
if (ep->bEndpointAddress & USB_DIR_IN)
ep_in = ep;
else
ep_out = ep;
}
/* is it an interrupt endpoint? */
else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_INT) {
ep_int = ep;
}
}
US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n",
ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0);
#ifdef CONFIG_USB_STORAGE_SDDR09
if (protocol == US_PR_EUSB_SDDR09 || protocol == US_PR_DPCM_USB) {
/* set the configuration -- STALL is an acceptable response here */
result = usb_set_configuration(dev, 1);
US_DEBUGP("Result from usb_set_configuration is %d\n", result);
if (result == -EPIPE) {
US_DEBUGP("-- stall on control interface\n");
} else if (result != 0) {
/* it's not a stall, but another error -- time to bail */
US_DEBUGP("-- Unknown error. Rejecting device\n");
return -EIO;
}
}
#endif
/* Do some basic sanity checks, and bail if we find a problem */
if (!ep_in || !ep_out || (protocol == US_PR_CBI && !ep_int)) {
US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
return -EIO;
}
/* At this point, we've decided to try to use the device */
usb_get_dev(dev);
/* Store the entries */
us->unusual_dev = unusual_dev;
us->subclass = unusual_dev->useProtocol;
us->protocol = unusual_dev->useTransport;
us->flags = unusual_dev->flags;
/* fetch the strings */
/* Read the device's string descriptors */
if (dev->descriptor.iManufacturer)
usb_string(dev, dev->descriptor.iManufacturer,
mf, sizeof(mf));
us->vendor, sizeof(us->vendor));
if (dev->descriptor.iProduct)
usb_string(dev, dev->descriptor.iProduct,
prod, sizeof(prod));
if (dev->descriptor.iSerialNumber && !(flags & US_FL_IGNORE_SER))
us->product, sizeof(us->product));
if (dev->descriptor.iSerialNumber && !(us->flags & US_FL_IGNORE_SER))
usb_string(dev, dev->descriptor.iSerialNumber,
serial, sizeof(serial));
/* New device -- allocate memory and initialize */
if ((us = (struct us_data *)kmalloc(sizeof(struct us_data),
GFP_KERNEL)) == NULL) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n");
usb_put_dev(dev);
return -ENOMEM;
}
memset(us, 0, sizeof(struct us_data));
/* Initialize the mutexes only when the struct is new */
init_completion(&(us->notify));
init_MUTEX_LOCKED(&(us->dev_semaphore));
/* copy over the subclass and protocol data */
us->subclass = subclass;
us->protocol = protocol;
us->flags = flags;
us->unusual_dev = unusual_dev;
us->serial, sizeof(us->serial));
/* copy over the endpoint data */
us->ep_in = ep_in->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
us->ep_out = ep_out->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
if (ep_int) {
us->ep_int = ep_int->bEndpointAddress &
USB_ENDPOINT_NUMBER_MASK;
us->ep_bInterval = ep_int->bInterval;
}
else
us->ep_int = us->ep_bInterval = 0;
/* establish the connection to the new device */
us->ifnum = ifnum;
us->pusb_dev = dev;
/* copy over the identifiying strings */
strncpy(us->vendor, mf, USB_STOR_STRING_LEN);
strncpy(us->product, prod, USB_STOR_STRING_LEN);
strncpy(us->serial, serial, USB_STOR_STRING_LEN);
/* Use the unusual_dev strings if the device didn't provide them */
if (strlen(us->vendor) == 0) {
if (unusual_dev->vendorName)
strncpy(us->vendor, unusual_dev->vendorName,
USB_STOR_STRING_LEN);
sizeof(us->vendor) - 1);
else
strncpy(us->vendor, "Unknown",
USB_STOR_STRING_LEN);
strcpy(us->vendor, "Unknown");
}
if (strlen(us->product) == 0) {
if (unusual_dev->productName)
strncpy(us->product, unusual_dev->productName,
USB_STOR_STRING_LEN);
sizeof(us->product) - 1);
else
strncpy(us->product, "Unknown",
USB_STOR_STRING_LEN);
strcpy(us->product, "Unknown");
}
if (strlen(us->serial) == 0)
strncpy(us->serial, "None", USB_STOR_STRING_LEN);
strcpy(us->serial, "None");
}
/*
* Set the handler pointers based on the protocol
* Again, this data is persistent across reattachments
*/
/* Get the transport settings */
static int get_transport(struct us_data *us)
{
switch (us->protocol) {
case US_PR_CB:
us->transport_name = "Control/Bulk";
......@@ -783,15 +558,19 @@ static int storage_probe(struct usb_interface *intf,
#endif
default:
/* us->transport_name = "Unknown"; */
goto BadDevice;
return -EIO;
}
US_DEBUGP("Transport: %s\n", us->transport_name);
/* fix for single-lun devices */
if (us->flags & US_FL_SINGLE_LUN)
us->max_lun = 0;
return 0;
}
/* Get the protocol settings */
static int get_protocol(struct us_data *us)
{
switch (us->subclass) {
case US_SC_RBC:
us->protocol_name = "Reduced Block Commands (RBC)";
......@@ -834,173 +613,335 @@ static int storage_probe(struct usb_interface *intf,
#endif
default:
/* us->protocol_name = "Unknown"; */
goto BadDevice;
return -EIO;
}
US_DEBUGP("Protocol: %s\n", us->protocol_name);
return 0;
}
/* allocate the URB, the usb_ctrlrequest, and the IRQ URB */
if (usb_stor_allocate_urbs(us))
goto BadDevice;
/* Get the pipe settings */
static int get_pipes(struct us_data *us)
{
struct usb_host_interface *altsetting =
&us->pusb_intf->altsetting[us->pusb_intf->act_altsetting];
int i;
struct usb_endpoint_descriptor *ep;
struct usb_endpoint_descriptor *ep_in = NULL;
struct usb_endpoint_descriptor *ep_out = NULL;
struct usb_endpoint_descriptor *ep_int = NULL;
/*
* Find the endpoints we need.
* We are expecting a minimum of 2 endpoints - in and out (bulk).
* An optional interrupt is OK (necessary for CBI protocol).
* We will ignore any others.
*/
for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
ep = &altsetting->endpoint[i].desc;
/* Is it a BULK endpoint? */
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_BULK) {
/* BULK in or out? */
if (ep->bEndpointAddress & USB_DIR_IN)
ep_in = ep;
else
ep_out = ep;
}
/* Is it an interrupt endpoint? */
else if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_INT) {
ep_int = ep;
}
}
US_DEBUGP("Endpoints: In: 0x%p Out: 0x%p Int: 0x%p (Period %d)\n",
ep_in, ep_out, ep_int, ep_int ? ep_int->bInterval : 0);
if (!ep_in || !ep_out || (us->protocol == US_PR_CBI && !ep_int)) {
US_DEBUGP("Endpoint sanity check failed! Rejecting dev.\n");
return -EIO;
}
/* Calculate and store the pipe values */
us->send_ctrl_pipe = usb_sndctrlpipe(us->pusb_dev, 0);
us->recv_ctrl_pipe = usb_rcvctrlpipe(us->pusb_dev, 0);
us->send_bulk_pipe = usb_sndbulkpipe(us->pusb_dev,
ep_out->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
us->recv_bulk_pipe = usb_rcvbulkpipe(us->pusb_dev,
ep_in->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
if (ep_int) {
us->recv_intr_pipe = usb_rcvintpipe(us->pusb_dev,
ep_int->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
us->ep_bInterval = ep_int->bInterval;
}
return 0;
}
/* Initialize all the dynamic resources we need */
static int usb_stor_acquire_resources(struct us_data *us)
{
int p;
/* Allocate the USB control blocks */
US_DEBUGP("Allocating usb_ctrlrequest\n");
us->dr = kmalloc(sizeof(*us->dr), GFP_KERNEL);
if (!us->dr) {
US_DEBUGP("allocation failed\n");
return -ENOMEM;
}
US_DEBUGP("Allocating URB\n");
us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!us->current_urb) {
US_DEBUGP("allocation failed\n");
return -ENOMEM;
}
US_DEBUGP("Allocating scatter-gather request block\n");
us->current_sg = kmalloc(sizeof(*us->current_sg), GFP_KERNEL);
if (!us->current_sg) {
US_DEBUGP("allocation failed\n");
return -ENOMEM;
}
/* Lock the device while we carry out the next two operations */
down(&us->dev_semaphore);
/* For bulk-only devices, determine the max LUN value */
if (us->protocol == US_PR_BULK)
us->max_lun = usb_stor_Bulk_max_lun(us);
/*
* Since this is a new device, we need to generate a scsi
* host definition, and register with the higher SCSI layers
*/
/* Just before we start our control thread, initialize
* the device if it needs initialization */
if (unusual_dev && unusual_dev->initFunction)
unusual_dev->initFunction(us);
if (us->unusual_dev->initFunction)
us->unusual_dev->initFunction(us);
/* start up our control thread */
up(&us->dev_semaphore);
/* Start up our control thread */
atomic_set(&us->sm_state, US_STATE_IDLE);
us->pid = kernel_thread(usb_stor_control_thread, us,
CLONE_VM);
if (us->pid < 0) {
p = kernel_thread(usb_stor_control_thread, us, CLONE_VM);
if (p < 0) {
printk(KERN_WARNING USB_STORAGE
"Unable to start control thread\n");
goto BadDevice;
return p;
}
us->pid = p;
/* wait for the thread to start */
/* Wait for the thread to start */
wait_for_completion(&(us->notify));
/* unlock the device pointers */
up(&(us->dev_semaphore));
/* now register */
/*
* Since this is a new device, we need to register a SCSI
* host definition with the higher SCSI layers.
*/
us->host = scsi_register(&usb_stor_host_template, sizeof(us));
if (!us->host) {
printk(KERN_WARNING USB_STORAGE
"Unable to register the scsi host\n");
return -EBUSY;
}
/* tell the control thread to exit */
us->srb = NULL;
up(&us->sema);
wait_for_completion(&us->notify);
/* Set the hostdata to prepare for scanning */
us->host->hostdata[0] = (unsigned long) us;
return 0;
}
/* re-lock the device pointers */
/* Dissociate from the USB device */
static void dissociate_dev(struct us_data *us)
{
US_DEBUGP("-- %s\n", __FUNCTION__);
down(&us->dev_semaphore);
usb_set_intfdata(us->pusb_intf, NULL);
usb_put_dev(us->pusb_dev);
us->pusb_dev = NULL;
us->pusb_intf = NULL;
up(&us->dev_semaphore);
}
/* Release all our static and dynamic resources */
void usb_stor_release_resources(struct us_data *us)
{
/*
* The host must already have been removed
* and dissociate_dev() must have been called.
*/
/* Finish the SCSI host removal sequence */
if (us->host) {
(struct us_data *) us->host->hostdata[0] = NULL;
scsi_unregister(us->host);
}
/* Kill the control thread
*
* Enqueue the command, wake up the thread, and wait for
* notification that it has exited.
*/
if (us->pid) {
US_DEBUGP("-- sending exit command to thread\n");
BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE);
us->srb = NULL;
up(&(us->sema));
wait_for_completion(&(us->notify));
}
/* Call the destructor routine, if it exists */
if (us->extra_destructor) {
US_DEBUGP("-- calling extra_destructor()\n");
us->extra_destructor(us->extra);
}
/* Destroy the extra data */
if (us->extra) {
kfree(us->extra);
}
/* Free the USB control blocks */
if (us->current_sg)
kfree(us->current_sg);
if (us->current_urb)
usb_free_urb(us->current_urb);
if (us->dr)
kfree(us->dr);
/* Free the structure itself */
kfree(us);
US_DEBUGP("-- %s finished\n", __FUNCTION__);
}
/* Probe to see if we can drive a newly-connected USB device */
static int storage_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct us_data *us;
const int id_index = id - storage_usb_ids;
int result;
US_DEBUGP("USB Mass Storage device detected\n");
US_DEBUGP("act_altsetting is %d, id_index is %d\n",
intf->act_altsetting, id_index);
/* Allocate the us_data structure and initialize the mutexes */
us = (struct us_data *) kmalloc(sizeof(*us), GFP_KERNEL);
if (!us) {
printk(KERN_WARNING USB_STORAGE "Out of memory\n");
return -ENOMEM;
}
memset(us, 0, sizeof(struct us_data));
init_MUTEX(&(us->dev_semaphore));
init_MUTEX_LOCKED(&(us->sema));
init_completion(&(us->notify));
/* Fill in the device-related fields */
us->pusb_dev = interface_to_usbdev(intf);
us->pusb_intf = intf;
us->ifnum = intf->altsetting->desc.bInterfaceNumber;
/* Store our private data in the interface and increment the
* device's reference count */
usb_set_intfdata(intf, us);
usb_get_dev(us->pusb_dev);
/*
* Get the unusual_devs entries and the descriptors
*
* id_index is calculated in the declaration to be the index number
* of the match from the usb_device_id table, so we can find the
* corresponding entry in the private table.
*/
get_device_info(us, &us_unusual_dev_list[id_index]);
#ifdef CONFIG_USB_STORAGE_SDDR09
if (us->protocol == US_PR_EUSB_SDDR09 ||
us->protocol == US_PR_DPCM_USB) {
/* set the configuration -- STALL is an acceptable response here */
result = usb_set_configuration(us->pusb_dev, 1);
US_DEBUGP("Result from usb_set_configuration is %d\n", result);
if (result == -EPIPE) {
US_DEBUGP("-- stall on control interface\n");
} else if (result != 0) {
/* it's not a stall, but another error -- time to bail */
US_DEBUGP("-- Unknown error. Rejecting device\n");
goto BadDevice;
}
}
#endif
/* set the hostdata to prepare for scanning */
us->host->hostdata[0] = (unsigned long)us;
/* Get the transport, protocol, and pipe settings */
result = get_transport(us);
if (result)
goto BadDevice;
result = get_protocol(us);
if (result)
goto BadDevice;
result = get_pipes(us);
if (result)
goto BadDevice;
/* Acquire all the other resources */
result = usb_stor_acquire_resources(us);
if (result)
goto BadDevice;
/* now add the host */
/* Finally, add the host (this does SCSI device scanning) */
result = scsi_add_host(us->host, &intf->dev);
if (result) {
printk(KERN_WARNING USB_STORAGE
"Unable to add the scsi host\n");
/* tell the control thread to exit */
us->srb = NULL;
up(&us->sema);
wait_for_completion(&us->notify);
/* re-lock the device pointers */
down(&us->dev_semaphore);
goto BadDevice;
}
printk(KERN_DEBUG
"WARNING: USB Mass Storage data integrity not assured\n");
printk(KERN_DEBUG
"USB Mass Storage device found at %d\n", dev->devnum);
/* save a pointer to our structure */
usb_set_intfdata(intf, us);
"USB Mass Storage device found at %d\n", us->pusb_dev->devnum);
return 0;
/* we come here if there are any problems */
/* us->dev_semaphore must be locked */
/* We come here if there are any problems */
BadDevice:
US_DEBUGP("storage_probe() failed\n");
usb_stor_deallocate_urbs(us);
up(&us->dev_semaphore);
kfree(us);
return -EIO;
dissociate_dev(us);
usb_stor_release_resources(us);
return result;
}
/* Handle a disconnect event from the USB core */
static void storage_disconnect(struct usb_interface *intf)
{
struct us_data *us;
struct us_data *us = usb_get_intfdata(intf);
struct scsi_device *sdev;
US_DEBUGP("storage_disconnect() called\n");
us = usb_get_intfdata(intf);
usb_set_intfdata(intf, NULL);
/* set devices offline -- need host lock for this */
/* Set devices offline -- need host lock for this */
scsi_lock(us->host);
list_for_each_entry(sdev, &us->host->my_devices, siblings)
sdev->online = 0;
scsi_unlock(us->host);
/* prevent new USB transfers and stop the current command */
/* Prevent new USB transfers and stop the current command */
set_bit(US_FLIDX_DISCONNECTING, &us->flags);
usb_stor_stop_transport(us);
/* lock device access -- no need to unlock, as we're going away */
down(&(us->dev_semaphore));
/* TODO: somehow, wait for the device to
* be 'idle' (tasklet completion) */
/* remove the pointer to the data structure we were using */
(struct us_data*)us->host->hostdata[0] = NULL;
/* Dissociate from the USB device */
dissociate_dev(us);
/* begin SCSI host removal sequence */
if(scsi_remove_host(us->host)) {
US_DEBUGP("-- SCSI refused to unregister\n");
/* Begin the SCSI host removal sequence */
if (scsi_remove_host(us->host)) {
US_DEBUGP("-- SCSI refused to remove the host\n");
BUG();
return;
};
/* finish SCSI host removal sequence */
scsi_unregister(us->host);
/* Kill the control threads
*
* Enqueue the command, wake up the thread, and wait for
* notification that it has exited.
*/
US_DEBUGP("-- sending exit command to thread\n");
BUG_ON(atomic_read(&us->sm_state) != US_STATE_IDLE);
us->srb = NULL;
up(&(us->sema));
wait_for_completion(&(us->notify));
/* free allocated urbs */
usb_stor_deallocate_urbs(us);
/* If there's extra data in the us_data structure then
* free that first */
if (us->extra) {
/* call the destructor routine, if it exists */
if (us->extra_destructor) {
US_DEBUGP("-- calling extra_destructor()\n");
us->extra_destructor(us->extra);
}
/* destroy the extra data */
US_DEBUGP("-- freeing the data structure\n");
kfree(us->extra);
}
/* up the semaphore so auto-code-checkers won't complain about
* the down/up imbalance */
up(&(us->dev_semaphore));
/* TODO: somehow, wait for the device to
* be 'idle' (tasklet completion) */
/* free the structure itself */
kfree (us);
/* Release all our other resources */
usb_stor_release_resources(us);
}
/***********************************************************************
......
......@@ -107,6 +107,7 @@ struct us_data {
*/
struct semaphore dev_semaphore; /* protect pusb_dev */
struct usb_device *pusb_dev; /* this usb_device */
struct usb_interface *pusb_intf; /* this interface */
unsigned long flags; /* from filter initially */
unsigned int send_bulk_pipe; /* cached pipe values */
unsigned int recv_bulk_pipe;
......@@ -114,7 +115,7 @@ struct us_data {
unsigned int recv_ctrl_pipe;
unsigned int recv_intr_pipe;
/* information about the device -- always good */
/* information about the device */
char vendor[USB_STOR_STRING_LEN];
char product[USB_STOR_STRING_LEN];
char serial[USB_STOR_STRING_LEN];
......@@ -124,11 +125,7 @@ struct us_data {
u8 protocol;
u8 max_lun;
/* information about the device -- only good if device is attached */
u8 ifnum; /* interface number */
u8 ep_in; /* bulk in endpoint */
u8 ep_out; /* bulk out endpoint */
u8 ep_int; /* interrupt endpoint */
u8 ep_bInterval; /* interrupt interval */
/* function pointers for this device */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment