patch to shift memory allocations to usb_alloc_urb()

Oliver Neukum <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
Hi,

this proved harder than it looks like. I can use cdc-acm over ohci with
this patch. So what do you think?

	Regards
		Oliver

--
diff -urp linux-2.6.22rc6vanilla/include/linux/usb.h linux-2.6.22-rc6-storage/include/linux/usb.h
--- linux-2.6.22rc6vanilla/include/linux/usb.h	2007-06-29 13:33:17.000000000 +0200
+++ linux-2.6.22-rc6-storage/include/linux/usb.h	2007-06-27 14:41:59.000000000 +0200
@@ -1128,9 +1128,9 @@ struct urb
 	/* private: usb core and host controller only fields in the urb */
 	struct kref kref;		/* reference count of the URB */
 	spinlock_t lock;		/* lock for the URB */
-	void *hcpriv;			/* private data for host controller */
 	atomic_t use_count;		/* concurrent submissions counter */
 	u8 reject;			/* submissions will fail */
+	struct usb_hcd *rh_handed_over;
 
 	/* public: documented fields in the urb that can be used by drivers */
 	struct list_head urb_list;	/* list head for use by the urb's
@@ -1152,7 +1152,7 @@ struct urb
 	int error_count;		/* (return) number of ISO errors */
 	void *context;			/* (in) context for completion */
 	usb_complete_t complete;	/* (in) completion routine */
-	struct usb_iso_packet_descriptor iso_frame_desc[0];
+	struct usb_iso_packet_descriptor *iso_frames;
 					/* (in) ISO ONLY */
 };
 
@@ -1263,7 +1263,14 @@ static inline void usb_fill_int_urb (str
 }
 
 extern void usb_init_urb(struct urb *urb);
-extern struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);
+extern struct urb *usb_alloc_urb(struct usb_device *dev,
+					int pipe,
+					size_t buffer_length,
+					int type,
+					unsigned int iso_packets,
+					long transfer_flags,
+					int interval,
+					gfp_t mem_flags);
 extern void usb_free_urb(struct urb *urb);
 #define usb_put_urb usb_free_urb
 extern struct urb *usb_get_urb(struct urb *urb);
diff -urp linux-2.6.22rc6vanilla/drivers/usb/core/devio.c linux-2.6.22-rc6-storage/drivers/usb/core/devio.c
--- linux-2.6.22rc6vanilla/drivers/usb/core/devio.c	2007-06-29 13:33:00.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/core/devio.c	2007-06-27 14:27:35.000000000 +0200
@@ -207,14 +207,14 @@ err:
  * async list handling
  */
 
-static struct async *alloc_async(unsigned int numisoframes)
+static struct async *alloc_async(struct usb_device *dev, int pipe, size_t buffer_length, int type,  unsigned int numisoframes, int interval)
 {
         unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
         struct async *as = kzalloc(assize, GFP_KERNEL);
 
         if (!as)
                 return NULL;
-	as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
+	as->urb = usb_alloc_urb(dev, pipe, buffer_length, type, numisoframes, 0, interval, GFP_KERNEL);
 	if (!as->urb) {
 		kfree(as);
 		return NULL;
@@ -909,7 +909,7 @@ static int proc_do_submiturb(struct dev_
 	struct async *as;
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
-	int ret, ifnum = -1;
+	int ret, pipe, interval, ifnum = -1;
 
 	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
 			   URB_NO_FSBR|URB_ZERO_PACKET))
@@ -1027,7 +1027,15 @@ static int proc_do_submiturb(struct dev_
 	default:
 		return -EINVAL;
 	}
-	if (!(as = alloc_async(uurb->number_of_packets))) {
+
+	if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
+			ps->dev->speed == USB_SPEED_HIGH)
+		interval = 1 << min(15, ep->desc.bInterval - 1);
+	else
+		interval = ep->desc.bInterval;
+
+	pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
+	if (!(as = alloc_async(ps->dev, pipe, uurb->buffer_length, uurb->type,  uurb->number_of_packets, interval))) {
 		kfree(isopkt);
 		kfree(dr);
 		return -ENOMEM;
@@ -1038,23 +1046,16 @@ static int proc_do_submiturb(struct dev_
 		free_async(as);
 		return -ENOMEM;
 	}
-        as->urb->dev = ps->dev;
-        as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
-        as->urb->transfer_flags = uurb->flags;
+
 	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;
+		as->urb->iso_frames[u].offset = totlen;
+		as->urb->iso_frames[u].length = isopkt[u].length;
 		totlen += isopkt[u].length;
 	}
 	kfree(isopkt);
@@ -1128,10 +1129,10 @@ static int processcompl(struct async *as
 
 	if (usb_pipeisoc(urb->pipe)) {
 		for (i = 0; i < urb->number_of_packets; i++) {
-			if (put_user(urb->iso_frame_desc[i].actual_length,
+			if (put_user(urb->iso_frames[i].actual_length,
 				     &userurb->iso_frame_desc[i].actual_length))
 				return -EFAULT;
-			if (put_user(urb->iso_frame_desc[i].status,
+			if (put_user(urb->iso_frames[i].status,
 				     &userurb->iso_frame_desc[i].status))
 				return -EFAULT;
 		}
@@ -1242,10 +1243,10 @@ static int processcompl_compat(struct as
 
 	if (usb_pipeisoc(urb->pipe)) {
 		for (i = 0; i < urb->number_of_packets; i++) {
-			if (put_user(urb->iso_frame_desc[i].actual_length,
+			if (put_user(urb->iso_frames[i].actual_length,
 				     &userurb->iso_frame_desc[i].actual_length))
 				return -EFAULT;
-			if (put_user(urb->iso_frame_desc[i].status,
+			if (put_user(urb->iso_frames[i].status,
 				     &userurb->iso_frame_desc[i].status))
 				return -EFAULT;
 		}
diff -urp linux-2.6.22rc6vanilla/drivers/usb/core/hcd.c linux-2.6.22-rc6-storage/drivers/usb/core/hcd.c
--- linux-2.6.22rc6vanilla/drivers/usb/core/hcd.c	2007-06-29 13:33:00.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/core/hcd.c	2007-06-27 14:40:59.000000000 +0200
@@ -563,7 +563,7 @@ void usb_hcd_poll_rh_status(struct usb_h
 				hcd->poll_pending = 0;
 				hcd->status_urb = NULL;
 				urb->status = 0;
-				urb->hcpriv = NULL;
+				urb->rh_handed_over = NULL;
 				urb->actual_length = length;
 				memcpy(urb->transfer_buffer, buffer, length);
 			} else		/* urb has been unlinked */
@@ -611,7 +611,7 @@ static int rh_queue_status (struct usb_h
 		retval = -EINVAL;
 	} else {
 		hcd->status_urb = urb;
-		urb->hcpriv = hcd;	/* indicate it's queued */
+		urb->rh_handed_over = hcd;	/* indicate it's queued */
 
 		if (!hcd->uses_new_polling)
 			mod_timer (&hcd->rh_timer, jiffies +
@@ -654,7 +654,7 @@ static int usb_rh_urb_dequeue (struct us
 		spin_lock (&hcd_root_hub_lock);
 		if (urb == hcd->status_urb) {
 			hcd->status_urb = NULL;
-			urb->hcpriv = NULL;
+			urb->rh_handed_over = NULL;
 		} else
 			urb = NULL;		/* wasn't fully queued */
 		spin_unlock (&hcd_root_hub_lock);
Nur in linux-2.6.22-rc6-storage/drivers/usb/core: hcd.c~.
diff -urp linux-2.6.22rc6vanilla/drivers/usb/core/hcd.h linux-2.6.22-rc6-storage/drivers/usb/core/hcd.h
--- linux-2.6.22rc6vanilla/drivers/usb/core/hcd.h	2007-06-29 13:33:00.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/core/hcd.h	2007-06-28 09:52:42.000000000 +0200
@@ -188,6 +188,18 @@ struct hc_driver {
 					gfp_t mem_flags);
 	int	(*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
 
+	int	(*urb_compute_space) (struct usb_hcd *hcd,
+					struct usb_device *dev,
+					int pipe,
+					size_t buffer_length,
+					int type,
+					unsigned int iso_packets,
+					int transfer_flags);
+	int	(*urb_init) (struct usb_hcd *hcd,
+				struct urb *urb,
+				int memory,
+				gfp_t mem_flags);
+
 	/* hw synch, freeing endpoint resources that urb_dequeue can't */
 	void 	(*endpoint_disable)(struct usb_hcd *hcd,
 			struct usb_host_endpoint *ep);
diff -urp linux-2.6.22rc6vanilla/drivers/usb/core/hub.c linux-2.6.22-rc6-storage/drivers/usb/core/hub.c
--- linux-2.6.22rc6vanilla/drivers/usb/core/hub.c	2007-06-29 13:33:00.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/core/hub.c	2007-06-27 14:32:53.000000000 +0200
@@ -818,7 +818,7 @@ static int hub_configure(struct usb_hub 
 	if (maxp > sizeof(*hub->buffer))
 		maxp = sizeof(*hub->buffer);
 
-	hub->urb = usb_alloc_urb(0, GFP_KERNEL);
+	hub->urb = usb_alloc_urb(hdev, pipe, maxp, PIPE_INTERRUPT, 0, URB_NO_TRANSFER_DMA_MAP, endpoint->bInterval, GFP_KERNEL);
 	if (!hub->urb) {
 		message = "couldn't allocate interrupt urb";
 		ret = -ENOMEM;
@@ -828,7 +828,6 @@ static int hub_configure(struct usb_hub 
 	usb_fill_int_urb(hub->urb, hdev, pipe, *hub->buffer, maxp, hub_irq,
 		hub, endpoint->bInterval);
 	hub->urb->transfer_dma = hub->buffer_dma;
-	hub->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 
 	/* maybe cycle the hub leds */
 	if (hub->has_indicators && blinkenlights)
diff -urp linux-2.6.22rc6vanilla/drivers/usb/core/message.c linux-2.6.22-rc6-storage/drivers/usb/core/message.c
--- linux-2.6.22rc6vanilla/drivers/usb/core/message.c	2007-06-29 13:33:00.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/core/message.c	2007-06-29 14:37:57.000000000 +0200
@@ -77,7 +77,7 @@ static int usb_internal_control_msg(stru
 	int retv;
 	int length;
 
-	urb = usb_alloc_urb(0, GFP_NOIO);
+	urb = usb_alloc_urb(usb_dev, pipe, len, PIPE_CONTROL, 0, 0, 0, GFP_NOIO);
 	if (!urb)
 		return -ENOMEM;
   
@@ -85,6 +85,7 @@ static int usb_internal_control_msg(stru
 			     len, usb_api_blocking_completion, NULL);
 
 	retv = usb_start_wait_urb(urb, timeout, &length);
+
 	if (retv < 0)
 		return retv;
 	else
@@ -209,23 +210,31 @@ int usb_bulk_msg(struct usb_device *usb_
 {
 	struct urb *urb;
 	struct usb_host_endpoint *ep;
+	int is_int, interval = 0;
 
 	ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out)
 			[usb_pipeendpoint(pipe)];
 	if (!ep || len < 0)
 		return -EINVAL;
 
-	urb = usb_alloc_urb(0, GFP_KERNEL);
+	is_int = (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+			USB_ENDPOINT_XFER_INT;
+	if (is_int) {
+		interval = ep->desc.bInterval;
+		pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
+	}
+
+	urb = usb_alloc_urb(usb_dev, pipe, len,
+				is_int ? PIPE_INTERRUPT : PIPE_BULK,
+				0, 0, interval, GFP_KERNEL);
 	if (!urb)
 		return -ENOMEM;
 
-	if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
-			USB_ENDPOINT_XFER_INT) {
-		pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
+	if (is_int)
 		usb_fill_int_urb(urb, usb_dev, pipe, data, len,
 				usb_api_blocking_completion, NULL,
 				ep->desc.bInterval);
-	} else
+	else
 		usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
 				usb_api_blocking_completion, NULL);
 
@@ -391,22 +400,6 @@ int usb_sg_init (
 	for (i = 0; i < io->entries; i++) {
 		unsigned		len;
 
-		io->urbs [i] = usb_alloc_urb (0, mem_flags);
-		if (!io->urbs [i]) {
-			io->entries = i;
-			goto nomem;
-		}
-
-		io->urbs [i]->dev = NULL;
-		io->urbs [i]->pipe = pipe;
-		io->urbs [i]->interval = period;
-		io->urbs [i]->transfer_flags = urb_flags;
-
-		io->urbs [i]->complete = sg_complete;
-		io->urbs [i]->context = io;
-		io->urbs [i]->status = -EINPROGRESS;
-		io->urbs [i]->actual_length = 0;
-
 		/*
 		 * Some systems need to revert to PIO when DMA is temporarily
 		 * unavailable.  For their sakes, both transfer_buffer and
@@ -439,6 +432,22 @@ int usb_sg_init (
 				io->entries = i + 1;
 		}
 		io->urbs [i]->transfer_buffer_length = len;
+
+		io->urbs [i] = usb_alloc_urb (dev, pipe, len, PIPE_BULK, 0, urb_flags, 0, mem_flags);
+		if (!io->urbs [i]) {
+			io->entries = i;
+			goto nomem;
+		}
+
+		io->urbs [i]->dev = NULL;
+		io->urbs [i]->interval = period;
+
+		io->urbs [i]->complete = sg_complete;
+		io->urbs [i]->context = io;
+		io->urbs [i]->status = -EINPROGRESS;
+		io->urbs [i]->actual_length = 0;
+
+
 	}
 	io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;
 
@@ -628,6 +637,7 @@ int usb_get_descriptor(struct usb_device
 				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
 				(type << 8) + index, 0, buf, size,
 				USB_CTRL_GET_TIMEOUT);
+
 		if (result == 0 || result == -EPIPE)
 			continue;
 		if (result > 1 && ((u8 *)buf)[1] != type) {
@@ -864,6 +874,7 @@ int usb_get_device_descriptor(struct usb
 
 	if (size > sizeof(*desc))
 		return -EINVAL;
+
 	desc = kmalloc(sizeof(*desc), GFP_NOIO);
 	if (!desc)
 		return -ENOMEM;
diff -urp linux-2.6.22rc6vanilla/drivers/usb/core/urb.c linux-2.6.22-rc6-storage/drivers/usb/core/urb.c
--- linux-2.6.22rc6vanilla/drivers/usb/core/urb.c	2007-06-29 13:28:31.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/core/urb.c	2007-06-28 09:53:02.000000000 +0200
@@ -11,6 +11,7 @@
 static void urb_destroy(struct kref *kref)
 {
 	struct urb *urb = to_urb(kref);
+	kfree(urb->iso_frames);
 	kfree(urb);
 }
 
@@ -53,18 +54,47 @@ void usb_init_urb(struct urb *urb)
  *
  * The driver must call usb_free_urb() when it is finished with the urb.
  */
-struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
+struct urb *usb_alloc_urb(struct usb_device *dev,
+					int pipe,
+					size_t buffer_length,
+					int type,
+					unsigned int iso_packets,
+					long transfer_flags,
+					int interval,
+					gfp_t mem_flags)
 {
 	struct urb *urb;
+	struct usb_iso_packet_descriptor *frames = NULL;
+	struct usb_hcd	*hcd = bus_to_hcd(dev->bus);
+	int space;
 
-	urb = kmalloc(sizeof(struct urb) +
-		iso_packets * sizeof(struct usb_iso_packet_descriptor),
-		mem_flags);
+	space = (hcd->driver->urb_compute_space) (hcd, dev, pipe, buffer_length, type, iso_packets, transfer_flags);
+	if (space < 0)
+		return NULL;
+
+	if (iso_packets) {
+		frames = kmalloc(iso_packets * sizeof(struct usb_iso_packet_descriptor), mem_flags);
+		if (!frames)
+			return NULL;
+	}
+
+	urb = kmalloc(space, mem_flags);
 	if (!urb) {
 		err("alloc_urb: kmalloc failed");
+		kfree(frames);
 		return NULL;
 	}
 	usb_init_urb(urb);
+	urb->dev = dev;
+	urb->pipe = pipe;
+	urb->iso_frames = frames;
+	urb->transfer_flags = transfer_flags;
+	urb->interval = interval;
+	if (0 > (hcd->driver->urb_init)(hcd, urb, space, mem_flags)) {
+		kfree(urb);
+		kfree(frames);
+		return NULL;
+	}
 	return urb;
 }
 
@@ -223,7 +253,7 @@ int usb_submit_urb(struct urb *urb, gfp_
 	struct usb_device	*dev;
 	int			is_out;
 
-	if (!urb || urb->hcpriv || !urb->complete)
+	if (!urb || !urb->complete)
 		return -EINVAL;
 	if (!(dev = urb->dev) ||
 	    (dev->state < USB_STATE_DEFAULT) ||
@@ -278,11 +308,11 @@ int usb_submit_urb(struct urb *urb, gfp_
 		if (urb->number_of_packets <= 0)		    
 			return -EINVAL;
 		for (n = 0; n < urb->number_of_packets; n++) {
-			len = urb->iso_frame_desc[n].length;
+			len = urb->iso_frames[n].length;
 			if (len < 0 || len > max) 
 				return -EMSGSIZE;
-			urb->iso_frame_desc[n].status = -EXDEV;
-			urb->iso_frame_desc[n].actual_length = 0;
+			urb->iso_frames[n].status = -EXDEV;
+			urb->iso_frames[n].actual_length = 0;
 		}
 	}
 
diff -urp linux-2.6.22rc6vanilla/drivers/usb/host/ohci.h linux-2.6.22-rc6-storage/drivers/usb/host/ohci.h
--- linux-2.6.22rc6vanilla/drivers/usb/host/ohci.h	2007-06-29 13:28:34.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/host/ohci.h	2007-06-28 09:46:55.000000000 +0200
@@ -326,6 +326,7 @@ struct ohci_regs {
 typedef struct urb_priv {
 	struct ed		*ed;
 	u16			length;		// # tds in this request
+	u16			alloc_length;
 	u16			td_cnt;		// tds already serviced
 	struct list_head	pending;
 	struct td		*td [0];	// all TDs in this request
@@ -401,6 +402,11 @@ struct ohci_hcd {
 
 };
 
+struct ohci_urb {
+	struct urb	urb;
+	urb_priv_t	hcpriv;
+};
+
 /* convert between an hcd pointer and the corresponding ohci_hcd */
 static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
 {
diff -urp linux-2.6.22rc6vanilla/drivers/usb/host/ohci-hcd.c linux-2.6.22-rc6-storage/drivers/usb/host/ohci-hcd.c
--- linux-2.6.22rc6vanilla/drivers/usb/host/ohci-hcd.c	2007-06-29 13:33:00.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/host/ohci-hcd.c	2007-06-29 09:07:15.000000000 +0200
@@ -53,7 +53,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#undef OHCI_VERBOSE_DEBUG	/* not always helpful */
+#define OHCI_VERBOSE_DEBUG	/* not always helpful */
 
 /* For initializing controller (mask in an HCFS mode too) */
 #define	OHCI_CONTROL_INIT	OHCI_CTRL_CBSR
@@ -113,6 +113,82 @@ MODULE_PARM_DESC (no_handshake, "true (n
 
 /*-------------------------------------------------------------------------*/
 
+static int ohci_urb_compute_space(struct usb_hcd *hcd,
+					struct usb_device *dev,
+					int pipe,
+					size_t buffer_length,
+					int type,
+					unsigned int iso_packets,
+					int transfer_flags)
+{
+	int size = 0;
+
+	/* for the private part of the URB we need the number of TDs (size) */
+	switch (type) {
+		case PIPE_CONTROL:
+			/* td_submit_urb() doesn't yet handle these */
+			if (buffer_length > 4096)
+				return -EMSGSIZE;
+
+			/* 1 TD for setup, 1 for ACK, plus ... */
+			size = 2;
+			/* FALLTHROUGH */
+		// case PIPE_INTERRUPT:
+		// case PIPE_BULK:
+		default:
+			/* one TD for every 4096 Bytes (can be upto 8K) */
+			size += buffer_length / 4096;
+			/* ... and for any remaining bytes ... */
+			if ((buffer_length % 4096) != 0)
+				size++;
+			/* ... and maybe a zero length packet to wrap it up */
+			if (size == 0)
+				size++;
+			else if ((transfer_flags & URB_ZERO_PACKET) != 0
+				&& (buffer_length
+					% usb_maxpacket (dev, pipe,
+						usb_pipeout (pipe))) == 0)
+				size++;
+			break;
+		case PIPE_ISOCHRONOUS: /* number of packets from URB */
+			size = iso_packets;
+			break;
+	}
+	return size * sizeof(struct td) + sizeof(struct ohci_urb);
+}
+
+static int ohci_urb_init(struct usb_hcd *hcd,
+		struct urb *urb,
+		int memory,
+		gfp_t mem_flags)
+{
+	struct ohci_urb *ou = (struct ohci_urb *)urb;
+	struct usb_host_endpoint *ep;
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+	struct ed *ed;
+	int i, size;
+
+	size = ou->hcpriv.alloc_length = (memory - sizeof(struct ohci_urb)) / sizeof(struct td);
+
+	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
+			[usb_pipeendpoint(urb->pipe)];
+	/* every endpoint has an ed, locate and maybe (re)initialize it */
+	if (! (ed = ed_get (ohci, ep, urb->dev, urb->pipe, urb->interval)))
+		return -ENOMEM;
+	ou->hcpriv.ed = ed;
+
+	/* allocate the TDs (deferring hash chain updates) */
+	for (i = 0; i < size; i++) {
+		ou->hcpriv.td[i] = td_alloc(ohci, mem_flags);
+		if (!ou->hcpriv.td[i]) {
+			urb_free_priv(ohci, &ou->hcpriv);
+			return -ENOMEM;
+		}
+	}
+
+	return 0;
+}
+
 /*
  * queue up an urb for anything except the root hub
  */
@@ -123,20 +199,18 @@ static int ohci_urb_enqueue (
 	gfp_t		mem_flags
 ) {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
-	struct ed	*ed;
-	urb_priv_t	*urb_priv;
+	urb_priv_t	*urb_priv = &(((struct ohci_urb *)urb)->hcpriv);
+	struct ed	*ed = urb_priv->ed;
 	unsigned int	pipe = urb->pipe;
-	int		i, size = 0;
+	int		size = 0;
 	unsigned long	flags;
 	int		retval = 0;
+	u16		orig = urb_priv->alloc_length;
 
 #ifdef OHCI_VERBOSE_DEBUG
 	urb_print (urb, "SUB", usb_pipein (pipe));
 #endif
 
-	/* every endpoint has a ed, locate and maybe (re)initialize it */
-	if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
-		return -ENOMEM;
 
 	/* for the private part of the URB we need the number of TDs (size) */
 	switch (ed->type) {
@@ -170,26 +244,17 @@ static int ohci_urb_enqueue (
 			break;
 	}
 
+	if (size > orig)
+		return -EMSGSIZE;
+	BUG_ON(ed == NULL);
+
 	/* allocate the private part of the URB */
-	urb_priv = kmalloc (sizeof (urb_priv_t) + size * sizeof (struct td *),
-			mem_flags);
-	if (!urb_priv)
-		return -ENOMEM;
-	memset (urb_priv, 0, sizeof (urb_priv_t) + size * sizeof (struct td *));
+	memset (urb_priv, 0, sizeof (urb_priv_t));
 	INIT_LIST_HEAD (&urb_priv->pending);
+	urb_priv->alloc_length = orig;
 	urb_priv->length = size;
 	urb_priv->ed = ed;
 
-	/* allocate the TDs (deferring hash chain updates) */
-	for (i = 0; i < size; i++) {
-		urb_priv->td [i] = td_alloc (ohci, mem_flags);
-		if (!urb_priv->td [i]) {
-			urb_priv->length = i;
-			urb_free_priv (ohci, urb_priv);
-			return -ENOMEM;
-		}
-	}
-
 	spin_lock_irqsave (&ohci->lock, flags);
 
 	/* don't submit to a dead HC */
@@ -206,7 +271,6 @@ static int ohci_urb_enqueue (
 	spin_lock (&urb->lock);
 	if (urb->status != -EINPROGRESS) {
 		spin_unlock (&urb->lock);
-		urb->hcpriv = urb_priv;
 		finish_urb (ohci, urb);
 		retval = 0;
 		goto fail;
@@ -237,14 +301,11 @@ static int ohci_urb_enqueue (
 	 * enable that part of the schedule, if needed
 	 * and update count of queued periodic urbs
 	 */
-	urb->hcpriv = urb_priv;
 	td_submit_urb (ohci, urb);
 
 fail0:
 	spin_unlock (&urb->lock);
 fail:
-	if (retval)
-		urb_free_priv (ohci, urb_priv);
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	return retval;
 }
@@ -257,7 +318,8 @@ fail:
  */
 static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 {
-	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+	struct ohci_urb *ourb = (struct ohci_urb *)urb;
 	unsigned long		flags;
 
 #ifdef OHCI_VERBOSE_DEBUG
@@ -272,18 +334,15 @@ static int ohci_urb_dequeue (struct usb_
 		 * handed to us, flag it for unlink and giveback, and force
 		 * some upcoming INTR_SF to call finish_unlinks()
 		 */
-		urb_priv = urb->hcpriv;
-		if (urb_priv) {
-			if (urb_priv->ed->state == ED_OPER)
-				start_ed_unlink (ohci, urb_priv->ed);
-		}
+		urb_priv = &ourb->hcpriv;
+		if (urb_priv->ed->state == ED_OPER)
+			start_ed_unlink (ohci, urb_priv->ed);
 	} else {
 		/*
 		 * with HC dead, we won't respect hc queue pointers
 		 * any more ... just clean up every urb's memory.
 		 */
-		if (urb->hcpriv)
-			finish_urb (ohci, urb);
+		finish_urb(ohci, urb);
 	}
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	return 0;
diff -urp linux-2.6.22rc6vanilla/drivers/usb/host/ohci-pci.c linux-2.6.22-rc6-storage/drivers/usb/host/ohci-pci.c
--- linux-2.6.22rc6vanilla/drivers/usb/host/ohci-pci.c	2007-06-29 13:33:01.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/host/ohci-pci.c	2007-06-27 17:36:59.000000000 +0200
@@ -281,6 +281,8 @@ static const struct hc_driver ohci_pci_h
 	.urb_enqueue =		ohci_urb_enqueue,
 	.urb_dequeue =		ohci_urb_dequeue,
 	.endpoint_disable =	ohci_endpoint_disable,
+	.urb_compute_space =	ohci_urb_compute_space,
+	.urb_init =		ohci_urb_init,
 
 	/*
 	 * scheduling support
diff -urp linux-2.6.22rc6vanilla/drivers/usb/host/ohci-q.c linux-2.6.22-rc6-storage/drivers/usb/host/ohci-q.c
--- linux-2.6.22rc6vanilla/drivers/usb/host/ohci-q.c	2007-02-04 19:44:54.000000000 +0100
+++ linux-2.6.22-rc6-storage/drivers/usb/host/ohci-q.c	2007-06-29 14:36:25.000000000 +0200
@@ -11,21 +11,20 @@
 
 static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
 {
-	int		last = urb_priv->length - 1;
+	int		last = urb_priv->alloc_length - 1;
 
 	if (last >= 0) {
 		int		i;
 		struct td	*td;
 
 		for (i = 0; i <= last; i++) {
-			td = urb_priv->td [i];
+			td = urb_priv->td[i];
 			if (td)
-				td_free (hc, td);
+				td_free(hc, td);
 		}
 	}
 
 	list_del (&urb_priv->pending);
-	kfree (urb_priv);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -40,11 +39,9 @@ finish_urb (struct ohci_hcd *ohci, struc
 __releases(ohci->lock)
 __acquires(ohci->lock)
 {
+	//struct ohci_urb *ourb = (struct ohci_urb *)urb;
 	// ASSERT (urb->hcpriv != 0);
 
-	urb_free_priv (ohci, urb->hcpriv);
-	urb->hcpriv = NULL;
-
 	spin_lock (&urb->lock);
 	if (likely (urb->status == -EINPROGRESS))
 		urb->status = 0;
@@ -507,8 +504,9 @@ td_fill (struct ohci_hcd *ohci, u32 info
 	dma_addr_t data, int len,
 	struct urb *urb, int index)
 {
+	struct ohci_urb	*ourb = (struct ohci_urb *)urb;
 	struct td		*td, *td_pt;
-	struct urb_priv		*urb_priv = urb->hcpriv;
+	struct urb_priv	*urb_priv = &ourb->hcpriv;
 	int			is_iso = info & TD_ISO;
 	int			hash;
 
@@ -531,7 +529,6 @@ td_fill (struct ohci_hcd *ohci, u32 info
 
 	/* use this td as the next dummy */
 	td_pt = urb_priv->td [index];
-
 	/* fill the old dummy TD */
 	td = urb_priv->td [index] = urb_priv->ed->dummy;
 	urb_priv->ed->dummy = td_pt;
@@ -543,7 +540,6 @@ td_fill (struct ohci_hcd *ohci, u32 info
 	td->data_dma = data;
 	if (!len)
 		data = 0;
-
 	td->hwINFO = cpu_to_hc32 (ohci, info);
 	if (is_iso) {
 		td->hwCBP = cpu_to_hc32 (ohci, data & 0xFFFFF000);
@@ -558,15 +554,12 @@ td_fill (struct ohci_hcd *ohci, u32 info
 	else
 		td->hwBE = 0;
 	td->hwNextTD = cpu_to_hc32 (ohci, td_pt->td_dma);
-
 	/* append to queue */
 	list_add_tail (&td->td_list, &td->ed->td_list);
-
 	/* hash it for later reverse mapping */
 	hash = TD_HASH_FUNC (td->td_dma);
 	td->td_hash = ohci->td_hash [hash];
 	ohci->td_hash [hash] = td;
-
 	/* HC might read the TD (or cachelines) right away ... */
 	wmb ();
 	td->ed->hwTailP = td->hwNextTD;
@@ -583,7 +576,8 @@ static void td_submit_urb (
 	struct ohci_hcd	*ohci,
 	struct urb	*urb
 ) {
-	struct urb_priv	*urb_priv = urb->hcpriv;
+	struct ohci_urb *ourb = (struct ohci_urb *)urb;
+	struct urb_priv	*urb_priv = &ourb->hcpriv;
 	dma_addr_t	data;
 	int		data_len = urb->transfer_buffer_length;
 	int		cnt = 0;
@@ -686,8 +680,8 @@ static void td_submit_urb (
 			frame += cnt * urb->interval;
 			frame &= 0xffff;
 			td_fill (ohci, TD_CC | TD_ISO | frame,
-				data + urb->iso_frame_desc [cnt].offset,
-				urb->iso_frame_desc [cnt].length, urb, cnt);
+				data + urb->iso_frames[cnt].offset,
+				urb->iso_frames[cnt].length, urb, cnt);
 		}
 		periodic = ohci_to_hcd(ohci)->self.bandwidth_isoc_reqs++ == 0
 			&& ohci_to_hcd(ohci)->self.bandwidth_int_reqs == 0;
@@ -732,7 +726,7 @@ static void td_done (struct ohci_hcd *oh
 			return;
 
 		if (usb_pipeout (urb->pipe))
-			dlen = urb->iso_frame_desc [td->index].length;
+			dlen = urb->iso_frames[td->index].length;
 		else {
 			/* short reads are always OK for ISO */
 			if (cc == TD_DATAUNDERRUN)
@@ -740,8 +734,8 @@ static void td_done (struct ohci_hcd *oh
 			dlen = tdPSW & 0x3ff;
 		}
 		urb->actual_length += dlen;
-		urb->iso_frame_desc [td->index].actual_length = dlen;
-		urb->iso_frame_desc [td->index].status = cc_to_error [cc];
+		urb->iso_frames[td->index].actual_length = dlen;
+		urb->iso_frames[td->index].status = cc_to_error [cc];
 
 		if (cc != TD_CC_NOERROR)
 			ohci_vdbg (ohci,
@@ -967,12 +961,14 @@ rescan_this:
 		list_for_each_safe (entry, tmp, &ed->td_list) {
 			struct td	*td;
 			struct urb	*urb;
+			struct ohci_urb *ourb;
 			urb_priv_t	*urb_priv;
 			__hc32		savebits;
 
 			td = list_entry (entry, struct td, td_list);
 			urb = td->urb;
-			urb_priv = td->urb->hcpriv;
+			ourb = (struct ohci_urb *)urb;
+			urb_priv = &ourb->hcpriv;
 
 			if (urb->status == -EINPROGRESS) {
 				prev = &td->hwNextTD;
@@ -1075,7 +1071,7 @@ dl_done_list (struct ohci_hcd *ohci)
 	while (td) {
 		struct td	*td_next = td->next_dl_td;
 		struct urb	*urb = td->urb;
-		urb_priv_t	*urb_priv = urb->hcpriv;
+		urb_priv_t	*urb_priv = &(((struct ohci_urb *)urb)->hcpriv);
 		struct ed	*ed = td->ed;
 
 		/* update URB's length and status from TD */
diff -urp linux-2.6.22rc6vanilla/drivers/usb/class/cdc-acm.c linux-2.6.22-rc6-storage/drivers/usb/class/cdc-acm.c
--- linux-2.6.22rc6vanilla/drivers/usb/class/cdc-acm.c	2007-06-29 13:33:00.000000000 +0200
+++ linux-2.6.22-rc6-storage/drivers/usb/class/cdc-acm.c	2007-06-28 16:20:49.000000000 +0200
@@ -989,7 +989,14 @@ skip_normal_probe:
 		goto alloc_fail4;
 	}
 
-	acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
+	acm->ctrlurb = usb_alloc_urb(usb_dev,
+				usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
+				ctrlsize,
+				PIPE_INTERRUPT,
+				0,
+				URB_NO_TRANSFER_DMA_MAP,
+				epctrl->bInterval,
+				GFP_KERNEL);
 	if (!acm->ctrlurb) {
 		dev_dbg(&intf->dev, "out of memory (ctrlurb kmalloc)");
 		goto alloc_fail5;
@@ -997,7 +1004,15 @@ skip_normal_probe:
 	for (i = 0; i < num_rx_buf; i++) {
 		struct acm_ru *rcv = &(acm->ru[i]);
 
-		if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
+		if (!(rcv->urb = usb_alloc_urb(usb_dev,
+				acm->rx_endpoint,
+				acm->readsize,
+				PIPE_BULK,
+				0,
+				URB_NO_TRANSFER_DMA_MAP,	
+				0,
+				GFP_KERNEL
+		))) {
 			dev_dbg(&intf->dev, "out of memory (read urbs usb_alloc_urb)");
 			goto alloc_fail7;
 		}
@@ -1013,7 +1028,14 @@ skip_normal_probe:
 			goto alloc_fail7;
 		}
 	}
-	acm->writeurb = usb_alloc_urb(0, GFP_KERNEL);
+	acm->writeurb = usb_alloc_urb(usb_dev,
+				usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+				acm->writesize,
+				PIPE_BULK,
+				0,
+				URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP,
+				0,
+				GFP_KERNEL);
 	if (!acm->writeurb) {
 		dev_dbg(&intf->dev, "out of memory (writeurb kmalloc)");
 		goto alloc_fail7;

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.