Re: [linux-usb-devel] anchors and their use
Am Freitag, 25. Mai 2007 04:30 schrieb Alan Stern: For a simple example driver, this is getting distressingly complicated. Our API is growing. We've introduced pre/post_reset and autosuspend within a recentlyish timeframe. How could a generic example avoid reflecting that? Instead of worrying too much about error reporting, how about implementing exclusive-open semantics? That would simplify things a lot. Note that for simple drivers, exclusive-open is the rule rather than the exception. It does not help. As yet I don't try to trace whose requests fail. Were I to do that, the patch would become even larger. In that sense it does implement exclusive open. Apart from that a generic example must have proper error handling. If we don't do it there we'll pay for it later fixing all derived drivers. The order of your new routines is strange: suspend, pre_reset, resume, post_reset. It's more natural to do suspend, resume, pre_reset, post_reset. Before an event - after an event. I'll change it. Furthermore, I'll break up this patch into pieces to make it simpler to review. There is no call to usb_pm_put_interface(). Oops. Thanks. Regards Oliver - 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
Re: [linux-usb-devel] anchors and their use
Am Dienstag, 22. Mai 2007 21:48 schrieb David Brownell: On Tuesday 22 May 2007, Alan Stern wrote: Timeouts are specified in jiffies, so your timeout argument should be long or unsigned long, not int. Timeouts are best specified in milliseconds though... that's been the policy inside the USB stack since someone's search-and-destroy mission a few years back. Most people don't handle jiffies right. Hi, here's the use of anchors to implement a couple of methods in the skeleton driver, which is thus brought up to standard. This patch does: - correctly handle disconnect with an anchor - correctly handle suspend with an anchor - correctly handle pre_reset with an anchor in order to have a correct handling of pre_reset it further: - introduces error reporting in the write path - reports resets to user space - implements flush() to isolate consecutive calls to open() Regards Oliver --- --- a/drivers/usb/usb-skeleton.c2007-05-22 14:50:34.0 +0200 +++ b/drivers/usb/usb-skeleton.c2007-05-24 08:47:29.0 +0200 @@ -34,10 +34,6 @@ static struct usb_device_id skel_table [ }; MODULE_DEVICE_TABLE(usb, skel_table); -/* to prevent a race between open and disconnect */ -static DEFINE_MUTEX(skel_open_lock); - - /* Get a minor range for your devices from the usb maintainer */ #define USB_SKEL_MINOR_BASE192 @@ -54,16 +50,20 @@ struct usb_skel { struct usb_device *udev; /* the usb device for this device */ struct usb_interface*interface; /* the interface for this device */ struct semaphorelimit_sem; /* limiting the number of writes in progress */ + struct usb_anchor submitted; /* in case we need to retract our submissions */ unsigned char *bulk_in_buffer;/* the buffer to receive data */ size_t bulk_in_size; /* the size of the receive buffer */ __u8bulk_in_endpointAddr; /* the address of the bulk in endpoint */ __u8bulk_out_endpointAddr; /* the address of the bulk out endpoint */ + int errors; /* the last request tanked */ + spinlock_t err_lock; /* lock for errors */ struct kref kref; struct mutexio_mutex; /* synchronize I/O with disconnect */ }; #define to_skel_dev(d) container_of(d, struct usb_skel, kref) static struct usb_driver skel_driver; +static void skel_draw_down(struct usb_skel *dev); static void skel_delete(struct kref *kref) { @@ -83,10 +83,8 @@ static int skel_open(struct inode *inode subminor = iminor(inode); - mutex_lock(skel_open_lock); interface = usb_find_interface(skel_driver, subminor); if (!interface) { - mutex_unlock(skel_open_lock); err (%s - error, can't find device for minor %d, __FUNCTION__, subminor); retval = -ENODEV; @@ -95,25 +93,26 @@ static int skel_open(struct inode *inode dev = usb_get_intfdata(interface); if (!dev) { - mutex_unlock(skel_open_lock); retval = -ENODEV; goto exit; } /* increment our usage count for the device */ kref_get(dev-kref); - /* now we can drop the lock */ - mutex_unlock(skel_open_lock); + /* to guard against an ongoing reset */ + mutex_lock(dev-io_mutex); /* prevent the device from being autosuspended */ retval = usb_autopm_get_interface(interface); if (retval) { + mutex_unlock(dev-io_mutex); kref_put(dev-kref, skel_delete); goto exit; } /* save our object in the file's private structure */ file-private_data = dev; + mutex_unlock(dev-io_mutex); exit: return retval; @@ -138,6 +137,30 @@ static int skel_release(struct inode *in return 0; } +static int skel_flush(struct file *file, fl_owner_t id) +{ + struct usb_skel *dev; + int res; + + dev = (struct usb_skel *)file-private_data; + if (dev == NULL) + return -ENODEV; + + /* wait for io to stop */ + mutex_lock(dev-io_mutex); + skel_draw_down(dev); + + /* read out errors, leave subsequent opens a clean slate */ + spin_lock_irq(dev-err_lock); + res = dev-errors ? (dev-errors == -EPIPE ? -EPIPE : -EIO) : 0; + dev-errors = 0; + spin_unlock_irq(dev-err_lock); + + mutex_unlock(dev-io_mutex); + + return res; +} + static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos) { struct usb_skel *dev; @@ -179,14 +202,17 @@ static void skel_write_bulk_callback(str dev = (struct usb_skel *)urb-context;
Re: [linux-usb-devel] anchors and their use
On Thu, 24 May 2007, Oliver Neukum wrote: Hi, here's the use of anchors to implement a couple of methods in the skeleton driver, which is thus brought up to standard. This patch does: - correctly handle disconnect with an anchor - correctly handle suspend with an anchor - correctly handle pre_reset with an anchor in order to have a correct handling of pre_reset it further: - introduces error reporting in the write path - reports resets to user space - implements flush() to isolate consecutive calls to open() For a simple example driver, this is getting distressingly complicated. Instead of worrying too much about error reporting, how about implementing exclusive-open semantics? That would simplify things a lot. Note that for simple drivers, exclusive-open is the rule rather than the exception. The order of your new routines is strange: suspend, pre_reset, resume, post_reset. It's more natural to do suspend, resume, pre_reset, post_reset. There is no call to usb_pm_put_interface(). Alan Stern - 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
Re: [linux-usb-devel] anchors and their use
Am Dienstag, 22. Mai 2007 17:12 schrieb Alan Stern: Very good. I did notice two more things: Timeouts are specified in jiffies, so your timeout argument should be long or unsigned long, not int. There's a race if two threads call usb_unanchor_urb() for the same URB at the same time. You need to recheck while holding the anchor's spinlock that urb-anchor is still equal to anchor. You might also want to add WARN_ON(urb-anchor != NULL); to usb_anchor_urb(), just as a precaution. OK, these are fixed and the timeout given in milliseconds, as David recommended. I looked into the inlining issue and the inlined version wins in terms of size. Regards Oliver - --- a/include/linux/usb.h 2007-05-22 14:51:01.0 +0200 +++ b/include/linux/usb.h 2007-05-23 10:20:35.0 +0200 @@ -958,11 +958,26 @@ struct usb_iso_packet_descriptor { struct urb; +struct usb_anchor { + struct list_head urb_list; + wait_queue_head_t wait; + spinlock_t lock; +}; + +static inline void init_usb_anchor(struct usb_anchor *anchor) +{ + INIT_LIST_HEAD(anchor-urb_list); + init_waitqueue_head(anchor-wait); + spin_lock_init(anchor-lock); +} + typedef void (*usb_complete_t)(struct urb *); /** * struct urb - USB Request Block * @urb_list: For use by current owner of the URB. + * @anchor_list: membership in the list of an anchor + * @anchor: to anchor URBs to a common mooring * @pipe: Holds endpoint number, direction, type, and more. * Create these values with the eight macros available; * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is ctrl @@ -1135,6 +1150,8 @@ struct urb /* 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 * current owner */ + struct list_head anchor_list; /* the URB may be anchored by the driver */ + struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ unsigned int pipe; /* (in) pipe information */ int status; /* (return) non-ISO status */ @@ -1270,6 +1287,11 @@ extern struct urb *usb_get_urb(struct ur 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); +extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); +extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); +extern void usb_unanchor_urb(struct urb *urb); +extern int usb_wait_anchor_empty_timeout +(struct usb_anchor *anchor, unsigned long timeout); void *usb_buffer_alloc (struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); --- a/drivers/usb/core/hcd.c2007-05-22 14:50:32.0 +0200 +++ b/drivers/usb/core/hcd.c2007-05-22 15:36:17.0 +0200 @@ -1412,6 +1412,8 @@ void usb_hcd_giveback_urb (struct usb_hc } usbmon_urb_complete (hcd-self, urb); + usb_unanchor_urb(urb); + /* pass ownership to the completion handler */ urb-complete (urb); atomic_dec (urb-use_count); --- a/drivers/usb/core/urb.c2007-05-22 14:40:12.0 +0200 +++ b/drivers/usb/core/urb.c2007-05-23 10:20:01.0 +0200 @@ -4,6 +4,7 @@ #include linux/slab.h #include linux/init.h #include linux/usb.h +#include linux/wait.h #include hcd.h #define to_urb(d) container_of(d, struct urb, kref) @@ -11,6 +12,7 @@ static void urb_destroy(struct kref *kref) { struct urb *urb = to_urb(kref); + kfree(urb); } @@ -34,6 +36,7 @@ void usb_init_urb(struct urb *urb) memset(urb, 0, sizeof(*urb)); kref_init(urb-kref); spin_lock_init(urb-lock); + INIT_LIST_HEAD(urb-anchor_list); } } @@ -100,8 +103,60 @@ struct urb * usb_get_urb(struct urb *urb kref_get(urb-kref); return urb; } - - + +/** + * usb_anchor_urb - anchors an URB while it is processed + * @urb: pointer to the urb to anchor + * @anchor: pointer to the anchor + * + * This can be called to have access to URBs which are to be executed + * without bothering to track them + */ + +void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor) +{ + unsigned long flags; + + spin_lock_irqsave(anchor-lock, flags); + usb_get_urb(urb); + list_add_tail(urb-anchor_list, anchor-urb_list); + urb-anchor = anchor; + spin_unlock_irqrestore(anchor-lock, flags); +} + +/** + * usb_unanchor_urb - unanchors an URB + * @urb: pointer to the urb to anchor + * + * Call this to stop the system keeping track of this URB + */ + +void usb_unanchor_urb(struct urb *urb) +{ + unsigned long flags; + struct usb_anchor *anchor; + +
Re: [linux-usb-devel] anchors and their use
On Wed, 23 May 2007, Oliver Neukum wrote: OK, these are fixed and the timeout given in milliseconds, as David recommended. I looked into the inlining issue and the inlined version wins in terms of size. @@ -1270,6 +1287,11 @@ extern struct urb *usb_get_urb(struct ur 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); +extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); +extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); +extern void usb_unanchor_urb(struct urb *urb); +extern int usb_wait_anchor_empty_timeout +(struct usb_anchor *anchor, unsigned long timeout); Suspicious line break. +int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned long timeout) +{ + int res; + + res = wait_event_timeout(anchor-wait, list_empty(anchor-urb_list), timeout * HZ / 1000); What's wrong with msecs_to_jiffies()? Ironically, it wants its argument to be an unsigned int! Alan Stern - 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
Re: [linux-usb-devel] anchors and their use
Am Mittwoch, 23. Mai 2007 17:39 schrieb Alan Stern: On Wed, 23 May 2007, Oliver Neukum wrote: OK, these are fixed and the timeout given in milliseconds, as David recommended. I looked into the inlining issue and the inlined version wins in terms of size. @@ -1270,6 +1287,11 @@ extern struct urb *usb_get_urb(struct ur 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); +extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); +extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); +extern void usb_unanchor_urb(struct urb *urb); +extern int usb_wait_anchor_empty_timeout +(struct usb_anchor *anchor, unsigned long timeout); Suspicious line break. This is what I get when I want to keep the 80 column limit. +int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned long timeout) +{ + int res; + + res = wait_event_timeout(anchor-wait, list_empty(anchor-urb_list), timeout * HZ / 1000); What's wrong with msecs_to_jiffies()? Nothing. The defficiency is my mind and memory. I'll make the change. Regards Oliver - 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
Re: [linux-usb-devel] anchors and their use
On Wed, 23 May 2007, Oliver Neukum wrote: +extern int usb_wait_anchor_empty_timeout +(struct usb_anchor *anchor, unsigned long timeout); Suspicious line break. This is what I get when I want to keep the 80 column limit. I would write it like this: extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, unsigned long timeout); Alan Stern - 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
Re: [linux-usb-devel] anchors and their use
Here we go again. Regards Oliver --- --- a/drivers/usb/core/hcd.c2007-05-22 14:50:32.0 +0200 +++ b/drivers/usb/core/hcd.c2007-05-22 15:36:17.0 +0200 @@ -1412,6 +1412,8 @@ void usb_hcd_giveback_urb (struct usb_hc } usbmon_urb_complete (hcd-self, urb); + usb_unanchor_urb(urb); + /* pass ownership to the completion handler */ urb-complete (urb); atomic_dec (urb-use_count); --- a/include/linux/usb.h 2007-05-22 14:51:01.0 +0200 +++ b/include/linux/usb.h 2007-05-23 18:49:02.0 +0200 @@ -958,11 +958,26 @@ struct usb_iso_packet_descriptor { struct urb; +struct usb_anchor { + struct list_head urb_list; + wait_queue_head_t wait; + spinlock_t lock; +}; + +static inline void init_usb_anchor(struct usb_anchor *anchor) +{ + INIT_LIST_HEAD(anchor-urb_list); + init_waitqueue_head(anchor-wait); + spin_lock_init(anchor-lock); +} + typedef void (*usb_complete_t)(struct urb *); /** * struct urb - USB Request Block * @urb_list: For use by current owner of the URB. + * @anchor_list: membership in the list of an anchor + * @anchor: to anchor URBs to a common mooring * @pipe: Holds endpoint number, direction, type, and more. * Create these values with the eight macros available; * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is ctrl @@ -1135,6 +1150,8 @@ struct urb /* 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 * current owner */ + struct list_head anchor_list; /* the URB may be anchored by the driver */ + struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ unsigned int pipe; /* (in) pipe information */ int status; /* (return) non-ISO status */ @@ -1270,6 +1287,11 @@ extern struct urb *usb_get_urb(struct ur 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); +extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); +extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); +extern void usb_unanchor_urb(struct urb *urb); +extern int usb_wait_anchor_empty_timeout +(struct usb_anchor *anchor, unsigned int timeout); void *usb_buffer_alloc (struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); --- a/drivers/usb/core/urb.c2007-05-22 14:40:12.0 +0200 +++ b/drivers/usb/core/urb.c2007-05-23 18:48:06.0 +0200 @@ -4,6 +4,7 @@ #include linux/slab.h #include linux/init.h #include linux/usb.h +#include linux/wait.h #include hcd.h #define to_urb(d) container_of(d, struct urb, kref) @@ -11,6 +12,7 @@ static void urb_destroy(struct kref *kref) { struct urb *urb = to_urb(kref); + kfree(urb); } @@ -34,6 +36,7 @@ void usb_init_urb(struct urb *urb) memset(urb, 0, sizeof(*urb)); kref_init(urb-kref); spin_lock_init(urb-lock); + INIT_LIST_HEAD(urb-anchor_list); } } @@ -100,8 +103,60 @@ struct urb * usb_get_urb(struct urb *urb kref_get(urb-kref); return urb; } - - + +/** + * usb_anchor_urb - anchors an URB while it is processed + * @urb: pointer to the urb to anchor + * @anchor: pointer to the anchor + * + * This can be called to have access to URBs which are to be executed + * without bothering to track them + */ + +void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor) +{ + unsigned long flags; + + spin_lock_irqsave(anchor-lock, flags); + usb_get_urb(urb); + list_add_tail(urb-anchor_list, anchor-urb_list); + urb-anchor = anchor; + spin_unlock_irqrestore(anchor-lock, flags); +} + +/** + * usb_unanchor_urb - unanchors an URB + * @urb: pointer to the urb to anchor + * + * Call this to stop the system keeping track of this URB + */ + +void usb_unanchor_urb(struct urb *urb) +{ + unsigned long flags; + struct usb_anchor *anchor; + + if (!urb) + return; + + anchor = urb-anchor; + if (!anchor) + return; + + spin_lock_irqsave(anchor-lock, flags); + if (unlikely(anchor != urb-anchor)) { + /* we've lost the race to another thread */ + spin_unlock_irqrestore(anchor-lock, flags); + return; + } + urb-anchor = NULL; + list_del(urb-anchor_list); + spin_unlock_irqrestore(anchor-lock, flags); + usb_put_urb(urb); + if (list_empty(anchor-urb_list)) + wake_up(anchor-wait); +} + /*---*/ /** @@ -477,12 +532,57 @@ void
Re: [linux-usb-devel] anchors and their use
Am Mittwoch, 16. Mai 2007 17:30 schrieb Alan Stern: This won't build because you forgot to export usb_unanchor_urb(). You could make usb_init_anchor() non-inline. I'm not sure where tradeoff lies, but you might be over the limit. I don't like the way you combined the error handling in usb-skeleton with the anchor stuff. Better to keep the two things in separate patches. Hi, I hope this version addresses your concerns Regards Oliver -- --- a/include/linux/usb.h 2007-05-22 14:51:01.0 +0200 +++ b/include/linux/usb.h 2007-05-22 15:36:17.0 +0200 @@ -958,11 +958,26 @@ struct usb_iso_packet_descriptor { struct urb; +struct usb_anchor { + struct list_head urb_list; + wait_queue_head_t wait; + spinlock_t lock; +}; + +static inline void init_usb_anchor(struct usb_anchor *anchor) +{ + INIT_LIST_HEAD(anchor-urb_list); + init_waitqueue_head(anchor-wait); + spin_lock_init(anchor-lock); +} + typedef void (*usb_complete_t)(struct urb *); /** * struct urb - USB Request Block * @urb_list: For use by current owner of the URB. + * @anchor_list: membership in the list of an anchor + * @anchor: to anchor URBs to a common mooring * @pipe: Holds endpoint number, direction, type, and more. * Create these values with the eight macros available; * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is ctrl @@ -1135,6 +1150,8 @@ struct urb /* 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 * current owner */ + struct list_head anchor_list; /* the URB may be anchored by the driver */ + struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ unsigned int pipe; /* (in) pipe information */ int status; /* (return) non-ISO status */ @@ -1270,6 +1287,10 @@ extern struct urb *usb_get_urb(struct ur 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); +extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); +extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); +extern void usb_unanchor_urb(struct urb *urb); +extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, int timeout); void *usb_buffer_alloc (struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); --- a/drivers/usb/core/hcd.c2007-05-22 14:50:32.0 +0200 +++ b/drivers/usb/core/hcd.c2007-05-22 15:36:17.0 +0200 @@ -1412,6 +1412,8 @@ void usb_hcd_giveback_urb (struct usb_hc } usbmon_urb_complete (hcd-self, urb); + usb_unanchor_urb(urb); + /* pass ownership to the completion handler */ urb-complete (urb); atomic_dec (urb-use_count); --- a/drivers/usb/core/urb.c2007-05-22 14:40:12.0 +0200 +++ b/drivers/usb/core/urb.c2007-05-22 15:38:32.0 +0200 @@ -4,6 +4,7 @@ #include linux/slab.h #include linux/init.h #include linux/usb.h +#include linux/wait.h #include hcd.h #define to_urb(d) container_of(d, struct urb, kref) @@ -11,6 +12,7 @@ static void urb_destroy(struct kref *kref) { struct urb *urb = to_urb(kref); + kfree(urb); } @@ -34,6 +36,7 @@ void usb_init_urb(struct urb *urb) memset(urb, 0, sizeof(*urb)); kref_init(urb-kref); spin_lock_init(urb-lock); + INIT_LIST_HEAD(urb-anchor_list); } } @@ -100,8 +103,55 @@ struct urb * usb_get_urb(struct urb *urb kref_get(urb-kref); return urb; } - - + +/** + * usb_anchor_urb - anchors an URB while it is processed + * @urb: pointer to the urb to anchor + * @anchor: pointer to the anchor + * + * This can be called to have access to URBs which are to be executed + * without bothering to track them + */ + +void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor) +{ + unsigned long flags; + + spin_lock_irqsave(anchor-lock, flags); + usb_get_urb(urb); + list_add_tail(urb-anchor_list, anchor-urb_list); + urb-anchor = anchor; + spin_unlock_irqrestore(anchor-lock, flags); +} + +/** + * usb_unanchor_urb - unanchors an URB + * @urb: pointer to the urb to anchor + * + * Call this to stop the system keeping track of this URB + */ + +void usb_unanchor_urb(struct urb *urb) +{ + unsigned long flags; + struct usb_anchor *anchor; + + if (!urb) + return; + + anchor = urb-anchor; + if (!anchor) + return; + + spin_lock_irqsave(anchor-lock, flags); + urb-anchor = NULL; + list_del(urb-anchor_list); + spin_unlock_irqrestore(anchor-lock, flags); +
Re: [linux-usb-devel] anchors and their use
On Tue, 22 May 2007, Oliver Neukum wrote: Am Mittwoch, 16. Mai 2007 17:30 schrieb Alan Stern: This won't build because you forgot to export usb_unanchor_urb(). You could make usb_init_anchor() non-inline. I'm not sure where tradeoff lies, but you might be over the limit. I don't like the way you combined the error handling in usb-skeleton with the anchor stuff. Better to keep the two things in separate patches. Hi, I hope this version addresses your concerns Very good. I did notice two more things: Timeouts are specified in jiffies, so your timeout argument should be long or unsigned long, not int. There's a race if two threads call usb_unanchor_urb() for the same URB at the same time. You need to recheck while holding the anchor's spinlock that urb-anchor is still equal to anchor. You might also want to add WARN_ON(urb-anchor != NULL); to usb_anchor_urb(), just as a precaution. Alan Stern - 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
Re: [linux-usb-devel] anchors and their use
On Tuesday 22 May 2007, Alan Stern wrote: Timeouts are specified in jiffies, so your timeout argument should be long or unsigned long, not int. Timeouts are best specified in milliseconds though... that's been the policy inside the USB stack since someone's search-and-destroy mission a few years back. Most people don't handle jiffies right. - Dave - 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
Re: [linux-usb-devel] anchors and their use
Am Dienstag, 22. Mai 2007 21:48 schrieb David Brownell: On Tuesday 22 May 2007, Alan Stern wrote: Timeouts are specified in jiffies, so your timeout argument should be long or unsigned long, not int. Timeouts are best specified in milliseconds though... that's been the policy inside the USB stack since someone's search-and-destroy mission a few years back. Most people don't handle jiffies right. Very well. I'll go to millisecond specified as unsigned long. Regards Oliver -- SUSE LINUX Products GmbH, GF: Markus Rex, HRB 16746 (AG Nürnberg) This signature is a legal requirement - 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
Re: [linux-usb-devel] anchors and their use
On Mon, 21 May 2007, Oliver Neukum wrote: I don't like the way you combined the error handling in usb-skeleton with the anchor stuff. Better to keep the two things in separate patches. Problems with the packaging or the code? Just the packaging. Alan Stern - 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
Re: [linux-usb-devel] anchors and their use
Am Mittwoch, 16. Mai 2007 17:30 schrieb Alan Stern: On Wed, 16 May 2007, Oliver Neukum wrote: Hi Alan, list, here's the patch to introduce anchors for use with fire-and-forget techniques and a modification for the skeleton driver to use them. This should make implementing pre/post_reset and suspend/resume much easier. This won't build because you forgot to export usb_unanchor_urb(). %$% (censored) I'll redo the patch. It seems like I diffed an old version. You could make usb_init_anchor() non-inline. I'm not sure where tradeoff lies, but you might be over the limit. I'll do test compilations. I don't like the way you combined the error handling in usb-skeleton with the anchor stuff. Better to keep the two things in separate patches. Problems with the packaging or the code? There's no need for the version of skel_draw_down() which acquires the mutex. You use it only in skel_flush(), so you might as well acquire the mutex in the caller. OK. Regards Oliver - 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
[linux-usb-devel] anchors and their use
Hi Alan, list, here's the patch to introduce anchors for use with fire-and-forget techniques and a modification for the skeleton driver to use them. This should make implementing pre/post_reset and suspend/resume much easier. Regards Oliver -- --- a/include/linux/usb.h 2007-05-04 10:50:18.0 +0200 +++ b/include/linux/usb.h 2007-05-08 12:47:27.0 +0200 @@ -958,11 +958,26 @@ struct usb_iso_packet_descriptor { struct urb; +struct usb_anchor { + struct list_head urb_list; + wait_queue_head_t wait; + spinlock_t lock; +}; + +static inline void init_usb_anchor(struct usb_anchor *anchor) +{ + INIT_LIST_HEAD(anchor-urb_list); + init_waitqueue_head(anchor-wait); + spin_lock_init(anchor-lock); +} + typedef void (*usb_complete_t)(struct urb *); /** * struct urb - USB Request Block * @urb_list: For use by current owner of the URB. + * @anchor_list: membership in the list of an anchor + * @anchor: to anchor URBs to a common mooring * @pipe: Holds endpoint number, direction, type, and more. * Create these values with the eight macros available; * usb_{snd,rcv}TYPEpipe(dev,endpoint), where the TYPE is ctrl @@ -1135,6 +1150,8 @@ struct urb /* 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 * current owner */ + struct list_head anchor_list; /* the URB may be anchored by the driver */ + struct usb_anchor *anchor; struct usb_device *dev; /* (in) pointer to associated device */ unsigned int pipe; /* (in) pipe information */ int status; /* (return) non-ISO status */ @@ -1270,6 +1287,10 @@ extern struct urb *usb_get_urb(struct ur 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); +extern void usb_kill_anchored_urbs(struct usb_anchor *anchor); +extern void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor); +extern void usb_unanchor_urb(struct urb *urb); +extern int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor, int timeout); void *usb_buffer_alloc (struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma); --- a/drivers/usb/core/hcd.c2007-05-04 12:04:29.0 +0200 +++ b/drivers/usb/core/hcd.c2007-05-07 15:19:01.0 +0200 @@ -1408,6 +1408,8 @@ void usb_hcd_giveback_urb (struct usb_hc } usbmon_urb_complete (hcd-self, urb); + usb_unanchor_urb(urb); + /* pass ownership to the completion handler */ urb-complete (urb); atomic_dec (urb-use_count); --- a/drivers/usb/core/urb.c2007-05-04 10:53:14.0 +0200 +++ b/drivers/usb/core/urb.c2007-05-16 11:32:15.0 +0200 @@ -4,6 +4,7 @@ #include linux/slab.h #include linux/init.h #include linux/usb.h +#include linux/wait.h #include hcd.h #define to_urb(d) container_of(d, struct urb, kref) @@ -11,6 +12,7 @@ static void urb_destroy(struct kref *kref) { struct urb *urb = to_urb(kref); + kfree(urb); } @@ -34,6 +36,7 @@ void usb_init_urb(struct urb *urb) memset(urb, 0, sizeof(*urb)); kref_init(urb-kref); spin_lock_init(urb-lock); + INIT_LIST_HEAD(urb-anchor_list); } } @@ -100,8 +103,55 @@ struct urb * usb_get_urb(struct urb *urb kref_get(urb-kref); return urb; } - - + +/** + * usb_anchor_urb - anchors an URB while it is processed + * @urb: pointer to the urb to anchor + * @anchor: pointer to the anchor + * + * This can be called to have access to URBs which are to be executed + * without bothering to track them + */ + +void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor) +{ + unsigned long flags; + + spin_lock_irqsave(anchor-lock, flags); + usb_get_urb(urb); + list_add_tail(urb-anchor_list, anchor-urb_list); + urb-anchor = anchor; + spin_unlock_irqrestore(anchor-lock, flags); +} + +/** + * usb_unanchor_urb - unanchors an URB + * @urb: pointer to the urb to anchor + * + * Call this to stop the system keeping track of this URB + */ + +void usb_unanchor_urb(struct urb *urb) +{ + unsigned long flags; + struct usb_anchor *anchor; + + if (!urb) + return; + + anchor = urb-anchor; + if (!anchor) + return; + + spin_lock_irqsave(anchor-lock, flags); + urb-anchor = NULL; + list_del(urb-anchor_list); + spin_unlock_irqrestore(anchor-lock, flags); + usb_put_urb(urb); + if (list_empty(anchor-urb_list)) + wake_up(anchor-wait); +} + /*---*/ /** @@ -477,12 +527,56 @@ void
Re: [linux-usb-devel] anchors and their use
On Wed, 16 May 2007, Oliver Neukum wrote: Hi Alan, list, here's the patch to introduce anchors for use with fire-and-forget techniques and a modification for the skeleton driver to use them. This should make implementing pre/post_reset and suspend/resume much easier. This won't build because you forgot to export usb_unanchor_urb(). You could make usb_init_anchor() non-inline. I'm not sure where tradeoff lies, but you might be over the limit. I don't like the way you combined the error handling in usb-skeleton with the anchor stuff. Better to keep the two things in separate patches. There's no need for the version of skel_draw_down() which acquires the mutex. You use it only in skel_flush(), so you might as well acquire the mutex in the caller. Alan Stern - 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