[PATCH] usbdevfs: allocate async early, to allow some cleanup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



get rid of temporary iso frame descriptor (isopkt)
only set urb fields if applicable for respective urb type

Signed-off-by: Stefan Brüns <stefan.bruens@xxxxxxxxxxxxxx>
---
 drivers/usb/core/devio.c |   64 
+++++++++++++++++++++-------------------------
 1 files changed, 29 insertions(+), 35 deletions(-)

diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 6e8bcdf..4a66dcf 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1061,6 +1061,11 @@ static int proc_do_submiturb(struct dev_state *ps, 
struct usbdevfs_urb *uurb,
 	}
 	if (!ep)
 		return -ENOENT;
+	if(uurb->type != USBDEVFS_URB_TYPE_ISO) {
+		as = alloc_async(0);
+		if (!as)
+			return -ENOMEM;
+	}
 	switch(uurb->type) {
 	case USBDEVFS_URB_TYPE_CONTROL:
 		if (!usb_endpoint_xfer_control(&ep->desc))
@@ -1071,20 +1076,23 @@ static int proc_do_submiturb(struct dev_state *ps, 
struct usbdevfs_urb *uurb,
 		    uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
 			return -EINVAL;
 		dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
-		if (!dr)
+		if (!dr) {
+			free_async(as);
 			return -ENOMEM;
+		}
+		as->urb->setup_packet = (unsigned char *)dr;
 		if (copy_from_user(dr, uurb->buffer, 8)) {
-			kfree(dr);
+			free_async(as);
 			return -EFAULT;
 		}
 		if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
-			kfree(dr);
+			free_async(as);
 			return -EINVAL;
 		}
 		ret = check_ctrlrecip(ps, dr->bRequestType,
 				      le16_to_cpup(&dr->wIndex));
 		if (ret) {
-			kfree(dr);
+			free_async(as);
 			return ret;
 		}
 		uurb->number_of_packets = 0;
@@ -1120,27 +1128,31 @@ static int proc_do_submiturb(struct dev_state *ps, 
struct usbdevfs_urb *uurb,
 			return -EINVAL;
 		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) *
 				   uurb->number_of_packets;
-		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
-			return -ENOMEM;
-		if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
-			kfree(isopkt);
+		if (!access_ok(VERIFY_READ, iso_frame_desc, isofrmlen)) {
 			return -EFAULT;
 		}
+		as = alloc_async(uurb->number_of_packets);
+		if(!as)
+			return -ENOMEM;
 		for (totlen = u = 0; u < uurb->number_of_packets; u++) {
 			/* arbitrary limit,
 			 * sufficient for USB 2.0 high-bandwidth iso */
-			if (isopkt[u].length > 8192) {
-				kfree(isopkt);
+			if (iso_frame_desc[u].length > 8192) {
+				free_async(as);
 				return -EINVAL;
 			}
-			totlen += isopkt[u].length;
+			as->urb->iso_frame_desc[u].offset = totlen;
+			as->urb->iso_frame_desc[u].length = iso_frame_desc[u].length;
+			totlen += iso_frame_desc[u].length;
 		}
 		/* 3072 * 64 microframes */
 		if (totlen > 196608) {
-			kfree(isopkt);
+			free_async(as);
 			return -EINVAL;
 		}
 		uurb->buffer_length = totlen;
+		as->urb->start_frame = uurb->start_frame;
+		as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
 		break;
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
@@ -1149,6 +1161,10 @@ static int proc_do_submiturb(struct dev_state *ps, 
struct usbdevfs_urb *uurb,
 			return -EINVAL;
 		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 			return -EINVAL;
+		if (ps->dev->speed == USB_SPEED_HIGH)
+			as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
+		else
+			as->urb->interval = ep->desc.bInterval;
 		break;
 
 	default:
@@ -1157,22 +1173,13 @@ static int proc_do_submiturb(struct dev_state *ps, 
struct usbdevfs_urb *uurb,
 	if (uurb->buffer_length > 0 &&
 			!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
 				uurb->buffer, uurb->buffer_length)) {
-		kfree(isopkt);
-		kfree(dr);
+		free_async(as);
 		return -EFAULT;
 	}
-	as = alloc_async(uurb->number_of_packets);
-	if (!as) {
-		kfree(isopkt);
-		kfree(dr);
-		return -ENOMEM;
-	}
 	if (uurb->buffer_length > 0) {
 		as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
 				GFP_KERNEL);
 		if (!as->urb->transfer_buffer) {
-			kfree(isopkt);
-			kfree(dr);
 			free_async(as);
 			return -ENOMEM;
 		}
@@ -1200,22 +1207,9 @@ static int proc_do_submiturb(struct dev_state *ps, 
struct usbdevfs_urb *uurb,
 	as->urb->transfer_flags = u;
 
 	as->urb->transfer_buffer_length = uurb->buffer_length;
-	as->urb->setup_packet = (unsigned char *)dr;
-	as->urb->start_frame = uurb->start_frame;
 	as->urb->number_of_packets = uurb->number_of_packets;
-	if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
-			ps->dev->speed == USB_SPEED_HIGH)
-		as->urb->interval = 1 << min(15, ep->desc.bInterval - 1);
-	else
-		as->urb->interval = ep->desc.bInterval;
 	as->urb->context = as;
 	as->urb->complete = async_completed;
-	for (totlen = u = 0; u < uurb->number_of_packets; u++) {
-		as->urb->iso_frame_desc[u].offset = totlen;
-		as->urb->iso_frame_desc[u].length = isopkt[u].length;
-		totlen += isopkt[u].length;
-	}
-	kfree(isopkt);
 	as->ps = ps;
 	as->userurb = arg;
 	if (is_in && uurb->buffer_length > 0)
-- 
1.5.6

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux