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

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

into kroah.com:/home/greg/linux/BK/usb-2.6
parents 501a9693 4913d930
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
* v0.22 - probe only the control interface. if usbcore doesn't choose the * v0.22 - probe only the control interface. if usbcore doesn't choose the
* config we want, sysadmin changes bConfigurationValue in sysfs. * config we want, sysadmin changes bConfigurationValue in sysfs.
* v0.23 - use softirq for rx processing, as needed by tty layer * v0.23 - use softirq for rx processing, as needed by tty layer
* v0.24 - change probe method to evaluate CDC union descriptor
*/ */
/* /*
...@@ -60,6 +61,8 @@ ...@@ -60,6 +61,8 @@
#include <linux/usb.h> #include <linux/usb.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include "cdc-acm.h"
/* /*
* Version Information * Version Information
*/ */
...@@ -67,102 +70,12 @@ ...@@ -67,102 +70,12 @@
#define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik" #define DRIVER_AUTHOR "Armin Fuerst, Pavel Machek, Johannes Erdfelt, Vojtech Pavlik"
#define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters" #define DRIVER_DESC "USB Abstract Control Model driver for USB modems and ISDN adapters"
/*
* CMSPAR, some architectures can't have space and mark parity.
*/
#ifndef CMSPAR
#define CMSPAR 0
#endif
/*
* Major and minor numbers.
*/
#define ACM_TTY_MAJOR 166
#define ACM_TTY_MINORS 32
/*
* Requests.
*/
#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
#define ACM_REQ_COMMAND 0x00
#define ACM_REQ_RESPONSE 0x01
#define ACM_REQ_SET_FEATURE 0x02
#define ACM_REQ_GET_FEATURE 0x03
#define ACM_REQ_CLEAR_FEATURE 0x04
#define ACM_REQ_SET_LINE 0x20
#define ACM_REQ_GET_LINE 0x21
#define ACM_REQ_SET_CONTROL 0x22
#define ACM_REQ_SEND_BREAK 0x23
/*
* IRQs.
*/
#define ACM_IRQ_NETWORK 0x00
#define ACM_IRQ_LINE_STATE 0x20
/*
* Output control lines.
*/
#define ACM_CTRL_DTR 0x01
#define ACM_CTRL_RTS 0x02
/*
* Input control lines and line errors.
*/
#define ACM_CTRL_DCD 0x01
#define ACM_CTRL_DSR 0x02
#define ACM_CTRL_BRK 0x04
#define ACM_CTRL_RI 0x08
#define ACM_CTRL_FRAMING 0x10
#define ACM_CTRL_PARITY 0x20
#define ACM_CTRL_OVERRUN 0x40
/*
* Line speed and caracter encoding.
*/
struct acm_line {
__u32 speed;
__u8 stopbits;
__u8 parity;
__u8 databits;
} __attribute__ ((packed));
/*
* Internal driver structures.
*/
struct acm {
struct usb_device *dev; /* the corresponding usb device */
struct usb_interface *control; /* control interface */
struct usb_interface *data; /* data interface */
struct tty_struct *tty; /* the corresponding tty */
struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
struct acm_line line; /* line coding (bits, stop, parity) */
struct work_struct work; /* work queue entry for line discipline waking up */
struct tasklet_struct bh; /* rx processing */
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
unsigned int ctrlout; /* output control lines (DTR, RTS) */
unsigned int writesize; /* max packet size for the output bulk endpoint */
unsigned int used; /* someone has this acm's device open */
unsigned int minor; /* acm minor number */
unsigned char throttle; /* throttled by tty layer */
unsigned char clocal; /* termios CLOCAL */
};
static struct usb_driver acm_driver; static struct usb_driver acm_driver;
static struct tty_driver *acm_tty_driver; static struct tty_driver *acm_tty_driver;
static struct acm *acm_table[ACM_TTY_MINORS]; static struct acm *acm_table[ACM_TTY_MINORS];
static DECLARE_MUTEX(open_sem);
#define ACM_READY(acm) (acm && acm->dev && acm->used) #define ACM_READY(acm) (acm && acm->dev && acm->used)
/* /*
...@@ -310,12 +223,14 @@ static void acm_write_bulk(struct urb *urb, struct pt_regs *regs) ...@@ -310,12 +223,14 @@ static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
struct acm *acm = (struct acm *)urb->context; struct acm *acm = (struct acm *)urb->context;
if (!ACM_READY(acm)) if (!ACM_READY(acm))
return; goto out;
if (urb->status) if (urb->status)
dbg("nonzero write bulk status received: %d", urb->status); dbg("nonzero write bulk status received: %d", urb->status);
schedule_work(&acm->work); schedule_work(&acm->work);
out:
acm->ready_for_write = 1;
} }
static void acm_softint(void *private) static void acm_softint(void *private)
...@@ -346,22 +261,23 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) ...@@ -346,22 +261,23 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
tty->driver_data = acm; tty->driver_data = acm;
acm->tty = tty; acm->tty = tty;
lock_kernel(); down(&open_sem);
if (acm->used++) { if (acm->used) {
unlock_kernel(); goto done;
return 0;
} }
unlock_kernel();
acm->ctrlurb->dev = acm->dev; acm->ctrlurb->dev = acm->dev;
if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
dbg("usb_submit_urb(ctrl irq) failed"); dbg("usb_submit_urb(ctrl irq) failed");
goto bail_out;
}
acm->readurb->dev = acm->dev; acm->readurb->dev = acm->dev;
if (usb_submit_urb(acm->readurb, GFP_KERNEL)) if (usb_submit_urb(acm->readurb, GFP_KERNEL)) {
dbg("usb_submit_urb(read bulk) failed"); dbg("usb_submit_urb(read bulk) failed");
goto bail_out_and_unlink;
}
acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS); acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS);
...@@ -369,7 +285,16 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp) ...@@ -369,7 +285,16 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
otherwise it is scheduled, and with high data rates data can get lost. */ otherwise it is scheduled, and with high data rates data can get lost. */
tty->low_latency = 1; tty->low_latency = 1;
done:
acm->used++;
up(&open_sem);
return 0; return 0;
bail_out_and_unlink:
usb_unlink_urb(acm->ctrlurb);
bail_out:
up(&open_sem);
return -EIO;
} }
static void acm_tty_close(struct tty_struct *tty, struct file *filp) static void acm_tty_close(struct tty_struct *tty, struct file *filp)
...@@ -379,6 +304,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) ...@@ -379,6 +304,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
if (!acm || !acm->used) if (!acm || !acm->used)
return; return;
down(&open_sem);
if (!--acm->used) { if (!--acm->used) {
if (acm->dev) { if (acm->dev) {
acm_set_control(acm, acm->ctrlout = 0); acm_set_control(acm, acm->ctrlout = 0);
...@@ -394,6 +320,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp) ...@@ -394,6 +320,7 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
kfree(acm); kfree(acm);
} }
} }
up(&open_sem);
} }
static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count)
...@@ -403,7 +330,7 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c ...@@ -403,7 +330,7 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c
if (!ACM_READY(acm)) if (!ACM_READY(acm))
return -EINVAL; return -EINVAL;
if (acm->writeurb->status == -EINPROGRESS) if (!acm->ready_for_write)
return 0; return 0;
if (!count) if (!count)
return 0; return 0;
...@@ -419,10 +346,11 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c ...@@ -419,10 +346,11 @@ static int acm_tty_write(struct tty_struct *tty, int from_user, const unsigned c
acm->writeurb->transfer_buffer_length = count; acm->writeurb->transfer_buffer_length = count;
acm->writeurb->dev = acm->dev; acm->writeurb->dev = acm->dev;
/* GFP_KERNEL probably works if from_user */ acm->ready_for_write = 0;
stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC); stat = usb_submit_urb(acm->writeurb, GFP_NOIO);
if (stat < 0) { if (stat < 0) {
dbg("usb_submit_urb(write bulk) failed"); dbg("usb_submit_urb(write bulk) failed");
acm->ready_for_write = 1;
return stat; return stat;
} }
...@@ -434,7 +362,7 @@ static int acm_tty_write_room(struct tty_struct *tty) ...@@ -434,7 +362,7 @@ static int acm_tty_write_room(struct tty_struct *tty)
struct acm *acm = tty->driver_data; struct acm *acm = tty->driver_data;
if (!ACM_READY(acm)) if (!ACM_READY(acm))
return -EINVAL; return -EINVAL;
return acm->writeurb->status == -EINPROGRESS ? 0 : acm->writesize; return !acm->ready_for_write ? 0 : acm->writesize;
} }
static int acm_tty_chars_in_buffer(struct tty_struct *tty) static int acm_tty_chars_in_buffer(struct tty_struct *tty)
...@@ -442,7 +370,7 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty) ...@@ -442,7 +370,7 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
struct acm *acm = tty->driver_data; struct acm *acm = tty->driver_data;
if (!ACM_READY(acm)) if (!ACM_READY(acm))
return -EINVAL; return -EINVAL;
return acm->writeurb->status == -EINPROGRESS ? acm->writeurb->transfer_buffer_length : 0; return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0;
} }
static void acm_tty_throttle(struct tty_struct *tty) static void acm_tty_throttle(struct tty_struct *tty)
...@@ -567,77 +495,102 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_ ...@@ -567,77 +495,102 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
* USB probe and disconnect routines. * USB probe and disconnect routines.
*/ */
#define CHECK_XFERTYPE(descr, xfer_type) (((descr)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == xfer_type)
static int acm_probe (struct usb_interface *intf, static int acm_probe (struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
struct usb_device *dev; struct union_desc *union_header = NULL;
char *buffer = intf->altsetting->extra;
int buflen = intf->altsetting->extralen;
struct usb_interface *control_interface;
struct usb_interface *data_interface;
struct usb_endpoint_descriptor *epctrl;
struct usb_endpoint_descriptor *epread;
struct usb_endpoint_descriptor *epwrite;
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct acm *acm; struct acm *acm;
struct usb_host_config *cfacm; int minor;
struct usb_interface *data = NULL; int ctrlsize,readsize;
struct usb_host_interface *ifcom, *ifdata = NULL; char *buf;
struct usb_endpoint_descriptor *epctrl = NULL;
struct usb_endpoint_descriptor *epread = NULL; if (!buffer) {
struct usb_endpoint_descriptor *epwrite = NULL; err("Wierd descriptor references");
int readsize, ctrlsize, minor, j; return -EINVAL;
unsigned char *buf; }
dev = interface_to_usbdev (intf); while (buflen > 0) {
if (buffer [1] != USB_DT_CS_INTERFACE) {
cfacm = dev->actconfig; err("skipping garbage");
goto next_desc;
/* We know we're probe()d with the control interface. */
ifcom = intf->cur_altsetting;
/* ACM doesn't guarantee the data interface is
* adjacent to the control interface, or that if one
* is there it's not for call management ... so find
* it
*/
for (j = 0; j < cfacm->desc.bNumInterfaces; j++) {
ifdata = cfacm->interface[j]->cur_altsetting;
data = cfacm->interface[j];
if (ifdata->desc.bInterfaceClass == USB_CLASS_CDC_DATA
&& ifdata->desc.bNumEndpoints == 2) {
epctrl = &ifcom->endpoint[0].desc;
epread = &ifdata->endpoint[0].desc;
epwrite = &ifdata->endpoint[1].desc;
if ((epctrl->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN
|| !CHECK_XFERTYPE(epctrl, USB_ENDPOINT_XFER_INT)
|| !CHECK_XFERTYPE(epread, USB_ENDPOINT_XFER_BULK)
|| !CHECK_XFERTYPE(epwrite, USB_ENDPOINT_XFER_BULK)
|| ((epread->bEndpointAddress & USB_DIR_IN)
^ (epwrite->bEndpointAddress & USB_DIR_IN)) != USB_DIR_IN) {
/* not suitable */
goto next_interface;
}
if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
/* descriptors are swapped */
epread = &ifdata->endpoint[1].desc;
epwrite = &ifdata->endpoint[0].desc;
}
dev_dbg(&intf->dev, "found data interface at %d\n", j);
break;
} else {
next_interface:
ifdata = NULL;
data = NULL;
} }
switch (buffer [2]) {
case CDC_UNION_TYPE: /* we've found it */
if (union_header) {
err("More than one union descriptor, skipping ...");
goto next_desc;
}
union_header = (struct union_desc *)buffer;
break;
default:
err("Ignoring extra header");
break;
}
next_desc:
buflen -= buffer[0];
buffer += buffer[0];
}
if (!union_header) {
dev_dbg(&intf->dev,"No union descriptor, giving up\n");
return -ENODEV;
} }
/* there's been a problem */ control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
if (!ifdata) { data_interface = usb_ifnum_to_if(usb_dev, union_header->bSlaveInterface0);
dev_dbg(&intf->dev, "data interface not found\n"); if (!control_interface || !data_interface) {
dev_dbg(&intf->dev,"no interfaces\n");
return -ENODEV; return -ENODEV;
}
if (usb_interface_claimed(data_interface)) { /* valid in this context */
dev_dbg(&intf->dev,"The data interface isn't available\n");
return -EBUSY;
}
/*workaround for switched interfaces */
if (data_interface->cur_altsetting->desc.bInterfaceClass != CDC_DATA_INTERFACE_TYPE) {
if (control_interface->cur_altsetting->desc.bInterfaceClass == CDC_DATA_INTERFACE_TYPE) {
struct usb_interface *t;
dev_dbg(&intf->dev,"Your device has switched interfaces.\n");
t = control_interface;
control_interface = data_interface;
data_interface = t;
} else {
return -EINVAL;
}
} }
if (data_interface->cur_altsetting->desc.bNumEndpoints < 2)
return -EINVAL;
epctrl = &control_interface->cur_altsetting->endpoint[0].desc;
epread = &data_interface->cur_altsetting->endpoint[0].desc;
epwrite = &data_interface->cur_altsetting->endpoint[1].desc;
/* workaround for switched endpoints */
if ((epread->bEndpointAddress & USB_DIR_IN) != USB_DIR_IN) {
/* descriptors are swapped */
struct usb_endpoint_descriptor *t;
dev_dbg(&intf->dev,"The data interface has switched endpoints\n");
t = epread;
epread = epwrite;
epwrite = t;
}
dbg("interfaces are valid");
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++); for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
if (acm_table[minor]) { if (acm_table[minor]) {
err("no more free acm devices"); err("no more free acm devices");
return -ENODEV; return -ENODEV;
...@@ -647,20 +600,21 @@ static int acm_probe (struct usb_interface *intf, ...@@ -647,20 +600,21 @@ static int acm_probe (struct usb_interface *intf,
dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n"); dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n");
return -ENOMEM; return -ENOMEM;
} }
memset(acm, 0, sizeof(struct acm)); memset(acm, 0, sizeof(struct acm));
ctrlsize = epctrl->wMaxPacketSize; ctrlsize = epctrl->wMaxPacketSize;
readsize = epread->wMaxPacketSize; readsize = epread->wMaxPacketSize;
acm->writesize = epwrite->wMaxPacketSize; acm->writesize = epwrite->wMaxPacketSize;
acm->control = intf; acm->control = control_interface;
acm->data = data; acm->data = data_interface;
acm->minor = minor; acm->minor = minor;
acm->dev = dev; acm->dev = usb_dev;
acm->bh.func = acm_rx_tasklet; acm->bh.func = acm_rx_tasklet;
acm->bh.data = (unsigned long) acm; acm->bh.data = (unsigned long) acm;
INIT_WORK(&acm->work, acm_softint, acm); INIT_WORK(&acm->work, acm_softint, acm);
acm->ready_for_write = 1;
if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) { if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
dev_dbg(&intf->dev, "out of memory (buf kmalloc)\n"); dev_dbg(&intf->dev, "out of memory (buf kmalloc)\n");
...@@ -693,29 +647,17 @@ static int acm_probe (struct usb_interface *intf, ...@@ -693,29 +647,17 @@ static int acm_probe (struct usb_interface *intf,
return -ENOMEM; return -ENOMEM;
} }
usb_fill_int_urb(acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress), usb_fill_int_urb(acm->ctrlurb, usb_dev, usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval); buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
usb_fill_bulk_urb(acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress), usb_fill_bulk_urb(acm->readurb, usb_dev, usb_rcvbulkpipe(usb_dev, epread->bEndpointAddress),
buf += ctrlsize, readsize, acm_read_bulk, acm); buf += ctrlsize, readsize, acm_read_bulk, acm);
acm->readurb->transfer_flags |= URB_NO_FSBR; acm->readurb->transfer_flags |= URB_NO_FSBR;
usb_fill_bulk_urb(acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress), usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
buf += readsize, acm->writesize, acm_write_bulk, acm); buf += readsize, acm->writesize, acm_write_bulk, acm);
acm->writeurb->transfer_flags |= URB_NO_FSBR; acm->writeurb->transfer_flags |= URB_NO_FSBR;
if ( (j = usb_driver_claim_interface(&acm_driver, data, acm)) != 0) {
err("claim failed");
usb_free_urb(acm->ctrlurb);
usb_free_urb(acm->readurb);
usb_free_urb(acm->writeurb);
kfree(acm);
kfree(buf);
return j;
}
tty_register_device(acm_tty_driver, minor, &intf->dev);
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor); dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
acm_set_control(acm, acm->ctrlout); acm_set_control(acm, acm->ctrlout);
...@@ -724,11 +666,14 @@ static int acm_probe (struct usb_interface *intf, ...@@ -724,11 +666,14 @@ static int acm_probe (struct usb_interface *intf,
acm->line.databits = 8; acm->line.databits = 8;
acm_set_line(acm, &acm->line); acm_set_line(acm, &acm->line);
usb_driver_claim_interface(&acm_driver, data_interface, acm);
tty_register_device(acm_tty_driver, minor, &intf->dev);
acm_table[minor] = acm; acm_table[minor] = acm;
usb_set_intfdata (intf, acm); usb_set_intfdata (intf, acm);
return 0; return 0;
} }
#undef CHECK_XFERTYPE
static void acm_disconnect(struct usb_interface *intf) static void acm_disconnect(struct usb_interface *intf)
{ {
...@@ -746,6 +691,8 @@ static void acm_disconnect(struct usb_interface *intf) ...@@ -746,6 +691,8 @@ static void acm_disconnect(struct usb_interface *intf)
usb_unlink_urb(acm->readurb); usb_unlink_urb(acm->readurb);
usb_unlink_urb(acm->writeurb); usb_unlink_urb(acm->writeurb);
flush_scheduled_work(); /* wait for acm_softint */
kfree(acm->ctrlurb->transfer_buffer); kfree(acm->ctrlurb->transfer_buffer);
usb_driver_release_interface(&acm_driver, acm->data); usb_driver_release_interface(&acm_driver, acm->data);
......
/*
*
* Includes for cdc-acm.c
*
* Mainly take from usbnet's cdc-ether part
*
*/
/*
* CMSPAR, some architectures can't have space and mark parity.
*/
#ifndef CMSPAR
#define CMSPAR 0
#endif
/*
* Major and minor numbers.
*/
#define ACM_TTY_MAJOR 166
#define ACM_TTY_MINORS 32
/*
* Requests.
*/
#define USB_RT_ACM (USB_TYPE_CLASS | USB_RECIP_INTERFACE)
#define ACM_REQ_COMMAND 0x00
#define ACM_REQ_RESPONSE 0x01
#define ACM_REQ_SET_FEATURE 0x02
#define ACM_REQ_GET_FEATURE 0x03
#define ACM_REQ_CLEAR_FEATURE 0x04
#define ACM_REQ_SET_LINE 0x20
#define ACM_REQ_GET_LINE 0x21
#define ACM_REQ_SET_CONTROL 0x22
#define ACM_REQ_SEND_BREAK 0x23
/*
* IRQs.
*/
#define ACM_IRQ_NETWORK 0x00
#define ACM_IRQ_LINE_STATE 0x20
/*
* Output control lines.
*/
#define ACM_CTRL_DTR 0x01
#define ACM_CTRL_RTS 0x02
/*
* Input control lines and line errors.
*/
#define ACM_CTRL_DCD 0x01
#define ACM_CTRL_DSR 0x02
#define ACM_CTRL_BRK 0x04
#define ACM_CTRL_RI 0x08
#define ACM_CTRL_FRAMING 0x10
#define ACM_CTRL_PARITY 0x20
#define ACM_CTRL_OVERRUN 0x40
/*
* Line speed and caracter encoding.
*/
struct acm_line {
__u32 speed;
__u8 stopbits;
__u8 parity;
__u8 databits;
} __attribute__ ((packed));
/*
* Internal driver structures.
*/
struct acm {
struct usb_device *dev; /* the corresponding usb device */
struct usb_interface *control; /* control interface */
struct usb_interface *data; /* data interface */
struct tty_struct *tty; /* the corresponding tty */
struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
struct acm_line line; /* line coding (bits, stop, parity) */
struct work_struct work; /* work queue entry for line discipline waking up */
struct tasklet_struct bh; /* rx processing */
unsigned int ctrlin; /* input control lines (DCD, DSR, RI, break, overruns) */
unsigned int ctrlout; /* output control lines (DTR, RTS) */
unsigned int writesize; /* max packet size for the output bulk endpoint */
unsigned int used; /* someone has this acm's device open */
unsigned int minor; /* acm minor number */
unsigned char throttle; /* throttled by tty layer */
unsigned char clocal; /* termios CLOCAL */
unsigned char ready_for_write; /* write urb can be used */
};
/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
struct union_desc {
u8 bLength;
u8 bDescriptorType;
u8 bDescriptorSubType;
u8 bMasterInterface0;
u8 bSlaveInterface0;
/* ... and there could be other slave interfaces */
} __attribute__ ((packed));
#define CDC_UNION_TYPE 0x06
#define CDC_DATA_INTERFACE_TYPE 0x0a
...@@ -761,6 +761,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, ...@@ -761,6 +761,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
usblp->minor, usblp->readurb->status); usblp->minor, usblp->readurb->status);
usblp->readurb->dev = usblp->dev; usblp->readurb->dev = usblp->dev;
usblp->readcount = 0; usblp->readcount = 0;
usblp->rcomplete = 0;
if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0) if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
dbg("error submitting urb"); dbg("error submitting urb");
count = -EIO; count = -EIO;
......
...@@ -244,17 +244,10 @@ extern struct usb_device *usb_alloc_dev(struct usb_device *parent, ...@@ -244,17 +244,10 @@ extern struct usb_device *usb_alloc_dev(struct usb_device *parent,
struct usb_bus *, unsigned port); struct usb_bus *, unsigned port);
extern int usb_new_device(struct usb_device *dev); extern int usb_new_device(struct usb_device *dev);
extern void usb_disconnect(struct usb_device **); extern void usb_disconnect(struct usb_device **);
extern void usb_choose_address(struct usb_device *dev);
extern void usb_release_address(struct usb_device *dev);
/* exported to hub driver ONLY to support usb_reset_device () */
extern int usb_get_configuration(struct usb_device *dev); extern int usb_get_configuration(struct usb_device *dev);
extern void usb_destroy_configuration(struct usb_device *dev); extern void usb_destroy_configuration(struct usb_device *dev);
/* use these only before the device's address has been set */
#define usb_snddefctrl(dev) ((PIPE_CONTROL << 30))
#define usb_rcvdefctrl(dev) ((PIPE_CONTROL << 30) | USB_DIR_IN)
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
/* /*
......
...@@ -9,6 +9,11 @@ ...@@ -9,6 +9,11 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -19,11 +24,6 @@ ...@@ -19,11 +24,6 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/smp_lock.h> #include <linux/smp_lock.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#ifdef CONFIG_USB_DEBUG
#define DEBUG
#else
#undef DEBUG
#endif
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usbdevice_fs.h> #include <linux/usbdevice_fs.h>
#include <linux/suspend.h> #include <linux/suspend.h>
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */ static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */
static LIST_HEAD(hub_list); /* List of all hubs (for cleanup) */
static DECLARE_WAIT_QUEUE_HEAD(khubd_wait); static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
static pid_t khubd_pid = 0; /* PID of khubd */ static pid_t khubd_pid = 0; /* PID of khubd */
...@@ -268,7 +267,7 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs) ...@@ -268,7 +267,7 @@ static void hub_irq(struct urb *urb, struct pt_regs *regs)
if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0 if ((status = usb_submit_urb (hub->urb, GFP_ATOMIC)) != 0
/* ENODEV means we raced disconnect() */ /* ENODEV means we raced disconnect() */
&& status != -ENODEV) && status != -ENODEV)
dev_err (&hub->intf->dev, "resubmit --> %d\n", urb->status); dev_err (&hub->intf->dev, "resubmit --> %d\n", status);
if (status == 0) if (status == 0)
hub->urb_active = 1; hub->urb_active = 1;
done: done:
...@@ -646,7 +645,6 @@ static void hub_disconnect(struct usb_interface *intf) ...@@ -646,7 +645,6 @@ static void hub_disconnect(struct usb_interface *intf)
/* Delete it and then reset it */ /* Delete it and then reset it */
list_del_init(&hub->event_list); list_del_init(&hub->event_list);
list_del_init(&hub->hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags); spin_unlock_irqrestore(&hub_event_lock, flags);
...@@ -695,7 +693,6 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -695,7 +693,6 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
struct usb_device *hdev; struct usb_device *hdev;
struct usb_hub *hub; struct usb_hub *hub;
struct device *hub_dev; struct device *hub_dev;
unsigned long flags;
desc = intf->cur_altsetting; desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf); hdev = interface_to_usbdev(intf);
...@@ -711,23 +708,19 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -711,23 +708,19 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
} }
/* Multiple endpoints? What kind of mutant ninja-hub is this? */ /* Multiple endpoints? What kind of mutant ninja-hub is this? */
if (desc->desc.bNumEndpoints != 1) { if (desc->desc.bNumEndpoints != 1)
goto descriptor_error; goto descriptor_error;
}
endpoint = &desc->endpoint[0].desc; endpoint = &desc->endpoint[0].desc;
/* Output endpoint? Curiouser and curiouser.. */ /* Output endpoint? Curiouser and curiouser.. */
if (!(endpoint->bEndpointAddress & USB_DIR_IN)) { if (!(endpoint->bEndpointAddress & USB_DIR_IN))
goto descriptor_error; goto descriptor_error;
}
/* If it's not an interrupt endpoint, we'd better punt! */ /* If it's not an interrupt endpoint, we'd better punt! */
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
!= USB_ENDPOINT_XFER_INT) { != USB_ENDPOINT_XFER_INT)
goto descriptor_error; goto descriptor_error;
return -EIO;
}
/* We found a hub */ /* We found a hub */
dev_info (hub_dev, "USB hub found\n"); dev_info (hub_dev, "USB hub found\n");
...@@ -745,12 +738,6 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) ...@@ -745,12 +738,6 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
init_MUTEX(&hub->khubd_sem); init_MUTEX(&hub->khubd_sem);
INIT_WORK(&hub->leds, led_work, hub); INIT_WORK(&hub->leds, led_work, hub);
/* Record the new hub's existence */
spin_lock_irqsave(&hub_event_lock, flags);
INIT_LIST_HEAD(&hub->hub_list);
list_add(&hub->hub_list, &hub_list);
spin_unlock_irqrestore(&hub_event_lock, flags);
usb_set_intfdata (intf, hub); usb_set_intfdata (intf, hub);
if (hdev->speed == USB_SPEED_HIGH) if (hdev->speed == USB_SPEED_HIGH)
...@@ -845,6 +832,234 @@ static void hub_start_disconnect(struct usb_device *hdev) ...@@ -845,6 +832,234 @@ static void hub_start_disconnect(struct usb_device *hdev)
dev_err(&hdev->dev, "cannot disconnect hub!\n"); dev_err(&hdev->dev, "cannot disconnect hub!\n");
} }
static void choose_address(struct usb_device *udev)
{
int devnum;
struct usb_bus *bus = udev->bus;
/* If khubd ever becomes multithreaded, this will need a lock */
/* Try to allocate the next devnum beginning at bus->devnum_next. */
devnum = find_next_zero_bit(bus->devmap.devicemap, 128,
bus->devnum_next);
if (devnum >= 128)
devnum = find_next_zero_bit(bus->devmap.devicemap, 128, 1);
bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
if (devnum < 128) {
set_bit(devnum, bus->devmap.devicemap);
udev->devnum = devnum;
}
}
static void release_address(struct usb_device *udev)
{
if (udev->devnum > 0) {
clear_bit(udev->devnum, udev->bus->devmap.devicemap);
udev->devnum = -1;
}
}
/**
* usb_disconnect - disconnect a device (usbcore-internal)
* @pdev: pointer to device being disconnected
* Context: !in_interrupt ()
*
* Something got disconnected. Get rid of it, and all of its children.
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
void usb_disconnect(struct usb_device **pdev)
{
struct usb_device *udev = *pdev;
struct usb_bus *bus;
struct usb_operations *ops;
int i;
if (!udev) {
pr_debug ("%s nodev\n", __FUNCTION__);
return;
}
bus = udev->bus;
if (!bus) {
pr_debug ("%s nobus\n", __FUNCTION__);
return;
}
ops = bus->op;
*pdev = NULL;
/* mark the device as inactive, so any further urb submissions for
* this device will fail.
*/
udev->state = USB_STATE_NOTATTACHED;
down(&udev->serialize);
dev_info (&udev->dev, "USB disconnect, address %d\n", udev->devnum);
/* Free up all the children before we remove this device */
for (i = 0; i < USB_MAXCHILDREN; i++) {
struct usb_device **child = udev->children + i;
if (*child)
usb_disconnect(child);
}
/* deallocate hcd/hardware state ... nuking all pending urbs and
* cleaning up all state associated with the current configuration
*/
usb_disable_device(udev, 0);
/* Free the device number and remove the /proc/bus/usb entry */
dev_dbg (&udev->dev, "unregistering device\n");
release_address(udev);
usbfs_remove_device(udev);
up(&udev->serialize);
device_unregister(&udev->dev);
}
static int choose_configuration(struct usb_device *udev)
{
int c, i;
/* NOTE: this should interact with hub power budgeting */
c = udev->config[0].desc.bConfigurationValue;
if (udev->descriptor.bNumConfigurations != 1) {
for (i = 0; i < udev->descriptor.bNumConfigurations; i++) {
struct usb_interface_descriptor *desc;
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
desc = &udev->config[i].intf_cache[0]
->altsetting->desc;
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
if (desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff)
continue;
c = udev->config[i].desc.bConfigurationValue;
break;
}
dev_info(&udev->dev,
"configuration #%d chosen from %d choices\n",
c, udev->descriptor.bNumConfigurations);
}
return c;
}
#ifdef DEBUG
static void show_string(struct usb_device *udev, char *id, int index)
{
char *buf;
if (!index)
return;
if (!(buf = kmalloc(256, GFP_KERNEL)))
return;
if (usb_string(udev, index, buf, 256) > 0)
dev_printk(KERN_INFO, &udev->dev, "%s: %s\n", id, buf);
kfree(buf);
}
#else
static inline void show_string(struct usb_device *udev, char *id, int index)
{}
#endif
/*
* usb_new_device - perform initial device setup (usbcore-internal)
* @dev: newly addressed device (in ADDRESS state)
*
* This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
* for any device configuration. The caller owns dev->serialize, and
* the device is not visible through sysfs or other filesystem code.
*
* Returns 0 for success (device is configured and listed, with its
* interfaces, in sysfs); else a negative errno value. On error, one
* reference count to the device has been dropped.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver should ever call this; root hub registration
* uses it only indirectly.
*/
int usb_new_device(struct usb_device *udev)
{
int err;
int c;
err = usb_get_configuration(udev);
if (err < 0) {
dev_err(&udev->dev, "can't read configurations, error %d\n",
err);
goto fail;
}
/* Tell the world! */
dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
"SerialNumber=%d\n",
udev->descriptor.iManufacturer,
udev->descriptor.iProduct,
udev->descriptor.iSerialNumber);
if (udev->descriptor.iProduct)
show_string(udev, "Product",
udev->descriptor.iProduct);
if (udev->descriptor.iManufacturer)
show_string(udev, "Manufacturer",
udev->descriptor.iManufacturer);
if (udev->descriptor.iSerialNumber)
show_string(udev, "SerialNumber",
udev->descriptor.iSerialNumber);
/* put device-specific files into sysfs */
err = device_add (&udev->dev);
if (err) {
dev_err(&udev->dev, "can't device_add, error %d\n", err);
goto fail;
}
usb_create_sysfs_dev_files (udev);
/* choose and set the configuration. that registers the interfaces
* with the driver core, and lets usb device drivers bind to them.
*/
c = choose_configuration(udev);
if (c < 0)
dev_warn(&udev->dev,
"can't choose an initial configuration\n");
else {
err = usb_set_configuration(udev, c);
if (err) {
dev_err(&udev->dev, "can't set config #%d, error %d\n",
c, err);
device_del(&udev->dev);
goto fail;
}
}
/* USB device state == configured ... usable */
/* add a /proc/bus/usb entry */
usbfs_add_device(udev);
return 0;
fail:
udev->state = USB_STATE_NOTATTACHED;
release_address(udev);
usb_put_dev(udev);
return err;
}
static int hub_port_status(struct usb_device *hdev, int port, static int hub_port_status(struct usb_device *hdev, int port,
u16 *status, u16 *change) u16 *status, u16 *change)
{ {
...@@ -975,57 +1190,62 @@ static int hub_port_disable(struct usb_device *hdev, int port) ...@@ -975,57 +1190,62 @@ static int hub_port_disable(struct usb_device *hdev, int port)
/* USB 2.0 spec, 7.1.7.3 / fig 7-29: /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
* *
* Between connect detection and reset signaling there must be a delay * Between connect detection and reset signaling there must be a delay
* of 100ms at least for debounce and power-settling. The corresponding * of 100ms at least for debounce and power-settling. The corresponding
* timer shall restart whenever the downstream port detects a disconnect. * timer shall restart whenever the downstream port detects a disconnect.
* *
* Apparently there are some bluetooth and irda-dongles and a number * Apparently there are some bluetooth and irda-dongles and a number of
* of low-speed devices which require longer delays of about 200-400ms. * low-speed devices for which this debounce period may last over a second.
* Not covered by the spec - but easy to deal with. * Not covered by the spec - but easy to deal with.
* *
* This implementation uses 400ms minimum debounce timeout and checks * This implementation uses a 1500ms total debounce timeout; if the
* every 25ms for transient disconnects to restart the delay. * connection isn't stable by then it returns -ETIMEDOUT. It checks
* every 25ms for transient disconnects. When the port status has been
* unchanged for 100ms it returns the port status.
*/ */
#define HUB_DEBOUNCE_TIMEOUT 400 #define HUB_DEBOUNCE_TIMEOUT 1500
#define HUB_DEBOUNCE_STEP 25 #define HUB_DEBOUNCE_STEP 25
#define HUB_DEBOUNCE_STABLE 4 #define HUB_DEBOUNCE_STABLE 100
static int hub_port_debounce(struct usb_device *hdev, int port) static int hub_port_debounce(struct usb_device *hdev, int port)
{ {
int ret; int ret;
int delay_time, stable_count; int total_time, stable_time = 0;
u16 portchange, portstatus; u16 portchange, portstatus;
unsigned connection; unsigned connection = 0xffff;
connection = 0;
stable_count = 0;
for (delay_time = 0; delay_time < HUB_DEBOUNCE_TIMEOUT; delay_time += HUB_DEBOUNCE_STEP) {
msleep(HUB_DEBOUNCE_STEP);
for (total_time = 0; ; total_time += HUB_DEBOUNCE_STEP) {
ret = hub_port_status(hdev, port, &portstatus, &portchange); ret = hub_port_status(hdev, port, &portstatus, &portchange);
if (ret < 0) if (ret < 0)
return ret; return ret;
if ((portstatus & USB_PORT_STAT_CONNECTION) == connection) { if (!(portchange & USB_PORT_STAT_C_CONNECTION) &&
if (connection) { (portstatus & USB_PORT_STAT_CONNECTION) == connection) {
if (++stable_count == HUB_DEBOUNCE_STABLE) stable_time += HUB_DEBOUNCE_STEP;
break; if (stable_time >= HUB_DEBOUNCE_STABLE)
} break;
} else { } else {
stable_count = 0; stable_time = 0;
connection = portstatus & USB_PORT_STAT_CONNECTION;
} }
connection = portstatus & USB_PORT_STAT_CONNECTION;
if ((portchange & USB_PORT_STAT_C_CONNECTION)) { if (portchange & USB_PORT_STAT_C_CONNECTION) {
clear_port_feature(hdev, port+1, USB_PORT_FEAT_C_CONNECTION); clear_port_feature(hdev, port+1,
USB_PORT_FEAT_C_CONNECTION);
} }
if (total_time >= HUB_DEBOUNCE_TIMEOUT)
break;
msleep(HUB_DEBOUNCE_STEP);
} }
dev_dbg (hubdev (hdev), dev_dbg (hubdev (hdev),
"debounce: port %d: delay %dms stable %d status 0x%x\n", "debounce: port %d: total %dms stable %dms status 0x%x\n",
port + 1, delay_time, stable_count, portstatus); port + 1, total_time, stable_time, portstatus);
return (portstatus & USB_PORT_STAT_CONNECTION) ? 0 : -ENOTCONN; if (stable_time < HUB_DEBOUNCE_STABLE)
return -ETIMEDOUT;
return portstatus;
} }
static int hub_set_address(struct usb_device *udev) static int hub_set_address(struct usb_device *udev)
...@@ -1037,7 +1257,7 @@ static int hub_set_address(struct usb_device *udev) ...@@ -1037,7 +1257,7 @@ static int hub_set_address(struct usb_device *udev)
if (udev->state != USB_STATE_DEFAULT && if (udev->state != USB_STATE_DEFAULT &&
udev->state != USB_STATE_ADDRESS) udev->state != USB_STATE_ADDRESS)
return -EINVAL; return -EINVAL;
retval = usb_control_msg(udev, usb_snddefctrl(udev), retval = usb_control_msg(udev, (PIPE_CONTROL << 30) /* Address 0 */,
USB_REQ_SET_ADDRESS, 0, udev->devnum, 0, USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
if (retval == 0) if (retval == 0)
...@@ -1111,7 +1331,7 @@ hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port) ...@@ -1111,7 +1331,7 @@ hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port)
/* set the address */ /* set the address */
if (udev->devnum <= 0) { if (udev->devnum <= 0) {
usb_choose_address(udev); choose_address(udev);
if (udev->devnum <= 0) if (udev->devnum <= 0)
goto fail; goto fail;
...@@ -1166,7 +1386,7 @@ hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port) ...@@ -1166,7 +1386,7 @@ hub_port_init (struct usb_device *hdev, struct usb_device *udev, int port)
udev->devnum, retval); udev->devnum, retval);
fail: fail:
hub_port_disable(hdev, port); hub_port_disable(hdev, port);
usb_release_address(udev); release_address(udev);
usb_put_dev(udev); usb_put_dev(udev);
up(&usb_address0_sem); up(&usb_address0_sem);
return retval; return retval;
...@@ -1271,7 +1491,14 @@ hub_power_remaining (struct usb_hub *hub, struct usb_device *hdev) ...@@ -1271,7 +1491,14 @@ hub_power_remaining (struct usb_hub *hub, struct usb_device *hdev)
} }
return remaining; return remaining;
} }
/* Handle physical or logical connection change events.
* This routine is called when:
* a port connection-change occurs;
* a port enable-change occurs (often caused by EMI);
* usb_reset_device() encounters changed descriptors (as from
* a firmware download)
*/
static void hub_port_connect_change(struct usb_hub *hub, int port, static void hub_port_connect_change(struct usb_hub *hub, int port,
u16 portstatus, u16 portchange) u16 portstatus, u16 portchange)
{ {
...@@ -1282,9 +1509,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port, ...@@ -1282,9 +1509,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port,
dev_dbg (hub_dev, dev_dbg (hub_dev,
"port %d, status %04x, change %04x, %s\n", "port %d, status %04x, change %04x, %s\n",
port + 1, portstatus, portchange, portspeed (portstatus)); port + 1, portstatus, portchange, portspeed (portstatus));
/* Clear the connection change status */
clear_port_feature(hdev, port + 1, USB_PORT_FEAT_C_CONNECTION);
if (hub->has_indicators) { if (hub->has_indicators) {
set_port_led(hdev, port + 1, HUB_LED_AUTO); set_port_led(hdev, port + 1, HUB_LED_AUTO);
...@@ -1295,6 +1519,17 @@ static void hub_port_connect_change(struct usb_hub *hub, int port, ...@@ -1295,6 +1519,17 @@ static void hub_port_connect_change(struct usb_hub *hub, int port,
if (hdev->children[port]) if (hdev->children[port])
usb_disconnect(&hdev->children[port]); usb_disconnect(&hdev->children[port]);
if (portchange & USB_PORT_STAT_C_CONNECTION) {
status = hub_port_debounce(hdev, port);
if (status < 0) {
dev_err (hub_dev,
"connect-debounce failed, port %d disabled\n",
port+1);
goto done;
}
portstatus = status;
}
/* Return now if nothing is connected */ /* Return now if nothing is connected */
if (!(portstatus & USB_PORT_STAT_CONNECTION)) { if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
...@@ -1308,13 +1543,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port, ...@@ -1308,13 +1543,6 @@ static void hub_port_connect_change(struct usb_hub *hub, int port,
goto done; goto done;
return; return;
} }
if (hub_port_debounce(hdev, port)) {
dev_err (hub_dev,
"connect-debounce failed, port %d disabled\n",
port+1);
goto done;
}
for (i = 0; i < SET_CONFIG_TRIES; i++) { for (i = 0; i < SET_CONFIG_TRIES; i++) {
struct usb_device *udev; struct usb_device *udev;
...@@ -1416,6 +1644,7 @@ static void hub_events(void) ...@@ -1416,6 +1644,7 @@ static void hub_events(void)
u16 portstatus; u16 portstatus;
u16 portchange; u16 portchange;
int i, ret; int i, ret;
int connect_change;
/* /*
* We restart the list every time to avoid a deadlock with * We restart the list every time to avoid a deadlock with
...@@ -1461,16 +1690,22 @@ static void hub_events(void) ...@@ -1461,16 +1690,22 @@ static void hub_events(void)
for (i = 0; i < hub->descriptor->bNbrPorts; i++) { for (i = 0; i < hub->descriptor->bNbrPorts; i++) {
ret = hub_port_status(hdev, i, &portstatus, &portchange); ret = hub_port_status(hdev, i, &portstatus, &portchange);
if (ret < 0) { if (ret < 0)
continue; continue;
} connect_change = 0;
if (portchange & USB_PORT_STAT_C_CONNECTION) { if (portchange & USB_PORT_STAT_C_CONNECTION) {
hub_port_connect_change(hub, i, portstatus, portchange); clear_port_feature(hdev,
} else if (portchange & USB_PORT_STAT_C_ENABLE) { i + 1, USB_PORT_FEAT_C_CONNECTION);
dev_dbg (hub_dev, connect_change = 1;
"port %d enable change, status %08x\n", }
i + 1, portstatus);
if (portchange & USB_PORT_STAT_C_ENABLE) {
if (!connect_change)
dev_dbg (hub_dev,
"port %d enable change, "
"status %08x\n",
i + 1, portstatus);
clear_port_feature(hdev, clear_port_feature(hdev,
i + 1, USB_PORT_FEAT_C_ENABLE); i + 1, USB_PORT_FEAT_C_ENABLE);
...@@ -1481,15 +1716,14 @@ static void hub_events(void) ...@@ -1481,15 +1716,14 @@ static void hub_events(void)
* Works at least with mouse driver. * Works at least with mouse driver.
*/ */
if (!(portstatus & USB_PORT_STAT_ENABLE) if (!(portstatus & USB_PORT_STAT_ENABLE)
&& (portstatus & USB_PORT_STAT_CONNECTION) && !connect_change
&& (hdev->children[i])) { && hdev->children[i]) {
dev_err (hub_dev, dev_err (hub_dev,
"port %i " "port %i "
"disabled by hub (EMI?), " "disabled by hub (EMI?), "
"re-enabling...", "re-enabling...",
i + 1); i + 1);
hub_port_connect_change(hub, connect_change = 1;
i, portstatus, portchange);
} }
} }
...@@ -1517,6 +1751,10 @@ static void hub_events(void) ...@@ -1517,6 +1751,10 @@ static void hub_events(void)
clear_port_feature(hdev, clear_port_feature(hdev,
i + 1, USB_PORT_FEAT_C_RESET); i + 1, USB_PORT_FEAT_C_RESET);
} }
if (connect_change)
hub_port_connect_change(hub, i,
portstatus, portchange);
} /* end for i */ } /* end for i */
/* deal with hub status changes */ /* deal with hub status changes */
...@@ -1581,9 +1819,6 @@ static struct usb_driver hub_driver = { ...@@ -1581,9 +1819,6 @@ static struct usb_driver hub_driver = {
.id_table = hub_id_table, .id_table = hub_id_table,
}; };
/*
* This should be a separate module.
*/
int usb_hub_init(void) int usb_hub_init(void)
{ {
pid_t pid; pid_t pid;
......
...@@ -202,7 +202,6 @@ struct usb_hub { ...@@ -202,7 +202,6 @@ struct usb_hub {
int error; /* last reported error */ int error; /* last reported error */
int nerrors; /* track consecutive errors */ int nerrors; /* track consecutive errors */
struct list_head hub_list; /* all hubs */
struct list_head event_list; /* hubs w/data or errs ready */ struct list_head event_list; /* hubs w/data or errs ready */
struct usb_hub_descriptor *descriptor; /* class descriptor */ struct usb_hub_descriptor *descriptor; /* class descriptor */
......
...@@ -566,7 +566,7 @@ void usb_sg_cancel (struct usb_sg_request *io) ...@@ -566,7 +566,7 @@ void usb_sg_cancel (struct usb_sg_request *io)
*/ */
int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
{ {
int i = 5; int i = 3;
int result; int result;
memset(buf,0,size); // Make sure we parse really received data memset(buf,0,size); // Make sure we parse really received data
...@@ -579,9 +579,6 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char ...@@ -579,9 +579,6 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char
HZ * USB_CTRL_GET_TIMEOUT)) > 0 HZ * USB_CTRL_GET_TIMEOUT)) > 0
|| result != -EPIPE) || result != -EPIPE)
break; break;
dev_dbg (&dev->dev, "RETRY descriptor, result %d\n", result);
result = -ENOMSG;
} }
return result; return result;
} }
......
...@@ -944,235 +944,6 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size, ...@@ -944,235 +944,6 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
return -1; return -1;
} }
/**
* usb_disconnect - disconnect a device (usbcore-internal)
* @pdev: pointer to device being disconnected
* Context: !in_interrupt ()
*
* Something got disconnected. Get rid of it, and all of its children.
*
* Only hub drivers (including virtual root hub drivers for host
* controllers) should ever call this.
*
* This call is synchronous, and may not be used in an interrupt context.
*/
void usb_disconnect(struct usb_device **pdev)
{
struct usb_device *dev = *pdev;
struct usb_bus *bus;
struct usb_operations *ops;
int i;
might_sleep ();
if (!dev) {
pr_debug ("%s nodev\n", __FUNCTION__);
return;
}
bus = dev->bus;
if (!bus) {
pr_debug ("%s nobus\n", __FUNCTION__);
return;
}
ops = bus->op;
*pdev = NULL;
/* mark the device as inactive, so any further urb submissions for
* this device will fail.
*/
dev->state = USB_STATE_NOTATTACHED;
down(&dev->serialize);
dev_info (&dev->dev, "USB disconnect, address %d\n", dev->devnum);
/* Free up all the children before we remove this device */
for (i = 0; i < USB_MAXCHILDREN; i++) {
struct usb_device **child = dev->children + i;
if (*child)
usb_disconnect(child);
}
/* deallocate hcd/hardware state ... nuking all pending urbs and
* cleaning up all state associated with the current configuration
*/
usb_disable_device(dev, 0);
/* Free the device number and remove the /proc/bus/usb entry */
dev_dbg (&dev->dev, "unregistering device\n");
usb_release_address(dev);
usbfs_remove_device(dev);
up(&dev->serialize);
device_unregister(&dev->dev);
}
/**
* usb_choose_address - pick device address (usbcore-internal)
* @dev: newly detected device (in DEFAULT state)
*
* Picks a device address. It's up to the hub (or root hub) driver
* to handle and manage enumeration, starting from the DEFAULT state.
* Only hub drivers (but not virtual root hub drivers for host
* controllers) should ever call this.
*/
void usb_choose_address(struct usb_device *dev)
{
int devnum;
// FIXME needs locking for SMP!!
/* why? this is called only from the hub thread,
* which hopefully doesn't run on multiple CPU's simultaneously 8-)
*/
/* Try to allocate the next devnum beginning at bus->devnum_next. */
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, dev->bus->devnum_next);
if (devnum >= 128)
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
dev->bus->devnum_next = ( devnum >= 127 ? 1 : devnum + 1);
if (devnum < 128) {
set_bit(devnum, dev->bus->devmap.devicemap);
dev->devnum = devnum;
}
}
/**
* usb_release_address - deallocate device address (usbcore-internal)
* @dev: newly removed device
*
* Removes and deallocates the address assigned to a device.
* Only hub drivers (but not virtual root hub drivers for host
* controllers) should ever call this.
*/
void usb_release_address(struct usb_device *dev)
{
if (dev->devnum > 0) {
clear_bit(dev->devnum, dev->bus->devmap.devicemap);
dev->devnum = -1;
}
}
static inline void usb_show_string(struct usb_device *dev, char *id, int index)
{
char *buf;
if (!index)
return;
if (!(buf = kmalloc(256, GFP_KERNEL)))
return;
if (usb_string(dev, index, buf, 256) > 0)
dev_printk(KERN_INFO, &dev->dev, "%s: %s\n", id, buf);
kfree(buf);
}
static int usb_choose_configuration(struct usb_device *dev)
{
int c, i;
c = dev->config[0].desc.bConfigurationValue;
if (dev->descriptor.bNumConfigurations != 1) {
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
struct usb_interface_descriptor *desc;
/* heuristic: Linux is more likely to have class
* drivers, so avoid vendor-specific interfaces.
*/
desc = &dev->config[i].intf_cache[0]
->altsetting->desc;
if (desc->bInterfaceClass == USB_CLASS_VENDOR_SPEC)
continue;
/* COMM/2/all is CDC ACM, except 0xff is MSFT RNDIS */
if (desc->bInterfaceClass == USB_CLASS_COMM
&& desc->bInterfaceSubClass == 2
&& desc->bInterfaceProtocol == 0xff)
continue;
c = dev->config[i].desc.bConfigurationValue;
break;
}
dev_info(&dev->dev,
"configuration #%d chosen from %d choices\n",
c, dev->descriptor.bNumConfigurations);
}
return c;
}
/*
* usb_new_device - perform initial device setup (usbcore-internal)
* @dev: newly addressed device (in ADDRESS state)
*
* This is called with devices which have been enumerated, but not yet
* configured. The device descriptor is available, but not descriptors
* for any device configuration. The caller owns dev->serialize, and
* the device is not visible through sysfs or other filesystem code.
*
* Returns 0 for success (device is configured and listed, with its
* interfaces, in sysfs); else a negative errno value. On error, one
* reference count to the device has been dropped.
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Only the hub driver should ever call this; root hub registration
* uses it only indirectly.
*/
int usb_new_device(struct usb_device *dev)
{
int err;
int c;
err = usb_get_configuration(dev);
if (err < 0) {
dev_err(&dev->dev, "can't read configurations, error %d\n",
err);
goto fail;
}
/* Tell the world! */
dev_dbg(&dev->dev, "new device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
dev->descriptor.iManufacturer, dev->descriptor.iProduct, dev->descriptor.iSerialNumber);
#ifdef DEBUG
if (dev->descriptor.iProduct)
usb_show_string(dev, "Product", dev->descriptor.iProduct);
if (dev->descriptor.iManufacturer)
usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
if (dev->descriptor.iSerialNumber)
usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
#endif
/* put device-specific files into sysfs */
err = device_add (&dev->dev);
if (err) {
dev_err(&dev->dev, "can't device_add, error %d\n", err);
goto fail;
}
usb_create_sysfs_dev_files (dev);
/* choose and set the configuration. that registers the interfaces
* with the driver core, and lets usb device drivers bind to them.
* NOTE: should interact with hub power budgeting.
*/
c = usb_choose_configuration(dev);
err = usb_set_configuration(dev, c);
if (err) {
dev_err(&dev->dev, "can't set config #%d, error %d\n", c, err);
device_del(&dev->dev);
goto fail;
}
/* USB device state == configured ... usable */
/* add a /proc/bus/usb entry */
usbfs_add_device(dev);
return 0;
fail:
dev->state = USB_STATE_NOTATTACHED;
usb_release_address(dev);
usb_put_dev(dev);
return err;
}
/** /**
* usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP * usb_buffer_alloc - allocate dma-consistent buffer for URB_NO_xxx_DMA_MAP
* @dev: device the buffer will be used with * @dev: device the buffer will be used with
......
...@@ -825,8 +825,7 @@ static int dummy_urb_enqueue ( ...@@ -825,8 +825,7 @@ static int dummy_urb_enqueue (
dum = container_of (hcd, struct dummy, hcd); dum = container_of (hcd, struct dummy, hcd);
spin_lock_irqsave (&dum->lock, flags); spin_lock_irqsave (&dum->lock, flags);
if (!dum->hdev) dum->hdev = urb->dev->hcpriv;
dum->hdev = urb->dev->hcpriv;
urb->hcpriv = dum; urb->hcpriv = dum;
if (usb_pipetype (urb->pipe) == PIPE_CONTROL) if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
urb->error_count = 1; /* mark as a new urb */ urb->error_count = 1; /* mark as a new urb */
...@@ -994,10 +993,17 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) ...@@ -994,10 +993,17 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
return limit; return limit;
} }
#define is_active(dum) ((dum->port_status & \
(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
USB_PORT_STAT_SUSPEND)) \
== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
{ {
int i; int i;
if (!is_active (dum))
return NULL;
if ((address & ~USB_DIR_IN) == 0) if ((address & ~USB_DIR_IN) == 0)
return &dum->ep [0]; return &dum->ep [0];
for (i = 1; i < DUMMY_ENDPOINTS; i++) { for (i = 1; i < DUMMY_ENDPOINTS; i++) {
...@@ -1011,6 +1017,8 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address) ...@@ -1011,6 +1017,8 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
return NULL; return NULL;
} }
#undef is_active
#define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE) #define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE)
#define Dev_InRequest (Dev_Request | USB_DIR_IN) #define Dev_InRequest (Dev_Request | USB_DIR_IN)
#define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE) #define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
...@@ -1404,9 +1412,8 @@ static int dummy_hub_control ( ...@@ -1404,9 +1412,8 @@ static int dummy_hub_control (
break; break;
case USB_PORT_FEAT_POWER: case USB_PORT_FEAT_POWER:
dum->port_status = 0; dum->port_status = 0;
dum->address = 0;
dum->hdev = 0;
dum->resuming = 0; dum->resuming = 0;
stop_activity(dum, dum->driver);
break; break;
default: default:
dum->port_status &= ~(1 << wValue); dum->port_status &= ~(1 << wValue);
......
...@@ -2302,17 +2302,6 @@ eth_bind (struct usb_gadget *gadget) ...@@ -2302,17 +2302,6 @@ eth_bind (struct usb_gadget *gadget)
UTS_SYSNAME " " UTS_RELEASE "/%s", UTS_SYSNAME " " UTS_RELEASE "/%s",
gadget->name); gadget->name);
/* CDC subset ... recognized by Linux since 2.4.10, but Windows
* drivers aren't widely available.
*/
if (!cdc) {
device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
device_desc.idVendor =
__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
device_desc.idProduct =
__constant_cpu_to_le16(SIMPLE_PRODUCT_NUM);
}
/* If there's an RNDIS configuration, that's what Windows wants to /* If there's an RNDIS configuration, that's what Windows wants to
* be using ... so use these product IDs here and in the "linux.inf" * be using ... so use these product IDs here and in the "linux.inf"
* needed to install MSFT drivers. Current Linux kernels will use * needed to install MSFT drivers. Current Linux kernels will use
...@@ -2326,6 +2315,16 @@ eth_bind (struct usb_gadget *gadget) ...@@ -2326,6 +2315,16 @@ eth_bind (struct usb_gadget *gadget)
__constant_cpu_to_le16(RNDIS_PRODUCT_NUM); __constant_cpu_to_le16(RNDIS_PRODUCT_NUM);
snprintf (product_desc, sizeof product_desc, snprintf (product_desc, sizeof product_desc,
"RNDIS/%s", driver_desc); "RNDIS/%s", driver_desc);
/* CDC subset ... recognized by Linux since 2.4.10, but Windows
* drivers aren't widely available.
*/
} else if (!cdc) {
device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
device_desc.idVendor =
__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
device_desc.idProduct =
__constant_cpu_to_le16(SIMPLE_PRODUCT_NUM);
} }
/* support optional vendor/distro customization */ /* support optional vendor/distro customization */
......
...@@ -103,8 +103,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci); ...@@ -103,8 +103,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
static void hc_state_transitions(struct uhci_hcd *uhci); static void hc_state_transitions(struct uhci_hcd *uhci);
/* If a transfer is still active after this much time, turn off FSBR */ /* If a transfer is still active after this much time, turn off FSBR */
#define IDLE_TIMEOUT (HZ / 20) /* 50 ms */ #define IDLE_TIMEOUT msecs_to_jiffies(50)
#define FSBR_DELAY (HZ / 20) /* 50 ms */ #define FSBR_DELAY msecs_to_jiffies(50)
/* When we timeout an idle transfer for FSBR, we'll switch it over to */ /* When we timeout an idle transfer for FSBR, we'll switch it over to */
/* depth first traversal. We'll do it in groups of this number of TD's */ /* depth first traversal. We'll do it in groups of this number of TD's */
...@@ -1611,6 +1611,7 @@ static void stall_callback(unsigned long ptr) ...@@ -1611,6 +1611,7 @@ static void stall_callback(unsigned long ptr)
struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct uhci_hcd *uhci = hcd_to_uhci(hcd);
struct list_head list, *tmp, *head; struct list_head list, *tmp, *head;
unsigned long flags; unsigned long flags;
int called_uhci_finish_completion = 0;
INIT_LIST_HEAD(&list); INIT_LIST_HEAD(&list);
...@@ -1619,6 +1620,7 @@ static void stall_callback(unsigned long ptr) ...@@ -1619,6 +1620,7 @@ static void stall_callback(unsigned long ptr)
uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) { uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
uhci_remove_pending_urbps(uhci); uhci_remove_pending_urbps(uhci);
uhci_finish_completion(hcd, NULL); uhci_finish_completion(hcd, NULL);
called_uhci_finish_completion = 1;
} }
head = &uhci->urb_list; head = &uhci->urb_list;
...@@ -1646,6 +1648,10 @@ static void stall_callback(unsigned long ptr) ...@@ -1646,6 +1648,10 @@ static void stall_callback(unsigned long ptr)
} }
spin_unlock_irqrestore(&uhci->schedule_lock, flags); spin_unlock_irqrestore(&uhci->schedule_lock, flags);
/* Wake up anyone waiting for an URB to complete */
if (called_uhci_finish_completion)
wake_up_all(&uhci->waitqh);
head = &list; head = &list;
tmp = head->next; tmp = head->next;
while (tmp != head) { while (tmp != head) {
...@@ -1676,7 +1682,7 @@ static int init_stall_timer(struct usb_hcd *hcd) ...@@ -1676,7 +1682,7 @@ static int init_stall_timer(struct usb_hcd *hcd)
init_timer(&uhci->stall_timer); init_timer(&uhci->stall_timer);
uhci->stall_timer.function = stall_callback; uhci->stall_timer.function = stall_callback;
uhci->stall_timer.data = (unsigned long)hcd; uhci->stall_timer.data = (unsigned long)hcd;
uhci->stall_timer.expires = jiffies + (HZ / 10); uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100);
add_timer(&uhci->stall_timer); add_timer(&uhci->stall_timer);
return 0; return 0;
...@@ -1831,16 +1837,20 @@ static void reset_hc(struct uhci_hcd *uhci) ...@@ -1831,16 +1837,20 @@ static void reset_hc(struct uhci_hcd *uhci)
{ {
unsigned int io_addr = uhci->io_addr; unsigned int io_addr = uhci->io_addr;
/* Turn off PIRQ, SMI, and all interrupts. This also turns off
* the BIOS's USB Legacy Support.
*/
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
outw(0, uhci->io_addr + USBINTR);
/* Global reset for 50ms */ /* Global reset for 50ms */
uhci->state = UHCI_RESET; uhci->state = UHCI_RESET;
outw(USBCMD_GRESET, io_addr + USBCMD); outw(USBCMD_GRESET, io_addr + USBCMD);
set_current_state(TASK_UNINTERRUPTIBLE); msleep(50);
schedule_timeout((HZ*50+999) / 1000);
outw(0, io_addr + USBCMD); outw(0, io_addr + USBCMD);
/* Another 10ms delay */ /* Another 10ms delay */
set_current_state(TASK_UNINTERRUPTIBLE); msleep(10);
schedule_timeout((HZ*10+999) / 1000);
uhci->resume_detect = 0; uhci->resume_detect = 0;
} }
...@@ -1865,7 +1875,7 @@ static void wakeup_hc(struct uhci_hcd *uhci) ...@@ -1865,7 +1875,7 @@ static void wakeup_hc(struct uhci_hcd *uhci)
/* Global resume for >= 20ms */ /* Global resume for >= 20ms */
outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD); outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
uhci->state = UHCI_RESUMING_1; uhci->state = UHCI_RESUMING_1;
uhci->state_end = jiffies + (20*HZ+999) / 1000; uhci->state_end = jiffies + msecs_to_jiffies(20);
break; break;
case UHCI_RESUMING_1: /* End global resume */ case UHCI_RESUMING_1: /* End global resume */
...@@ -1990,7 +2000,9 @@ static void start_hc(struct uhci_hcd *uhci) ...@@ -1990,7 +2000,9 @@ static void start_hc(struct uhci_hcd *uhci)
} }
} }
/* Turn on all interrupts */ /* Turn on PIRQ and all interrupts */
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
USBLEGSUP_DEFAULT);
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
io_addr + USBINTR); io_addr + USBINTR);
...@@ -2054,15 +2066,10 @@ static int uhci_reset(struct usb_hcd *hcd) ...@@ -2054,15 +2066,10 @@ static int uhci_reset(struct usb_hcd *hcd)
uhci->io_addr = (unsigned long) hcd->regs; uhci->io_addr = (unsigned long) hcd->regs;
/* Turn off all interrupts */ /* Kick BIOS off this hardware and reset, so we won't get
outw(0, uhci->io_addr + USBINTR);
/* Maybe kick BIOS off this hardware. Then reset, so we won't get
* interrupts from any previous setup. * interrupts from any previous setup.
*/ */
reset_hc(uhci); reset_hc(uhci);
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
USBLEGSUP_DEFAULT);
return 0; return 0;
} }
...@@ -2369,14 +2376,18 @@ static int uhci_resume(struct usb_hcd *hcd) ...@@ -2369,14 +2376,18 @@ static int uhci_resume(struct usb_hcd *hcd)
/* /*
* Some systems don't maintain the UHCI register values * Some systems don't maintain the UHCI register values
* during a PM suspend/resume cycle, so reinitialize * during a PM suspend/resume cycle, so reinitialize
* the Frame Number, the Framelist Base Address, and the * the Frame Number, Framelist Base Address, Interrupt
* Interrupt Enable registers. * Enable, and Legacy Support registers.
*/ */
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
0);
outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM); outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);
outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD); outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
USBINTR_SP, uhci->io_addr + USBINTR); USBINTR_SP, uhci->io_addr + USBINTR);
uhci->resume_detect = 1; uhci->resume_detect = 1;
pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
USBLEGSUP_DEFAULT);
} else { } else {
reset_hc(uhci); reset_hc(uhci);
start_hc(uhci); start_hc(uhci);
......
...@@ -121,6 +121,7 @@ struct usb_eth_dev { ...@@ -121,6 +121,7 @@ struct usb_eth_dev {
#define VENDOR_ADMTEK 0x07a6 #define VENDOR_ADMTEK 0x07a6
#define VENDOR_AEILAB 0x3334 #define VENDOR_AEILAB 0x3334
#define VENDOR_ALLIEDTEL 0x07c9 #define VENDOR_ALLIEDTEL 0x07c9
#define VENDOR_ATEN 0x0557
#define VENDOR_BELKIN 0x050d #define VENDOR_BELKIN 0x050d
#define VENDOR_BILLIONTON 0x08dd #define VENDOR_BILLIONTON 0x08dd
#define VENDOR_COMPAQ 0x049f #define VENDOR_COMPAQ 0x049f
...@@ -150,6 +151,8 @@ struct usb_eth_dev { ...@@ -150,6 +151,8 @@ struct usb_eth_dev {
PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601, PEGASUS_DEV( "3Com USB Ethernet 3C460B", VENDOR_3COM, 0x4601,
DEFAULT_GPIO_RESET | PEGASUS_II ) DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "ATEN USB Ethernet UC-110T", VENDOR_ATEN, 0x2007,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c, PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x110c,
DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA ) DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104, PEGASUS_DEV( "USB HPNA/Ethernet", VENDOR_ABOCOM, 0x4104,
......
...@@ -78,8 +78,8 @@ static int usb_serial_device_probe (struct device *dev) ...@@ -78,8 +78,8 @@ static int usb_serial_device_probe (struct device *dev)
minor = port->number; minor = port->number;
tty_register_device (usb_serial_tty_driver, minor, dev); tty_register_device (usb_serial_tty_driver, minor, dev);
dev_info(&port->serial->dev->dev, dev_info(&port->serial->dev->dev,
"%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)\n", "%s converter now attached to ttyUSB%d\n",
driver->name, minor, minor); driver->name, minor);
exit: exit:
return retval; return retval;
......
...@@ -1504,6 +1504,7 @@ static int ftdi_write (struct usb_serial_port *port, int from_user, ...@@ -1504,6 +1504,7 @@ static int ftdi_write (struct usb_serial_port *port, int from_user,
if (status) { if (status) {
err("%s - failed submitting write urb, error %d", __FUNCTION__, status); err("%s - failed submitting write urb, error %d", __FUNCTION__, status);
count = status; count = status;
kfree (buffer);
} }
/* we are done with this urb, so let the host driver /* we are done with this urb, so let the host driver
......
...@@ -247,6 +247,8 @@ static struct usb_device_id id_table [] = { ...@@ -247,6 +247,8 @@ static struct usb_device_id id_table [] = {
.driver_info = (kernel_ulong_t)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID), { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe }, .driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID),
.driver_info = (kernel_ulong_t)&palm_os_4_probe },
{ }, /* optional parameter entry */ { }, /* optional parameter entry */
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -290,6 +292,7 @@ static struct usb_device_id id_table_combined [] = { ...@@ -290,6 +292,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) }, { USB_DEVICE(SAMSUNG_VENDOR_ID, SAMSUNG_SPH_I500_ID) },
{ USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) }, { USB_DEVICE(GARMIN_VENDOR_ID, GARMIN_IQUE_3600_ID) },
{ USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) }, { USB_DEVICE(ACEECA_VENDOR_ID, ACEECA_MEZ1000_ID) },
{ USB_DEVICE(KYOCERA_VENDOR_ID, KYOCERA_7135_ID) },
{ }, /* optional parameter entry */ { }, /* optional parameter entry */
{ } /* Terminating entry */ { } /* Terminating entry */
}; };
...@@ -515,6 +518,7 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig ...@@ -515,6 +518,7 @@ static int visor_write (struct usb_serial_port *port, int from_user, const unsig
dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n", dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed with status = %d\n",
__FUNCTION__, status); __FUNCTION__, status);
count = status; count = status;
kfree (buffer);
} else { } else {
bytes_out += count; bytes_out += count;
} }
...@@ -795,7 +799,7 @@ static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_i ...@@ -795,7 +799,7 @@ static int palm_os_4_probe (struct usb_serial *serial, const struct usb_device_i
dev_err(dev, "%s - error %d getting connection info\n", dev_err(dev, "%s - error %d getting connection info\n",
__FUNCTION__, retval); __FUNCTION__, retval);
else else
usb_serial_debug_data (__FILE__, __FUNCTION__, 0x14, transfer_buffer); usb_serial_debug_data (__FILE__, __FUNCTION__, retval, transfer_buffer);
kfree (transfer_buffer); kfree (transfer_buffer);
return 0; return 0;
...@@ -881,18 +885,19 @@ static int treo_attach (struct usb_serial *serial) ...@@ -881,18 +885,19 @@ static int treo_attach (struct usb_serial *serial)
/* Only do this endpoint hack for the Handspring devices with /* Only do this endpoint hack for the Handspring devices with
* interrupt in endpoints, which for now are the Treo devices. */ * interrupt in endpoints, which for now are the Treo devices. */
if ((serial->dev->descriptor.idVendor != HANDSPRING_VENDOR_ID) || if (!((serial->dev->descriptor.idVendor == HANDSPRING_VENDOR_ID) ||
(serial->dev->descriptor.idVendor == KYOCERA_VENDOR_ID)) ||
(serial->num_interrupt_in == 0)) (serial->num_interrupt_in == 0))
return 0; return 0;
dbg("%s", __FUNCTION__); dbg("%s", __FUNCTION__);
/* /*
* It appears that Treos want to use the 1st interrupt endpoint to * It appears that Treos and Kyoceras want to use the
* communicate with the 2nd bulk out endpoint, so let's swap the 1st * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint,
* and 2nd bulk in and interrupt endpoints. Note that swapping the * so let's swap the 1st and 2nd bulk in and interrupt endpoints.
* bulk out endpoints would break lots of apps that want to communicate * Note that swapping the bulk out endpoints would break lots of
* on the second port. * apps that want to communicate on the second port.
*/ */
#define COPY_PORT(dest, src) \ #define COPY_PORT(dest, src) \
dest->read_urb = src->read_urb; \ dest->read_urb = src->read_urb; \
......
...@@ -55,6 +55,9 @@ ...@@ -55,6 +55,9 @@
#define ACEECA_VENDOR_ID 0x4766 #define ACEECA_VENDOR_ID 0x4766
#define ACEECA_MEZ1000_ID 0x0001 #define ACEECA_MEZ1000_ID 0x0001
#define KYOCERA_VENDOR_ID 0x0C88
#define KYOCERA_7135_ID 0x0021
/**************************************************************************** /****************************************************************************
* Handspring Visor Vendor specific request codes (bRequest values) * Handspring Visor Vendor specific request codes (bRequest values)
* A big thank you to Handspring for providing the following information. * A big thank you to Handspring for providing the following information.
......
...@@ -359,13 +359,19 @@ UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999, ...@@ -359,13 +359,19 @@ UNUSUAL_DEV( 0x057b, 0x0000, 0x0300, 0x9999,
UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210, UNUSUAL_DEV( 0x0595, 0x4343, 0x0000, 0x2210,
"Fujifilm", "Fujifilm",
"Digital Camera EX-20 DSC", "Digital Camera EX-20 DSC",
US_SC_8070, US_PR_CBI, NULL, 0 ), US_SC_8070, US_PR_DEVICE, NULL, 0 ),
UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200, UNUSUAL_DEV( 0x059f, 0xa601, 0x0200, 0x0200,
"LaCie", "LaCie",
"USB Hard Disk", "USB Hard Disk",
US_SC_RBC, US_PR_CB, NULL, 0 ), US_SC_RBC, US_PR_CB, NULL, 0 ),
/* Submitted by Jol Bourquard <numlock@freesurf.ch> */
UNUSUAL_DEV( 0x05ab, 0x0060, 0x1104, 0x1110,
"In-System",
"PyroGate External CD-ROM Enclosure (FCD-523)",
US_SC_SCSI, US_PR_BULK, NULL, 0 ),
#ifdef CONFIG_USB_STORAGE_ISD200 #ifdef CONFIG_USB_STORAGE_ISD200
UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110,
"In-System", "In-System",
......
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