summaryrefslogtreecommitdiffstats
path: root/drivers/usb/uhci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/uhci.c')
-rw-r--r--drivers/usb/uhci.c174
1 files changed, 83 insertions, 91 deletions
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index 0a0d32f69..40cf2f746 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -2,12 +2,16 @@
* Universal Host Controller Interface driver for USB.
*
* (C) Copyright 1999 Linus Torvalds
- * (C) Copyright 1999-2000 Johannes Erdfelt, jerdfelt@sventech.com
+ * (C) Copyright 1999-2000 Johannes Erdfelt, johannes@erdfelt.com
* (C) Copyright 1999 Randy Dunlap
* (C) Copyright 1999 Georg Acher, acher@in.tum.de
* (C) Copyright 1999 Deti Fliegl, deti@fliegl.de
* (C) Copyright 1999 Thomas Sailer, sailer@ife.ee.ethz.ch
* (C) Copyright 1999 Roman Weissgaerber, weissg@vienna.at
+ * (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
+ * support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
+ * (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
+ *
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
@@ -21,6 +25,7 @@
* - working around the horridness of the rest
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
@@ -46,7 +51,6 @@
#include "uhci-debug.h"
#include <linux/pm.h>
-static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data);
static int debug = 1;
MODULE_PARM(debug, "i");
@@ -56,8 +60,6 @@ static kmem_cache_t *uhci_td_cachep;
static kmem_cache_t *uhci_qh_cachep;
static kmem_cache_t *uhci_up_cachep; /* urb_priv */
-static LIST_HEAD(uhci_list);
-
static int rh_submit_urb(struct urb *urb);
static int rh_unlink_urb(struct urb *urb);
static int uhci_get_current_frame_number(struct usb_device *dev);
@@ -1753,11 +1755,11 @@ static void rh_int_timer_do(unsigned long ptr)
urbp = (struct urb_priv *)u->hcpriv;
if (urbp) {
/* Check if the FSBR timed out */
- if (urbp->fsbr && time_after(urbp->inserttime + IDLE_TIMEOUT, jiffies))
+ if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT))
uhci_fsbr_timeout(uhci, u);
/* Check if the URB timed out */
- if (u->timeout && time_after(u->timeout, jiffies)) {
+ if (u->timeout && time_after_eq(jiffies, u->timeout)) {
u->transfer_flags |= USB_ASYNC_UNLINK | USB_TIMEOUT_KILLED;
uhci_unlink_urb(u);
}
@@ -2343,9 +2345,7 @@ static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsign
uhci = alloc_uhci(io_addr, io_size);
if (!uhci)
return -ENOMEM;
-
- INIT_LIST_HEAD(&uhci->uhci_list);
- list_add(&uhci->uhci_list, &uhci_list);
+ dev->driver_data = uhci;
request_region(uhci->io_addr, io_size, "usb-uhci");
@@ -2358,21 +2358,13 @@ static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsign
if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb-uhci", uhci) == 0) {
uhci->irq = irq;
- if (!uhci_start_root_hub(uhci)) {
- struct pm_dev *pmdev;
+ pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
- pmdev = pm_register(PM_PCI_DEV,
- PM_PCI_ID(dev),
- handle_pm_event);
- if (pmdev)
- pmdev->data = uhci;
+ if (!uhci_start_root_hub(uhci))
return 0;
- }
}
/* Couldn't allocate IRQ if we got here */
- list_del(&uhci->uhci_list);
- INIT_LIST_HEAD(&uhci->uhci_list);
reset_hc(uhci);
release_region(uhci->io_addr, uhci->io_size);
@@ -2381,19 +2373,19 @@ static int setup_uhci(struct pci_dev *dev, int irq, unsigned int io_addr, unsign
return retval;
}
-static int found_uhci(struct pci_dev *dev)
+static int __devinit uhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int i;
/* disable legacy emulation */
- pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+ pci_write_config_word(dev, USBLEGSUP, 0);
if (pci_enable_device(dev) < 0)
- return -1;
+ return -ENODEV;
if (!dev->irq) {
err("found UHCI device with no IRQ assigned. check BIOS settings!");
- return -1;
+ return -ENODEV;
}
/* Search for the IO base address.. */
@@ -2409,32 +2401,77 @@ static int found_uhci(struct pci_dev *dev)
if (check_region(io_addr, io_size))
break;
+ pci_set_master(dev);
return setup_uhci(dev, dev->irq, io_addr, io_size);
}
- return -1;
+ return -ENODEV;
}
-static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst, void *data)
+static void __devexit uhci_pci_remove(struct pci_dev *dev)
{
- struct uhci *uhci = dev->data;
- switch (rqst) {
- case PM_SUSPEND:
- reset_hc(uhci);
- break;
- case PM_RESUME:
- reset_hc(uhci);
- start_hc(uhci);
- break;
- }
- return 0;
+ struct uhci *uhci = dev->driver_data;
+
+ if (uhci->bus->root_hub)
+ usb_disconnect(&uhci->bus->root_hub);
+
+ usb_deregister_bus(uhci->bus);
+
+ reset_hc(uhci);
+ release_region(uhci->io_addr, uhci->io_size);
+
+ uhci_free_pending_qhs(uhci);
+
+ release_uhci(uhci);
+}
+
+static void uhci_pci_suspend(struct pci_dev *dev)
+{
+ reset_hc((struct uhci *) dev->driver_data);
}
-static int __init uhci_init(void)
+static void uhci_pci_resume(struct pci_dev *dev)
+{
+ reset_hc((struct uhci *) dev->driver_data);
+ start_hc((struct uhci *) dev->driver_data);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct pci_device_id __devinitdata uhci_pci_ids [] = { {
+
+ /* handle any USB UHCI controller */
+ class: ((PCI_CLASS_SERIAL_USB << 8) | 0x00),
+ class_mask: ~0,
+
+ /* no matter who makes it */
+ vendor: PCI_ANY_ID,
+ device: PCI_ANY_ID,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+
+ }, { /* end: all zeroes */ }
+};
+
+MODULE_DEVICE_TABLE (pci, uhci_pci_ids);
+
+static struct pci_driver uhci_pci_driver = {
+ name: "usb-uhci",
+ id_table: &uhci_pci_ids [0],
+
+ probe: uhci_pci_probe,
+ remove: uhci_pci_remove,
+
+#ifdef CONFIG_PM
+ suspend: uhci_pci_suspend,
+ resume: uhci_pci_resume,
+#endif /* PM */
+};
+
+
+static int __init uhci_hcd_init(void)
{
int retval;
- struct pci_dev *dev;
- u8 type;
retval = -ENOMEM;
@@ -2461,25 +2498,8 @@ static int __init uhci_init(void)
if (!uhci_up_cachep)
goto up_failed;
- retval = -ENODEV;
- dev = NULL;
- for (;;) {
- dev = pci_find_class(PCI_CLASS_SERIAL_USB << 8, dev);
- if (!dev)
- break;
-
- /* Is it the UHCI programming interface? */
- pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
- if (type != 0)
- continue;
-
- /* Ok set it up */
- retval = found_uhci(dev);
- }
-
- /* We only want to return an error code if ther was an error */
- /* and we didn't find a UHCI controller */
- if (retval && list_empty(&uhci_list))
+ retval = pci_module_init (&uhci_pci_driver);
+ if (retval)
goto init_failed;
return 0;
@@ -2500,32 +2520,10 @@ td_failed:
return retval;
}
-void uhci_cleanup(void)
+static void __exit uhci_hcd_cleanup (void)
{
- struct list_head *tmp, *head = &uhci_list;
-
- tmp = head->next;
- while (tmp != head) {
- struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list);
-
- tmp = tmp->next;
-
- list_del(&uhci->uhci_list);
- INIT_LIST_HEAD(&uhci->uhci_list);
-
- if (uhci->bus->root_hub)
- usb_disconnect(&uhci->bus->root_hub);
-
- usb_deregister_bus(uhci->bus);
-
- reset_hc(uhci);
- release_region(uhci->io_addr, uhci->io_size);
-
- uhci_free_pending_qhs(uhci);
-
- release_uhci(uhci);
- }
-
+ pci_unregister_driver (&uhci_pci_driver);
+
if (kmem_cache_destroy(uhci_up_cachep))
printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
@@ -2536,14 +2534,8 @@ void uhci_cleanup(void)
printk(KERN_INFO "uhci: not all TD's were freed\n");
}
-static void __exit uhci_exit(void)
-{
- pm_unregister_all(handle_pm_event);
- uhci_cleanup();
-}
-
-module_init(uhci_init);
-module_exit(uhci_exit);
+module_init(uhci_hcd_init);
+module_exit(uhci_hcd_cleanup);
MODULE_AUTHOR("Linus Torvalds, Johannes Erdfelt, Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber");
MODULE_DESCRIPTION("USB Universal Host Controller Interface driver");