patch-2.4.23 linux-2.4.23/drivers/usb/acm.c

Next file: linux-2.4.23/drivers/usb/aiptek.c
Previous file: linux-2.4.23/drivers/usb/Makefile
Back to the patch index
Back to the overall index

diff -urN linux-2.4.22/drivers/usb/acm.c linux-2.4.23/drivers/usb/acm.c
@@ -363,9 +363,10 @@
 
 	count = (count > acm->writesize) ? acm->writesize : count;
 
-	if (from_user)
-		copy_from_user(acm->writeurb.transfer_buffer, buf, count);
-	else
+	if (from_user) {
+		if (copy_from_user(acm->writeurb.transfer_buffer, buf, count))
+			return -EFAULT;
+	} else
 		memcpy(acm->writeurb.transfer_buffer, buf, count);
 
 	acm->writeurb.transfer_buffer_length = count;
@@ -512,7 +513,7 @@
 	struct usb_config_descriptor *cfacm;
 	struct usb_interface_descriptor *ifcom, *ifdata;
 	struct usb_endpoint_descriptor *epctrl, *epread, *epwrite;
-	int readsize, ctrlsize, minor, i;
+	int readsize, ctrlsize, minor, i, j;
 	unsigned char *buf;
 
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
@@ -521,93 +522,98 @@
 
 		dbg("probing config %d", cfacm->bConfigurationValue);
 
-		if (cfacm->bNumInterfaces != 2 ||
-		    usb_interface_claimed(cfacm->interface + 0) ||
-		    usb_interface_claimed(cfacm->interface + 1))
-			continue;
-
-		ifcom = cfacm->interface[0].altsetting + 0;
-		ifdata = cfacm->interface[1].altsetting + 0;
-
-		if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
-			ifcom = cfacm->interface[1].altsetting + 0;
-			ifdata = cfacm->interface[0].altsetting + 0;
-			if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
+		for (j = 0; j < cfacm->bNumInterfaces - 1; j++) {
+
+			if (usb_interface_claimed(cfacm->interface + j) ||
+			    usb_interface_claimed(cfacm->interface + j + 1))
 				continue;
-		}
 
-		if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
-		    ifcom->bInterfaceProtocol != 1 || ifcom->bNumEndpoints < 1)
-			continue;
-
-		epctrl = ifcom->endpoint + 0;
-		epread = ifdata->endpoint + 0;
-		epwrite = ifdata->endpoint + 1;
-
-		if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
-		   (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
-		   ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
-			continue;
-
-		if ((epread->bEndpointAddress & 0x80) != 0x80) {
-			epread = ifdata->endpoint + 1;
-			epwrite = ifdata->endpoint + 0;
-		}
+			ifcom = cfacm->interface[j].altsetting + 0;
+			ifdata = cfacm->interface[j + 1].altsetting + 0;
 
-		usb_set_configuration(dev, cfacm->bConfigurationValue);
+			if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2) {
+				ifcom = cfacm->interface[j + 1].altsetting + 0;
+				ifdata = cfacm->interface[j].altsetting + 0;
+				if (ifdata->bInterfaceClass != 10 || ifdata->bNumEndpoints < 2)
+					continue;
+			}
 
-		for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
-		if (acm_table[minor]) {
-			err("no more free acm devices");
-			return NULL;
-		}
+			if (ifcom->bInterfaceClass != 2 || ifcom->bInterfaceSubClass != 2 ||
+			    ifcom->bInterfaceProtocol < 1 || ifcom->bInterfaceProtocol > 6 ||
+			    ifcom->bNumEndpoints < 1)
+				continue;
 
-		if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
-			err("out of memory");
-			return NULL;
-		}
-		memset(acm, 0, sizeof(struct acm));
+			epctrl = ifcom->endpoint + 0;
+			epread = ifdata->endpoint + 0;
+			epwrite = ifdata->endpoint + 1;
+
+			if ((epctrl->bEndpointAddress & 0x80) != 0x80 || (epctrl->bmAttributes & 3) != 3 ||
+			    (epread->bmAttributes & 3) != 2 || (epwrite->bmAttributes & 3) != 2 ||
+			    ((epread->bEndpointAddress & 0x80) ^ (epwrite->bEndpointAddress & 0x80)) != 0x80)
+				continue;
 
-		ctrlsize = epctrl->wMaxPacketSize;
-		readsize = epread->wMaxPacketSize;
-		acm->writesize = epwrite->wMaxPacketSize;
-		acm->iface = cfacm->interface;
-		acm->minor = minor;
-		acm->dev = dev;
-
-		acm->tqueue.routine = acm_softint;
-		acm->tqueue.data = acm;
-
-		if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
-			err("out of memory");
-			kfree(acm);
-			return NULL;
-		}
+			dbg("using interface %d\n", j);
+
+			if ((epread->bEndpointAddress & 0x80) != 0x80) {
+				epread = ifdata->endpoint + 1;
+				epwrite = ifdata->endpoint + 0;
+			}
 
-		FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
-			buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
+			usb_set_configuration(dev, cfacm->bConfigurationValue);
 
-		FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
-			buf += ctrlsize, readsize, acm_read_bulk, acm);
-		acm->readurb.transfer_flags |= USB_NO_FSBR;
+			for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
+			if (acm_table[minor]) {
+				err("no more free acm devices");
+				return NULL;
+			}
 
-		FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
-			buf += readsize, acm->writesize, acm_write_bulk, acm);
-		acm->writeurb.transfer_flags |= USB_NO_FSBR;
+			if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
+				err("out of memory");
+				return NULL;
+			}
+			memset(acm, 0, sizeof(struct acm));
 
-		printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+			ctrlsize = epctrl->wMaxPacketSize;
+			readsize = epread->wMaxPacketSize;
+			acm->writesize = epwrite->wMaxPacketSize;
+			acm->iface = cfacm->interface + j;
+			acm->minor = minor;
+			acm->dev = dev;
+
+			acm->tqueue.routine = acm_softint;
+			acm->tqueue.data = acm;
+
+			if (!(buf = kmalloc(ctrlsize + readsize + acm->writesize, GFP_KERNEL))) {
+				err("out of memory");
+				kfree(acm);
+				return NULL;
+			}
 
-		acm_set_control(acm, acm->ctrlout);
+			FILL_INT_URB(&acm->ctrlurb, dev, usb_rcvintpipe(dev, epctrl->bEndpointAddress),
+				     buf, ctrlsize, acm_ctrl_irq, acm, epctrl->bInterval);
 
-		acm->line.speed = cpu_to_le32(9600);
-		acm->line.databits = 8;
-		acm_set_line(acm, &acm->line);
+			FILL_BULK_URB(&acm->readurb, dev, usb_rcvbulkpipe(dev, epread->bEndpointAddress),
+				      buf += ctrlsize, readsize, acm_read_bulk, acm);
+			acm->readurb.transfer_flags |= USB_NO_FSBR;
 
-		usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
-		usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+			FILL_BULK_URB(&acm->writeurb, dev, usb_sndbulkpipe(dev, epwrite->bEndpointAddress),
+				      buf += readsize, acm->writesize, acm_write_bulk, acm);
+			acm->writeurb.transfer_flags |= USB_NO_FSBR;
 
-		tty_register_devfs(&acm_tty_driver, 0, minor);
-		return acm_table[minor] = acm;
+			printk(KERN_INFO "ttyACM%d: USB ACM device\n", minor);
+
+			acm_set_control(acm, acm->ctrlout);
+
+			acm->line.speed = cpu_to_le32(9600);
+			acm->line.databits = 8;
+			acm_set_line(acm, &acm->line);
+
+			usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
+			usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
+
+			tty_register_devfs(&acm_tty_driver, 0, minor);
+			return acm_table[minor] = acm;
+		}
 	}
 
 	return NULL;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)