fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / usb / host / sl811-hcd.c
index 99d43f7..5fa5647 100644 (file)
 #undef VERBOSE
 #undef PACKET_TRACE
 
-#include <linux/config.h>
-
-#ifdef CONFIG_USB_DEBUG
-#      define DEBUG
-#else
-#      undef DEBUG
-#endif
-
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
@@ -53,7 +45,8 @@
 #include <linux/list.h>
 #include <linux/interrupt.h>
 #include <linux/usb.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
+#include <linux/platform_device.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -435,7 +428,6 @@ static void finish_request(
        struct sl811            *sl811,
        struct sl811h_ep        *ep,
        struct urb              *urb,
-       struct pt_regs          *regs,
        int                     status
 ) __releases(sl811->lock) __acquires(sl811->lock)
 {
@@ -451,7 +443,7 @@ static void finish_request(
        spin_unlock(&urb->lock);
 
        spin_unlock(&sl811->lock);
-       usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, regs);
+       usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
        spin_lock(&sl811->lock);
 
        /* leave active endpoints in the schedule */
@@ -491,7 +483,7 @@ static void finish_request(
 }
 
 static void
-done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
+done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
 {
        u8                      status;
        struct urb              *urb;
@@ -604,7 +596,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
        /* error? retry, until "3 strikes" */
        } else if (++ep->error_count >= 3) {
                if (status & SL11H_STATMASK_TMOUT)
-                       urbstat = -ETIMEDOUT;
+                       urbstat = -ETIME;
                else if (status & SL11H_STATMASK_OVF)
                        urbstat = -EOVERFLOW;
                else
@@ -615,7 +607,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank, struct pt_regs *regs)
        }
 
        if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
-               finish_request(sl811, ep, urb, regs, urbstat);
+               finish_request(sl811, ep, urb, urbstat);
 }
 
 static inline u8 checkdone(struct sl811 *sl811)
@@ -648,7 +640,7 @@ static inline u8 checkdone(struct sl811 *sl811)
        return irqstat;
 }
 
-static irqreturn_t sl811h_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+static irqreturn_t sl811h_irq(struct usb_hcd *hcd)
 {
        struct sl811    *sl811 = hcd_to_sl811(hcd);
        u8              irqstat;
@@ -677,13 +669,13 @@ retry:
         * issued ... that's fine if they're different endpoints.
         */
        if (irqstat & SL11H_INTMASK_DONE_A) {
-               done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF), regs);
+               done(sl811, sl811->active_a, SL811_EP_A(SL811_HOST_BUF));
                sl811->active_a = NULL;
                sl811->stat_a++;
        }
 #ifdef USE_B
        if (irqstat & SL11H_INTMASK_DONE_B) {
-               done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF), regs);
+               done(sl811, sl811->active_b, SL811_EP_B(SL811_HOST_BUF));
                sl811->active_b = NULL;
                sl811->stat_b++;
        }
@@ -730,7 +722,7 @@ retry:
                                container_of(sl811->active_a
                                                ->hep->urb_list.next,
                                        struct urb, urb_list),
-                               NULL, -ESHUTDOWN);
+                               -ESHUTDOWN);
                        sl811->active_a = NULL;
                }
 #ifdef USE_B
@@ -782,6 +774,9 @@ retry:
 /* usb 1.1 says max 90% of a frame is available for periodic transfers.
  * this driver doesn't promise that much since it's got to handle an
  * IRQ per packet; irq handling latencies also use up that time.
+ *
+ * NOTE:  the periodic schedule is a sparse tree, with the load for
+ * each branch minimized.  see fig 3.5 in the OHCI spec for example.
  */
 #define        MAX_PERIODIC_LOAD       500     /* out of 1000 usec */
 
@@ -815,7 +810,7 @@ static int sl811h_urb_enqueue(
        struct usb_hcd          *hcd,
        struct usb_host_endpoint *hep,
        struct urb              *urb,
-       int                     mem_flags
+       gfp_t                   mem_flags
 ) {
        struct sl811            *sl811 = hcd_to_sl811(hcd);
        struct usb_device       *udev = urb->dev;
@@ -835,7 +830,7 @@ static int sl811h_urb_enqueue(
 
        /* avoid all allocations within spinlocks */
        if (!hep->hcpriv)
-               ep = kcalloc(1, sizeof *ep, mem_flags);
+               ep = kzalloc(sizeof *ep, mem_flags);
 
        spin_lock_irqsave(&sl811->lock, flags);
 
@@ -843,6 +838,7 @@ static int sl811h_urb_enqueue(
        if (!(sl811->port1 & (1 << USB_PORT_FEAT_ENABLE))
                        || !HC_IS_RUNNING(hcd->state)) {
                retval = -ENODEV;
+               kfree(ep);
                goto fail;
        }
 
@@ -855,7 +851,7 @@ static int sl811h_urb_enqueue(
 
        } else {
                INIT_LIST_HEAD(&ep->schedule);
-               ep->udev = usb_get_dev(udev);
+               ep->udev = udev;
                ep->epnum = epnum;
                ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
                ep->defctrl = SL11H_HCTLMASK_ARM | SL11H_HCTLMASK_ENABLE;
@@ -911,8 +907,16 @@ static int sl811h_urb_enqueue(
        case PIPE_ISOCHRONOUS:
        case PIPE_INTERRUPT:
                urb->interval = ep->period;
-               if (ep->branch < PERIODIC_SIZE)
+               if (ep->branch < PERIODIC_SIZE) {
+                       /* NOTE:  the phase is correct here, but the value
+                        * needs offsetting by the transfer queue depth.
+                        * All current drivers ignore start_frame, so this
+                        * is unlikely to ever matter...
+                        */
+                       urb->start_frame = (sl811->frame & (PERIODIC_SIZE - 1))
+                                               + ep->branch;
                        break;
+               }
 
                retval = balance(sl811, ep->period, ep->load);
                if (retval < 0)
@@ -952,7 +956,7 @@ static int sl811h_urb_enqueue(
        spin_lock(&urb->lock);
        if (urb->status != -EINPROGRESS) {
                spin_unlock(&urb->lock);
-               finish_request(sl811, ep, urb, NULL, 0);
+               finish_request(sl811, ep, urb, 0);
                retval = 0;
                goto fail;
        }
@@ -1021,7 +1025,7 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
                }
 
                if (urb)
-                       finish_request(sl811, ep, urb, NULL, 0);
+                       finish_request(sl811, ep, urb, 0);
                else
                        VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
                                (sl811->active_a == ep) ? "A" : "B");
@@ -1046,7 +1050,6 @@ sl811h_endpoint_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
        if (!list_empty(&hep->urb_list))
                WARN("ep %p not empty?\n", ep);
 
-       usb_put_dev(ep->udev);
        kfree(ep);
        hep->hcpriv = NULL;
 }
@@ -1079,7 +1082,7 @@ sl811h_hub_status_data(struct usb_hcd *hcd, char *buf)
         */
        local_irq_save(flags);
        if (!timer_pending(&sl811->timer)) {
-               if (sl811h_irq( /* ~0, */ hcd, NULL) != IRQ_NONE)
+               if (sl811h_irq( /* ~0, */ hcd) != IRQ_NONE)
                        sl811->stat_lost++;
        }
        local_irq_restore(flags);
@@ -1122,7 +1125,7 @@ sl811h_hub_descriptor (
        desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp);
 
        /* two bitmaps:  ports removable, and legacy PortPwrCtrlMask */
-       desc->bitmap[0] = 1 << 1;
+       desc->bitmap[0] = 0 << 1;
        desc->bitmap[1] = ~0;
 }
 
@@ -1351,7 +1354,7 @@ error:
 #ifdef CONFIG_PM
 
 static int
-sl811h_hub_suspend(struct usb_hcd *hcd)
+sl811h_bus_suspend(struct usb_hcd *hcd)
 {
        // SOFs off
        DBG("%s\n", __FUNCTION__);
@@ -1359,7 +1362,7 @@ sl811h_hub_suspend(struct usb_hcd *hcd)
 }
 
 static int
-sl811h_hub_resume(struct usb_hcd *hcd)
+sl811h_bus_resume(struct usb_hcd *hcd)
 {
        // SOFs on
        DBG("%s\n", __FUNCTION__);
@@ -1368,8 +1371,8 @@ sl811h_hub_resume(struct usb_hcd *hcd)
 
 #else
 
-#define        sl811h_hub_suspend      NULL
-#define        sl811h_hub_resume       NULL
+#define        sl811h_bus_suspend      NULL
+#define        sl811h_bus_resume       NULL
 
 #endif
 
@@ -1513,7 +1516,7 @@ static int proc_sl811h_open(struct inode *inode, struct file *file)
        return single_open(file, proc_sl811h_show, PDE(inode)->data);
 }
 
-static struct file_operations proc_ops = {
+static const struct file_operations proc_ops = {
        .open           = proc_sl811h_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
@@ -1563,29 +1566,17 @@ static int
 sl811h_start(struct usb_hcd *hcd)
 {
        struct sl811            *sl811 = hcd_to_sl811(hcd);
-       struct usb_device       *udev;
 
        /* chip has been reset, VBUS power is off */
-
-       udev = usb_alloc_dev(NULL, &hcd->self, 0);
-       if (!udev)
-               return -ENOMEM;
-
-       udev->speed = USB_SPEED_FULL;
        hcd->state = HC_STATE_RUNNING;
 
-       if (sl811->board)
-               hcd->can_wakeup = sl811->board->can_wakeup;
-
-       if (usb_hcd_register_root_hub(udev, hcd) != 0) {
-               usb_put_dev(udev);
-               sl811h_stop(hcd);
-               return -ENODEV;
+       if (sl811->board) {
+               if (!device_can_wakeup(hcd->self.controller))
+                       device_init_wakeup(hcd->self.controller,
+                               sl811->board->can_wakeup);
+               hcd->power_budget = sl811->board->power * 2;
        }
 
-       if (sl811->board && sl811->board->power)
-               hub_set_power_budget(udev, sl811->board->power * 2);
-
        /* enable power and interupts */
        port_power(sl811, 1);
 
@@ -1625,31 +1616,28 @@ static struct hc_driver sl811h_hc_driver = {
         */
        .hub_status_data =      sl811h_hub_status_data,
        .hub_control =          sl811h_hub_control,
-       .hub_suspend =          sl811h_hub_suspend,
-       .hub_resume =           sl811h_hub_resume,
+       .bus_suspend =          sl811h_bus_suspend,
+       .bus_resume =           sl811h_bus_resume,
 };
 
 /*-------------------------------------------------------------------------*/
 
 static int __devexit
-sl811h_remove(struct device *dev)
+sl811h_remove(struct platform_device *dev)
 {
-       struct usb_hcd          *hcd = dev_get_drvdata(dev);
+       struct usb_hcd          *hcd = platform_get_drvdata(dev);
        struct sl811            *sl811 = hcd_to_sl811(hcd);
-       struct platform_device  *pdev;
        struct resource         *res;
 
-       pdev = container_of(dev, struct platform_device, dev);
-
        remove_debug_file(sl811);
        usb_remove_hcd(hcd);
 
        /* some platforms may use IORESOURCE_IO */
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       res = platform_get_resource(dev, IORESOURCE_MEM, 1);
        if (res)
                iounmap(sl811->data_reg);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       res = platform_get_resource(dev, IORESOURCE_MEM, 0);
        if (res)
                iounmap(sl811->addr_reg);
 
@@ -1658,11 +1646,10 @@ sl811h_remove(struct device *dev)
 }
 
 static int __devinit
-sl811h_probe(struct device *dev)
+sl811h_probe(struct platform_device *dev)
 {
        struct usb_hcd          *hcd;
        struct sl811            *sl811;
-       struct platform_device  *pdev;
        struct resource         *addr, *data;
        int                     irq;
        void __iomem            *addr_reg;
@@ -1675,30 +1662,33 @@ sl811h_probe(struct device *dev)
         * specific platform_data.  we don't probe for IRQs, and do only
         * minimal sanity checking.
         */
-       pdev = container_of(dev, struct platform_device, dev);
-       irq = platform_get_irq(pdev, 0);
-       if (pdev->num_resources < 3 || irq < 0)
+       irq = platform_get_irq(dev, 0);
+       if (dev->num_resources < 3 || irq < 0)
                return -ENODEV;
 
        /* refuse to confuse usbcore */
-       if (dev->dma_mask) {
+       if (dev->dev.dma_mask) {
                DBG("no we won't dma\n");
                return -EINVAL;
        }
 
        /* the chip may be wired for either kind of addressing */
-       addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       addr = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       data = platform_get_resource(dev, IORESOURCE_MEM, 1);
        retval = -EBUSY;
        if (!addr || !data) {
-               addr = platform_get_resource(pdev, IORESOURCE_IO, 0);
-               data = platform_get_resource(pdev, IORESOURCE_IO, 1);
+               addr = platform_get_resource(dev, IORESOURCE_IO, 0);
+               data = platform_get_resource(dev, IORESOURCE_IO, 1);
                if (!addr || !data)
                        return -ENODEV;
                ioaddr = 1;
-
-               addr_reg = (void __iomem *) addr->start;
-               data_reg = (void __iomem *) data->start;
+               /*
+                * NOTE: 64-bit resource->start is getting truncated
+                * to avoid compiler warning, assuming that ->start
+                * is always 32-bit for this case
+                */
+               addr_reg = (void __iomem *) (unsigned long) addr->start;
+               data_reg = (void __iomem *) (unsigned long) data->start;
        } else {
                addr_reg = ioremap(addr->start, 1);
                if (addr_reg == NULL) {
@@ -1714,7 +1704,7 @@ sl811h_probe(struct device *dev)
        }
 
        /* allocate and initialize hcd */
-       hcd = usb_create_hcd(&sl811h_hc_driver, dev, dev->bus_id);
+       hcd = usb_create_hcd(&sl811h_hc_driver, &dev->dev, dev->dev.bus_id);
        if (!hcd) {
                retval = -ENOMEM;
                goto err5;
@@ -1724,7 +1714,7 @@ sl811h_probe(struct device *dev)
 
        spin_lock_init(&sl811->lock);
        INIT_LIST_HEAD(&sl811->async);
-       sl811->board = dev->platform_data;
+       sl811->board = dev->dev.platform_data;
        init_timer(&sl811->timer);
        sl811->timer.function = sl811h_timer;
        sl811->timer.data = (unsigned long) sl811;
@@ -1758,7 +1748,7 @@ sl811h_probe(struct device *dev)
         * was on a system with single edge triggering, so most sorts of
         * triggering arrangement should work.
         */
-       retval = usb_add_hcd(hcd, irq, SA_INTERRUPT | SA_SHIRQ);
+       retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
        if (retval != 0)
                goto err6;
 
@@ -1786,45 +1776,45 @@ sl811h_probe(struct device *dev)
  */
 
 static int
-sl811h_suspend(struct device *dev, pm_message_t state, u32 phase)
+sl811h_suspend(struct platform_device *dev, pm_message_t state)
 {
-       struct usb_hcd  *hcd = dev_get_drvdata(dev);
+       struct usb_hcd  *hcd = platform_get_drvdata(dev);
        struct sl811    *sl811 = hcd_to_sl811(hcd);
        int             retval = 0;
 
-       if (phase != SUSPEND_POWER_DOWN)
-               return retval;
-
-       if (state <= PM_SUSPEND_MEM)
-               retval = sl811h_hub_suspend(hcd);
-       else
+       switch (state.event) {
+       case PM_EVENT_FREEZE:
+               retval = sl811h_bus_suspend(hcd);
+               break;
+       case PM_EVENT_SUSPEND:
+       case PM_EVENT_PRETHAW:          /* explicitly discard hw state */
                port_power(sl811, 0);
+               break;
+       }
        if (retval == 0)
-               dev->power.power_state = state;
+               dev->dev.power.power_state = state;
        return retval;
 }
 
 static int
-sl811h_resume(struct device *dev, u32 phase)
+sl811h_resume(struct platform_device *dev)
 {
-       struct usb_hcd  *hcd = dev_get_drvdata(dev);
+       struct usb_hcd  *hcd = platform_get_drvdata(dev);
        struct sl811    *sl811 = hcd_to_sl811(hcd);
 
-       if (phase != RESUME_POWER_ON)
-               return 0;
-
        /* with no "check to see if VBUS is still powered" board hook,
         * let's assume it'd only be powered to enable remote wakeup.
         */
-       if (dev->power.power_state > PM_SUSPEND_MEM
-                       || !hcd->can_wakeup) {
+       if (dev->dev.power.power_state.event == PM_EVENT_SUSPEND
+                       || !device_can_wakeup(&hcd->self.root_hub->dev)) {
                sl811->port1 = 0;
                port_power(sl811, 1);
+               usb_root_hub_lost_power(hcd->self.root_hub);
                return 0;
        }
 
-       dev->power.power_state = PMSG_ON;
-       return sl811h_hub_resume(hcd);
+       dev->dev.power.power_state = PMSG_ON;
+       return sl811h_bus_resume(hcd);
 }
 
 #else
@@ -1836,15 +1826,16 @@ sl811h_resume(struct device *dev, u32 phase)
 
 
 /* this driver is exported so sl811_cs can depend on it */
-struct device_driver sl811h_driver = {
-       .name =         (char *) hcd_name,
-       .bus =          &platform_bus_type,
-
+struct platform_driver sl811h_driver = {
        .probe =        sl811h_probe,
        .remove =       __devexit_p(sl811h_remove),
 
        .suspend =      sl811h_suspend,
        .resume =       sl811h_resume,
+       .driver = {
+               .name = (char *) hcd_name,
+               .owner = THIS_MODULE,
+       },
 };
 EXPORT_SYMBOL(sl811h_driver);
 
@@ -1856,12 +1847,12 @@ static int __init sl811h_init(void)
                return -ENODEV;
 
        INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
-       return driver_register(&sl811h_driver);
+       return platform_driver_register(&sl811h_driver);
 }
 module_init(sl811h_init);
 
 static void __exit sl811h_cleanup(void)
 {
-       driver_unregister(&sl811h_driver);
+       platform_driver_unregister(&sl811h_driver);
 }
 module_exit(sl811h_cleanup);