patch-2.3.41 linux/drivers/usb/usb.c
Next file: linux/drivers/usb/usb.h
Previous file: linux/drivers/usb/usb-uhci.h
Back to the patch index
Back to the overall index
- Lines: 423
- Date:
Thu Jan 27 16:40:53 2000
- Orig file:
v2.3.40/linux/drivers/usb/usb.c
- Orig date:
Fri Jan 21 18:19:17 2000
diff -u --recursive --new-file v2.3.40/linux/drivers/usb/usb.c linux/drivers/usb/usb.c
@@ -15,7 +15,7 @@
* It should be considered a slave, with no callbacks. Callbacks
* are evil.
*
- * $Id: usb.c,v 1.39 1999/12/27 15:17:47 acher Exp $
+ * $Id: usb.c,v 1.53 2000/01/14 16:19:09 acher Exp $
*/
#include <linux/config.h>
@@ -486,7 +486,8 @@
/*-------------------------------------------------------------------*/
void usb_free_urb(urb_t* urb)
{
- kfree(urb);
+ if(urb)
+ kfree(urb);
}
/*-------------------------------------------------------------------*/
int usb_submit_urb(urb_t *urb)
@@ -515,7 +516,7 @@
static void usb_api_blocking_completion(urb_t *urb)
{
api_wrapper_data *awd = (api_wrapper_data *)urb->context;
-
+
if (waitqueue_active(awd->wakeup))
wake_up(awd->wakeup);
#if 0
@@ -541,7 +542,7 @@
*-------------------------------------------------------------------*/
// Starts urb and waits for completion or timeout
-static int usb_start_wait_urb(urb_t *urb, int timeout, unsigned long* rval)
+static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
{
DECLARE_WAITQUEUE(wait, current);
DECLARE_WAIT_QUEUE_HEAD(wqh);
@@ -551,7 +552,7 @@
awd.wakeup=&wqh;
awd.handler=0;
init_waitqueue_head(&wqh);
- current->state = TASK_UNINTERRUPTIBLE;
+ current->state = TASK_INTERRUPTIBLE;
add_wait_queue(&wqh, &wait);
urb->context=&awd;
status=usb_submit_urb(urb);
@@ -572,15 +573,15 @@
if (!status) {
// timeout
- dbg("usb_control/bulk_msg: timeout");
+ printk("usb_control/bulk_msg: timeout\n");
usb_unlink_urb(urb); // remove urb safely
status=-ETIMEDOUT;
}
else
status=urb->status;
- if (rval)
- *rval=urb->actual_length;
+ if (actual_length)
+ *actual_length=urb->actual_length;
usb_free_urb(urb);
return status;
@@ -593,7 +594,7 @@
{
urb_t *urb;
int retv;
- unsigned long length;
+ int length;
urb=usb_alloc_urb(0);
if (!urb)
@@ -601,7 +602,7 @@
FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len, /* build urb */
(usb_complete_t)usb_api_blocking_completion,0);
-
+
retv=usb_start_wait_urb(urb,timeout, &length);
if (retv < 0)
return retv;
@@ -613,15 +614,25 @@
int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
__u16 value, __u16 index, void *data, __u16 size, int timeout)
{
- devrequest dr;
-
- dr.requesttype = requesttype;
- dr.request = request;
- dr.value = cpu_to_le16p(&value);
- dr.index = cpu_to_le16p(&index);
- dr.length = cpu_to_le16p(&size);
+ devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
+ int ret;
+
+ if(!dr)
+ return -ENOMEM;
+
+ dr->requesttype = requesttype;
+ dr->request = request;
+ dr->value = cpu_to_le16p(&value);
+ dr->index = cpu_to_le16p(&index);
+ dr->length = cpu_to_le16p(&size);
+
//dbg("usb_control_msg");
- return usb_internal_control_msg(dev, pipe, &dr, data, size, timeout);
+
+ ret=usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+
+ kfree(dr);
+
+ return ret;
}
/*-------------------------------------------------------------------*/
@@ -629,7 +640,7 @@
/* synchronous behavior */
int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe,
- void *data, int len, unsigned long *rval, int timeout)
+ void *data, int len, int *actual_length, int timeout)
{
urb_t *urb;
@@ -643,7 +654,7 @@
FILL_BULK_URB(urb,usb_dev,pipe,(unsigned char*)data,len, /* build urb */
(usb_complete_t)usb_api_blocking_completion,0);
- return usb_start_wait_urb(urb,timeout,rval);
+ return usb_start_wait_urb(urb,timeout,actual_length);
}
/*-------------------------------------------------------------------*/
@@ -1087,7 +1098,7 @@
for (i = 0; i < config->bNumInterfaces; i++) {
header = (struct usb_descriptor_header *)buffer;
- if (header->bLength > size) {
+ if ((header->bLength > size) || (header->bLength <= 2)) {
err("ran out of descriptors parsing");
return -1;
}
@@ -1222,7 +1233,8 @@
/* Free up all the children.. */
for (i = 0; i < USB_MAXCHILDREN; i++) {
struct usb_device **child = dev->children + i;
- usb_disconnect(child);
+ if (*child)
+ usb_disconnect(child);
}
/* remove /proc/bus/usb entry */
@@ -1246,6 +1258,9 @@
{
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 simulatenously 8-)
+ */
dev->descriptor.bMaxPacketSize0 = 8; /* Start off at 8 bytes */
devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
if (devnum < 128) {
@@ -1272,6 +1287,8 @@
{
int i = 5;
int result;
+
+ memset(buf,0,size); // Make sure we parse really received data
while (i--) {
if ((result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
@@ -1283,12 +1300,12 @@
return result;
}
-int usb_get_class_descriptor(struct usb_device *dev, unsigned char type,
- unsigned char id, unsigned char index, void *buf, int size)
+int usb_get_class_descriptor(struct usb_device *dev, int ifnum,
+ unsigned char type, unsigned char id, void *buf, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN,
- (type << 8) + id, index, buf, size, HZ * GET_TIMEOUT);
+ (type << 8) + id, ifnum, buf, size, HZ * GET_TIMEOUT);
}
int usb_get_string(struct usb_device *dev, unsigned short langid, unsigned char index, void *buf, int size)
@@ -1317,31 +1334,31 @@
USB_REQ_GET_STATUS, USB_DIR_IN | type, 0, target, data, 2, HZ * GET_TIMEOUT);
}
-int usb_get_protocol(struct usb_device *dev)
+int usb_get_protocol(struct usb_device *dev, int ifnum)
{
unsigned char type;
int ret;
if ((ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_PROTOCOL, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- 0, 1, &type, 1, HZ * GET_TIMEOUT)) < 0)
+ 0, ifnum, &type, 1, HZ * GET_TIMEOUT)) < 0)
return ret;
return type;
}
-int usb_set_protocol(struct usb_device *dev, int protocol)
+int usb_set_protocol(struct usb_device *dev, int ifnum, int protocol)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_PROTOCOL, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- protocol, 1, NULL, 0, HZ * SET_TIMEOUT);
+ protocol, ifnum, NULL, 0, HZ * SET_TIMEOUT);
}
-int usb_set_idle(struct usb_device *dev, int duration, int report_id)
+int usb_set_idle(struct usb_device *dev, int ifnum, int duration, int report_id)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- (duration << 8) | report_id, 1, NULL, 0, HZ * SET_TIMEOUT);
+ (duration << 8) | report_id, ifnum, NULL, 0, HZ * SET_TIMEOUT);
}
static void usb_set_maxpacket(struct usb_device *dev)
@@ -1373,10 +1390,11 @@
* endp: endpoint number in bits 0-3;
* direction flag in bit 7 (1 = IN, 0 = OUT)
*/
-int usb_clear_halt(struct usb_device *dev, int endp)
+int usb_clear_halt(struct usb_device *dev, int pipe)
{
int result;
__u16 status;
+ int endp=usb_pipeendpoint(pipe)|(usb_pipein(pipe)<<7);
/*
if (!usb_endpoint_halted(dev, endp & 0x0f, usb_endpoint_out(endp)))
@@ -1399,11 +1417,11 @@
if (status & 1)
return -EPIPE; /* still halted */
- usb_endpoint_running(dev, endp & 0x0f, usb_endpoint_out(endp));
+ usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
/* toggle is reset on clear */
- usb_settoggle(dev, endp & 0x0f, usb_endpoint_out(endp), 0);
+ usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
return 0;
}
@@ -1462,18 +1480,18 @@
return 0;
}
-int usb_get_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size)
+int usb_get_report(struct usb_device *dev, int ifnum, unsigned char type, unsigned char id, void *buf, int size)
{
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
USB_REQ_GET_REPORT, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- (type << 8) + id, index, buf, size, HZ * GET_TIMEOUT);
+ (type << 8) + id, ifnum, buf, size, HZ * GET_TIMEOUT);
}
-int usb_set_report(struct usb_device *dev, unsigned char type, unsigned char id, unsigned char index, void *buf, int size)
+int usb_set_report(struct usb_device *dev, int ifnum, unsigned char type, unsigned char id, void *buf, int size)
{
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE,
- (type << 8) + id, index, buf, size, HZ);
+ (type << 8) + id, ifnum, buf, size, HZ);
}
int usb_get_configuration(struct usb_device *dev)
@@ -1482,6 +1500,7 @@
unsigned int cfgno;
unsigned char buffer[8];
unsigned char *bigbuffer;
+ unsigned int tmp;
struct usb_config_descriptor *desc =
(struct usb_config_descriptor *)buffer;
@@ -1511,8 +1530,11 @@
/* We grab the first 8 bytes so we know how long the whole */
/* configuration is */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, buffer, 8);
- if (result < 0) {
- err("unable to get descriptor");
+ if (result < 8) {
+ if (result < 0)
+ err("unable to get descriptor");
+ else
+ err("config descriptor too short (expected %i, got %i)",8,result);
goto err;
}
@@ -1525,13 +1547,19 @@
result=-ENOMEM;
goto err;
}
-
+ tmp=desc->wTotalLength;
/* Now that we know the length, get the whole thing */
result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, desc->wTotalLength);
if (result < 0) {
err("couldn't get all of config descriptors");
kfree(bigbuffer);
goto err;
+ }
+
+ if (result < tmp) {
+ err("config descriptor too short (expected %i, got %i)",tmp,result);
+ kfree(bigbuffer);
+ goto err;
}
result = usb_parse_configuration(dev, &dev->config[cfgno], bigbuffer);
kfree(bigbuffer);
@@ -1551,13 +1579,17 @@
return result;
}
+/*
+ * usb_string:
+ * returns string length (> 0) or error (< 0)
+ */
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
unsigned char *tbuf;
int err;
unsigned int u, idx;
- if (size <= 0 || !buf)
+ if (size <= 0 || !buf || !index)
return -EINVAL;
buf[0] = 0;
tbuf = kmalloc(256, GFP_KERNEL);
@@ -1574,15 +1606,15 @@
err = usb_get_string(dev, dev->string_langid, index, tbuf, tbuf[0]);
if (err < 0)
goto errout;
- size--;
- for (idx = 0, u = 2; u < tbuf[0]; u += 2) {
+
+ size--; /* leave room for trailing NULL char in output buffer */
+ for (idx = 0, u = 2; u < err; u += 2) {
if (idx >= size)
break;
- if (tbuf[u+1]) {
- buf[idx++] = '?'; /* non ASCII character */
- continue;
- }
- buf[idx++] = tbuf[u];
+ if (tbuf[u+1]) /* high byte */
+ buf[idx++] = '?'; /* non-ASCII character */
+ else
+ buf[idx++] = tbuf[u];
}
buf[idx] = 0;
err = idx;
@@ -1603,6 +1635,7 @@
{
unsigned char *buf;
int addr, err;
+ int tmp;
info("USB new device connect, assigned device number %d", dev->devnum);
@@ -1615,13 +1648,15 @@
dev->devnum = 0;
err = usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8);
- if (err < 0) {
- err("USB device not responding, giving up (error=%d)", err);
+ if (err < 8) {
+ if (err < 0)
+ err("USB device not responding, giving up (error=%d)", err);
+ else
+ err("USB device descriptor short read (expected %i, got %i)",8,err);
clear_bit(addr, &dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
}
-
dev->epmaxpacketin [0] = dev->descriptor.bMaxPacketSize0;
dev->epmaxpacketout[0] = dev->descriptor.bMaxPacketSize0;
switch (dev->descriptor.bMaxPacketSize0) {
@@ -1644,9 +1679,15 @@
wait_ms(10); /* Let the SET_ADDRESS settle */
+ tmp = sizeof(dev->descriptor);
+
err = usb_get_device_descriptor(dev);
- if (err < 0) {
- err("unable to get device descriptor (error=%d)",err);
+ if (err < tmp) {
+ if (err < 0)
+ err("unable to get device descriptor (error=%d)",err);
+ else
+ err("USB device descriptor short read (expected %i, got %i)",tmp,err);
+
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
dev->devnum = -1;
return 1;
@@ -1684,9 +1725,12 @@
info("USB device number %d default language ID 0x%x", dev->devnum, dev->string_langid);
}
- usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
- usb_show_string(dev, "Product", dev->descriptor.iProduct);
- usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
+ if (dev->descriptor.iManufacturer)
+ usb_show_string(dev, "Manufacturer", dev->descriptor.iManufacturer);
+ if (dev->descriptor.iProduct)
+ usb_show_string(dev, "Product", dev->descriptor.iProduct);
+ if (dev->descriptor.iSerialNumber)
+ usb_show_string(dev, "SerialNumber", dev->descriptor.iSerialNumber);
/* now that the basic setup is over, add a /proc/bus/usb entry */
usbdevfs_add_device(dev);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)