diff options
author | Jeff Garzik <jeff@garzik.org> | 2006-09-30 23:55:03 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-09-30 23:55:03 -0400 |
commit | e993835441734c184d70d3716eed78a08eeb71c2 (patch) | |
tree | 583aa17813cdae1c4640e353f8c6df3f197e7548 /drivers/usb | |
parent | 360f654e7cda850034f3f6252a7a7cff3fa77356 (diff) | |
parent | 1bdfd554be94def718323659173517c5d4a69d25 (diff) |
Merge branch 'master' into upstream
Diffstat (limited to 'drivers/usb')
33 files changed, 440 insertions, 247 deletions
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c index b1046324441..113e484c763 100644 --- a/drivers/usb/core/driver.c +++ b/drivers/usb/core/driver.c @@ -24,6 +24,7 @@ #include <linux/device.h> #include <linux/usb.h> +#include <linux/workqueue.h> #include "hcd.h" #include "usb.h" @@ -302,11 +303,11 @@ int usb_driver_claim_interface(struct usb_driver *driver, dev->driver = &driver->drvwrap.driver; usb_set_intfdata(iface, priv); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); iface->condition = USB_INTERFACE_BOUND; mark_active(iface); iface->pm_usage_cnt = !(driver->supports_autosuspend); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); /* if interface was already added, bind now; else let * the future device_add() bind it, bypassing probe() @@ -355,11 +356,11 @@ void usb_driver_release_interface(struct usb_driver *driver, dev->driver = NULL; usb_set_intfdata(iface, NULL); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); iface->condition = USB_INTERFACE_UNBOUND; mark_quiesced(iface); iface->needs_remote_wakeup = 0; - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); } EXPORT_SYMBOL(usb_driver_release_interface); @@ -788,7 +789,7 @@ EXPORT_SYMBOL_GPL_FUTURE(usb_deregister); #ifdef CONFIG_PM -/* Caller has locked udev->pm_mutex */ +/* Caller has locked udev's pm_mutex */ static int suspend_device(struct usb_device *udev, pm_message_t msg) { struct usb_device_driver *udriver; @@ -815,7 +816,7 @@ done: return status; } -/* Caller has locked udev->pm_mutex */ +/* Caller has locked udev's pm_mutex */ static int resume_device(struct usb_device *udev) { struct usb_device_driver *udriver; @@ -841,7 +842,7 @@ done: return status; } -/* Caller has locked intf's usb_device's pm_mutex */ +/* Caller has locked intf's usb_device's pm mutex */ static int suspend_interface(struct usb_interface *intf, pm_message_t msg) { struct usb_driver *driver; @@ -1063,7 +1064,7 @@ int usb_resume_both(struct usb_device *udev) /* Propagate the resume up the tree, if necessary */ if (udev->state == USB_STATE_SUSPENDED) { if (parent) { - mutex_lock_nested(&parent->pm_mutex, parent->level); + usb_pm_lock(parent); parent->auto_pm = 1; status = usb_resume_both(parent); } else { @@ -1078,7 +1079,7 @@ int usb_resume_both(struct usb_device *udev) if (status == 0) status = resume_device(udev); if (parent) - mutex_unlock(&parent->pm_mutex); + usb_pm_unlock(parent); } else { /* Needed only for setting udev->dev.power.power_state.event @@ -1103,8 +1104,8 @@ int usb_resume_both(struct usb_device *udev) /** * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces - * @udev - the usb_device to autosuspend - * @dec_usage_cnt - flag to decrement @udev's PM-usage counter + * @udev: the usb_device to autosuspend + * @dec_usage_cnt: flag to decrement @udev's PM-usage counter * * This routine should be called when a core subsystem is finished using * @udev and wants to allow it to autosuspend. Examples would be when @@ -1128,20 +1129,20 @@ int usb_resume_both(struct usb_device *udev) */ void usb_autosuspend_device(struct usb_device *udev, int dec_usage_cnt) { - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->pm_usage_cnt -= dec_usage_cnt; if (udev->pm_usage_cnt <= 0) - schedule_delayed_work(&udev->autosuspend, + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, USB_AUTOSUSPEND_DELAY); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&udev->dev, "%s: cnt %d\n", // __FUNCTION__, udev->pm_usage_cnt); } /** * usb_autoresume_device - immediately autoresume a USB device and its interfaces - * @udev - the usb_device to autoresume - * @inc_usage_cnt - flag to increment @udev's PM-usage counter + * @udev: the usb_device to autoresume + * @inc_usage_cnt: flag to increment @udev's PM-usage counter * * This routine should be called when a core subsystem wants to use @udev * and needs to guarantee that it is not suspended. In addition, the @@ -1167,13 +1168,13 @@ int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt) { int status; - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->pm_usage_cnt += inc_usage_cnt; udev->auto_pm = 1; status = usb_resume_both(udev); if (status != 0) udev->pm_usage_cnt -= inc_usage_cnt; - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&udev->dev, "%s: status %d cnt %d\n", // __FUNCTION__, status, udev->pm_usage_cnt); return status; @@ -1181,7 +1182,7 @@ int usb_autoresume_device(struct usb_device *udev, int inc_usage_cnt) /** * usb_autopm_put_interface - decrement a USB interface's PM-usage counter - * @intf - the usb_interface whose counter should be decremented + * @intf: the usb_interface whose counter should be decremented * * This routine should be called by an interface driver when it is * finished using @intf and wants to allow it to autosuspend. A typical @@ -1214,13 +1215,13 @@ void usb_autopm_put_interface(struct usb_interface *intf) { struct usb_device *udev = interface_to_usbdev(intf); - mutex_lock_nested(&udev->pm_mutex, udev->level); - if (intf->condition != USB_INTERFACE_UNBOUND) { - if (--intf->pm_usage_cnt <= 0) - schedule_delayed_work(&udev->autosuspend, - USB_AUTOSUSPEND_DELAY); + usb_pm_lock(udev); + if (intf->condition != USB_INTERFACE_UNBOUND && + --intf->pm_usage_cnt <= 0) { + queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend, + USB_AUTOSUSPEND_DELAY); } - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&intf->dev, "%s: cnt %d\n", // __FUNCTION__, intf->pm_usage_cnt); } @@ -1228,7 +1229,7 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface); /** * usb_autopm_get_interface - increment a USB interface's PM-usage counter - * @intf - the usb_interface whose counter should be incremented + * @intf: the usb_interface whose counter should be incremented * * This routine should be called by an interface driver when it wants to * use @intf and needs to guarantee that it is not suspended. In addition, @@ -1262,7 +1263,7 @@ int usb_autopm_get_interface(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); int status; - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); if (intf->condition == USB_INTERFACE_UNBOUND) status = -ENODEV; else { @@ -1272,7 +1273,7 @@ int usb_autopm_get_interface(struct usb_interface *intf) if (status != 0) --intf->pm_usage_cnt; } - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); // dev_dbg(&intf->dev, "%s: status %d cnt %d\n", // __FUNCTION__, status, intf->pm_usage_cnt); return status; @@ -1288,10 +1289,10 @@ static int usb_suspend(struct device *dev, pm_message_t message) if (is_usb_device(dev)) { struct usb_device *udev = to_usb_device(dev); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->auto_pm = 0; status = usb_suspend_both(udev, message); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); } else status = 0; return status; @@ -1304,10 +1305,10 @@ static int usb_resume(struct device *dev) if (is_usb_device(dev)) { struct usb_device *udev = to_usb_device(dev); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->auto_pm = 0; status = usb_resume_both(udev); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); /* Rebind drivers that had no suspend method? */ } else diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index e86f6295708..37f9f5e7425 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -345,7 +345,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) struct usb_ctrlrequest *cmd; u16 typeReq, wValue, wIndex, wLength; u8 *ubuf = urb->transfer_buffer; - u8 tbuf [sizeof (struct usb_hub_descriptor)]; + u8 tbuf [sizeof (struct usb_hub_descriptor)] + __attribute__((aligned(4))); const u8 *bufp = tbuf; int len = 0; int patch_wakeup = 0; @@ -835,8 +836,7 @@ void usb_enable_root_hub_irq (struct usb_bus *bus) struct usb_hcd *hcd; hcd = container_of (bus, struct usb_hcd, self); - if (hcd->driver->hub_irq_enable && !hcd->poll_rh && - hcd->state != HC_STATE_HALT) + if (hcd->driver->hub_irq_enable && hcd->state != HC_STATE_HALT) hcd->driver->hub_irq_enable (hcd); } diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 2a8cb3c2b19..7676690a038 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -1779,7 +1779,7 @@ static int remote_wakeup(struct usb_device *udev) * to the parent hub! */ usb_lock_device(udev); - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); /* TRSMRCY = 10 msec */ @@ -1788,7 +1788,7 @@ static int remote_wakeup(struct usb_device *udev) if (status == 0) udev->dev.power.power_state.event = PM_EVENT_ON; } - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); if (status == 0) usb_autoresume_device(udev, 0); diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 60ef4ef0101..e4df9edf1bc 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -33,6 +33,7 @@ #include <linux/smp_lock.h> #include <linux/usb.h> #include <linux/mutex.h> +#include <linux/workqueue.h> #include <asm/io.h> #include <asm/scatterlist.h> @@ -47,6 +48,8 @@ const char *usbcore_name = "usbcore"; static int nousb; /* Disable USB when built into kernel image */ +struct workqueue_struct *ksuspend_usb_wq; /* For autosuspend */ + /** * usb_ifnum_to_if - get the interface object with a given interface number @@ -170,9 +173,9 @@ static void usb_release_dev(struct device *dev) udev = to_usb_device(dev); -#ifdef CONFIG_PM +#ifdef CONFIG_USB_SUSPEND cancel_delayed_work(&udev->autosuspend); - flush_scheduled_work(); + flush_workqueue(ksuspend_usb_wq); #endif usb_destroy_configuration(udev); usb_put_hcd(bus_to_hcd(udev->bus)); @@ -184,17 +187,44 @@ static void usb_release_dev(struct device *dev) #ifdef CONFIG_PM +static int ksuspend_usb_init(void) +{ + ksuspend_usb_wq = create_singlethread_workqueue("ksuspend_usbd"); + if (!ksuspend_usb_wq) + return -ENOMEM; + return 0; +} + +static void ksuspend_usb_cleanup(void) +{ + destroy_workqueue(ksuspend_usb_wq); +} + +#else + +#define ksuspend_usb_init() 0 +#define ksuspend_usb_cleanup() do {} while (0) + +#endif + +#ifdef CONFIG_USB_SUSPEND + /* usb_autosuspend_work - callback routine to autosuspend a USB device */ static void usb_autosuspend_work(void *_udev) { struct usb_device *udev = _udev; - mutex_lock_nested(&udev->pm_mutex, udev->level); + usb_pm_lock(udev); udev->auto_pm = 1; usb_suspend_both(udev, PMSG_SUSPEND); - mutex_unlock(&udev->pm_mutex); + usb_pm_unlock(udev); } +#else + +static void usb_autosuspend_work(void *_udev) +{} + #endif /** @@ -976,9 +1006,12 @@ static int __init usb_init(void) return 0; } + retval = ksuspend_usb_init(); + if (retval) + goto out; retval = bus_register(&usb_bus_type); if (retval) - goto out; + goto bus_register_failed; retval = usb_host_init(); if (retval) goto host_init_failed; @@ -1014,6 +1047,8 @@ major_init_failed: usb_host_cleanup(); host_init_failed: bus_unregister(&usb_bus_type); +bus_register_failed: + ksuspend_usb_cleanup(); out: return retval; } @@ -1035,6 +1070,7 @@ static void __exit usb_exit(void) usb_hub_cleanup(); usb_host_cleanup(); bus_unregister(&usb_bus_type); + ksuspend_usb_cleanup(); } subsys_initcall(usb_init); diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h index 0c09ecced6e..f69df137ec0 100644 --- a/drivers/usb/core/usb.h +++ b/drivers/usb/core/usb.h @@ -36,6 +36,16 @@ extern int usb_resume_both(struct usb_device *udev); extern int usb_port_suspend(struct usb_device *dev); extern int usb_port_resume(struct usb_device *dev); +static inline void usb_pm_lock(struct usb_device *udev) +{ + mutex_lock_nested(&udev->pm_mutex, udev->level); +} + +static inline void usb_pm_unlock(struct usb_device *udev) +{ + mutex_unlock(&udev->pm_mutex); +} + #else #define usb_suspend_both(udev, msg) 0 @@ -45,6 +55,8 @@ static inline int usb_resume_both(struct usb_device *udev) } #define usb_port_suspend(dev) 0 #define usb_port_resume(dev) 0 +static inline void usb_pm_lock(struct usb_device *udev) {} +static inline void usb_pm_unlock(struct usb_device *udev) {} #endif @@ -58,10 +70,15 @@ extern int usb_autoresume_device(struct usb_device *udev, int inc_busy_cnt); #else #define usb_autosuspend_device(udev, dec_busy_cnt) do {} while (0) -#define usb_autoresume_device(udev, inc_busy_cnt) 0 +static inline int usb_autoresume_device(struct usb_device *udev, + int inc_busy_cnt) +{ + return 0; +} #endif +extern struct workqueue_struct *ksuspend_usb_wq; extern struct bus_type usb_bus_type; extern struct usb_device_driver usb_generic_driver; diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index d00958a01cf..77beba485a8 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -1658,7 +1658,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) return -ENODEV; } - if (!request_mem_region(AT91_BASE_UDP, SZ_16K, driver_name)) { + if (!request_mem_region(AT91RM9200_BASE_UDP, SZ_16K, driver_name)) { DBG("someone's using UDC memory\n"); return -EBUSY; } @@ -1720,7 +1720,7 @@ static int __devinit at91udc_probe(struct platform_device *pdev) fail1: device_unregister(&udc->gadget.dev); fail0: - release_mem_region(AT91_BASE_UDP, SZ_16K); + release_mem_region(AT91RM9200_BASE_UDP, SZ_16K); DBG("%s probe failed, %d\n", driver_name, retval); return retval; } @@ -1742,7 +1742,7 @@ static int __devexit at91udc_remove(struct platform_device *pdev) free_irq(udc->board.vbus_pin, udc); free_irq(udc->udp_irq, udc); device_unregister(&udc->gadget.dev); - release_mem_region(AT91_BASE_UDP, SZ_16K); + release_mem_region(AT91RM9200_BASE_UDP, SZ_16K); clk_put(udc->iclk); clk_put(udc->fclk); diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index fdab97a27c0..4d2946e540c 100644 --- a/drivers/usb/gadget/dummy_hcd.c +++ b/drivers/usb/gadget/dummy_hcd.c @@ -816,15 +816,14 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) dum->gadget.dev.driver = &driver->driver; dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", driver->driver.name); - if ((retval = driver->bind (&dum->gadget)) != 0) { - dum->driver = NULL; - dum->gadget.dev.driver = NULL; - return retval; - } + if ((retval = driver->bind (&dum->gadget)) != 0) + goto err_bind_gadget; driver->driver.bus = dum->gadget.dev.parent->bus; - driver_register (&driver->driver); - device_bind_driver (&dum->gadget.dev); + if ((retval = driver_register (&driver->driver)) != 0) + goto err_register; + if ((retval = device_bind_driver (&dum->gadget.dev)) != 0) + goto err_bind_driver; /* khubd will enumerate this in a while */ spin_lock_irq (&dum->lock); @@ -834,6 +833,19 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) usb_hcd_poll_rh_status (dummy_to_hcd (dum)); return 0; + +err_bind_driver: + driver_unregister (&driver->driver); +err_register: + driver->unbind (&dum->gadget); + spin_lock_irq (&dum->lock); + dum->pullup = 0; + set_link_state (dum); + spin_unlock_irq (&dum->lock); +err_bind_gadget: + dum->driver = NULL; + dum->gadget.dev.driver = NULL; + return retval; } EXPORT_SYMBOL (usb_gadget_register_driver); @@ -916,7 +928,9 @@ static int dummy_udc_probe (struct platform_device *pdev) usb_get_hcd (dummy_to_hcd (dum)); platform_set_drvdata (pdev, dum); - device_create_file (&dum->gadget.dev, &dev_attr_function); + rc = device_create_file (&dum->gadget.dev, &dev_attr_function); + if (rc < 0) + device_unregister (&dum->gadget.dev); return rc; } @@ -1864,8 +1878,7 @@ static int dummy_start (struct usb_hcd *hcd) #endif /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ - device_create_file (dummy_dev(dum), &dev_attr_urbs); - return 0; + return device_create_file (dummy_dev(dum), &dev_attr_urbs); } static void dummy_stop (struct usb_hcd *hcd) diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 8d7f1e84cd7..c83d3b6c68f 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c @@ -567,6 +567,7 @@ struct lun { unsigned int ro : 1; unsigned int prevent_medium_removal : 1; unsigned int registered : 1; + unsigned int info_valid : 1; u32 sense_data; u32 sense_data_info; @@ -1656,6 +1657,7 @@ static int do_read(struct fsg_dev *fsg) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; bh->inreq->length = 0; bh->state = BUF_STATE_FULL; break; @@ -1691,6 +1693,7 @@ static int do_read(struct fsg_dev *fsg) if (nread < amount) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } @@ -1785,6 +1788,7 @@ static int do_write(struct fsg_dev *fsg) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data_info = usb_offset >> 9; + curlun->info_valid = 1; continue; } amount -= (amount & 511); @@ -1827,6 +1831,7 @@ static int do_write(struct fsg_dev *fsg) if (bh->outreq->status != 0) { curlun->sense_data = SS_COMMUNICATION_FAILURE; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } @@ -1868,6 +1873,7 @@ static int do_write(struct fsg_dev *fsg) if (nwritten < amount) { curlun->sense_data = SS_WRITE_ERROR; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } @@ -2010,6 +2016,7 @@ static int do_verify(struct fsg_dev *fsg) curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } @@ -2036,6 +2043,7 @@ static int do_verify(struct fsg_dev *fsg) if (nread == 0) { curlun->sense_data = SS_UNRECOVERED_READ_ERROR; curlun->sense_data_info = file_offset >> 9; + curlun->info_valid = 1; break; } file_offset += nread; @@ -2079,6 +2087,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) struct lun *curlun = fsg->curlun; u8 *buf = (u8 *) bh->buf; u32 sd, sdinfo; + int valid; /* * From the SCSI-2 spec., section 7.9 (Unit attention condition): @@ -2106,15 +2115,18 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) fsg->bad_lun_okay = 1; sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; sdinfo = 0; + valid = 0; } else { sd = curlun->sense_data; sdinfo = curlun->sense_data_info; + valid = curlun->info_valid << 7; curlun->sense_data = SS_NO_SENSE; curlun->sense_data_info = 0; + curlun->info_valid = 0; } memset(buf, 0, 18); - buf[0] = 0x80 | 0x70; // Valid, current error + buf[0] = valid | 0x70; // Valid, current error buf[2] = SK(sd); put_be32(&buf[3], sdinfo); // Sense information buf[7] = 18 - 8; // Additional sense length @@ -2703,6 +2715,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size, if (fsg->cmnd[0] != SC_REQUEST_SENSE) { curlun->sense_data = SS_NO_SENSE; curlun->sense_data_info = 0; + curlun->info_valid = 0; } } else { fsg->curlun = curlun = NULL; @@ -3332,6 +3345,7 @@ static void handle_exception(struct fsg_dev *fsg) curlun->sense_data = curlun->unit_attention_data = SS_NO_SENSE; curlun->sense_data_info = 0; + curlun->info_valid = 0; } fsg->state = FSG_STATE_IDLE; } @@ -3873,21 +3887,26 @@ static int __init fsg_bind(struct usb_gadget *gadget) for (i = 0; i < fsg->nluns; ++i) { curlun = &fsg->luns[i]; curlun->ro = mod_data.ro[i]; + curlun->dev.release = lun_release; curlun->dev.parent = &gadget->dev; curlun->dev.driver = &fsg_driver.driver; dev_set_drvdata(&curlun->dev, fsg); snprintf(curlun->dev.bus_id, BUS_ID_SIZE, "%s-lun%d", gadget->dev.bus_id, i); - if ((rc = device_register(&curlun->dev)) != 0) + if ((rc = device_register(&curlun->dev)) != 0) { INFO(fsg, "failed to register LUN%d: %d\n", i, rc); - else { - curlun->registered = 1; - curlun->dev.release = lun_release; - device_create_file(&curlun->dev, &dev_attr_ro); - device_create_file(&curlun->dev, &dev_attr_file); - kref_get(&fsg->ref); + goto out; + } + if ((rc = device_create_file(&curlun->dev, + &dev_attr_ro)) != 0 || + (rc = device_create_file(&curlun->dev, + &dev_attr_file)) != 0) { + device_unregister(&curlun->dev); + goto out; } + curlun->registered = 1; + kref_get(&fsg->ref); if (mod_data.file[i] && *mod_data.file[i]) { if ((rc = open_backing_file(curlun, diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 1027aa04583..d1d68c40225 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -715,17 +715,8 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) return IRQ_NOTMINE; } - /* NOTE: vendors didn't always make the same implementation - * choices for RHSC. Sometimes it triggers on an edge (like - * setting and maybe clearing a port status change bit); and - * it's level-triggered on other silicon, active until khubd - * clears all active port status change bits. Poll by timer - * til it's fully debounced and the difference won't matter. - */ if (ints & OHCI_INTR_RHSC) { ohci_vdbg (ohci, "rhsc\n"); - ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrdisable); - hcd->poll_rh = 1; ohci->next_statechange = jiffies + STATECHANGE_DELAY; ohci_writel (ohci, OHCI_INTR_RHSC, ®s->intrstatus); usb_hcd_poll_rh_status(hcd); @@ -743,13 +734,18 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs) if (ints & OHCI_INTR_RD) { ohci_vdbg (ohci, "resume detect\n"); ohci_writel (ohci, OHCI_INTR_RD, ®s->intrstatus); - if (hcd->state != HC_STATE_QUIESCING) + hcd->poll_rh = 1; + if (ohci->autostop) { + spin_lock (&ohci->lock); + ohci_rh_resume (ohci); + spin_unlock (&ohci->lock); + } else usb_hcd_resume_root_hub(hcd); } if (ints & OHCI_INTR_WDH) { if (HC_IS_RUNNING(hcd->state)) - ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable); + ohci_writel (ohci, OHCI_INTR_WDH, ®s->intrdisable); spin_lock (&ohci->lock); dl_done_list (ohci, ptregs); spin_unlock (&ohci->lock); diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c index 0b899339cac..ec75774abea 100644 --- a/drivers/usb/host/ohci-hub.c +++ b/drivers/usb/host/ohci-hub.c @@ -44,27 +44,17 @@ static void ohci_rhsc_enable (struct usb_hcd *hcd) ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrenable); } -#ifdef CONFIG_PM - #define OHCI_SCHED_ENABLES \ (OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE) static void dl_done_list (struct ohci_hcd *, struct pt_regs *); static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *); -static int ohci_restart (struct ohci_hcd *ohci); -static int ohci_bus_suspend (struct usb_hcd *hcd) +static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop) +__releases(ohci->lock) +__acquires(ohci->lock) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); int status = 0; - unsigned long flags; - - spin_lock_irqsave (&ohci->lock, flags); - - if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { - spin_unlock_irqrestore (&ohci->lock, flags); - return -ESHUTDOWN; - } ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); switch (ohci->hc_control & OHCI_CTRL_HCFS) { @@ -80,15 +70,16 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) ohci_dbg (ohci, "needs reinit!\n"); goto done; case OHCI_USB_SUSPEND: - ohci_dbg (ohci, "already suspended\n"); - goto done; + if (!ohci->autostop) { + ohci_dbg (ohci, "already suspended\n"); + goto done; + } } - ohci_dbg (ohci, "suspend root hub\n"); + ohci_dbg (ohci, "%s root hub\n", + autostop ? "auto-stop" : "suspend"); /* First stop any processing */ - if (ohci->hc_control & OHCI_SCHED_ENABLES) { - int limit; - + if (!autostop && (ohci->hc_control & OHCI_SCHED_ENABLES)) { ohci->hc_control &= ~OHCI_SCHED_ENABLES; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); @@ -98,27 +89,22 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) * then the last WDH could take 6+ msec */ ohci_dbg (ohci, "stopping schedules ...\n"); - limit = 2000; - while (limit > 0) { - udelay (250); - limit =- 250; - if (ohci_readl (ohci, &ohci->regs->intrstatus) - & OHCI_INTR_SF) - break; - } - dl_done_list (ohci, NULL); - mdelay (7); + ohci->autostop = 0; + spin_unlock_irq (&ohci->lock); + msleep (8); + spin_lock_irq (&ohci->lock); } dl_done_list (ohci, NULL); finish_unlinks (ohci, ohci_frame_no(ohci), NULL); - ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), - &ohci->regs->intrstatus); /* maybe resume can wake root hub */ - if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev)) + if (device_may_wakeup(&ohci_to_hcd(ohci)->self.root_hub->dev) || + autostop) ohci->hc_control |= OHCI_CTRL_RWE; - else + else { + ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); ohci->hc_control &= ~OHCI_CTRL_RWE; + } /* Suspend hub ... this is the "global (to this bus) suspend" mode, * which doesn't imply ports will first be individually suspended. @@ -129,13 +115,12 @@ static int ohci_bus_suspend (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); /* no resumes until devices finish suspending */ - ohci->next_statechange = jiffies + msecs_to_jiffies (5); - - /* no timer polling */ - hcd->poll_rh = 0; + if (!autostop) { + ohci->next_statechange = jiffies + msecs_to_jiffies (5); + ohci->autostop = 0; + } done: - spin_unlock_irqrestore (&ohci->lock, flags); return status; } @@ -147,25 +132,19 @@ static inline struct ed *find_head (struct ed *ed) return ed; } +static int ohci_restart (struct ohci_hcd *ohci); + /* caller has locked the root hub */ -static int ohci_bus_resume (struct usb_hcd *hcd) +static int ohci_rh_resume (struct ohci_hcd *ohci) +__releases(ohci->lock) +__acquires(ohci->lock) { - struct ohci_hcd *ohci = hcd_to_ohci (hcd); + struct usb_hcd *hcd = ohci_to_hcd (ohci); u32 temp, enables; int status = -EINPROGRESS; - unsigned long flags; - - if (time_before (jiffies, ohci->next_statechange)) - msleep(5); - - spin_lock_irqsave (&ohci->lock, flags); - - if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) { - spin_unlock_irqrestore (&ohci->lock, flags); - return -ESHUTDOWN; - } - + int autostopped = ohci->autostop; + ohci->autostop = 0; ohci->hc_control = ohci_readl (ohci, &ohci->regs->control); if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { @@ -185,7 +164,8 @@ static int ohci_bus_resume (struct usb_hcd *hcd) ohci->hc_control |= OHCI_USB_RESUME; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); - ohci_dbg (ohci, "resume root hub\n"); + ohci_dbg (ohci, "%s root hub\n", + autostopped ? "auto-start" : "resume"); break; case OHCI_USB_RESUME: /* HCFS changes sometime after INTR_RD */ @@ -200,16 +180,24 @@ static int ohci_bus_resume (struct usb_hcd *hcd) ohci_dbg (ohci, "lost power\n"); status = -EBUSY; } - spin_unlock_irqrestore (&ohci->lock, flags); +#ifdef CONFIG_PM if (status == -EBUSY) { - (void) ohci_init (ohci); - return ohci_restart (ohci); + if (!autostopped) { + spin_unlock_irq (&ohci->lock); + (void) ohci_init (ohci); + status = ohci_restart (ohci); + spin_lock_irq (&ohci->lock); + } + return status; } +#endif if (status != -EINPROGRESS) return status; + if (autostopped) + goto skip_resume; + spin_unlock_irq (&ohci->lock); temp = ohci->num_ports; - enables = 0; while (temp--) { u32 stat = ohci_readl (ohci, &ohci->regs->roothub.portstatus [temp]); @@ -242,17 +230,21 @@ static int ohci_bus_resume (struct usb_hcd *hcd) /* Sometimes PCI D3 suspend trashes frame timings ... */ periodic_reinit (ohci); + /* the following code is executed with ohci->lock held and + * irqs disabled if and only if autostopped is true + */ + +skip_resume: /* interrupts might have been disabled */ ohci_writel (ohci, OHCI_INTR_INIT, &ohci->regs->intrenable); if (ohci->ed_rm_list) ohci_writel (ohci, OHCI_INTR_SF, &ohci->regs->intrenable); - ohci_writel (ohci, ohci_readl (ohci, &ohci->regs->intrstatus), - &ohci->regs->intrstatus); /* Then re-enable operations */ ohci_writel (ohci, OHCI_USB_OPER, &ohci->regs->control); (void) ohci_readl (ohci, &ohci->regs->control); - msleep (3); + if (!autostopped) + msleep (3); temp = ohci->hc_control; temp &= OHCI_CTRL_RWC; @@ -262,7 +254,11 @@ static int ohci_bus_resume (struct usb_hcd *hcd) (void) ohci_readl (ohci, &ohci->regs->control); /* TRSMRCY */ - msleep (10); + if (!autostopped) { + msleep (10); + spin_lock_irq (&ohci->lock); + } + /* now ohci->lock is always held and irqs are always disabled */ /* keep it alive for more than ~5x suspend + resume costs */ ohci->next_statechange = jiffies + STATECHANGE_DELAY; @@ -299,6 +295,45 @@ static int ohci_bus_resume (struct usb_hcd *hcd) return 0; } +#ifdef CONFIG_PM + +static int ohci_bus_suspend (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int rc; + + spin_lock_irq (&ohci->lock); + + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) + rc = -ESHUTDOWN; + else + rc = ohci_rh_suspend (ohci, 0); + spin_unlock_irq (&ohci->lock); + return rc; +} + +static int ohci_bus_resume (struct usb_hcd *hcd) +{ + struct ohci_hcd *ohci = hcd_to_ohci (hcd); + int rc; + + if (time_before (jiffies, ohci->next_statechange)) + msleep(5); + + spin_lock_irq (&ohci->lock); + + if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))) + rc = -ESHUTDOWN; + else + rc = ohci_rh_resume (ohci); + spin_unlock_irq (&ohci->lock); + + /* poll until we know a device is connected or we autostop */ + if (rc == 0) + usb_hcd_poll_rh_status(hcd); + return rc; +} + #endif /* CONFIG_PM */ /*-------------------------------------------------------------------------*/ @@ -310,21 +345,11 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) { struct ohci_hcd *ohci = hcd_to_ohci (hcd); int i, changed = 0, length = 1; - int can_suspend; + int any_connected = 0, rhsc_enabled = 1; unsigned long flags; - can_suspend = device_may_wakeup(&hcd->self.root_hub->dev); spin_lock_irqsave (&ohci->lock, flags); - /* handle autosuspended root: finish resuming before - * letting khubd or root hub timer see state changes. - */ - if (unlikely((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER - || !HC_IS_RUNNING(hcd->state))) { - can_suspend = 0; - goto done; - } - /* undocumented erratum seen on at least rev D */ if ((ohci->flags & OHCI_QUIRK_AMD756) && (roothub_a (ohci) & RH_A_NDP) > MAX_ROOT_PORTS) { @@ -348,9 +373,8 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) for (i = 0; i < ohci->num_ports; i++) { u32 status = roothub_portstatus (ohci, i); - /* can't autosuspend with active ports */ - if ((status & RH_PS_PES) && !(status & RH_PS_PSS)) - can_suspend = 0; + /* can't autostop if ports are connected */ + any_connected |= (status & RH_PS_CCS); if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC | RH_PS_OCIC | RH_PS_PRSC)) { @@ -359,49 +383,73 @@ ohci_hub_status_data (struct usb_hcd *hcd, char *buf) buf [0] |= 1 << (i + 1); else buf [1] |= 1 << (i - 7); - continue; } } - /* after root hub changes, stop polling after debouncing - * for a while and maybe kicking in autosuspend + /* NOTE: vendors didn't always make the same implementation + * choices for RHSC. Sometimes it triggers on an edge (like + * setting and maybe clearing a port status change bit); and + * it's level-triggered on other silicon, active until khubd + * clears all active port status change bits. If it's still + * set (level-triggered) we must disable it and rely on + * polling until khubd re-enables it. */ - if (changed) { - ohci->next_statechange = jiffies + STATECHANGE_DELAY; - can_suspend = 0; - } else if (time_before (jiffies, ohci->next_statechange)) { - can_suspend = 0; - } else { -#ifdef CONFIG_PM - can_suspend = can_suspend - && !ohci->ed_rm_list - && ((OHCI_CTRL_HCFS | OHCI_SCHED_ENABLES) - & ohci->hc_control) - == OHCI_USB_OPER; -#endif - if (hcd->uses_new_polling) { + if (ohci_readl (ohci, &ohci->regs->intrstatus) & OHCI_INTR_RHSC) { + ohci_writel (ohci, OHCI_INTR_RHSC, &ohci->regs->intrdisable); + (void) ohci_readl (ohci, &ohci->regs->intrdisable); + rhsc_enabled = 0; + } + hcd->poll_rh = 1; + + /* carry out appropriate state changes */ + switch (ohci->hc_control & OHCI_CTRL_HCFS) { + + case OHCI_USB_OPER: + /* keep on polling until we know a device is connected + * and RHSC is enabled */ + if (!ohci->autostop) { + if (any_connected) { + if (rhsc_enabled) + hcd->poll_rh = 0; + } else { + ohci->autostop = 1; + ohci->next_statechange = jiffies + HZ; + } + + /* if no devices have been attached for one second, autostop */ + } else { + if (changed || any_connected) { + ohci->autostop = 0; + ohci->next_statechange = jiffies + + STATECHANGE_DELAY; + } else if (time_after_eq (jiffies, + ohci->next_statechange) + && !ohci->ed_rm_list + && !(ohci->hc_control & + OHCI_SCHED_ENABLES)) { + ohci_rh_suspend (ohci, 1); + } + } + break; + + /* if there is a port change, autostart or ask to be resumed */ + case OHCI_USB_SUSPEND: + case OHCI_USB_RESUME: + if (changed) { + if (ohci->autostop) + ohci_rh_resume (ohci); + else + usb_hcd_resume_root_hub (hcd); + } else { + /* everything is idle, no need for polling */ hcd->poll_rh = 0; - /* use INTR_RHSC iff INTR_RD won't apply */ - if (!can_suspend) - ohci_writel (ohci, OHCI_INTR_RHSC, - &ohci->regs->intrenable); } + break; } done: spin_unlock_irqrestore (&ohci->lock, flags); -#ifdef CONFIG_PM - /* save power by autosuspending idle root hubs; - * INTR_RD wakes us when there's work - */ - if (can_suspend && usb_trylock_device (hcd->self.root_hub) == 0) { - ohci_vdbg (ohci, "autosuspend\n"); - (void) ohci_bus_suspend (hcd); - usb_unlock_device (hcd->self.root_hub); - } -#endif - return changed ? length : 0; } @@ -572,9 +620,6 @@ static int ohci_hub_control ( break; case USB_PORT_FEAT_SUSPEND: temp = RH_PS_POCI; - if ((ohci->hc_control & OHCI_CTRL_HCFS) - != OHCI_USB_OPER) - usb_hcd_resume_root_hub(hcd); break; case USB_PORT_FEAT_C_SUSPEND: temp = RH_PS_PSSC; diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c index 3732db7d68e..87441855278 100644 --- a/drivers/usb/host/ohci-pci.c +++ b/drivers/usb/host/ohci-pci.c @@ -73,13 +73,14 @@ ohci_pci_start (struct usb_hcd *hcd) else if (pdev->vendor == PCI_VENDOR_ID_NS) { struct pci_dev *b; - b = pci_find_slot (pdev->bus->number, + b = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1)); if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO && b->vendor == PCI_VENDOR_ID_NS) { ohci->flags |= OHCI_QUIRK_SUPERIO; ohci_dbg (ohci, "Using NSC SuperIO setup\n"); } + pci_dev_put(b); } /* Check for Compaq's ZFMicro chipset, which needs short diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h index 93fdc3c3534..a2f42a2f47c 100644 --- a/drivers/usb/host/ohci.h +++ b/drivers/usb/host/ohci.h @@ -388,6 +388,7 @@ struct ohci_hcd { u32 hc_control; /* copy of hc control reg */ unsigned long next_statechange; /* suspend/resume */ u32 fminterval; /* saved register */ + unsigned autostop:1; /* rh auto stopping/stopped */ unsigned long flags; /* for HC bugs */ #define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */ diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c index b2bafc37c41..5f861331932 100644 --- a/drivers/usb/image/microtek.c +++ b/drivers/usb/image/microtek.c @@ -225,7 +225,7 @@ static inline void mts_debug_dump(struct mts_desc* desc) { } -static inline void mts_show_command(Scsi_Cmnd *srb) +static inline void mts_show_command(struct scsi_cmnd *srb) { char *what = NULL; @@ -309,7 +309,7 @@ static inline void mts_show_command(Scsi_Cmnd *srb) #else -static inline void mts_show_command(Scsi_Cmnd * dummy) +static inline void mts_show_command(struct scsi_cmnd * dummy) { } @@ -338,7 +338,7 @@ static int mts_slave_configure (struct scsi_device *s) return 0; } -static int mts_scsi_abort (Scsi_Cmnd *srb) +static int mts_scsi_abort(struct scsi_cmnd *srb) { struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); @@ -349,7 +349,7 @@ static int mts_scsi_abort (Scsi_Cmnd *srb) return FAILED; } -static int mts_scsi_host_reset (Scsi_Cmnd *srb) +static int mts_scsi_host_reset(struct scsi_cmnd *srb) { struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); int result, rc; @@ -366,8 +366,8 @@ static int mts_scsi_host_reset (Scsi_Cmnd *srb) return result ? FAILED : SUCCESS; } -static -int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback ); +static int +mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback); static void mts_transfer_cleanup( struct urb *transfer ); static void mts_do_sg(struct urb * transfer, struct pt_regs *regs); @@ -537,7 +537,7 @@ static const unsigned char mts_direction[256/8] = { #define MTS_DIRECTION_IS_IN(x) ((mts_direction[x>>3] >> (x & 7)) & 1) static void -mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc ) +mts_build_transfer_context(struct scsi_cmnd *srb, struct mts_desc* desc) { int pipe; struct scatterlist * sg; @@ -588,8 +588,8 @@ mts_build_transfer_context( Scsi_Cmnd *srb, struct mts_desc* desc ) } -static -int mts_scsi_queuecommand( Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback ) +static int +mts_scsi_queuecommand(struct scsi_cmnd *srb, mts_scsi_cmnd_callback callback) { struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); int err = 0; diff --git a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h index 926d4bdc674..d5d62a93905 100644 --- a/drivers/usb/image/microtek.h +++ b/drivers/usb/image/microtek.h @@ -8,14 +8,14 @@ * */ -typedef void (*mts_scsi_cmnd_callback)(Scsi_Cmnd *); +typedef void (*mts_scsi_cmnd_callback)(struct scsi_cmnd *); struct mts_transfer_context { struct mts_desc* instance; mts_scsi_cmnd_callback final_callback; - Scsi_Cmnd *srb; + struct scsi_cmnd *srb; void* data; unsigned data_length; diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c index 2a3e9e9b4b3..81b1ea01a17 100644 --- a/drivers/usb/input/hid-core.c +++ b/drivers/usb/input/hid-core.c @@ -1600,6 +1600,9 @@ void hid_init_reports(struct hid_device *hid) #define USB_VENDOR_ID_ALCOR 0x058f #define USB_DEVICE_ID_ALCOR_USBRS232 0x9720 +#define USB_VENDOR_ID_SUN 0x0430 +#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab + /* * Alphabetically sorted blacklist by quirk type. */ @@ -1729,6 +1732,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, diff --git a/drivers/usb/misc/phidgetkit.c b/drivers/usb/misc/phidgetkit.c index 9a8d137d39f..78e419904ab 100644 --- a/drivers/usb/misc/phidgetkit.c +++ b/drivers/usb/misc/phidgetkit.c @@ -44,20 +44,25 @@ struct driver_interfacekit { int inputs; int outputs; int has_lcd; + int amnesiac; }; -#define ifkit(_sensors, _inputs, _outputs, _lcd) \ -static struct driver_interfacekit ph_##_sensors##_inputs##_outputs = { \ + +#define ifkit(_sensors, _inputs, _outputs, _lcd, _amnesiac) \ +{ \ .sensors = _sensors, \ .inputs = _inputs, \ .outputs = _outputs, \ .has_lcd = _lcd, \ + .amnesiac = _amnesiac \ }; -ifkit(0, 0, 4, 0); -ifkit(8, 8, 8, 0); -ifkit(0, 4, 7, 1); -ifkit(8, 8, 4, 0); -ifkit(0, 8, 8, 1); -ifkit(0, 16, 16, 0); + +static const struct driver_interfacekit ph_004 = ifkit(0, 0, 4, 0, 0); +static const struct driver_interfacekit ph_888n = ifkit(8, 8, 8, 0, 1); +static const struct driver_interfacekit ph_888o = ifkit(8, 8, 8, 0, 0); +static const struct driver_interfacekit ph_047 = ifkit(0, 4, 7, 1, 0); +static const struct driver_interfacekit ph_884 = ifkit(8, 8, 4, 0, 0); +static const struct driver_interfacekit ph_088 = ifkit(0, 8, 8, 1, 0); +static const struct driver_interfacekit ph_01616 = ifkit(0, 16, 16, 0, 0); static unsigned long device_no; @@ -77,6 +82,7 @@ struct interfacekit { dma_addr_t data_dma; struct work_struct do_notify; + struct work_struct do_resubmit; unsigned long input_events; unsigned long sensor_events; }; @@ -84,8 +90,10 @@ struct interfacekit { static struct usb_device_id id_table[] = { {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT004), .driver_info = (kernel_ulong_t)&ph_004}, - {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888), - .driver_info = (kernel_ulong_t)&ph_888}, + {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0, 0x814), + .driver_info = (kernel_ulong_t)&ph_888o}, + {USB_DEVICE_VER(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT888, 0x0815, 0xffff), + .driver_info = (kernel_ulong_t)&ph_888n}, {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT047), .driver_info = (kernel_ulong_t)&ph_047}, {USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_INTERFACEKIT088), @@ -98,16 +106,11 @@ static struct usb_device_id id_table[] = { }; MODULE_DEVICE_TABLE(usb, id_table); -static int change_outputs(struct interfacekit *kit, int output_num, int enable) +static int set_outputs(struct interfacekit *kit) { u8 *buffer; int retval; - if (enable) - set_bit(output_num, &kit->outputs); - else - clear_bit(output_num, &kit->outputs); - buffer = kzalloc(4, GFP_KERNEL); if (!buffer) { dev_err(&kit->udev->dev, "%s - out of memory\n", __FUNCTION__); @@ -127,6 +130,9 @@ static int change_outputs(struct interfacekit *kit, int output_num, int enable) retval); kfree(buffer); + if (kit->ifkit->amnesiac) + schedule_delayed_work(&kit->do_resubmit, HZ / 2); + return retval < 0 ? retval : 0; } @@ -399,19 +405,29 @@ static void do_notify(void *data) } } +static void do_resubmit(void *data) +{ + set_outputs(data); +} + #define show_set_output(value) \ static ssize_t set_output##value(struct device *dev, \ struct device_attribute *attr, \ const char *buf, size_t count) \ { \ struct interfacekit *kit = dev_get_drvdata(dev); \ - int enabled; \ + int enable; \ int retval; \ \ - if (sscanf(buf, "%d", &enabled) < 1) \ + if (sscanf(buf, "%d", &enable) < 1) \ return -EINVAL; \ \ - retval = change_outputs(kit, value - 1, enabled); \ + if (enable) \ + set_bit(value - 1, &kit->outputs); \ + else \ + clear_bit(value - 1, &kit->outputs); \ + \ + retval = set_outputs(kit); \ \ return retval ? retval : count; \ } \ @@ -560,6 +576,7 @@ static int interfacekit_probe(struct usb_interface *intf, const struct usb_devic kit->udev = usb_get_dev(dev); kit->intf = intf; INIT_WORK(&kit->do_notify, do_notify, kit); + INIT_WORK(&kit->do_resubmit, do_resubmit, kit); usb_fill_int_urb(kit->irq, kit->udev, pipe, kit->data, maxp > URB_INT_SIZE ? URB_INT_SIZE : maxp, interfacekit_irq, kit, endpoint->bInterval); @@ -663,6 +680,7 @@ static void interfacekit_disconnect(struct usb_interface *interface) usb_buffer_free(kit->udev, URB_INT_SIZE, kit->data, kit->data_dma); cancel_delayed_work(&kit->do_notify); + cancel_delayed_work(&kit->do_resubmit); for (i=0; i<kit->ifkit->outputs; i++) device_remove_file(kit->dev, &dev_output_attrs[i]); diff --git a/drivers/usb/net/asix.c b/drivers/usb/net/asix.c index 9b97aa6384c..9c0eacf7055 100644 --- a/drivers/usb/net/asix.c +++ b/drivers/usb/net/asix.c @@ -1456,6 +1456,10 @@ static const struct usb_device_id products [] = { USB_DEVICE (0x07d1, 0x3c05), .driver_info = (unsigned long) &ax88772_info, }, { + // DLink DUB-E100 H/W Ver B1 Alternate + USB_DEVICE (0x2001, 0x3c05), + .driver_info = (unsigned long) &ax88772_info, +}, { // Linksys USB1000 USB_DEVICE (0x1737, 0x0039), .driver_info = (unsigned long) &ax88178_info, diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c index def3bb8e229..544d41fe9b9 100644 --- a/drivers/usb/net/kaweth.c +++ b/drivers/usb/net/kaweth.c @@ -165,6 +165,7 @@ static struct usb_device_id usb_klsi_table[] = { { USB_DEVICE(0x1645, 0x0005) }, /* Entrega E45 */ { USB_DEVICE(0x1645, 0x0008) }, /* Entrega USB Ethernet Adapter */ { USB_DEVICE(0x1645, 0x8005) }, /* PortGear Ethernet Adapter */ + { USB_DEVICE(0x1668, 0x0323) }, /* Actiontec USB Ethernet */ { USB_DEVICE(0x2001, 0x4000) }, /* D-link DSB-650C */ {} /* Null terminator */ }; diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c index b8e25af13f0..918cf5a77c0 100644 --- a/drivers/usb/net/pegasus.c +++ b/drivers/usb/net/pegasus.c @@ -45,7 +45,7 @@ /* * Version Information */ -#define DRIVER_VERSION "v0.6.13 (2005/11/13)" +#define DRIVER_VERSION "v0.6.14 (2006/09/27)" #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>" #define DRIVER_DESC "Pegasus/Pegasus II USB Ethernet driver" @@ -339,7 +339,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd) } fail: if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); + dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); return ret; } @@ -376,7 +376,7 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd) fail: if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); + dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); return -ETIMEDOUT; } @@ -413,7 +413,7 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata) fail: if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); + dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); return -ETIMEDOUT; } @@ -461,7 +461,7 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data) return ret; fail: if (netif_msg_drv(pegasus)) - dev_warn(&pegasus->intf->dev, "fail %s\n", __FUNCTION__); + dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__); return -ETIMEDOUT; } #endif /* PEGASUS_WRITE_EEPROM */ @@ -481,8 +481,12 @@ static void set_ethernet_addr(pegasus_t * pegasus) { __u8 node_id[6]; - get_node_id(pegasus, node_id); - set_registers(pegasus, EthID, sizeof (node_id), node_id); + if (pegasus->features & PEGASUS_II) { + get_registers(pegasus, 0x10, sizeof(node_id), node_id); + } else { + get_node_id(pegasus, node_id); + set_registers(pegasus, EthID, sizeof (node_id), node_id); + } memcpy(pegasus->net->dev_addr, node_id, sizeof (node_id)); } diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c index 6286aba86fa..d954ec34b01 100644 --- a/drivers/usb/serial/cyberjack.c +++ b/drivers/usb/serial/cyberjack.c @@ -214,14 +214,14 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b return (0); } - spin_lock(&port->lock); + spin_lock_bh(&port->lock); if (port->write_urb_busy) { - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); dbg("%s - already writing", __FUNCTION__); return 0; } port->write_urb_busy = 1; - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c index 1f7b72553f3..e774a27c6c9 100644 --- a/drivers/usb/serial/ftdi_sio.c +++ b/drivers/usb/serial/ftdi_sio.c @@ -344,6 +344,7 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2103_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2104_PID) }, + { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2106_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_1_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2201_2_PID) }, { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2202_1_PID) }, @@ -507,6 +508,9 @@ static struct usb_device_id id_table_combined [] = { { USB_DEVICE(FTDI_VID, FTDI_THORLABS_PID) }, { USB_DEVICE(TESTO_VID, TESTO_USB_INTERFACE_PID) }, { USB_DEVICE(FTDI_VID, FTDI_GAMMA_SCOUT_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13M_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13S_PID) }, + { USB_DEVICE(FTDI_VID, FTDI_TACTRIX_OPENPORT_13U_PID) }, { }, /* Optional parameter entry */ { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h index 77299996f7e..f0edb87d2dd 100644 --- a/drivers/usb/serial/ftdi_sio.h +++ b/drivers/usb/serial/ftdi_sio.h @@ -111,6 +111,7 @@ #define SEALEVEL_2102_PID 0x2102 /* SeaLINK+485 (2102) */ #define SEALEVEL_2103_PID 0x2103 /* SeaLINK+232I (2103) */ #define SEALEVEL_2104_PID 0x2104 /* SeaLINK+485I (2104) */ +#define SEALEVEL_2106_PID 0x9020 /* SeaLINK+422 (2106) */ #define SEALEVEL_2201_1_PID 0x2211 /* SeaPORT+2/232 (2201) Port 1 */ #define SEALEVEL_2201_2_PID 0x2221 /* SeaPORT+2/232 (2201) Port 2 */ #define SEALEVEL_2202_1_PID 0x2212 /* SeaPORT+2/485 (2202) Port 1 */ @@ -472,6 +473,15 @@ */ #define FTDI_GAMMA_SCOUT_PID 0xD678 /* Gamma Scout online */ +/* + * Tactrix OpenPort (ECU) devices. + * OpenPort 1.3M submitted by Donour Sizemore. + * OpenPort 1.3S and 1.3U submitted by Ian Abbott. + */ +#define FTDI_TACTRIX_OPENPORT_13M_PID 0xCC48 /* OpenPort 1.3 Mitsubishi */ +#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */ +#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */ + /* Commands */ #define FTDI_SIO_RESET 0 /* Reset the port */ #define FTDI_SIO_MODEM_CTRL 1 /* Set the modem control register */ diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c index 17271355639..21cbaa0fb96 100644 --- a/drivers/usb/serial/generic.c +++ b/drivers/usb/serial/generic.c @@ -175,14 +175,14 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char * /* only do something if we have a bulk out endpoint */ if (serial->num_bulk_out) { - spin_lock(&port->lock); + spin_lock_bh(&port->lock); if (port->write_urb_busy) { - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); dbg("%s - already writing", __FUNCTION__); return 0; } port->write_urb_busy = 1; - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); count = (count > port->bulk_out_size) ? port->bulk_out_size : count; diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c index bfc6998cd16..cbc725a6c58 100644 --- a/drivers/usb/serial/ipaq.c +++ b/drivers/usb/serial/ipaq.c @@ -479,6 +479,7 @@ static struct usb_device_id ipaq_id_table [] = { { USB_DEVICE(0x0BB4, 0x0A9D) }, /* SmartPhone USB Sync */ { USB_DEVICE(0x0BB4, 0x0A9E) }, /* SmartPhone USB Sync */ { USB_DEVICE(0x0BB4, 0x0A9F) }, /* SmartPhone USB Sync */ + { USB_DEVICE(0x0BB4, 0x0BCE) }, /* "High Tech Computer Corp" */ { USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */ { USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */ { USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */ diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c index 87306cb6f9f..812bc213a96 100644 --- a/drivers/usb/serial/ipw.c +++ b/drivers/usb/serial/ipw.c @@ -394,14 +394,14 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int return 0; } - spin_lock(&port->lock); + spin_lock_bh(&port->lock); if (port->write_urb_busy) { - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); dbg("%s - already writing", __FUNCTION__); return 0; } port->write_urb_busy = 1; - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); count = min(count, port->bulk_out_size); memcpy(port->bulk_out_buffer, buf, count); diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c index 1738b0b6a37..1b348df388e 100644 --- a/drivers/usb/serial/ir-usb.c +++ b/drivers/usb/serial/ir-usb.c @@ -342,14 +342,14 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int if (count == 0) return 0; - spin_lock(&port->lock); + spin_lock_bh(&port->lock); if (port->write_urb_busy) { - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); dbg("%s - already writing", __FUNCTION__); return 0; } port->write_urb_busy = 1; - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); transfer_buffer = port->write_urb->transfer_buffer; transfer_size = min(count, port->bulk_out_size - 1); diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c index 49b8dc039d1..59e777f1e8f 100644 --- a/drivers/usb/serial/keyspan_pda.c +++ b/drivers/usb/serial/keyspan_pda.c @@ -518,13 +518,13 @@ static int keyspan_pda_write(struct usb_serial_port *port, the TX urb is in-flight (wait until it completes) the device is full (wait until it says there is room) */ - spin_lock(&port->lock); + spin_lock_bh(&port->lock); if (port->write_urb_busy || priv->tx_throttled) { - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); return 0; } port->write_urb_busy = 1; - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); /* At this point the URB is in our control, nobody else can submit it again (the only sudden transition was the one from EINPROGRESS to diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c index e49f40913c2..a764ff4e326 100644 --- a/drivers/usb/serial/omninet.c +++ b/drivers/usb/serial/omninet.c @@ -256,14 +256,14 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf return (0); } - spin_lock(&wport->lock); + spin_lock_bh(&wport->lock); if (wport->write_urb_busy) { - spin_unlock(&wport->lock); + spin_unlock_bh(&wport->lock); dbg("%s - already writing", __FUNCTION__); return 0; } wport->write_urb_busy = 1; - spin_unlock(&wport->lock); + spin_unlock_bh(&wport->lock); count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c index 1036d436ed2..9c18173e33f 100644 --- a/drivers/usb/serial/pl2303.c +++ b/drivers/usb/serial/pl2303.c @@ -82,6 +82,7 @@ static struct usb_device_id id_table [] = { { USB_DEVICE(DATAPILOT_U2_VENDOR_ID, DATAPILOT_U2_PRODUCT_ID) }, { USB_DEVICE(BELKIN_VENDOR_ID, BELKIN_PRODUCT_ID) }, { USB_DEVICE(ALCOR_VENDOR_ID, ALCOR_PRODUCT_ID) }, + { USB_DEVICE(HUAWEI_VENDOR_ID, HUAWEI_PRODUCT_ID) }, { } /* Terminating entry */ }; diff --git a/drivers/usb/serial/pl2303.h b/drivers/usb/serial/pl2303.h index 762cc290ef5..65a5039665e 100644 --- a/drivers/usb/serial/pl2303.h +++ b/drivers/usb/serial/pl2303.h @@ -93,3 +93,7 @@ /* Alcor Micro Corp. USB 2.0 TO RS-232 */ #define ALCOR_VENDOR_ID 0x058F #define ALCOR_PRODUCT_ID 0x9720 + +/* Huawei E620 UMTS/HSDPA card (ID: 12d1:1001) */ +#define HUAWEI_VENDOR_ID 0x12d1 +#define HUAWEI_PRODUCT_ID 0x1001 diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c index 789771ecdb1..1e07dfad685 100644 --- a/drivers/usb/serial/safe_serial.c +++ b/drivers/usb/serial/safe_serial.c @@ -298,14 +298,14 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i dbg ("%s - write request of 0 bytes", __FUNCTION__); return (0); } - spin_lock(&port->lock); + spin_lock_bh(&port->lock); if (port->write_urb_busy) { - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); dbg("%s - already writing", __FUNCTION__); return 0; } port->write_urb_busy = 1; - spin_unlock(&port->lock); + spin_unlock_bh(&port->lock); packet_length = port->bulk_out_size; // get max packetsize diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig index 86e48c42d6a..422a4b288e3 100644 --- a/drivers/usb/storage/Kconfig +++ b/drivers/usb/storage/Kconfig @@ -8,8 +8,7 @@ comment "may also be needed; see USB_STORAGE Help for more information" config USB_STORAGE tristate "USB Mass Storage support" - depends on USB - select SCSI + depends on USB && SCSI ---help--- Say Y here if you want to connect USB mass storage devices to your computer's USB port. This is the driver you need for USB @@ -18,7 +17,7 @@ config USB_STORAGE similar devices. This driver may also be used for some cameras and card readers. - This option 'selects' (turns on, enables) 'SCSI', but you + This option depends on 'SCSI' support being enabled, but you probably also need 'SCSI device support: SCSI disk support' (BLK_DEV_SD) for most USB storage devices. diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h index 40bf159f7d5..c9a8d50106d 100644 --- a/drivers/usb/storage/unusual_devs.h +++ b/drivers/usb/storage/unusual_devs.h @@ -152,6 +152,13 @@ UNUSUAL_DEV( 0x0421, 0x042e, 0x0100, 0x0100, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_IGNORE_RESIDUE | US_FL_FIX_CAPACITY ), +/* Reported by Jon Hart <Jon.Hart@web.de> */ +UNUSUAL_DEV( 0x0421, 0x0434, 0x0100, 0x0100, + "Nokia", + "E60", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY | US_FL_IGNORE_RESIDUE ), + /* Reported by Sumedha Swamy <sumedhaswamy@gmail.com> and * Einar Th. Einarsson <einarthered@gmail.com> */ UNUSUAL_DEV( 0x0421, 0x0444, 0x0100, 0x0100, @@ -1277,6 +1284,13 @@ UNUSUAL_DEV( 0x0fce, 0xe031, 0x0000, 0x0000, US_SC_DEVICE, US_PR_DEVICE, NULL, US_FL_FIX_CAPACITY ), +/* Reported by Jan Mate <mate@fiit.stuba.sk> */ +UNUSUAL_DEV( 0x0fce, 0xe030, 0x0000, 0x0000, + "Sony Ericsson", + "P990i", + US_SC_DEVICE, US_PR_DEVICE, NULL, + US_FL_FIX_CAPACITY ), + /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu> * Tested on hardware version 1.10. * Entry is needed only for the initializer function override. |