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

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)