Hi,

after the discussion with Oliver at the LinuxTag last week, I started to
re-write the hci_usb driver to remove this ugly cruft around the URB
management in the driver. The basic driver (without ISOC support) is
working perfectly fine and thanks to the reference count of the URB and
the new USB anchor extension it is a really small and simple driver now.

However the buffer management for URBs that get re-submitted all the
time is really ugly. It can be done inside the driver, but I think the
USB core should provide some helpers here.

The attached patch is an attempt to integrate the buffer into the URB
and let the URB take care of freeing it when it is no longer needed.
This might not be optimal for all drivers, but it helps to reduce a lot
of code in many drivers. And of course the old method of allocating or
providing an external buffer is still available.

The main use cases are interrupt and bulk in endpoints where fragmented
packets are used and the driver has to reassemble them. In this cases
one or multiple URBs with and attached buffer can be used. When shutting
down these URBs via an USB anchor, it will take care of freeing the
buffers and the driver doesn't have to worry about.

The patch misses setup routines for interrupt and ISOC URBs, but they
are straight forward. Please let me know what you think.

Regards

Marcel

diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 94ea972..e683726 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -11,6 +11,11 @@
 static void urb_destroy(struct kref *kref)
 {
 	struct urb *urb = to_urb(kref);
+
+	if (urb->transfer_flags & URB_FREE_BUFFER)
+		usb_buffer_free(urb->dev, urb->transfer_buffer_length,
+				urb->transfer_buffer, urb->transfer_dma);
+
 	kfree(urb);
 }
 
@@ -478,6 +483,36 @@ void usb_kill_urb(struct urb *urb)
 	spin_unlock_irq(&urb->lock);
 }
 
+/**
+ * usb_setup_bulk_urb - macro to help initialize a bulk urb
+ * @urb: pointer to the urb to initialize.
+ * @dev: pointer to the struct usb_device for this urb.
+ * @pipe: the endpoint pipe
+ * @size: requested buffer size
+ * @mem_flags: affect whether allocation may block
+ * @complete_fn: pointer to the usb_complete_t function
+ * @context: what to set the urb context to.
+ *
+ * Initializes a bulk urb with the proper information needed to submit it
+ * to a device and allocate dma-consistent buffer for it.
+ */
+int usb_setup_bulk_urb(struct urb *urb, struct usb_device *dev,
+				unsigned int pipe, size_t size, gfp_t mem_flags,
+				usb_complete_t complete_fn, void *context)
+{
+	void *addr;
+
+	addr = usb_buffer_alloc(dev, size, mem_flags, &urb->transfer_dma);
+	if (!addr)
+		return -ENOMEM;
+
+	usb_fill_bulk_urb(urb, dev, pipe, addr, size, complete_fn, context);
+
+	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP | URB_FREE_BUFFER;
+
+	return 0;
+}
+
 EXPORT_SYMBOL(usb_init_urb);
 EXPORT_SYMBOL(usb_alloc_urb);
 EXPORT_SYMBOL(usb_free_urb);
@@ -485,4 +520,5 @@ EXPORT_SYMBOL(usb_get_urb);
 EXPORT_SYMBOL(usb_submit_urb);
 EXPORT_SYMBOL(usb_unlink_urb);
 EXPORT_SYMBOL(usb_kill_urb);
+EXPORT_SYMBOL(usb_setup_bulk_urb);
 
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 94bd38a..001b376 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -948,6 +948,7 @@ extern int usb_disabled(void);
 #define URB_ZERO_PACKET		0x0040	/* Finish bulk OUT with short packet */
 #define URB_NO_INTERRUPT	0x0080	/* HINT: no non-error interrupt
 					 * needed */
+#define URB_FREE_BUFFER		0x0100	/* Free transfer buffer with the URB */
 
 struct usb_iso_packet_descriptor {
 	unsigned int offset;
@@ -1271,6 +1272,10 @@ extern int usb_submit_urb(struct urb *urb, gfp_t mem_flags);
 extern int usb_unlink_urb(struct urb *urb);
 extern void usb_kill_urb(struct urb *urb);
 
+int usb_setup_bulk_urb(struct urb *urb, struct usb_device *dev,
+				unsigned int pipe, size_t size, gfp_t mem_flags,
+				usb_complete_t complete_fn, void *context);
+
 void *usb_buffer_alloc (struct usb_device *dev, size_t size,
 	gfp_t mem_flags, dma_addr_t *dma);
 void usb_buffer_free (struct usb_device *dev, size_t size,
-------------------------------------------------------------------------
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/
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to