int usb_loop_poll_hw(struct usb_ep *_ept, int is_rx) { struct msm_endpoint *act_ept, *ept = to_msm_endpoint(_ept); struct usb_info *ui = ept->ui; int done = 0; u32 n; /* Normally there is a read request in the endpoint, wait for new data */ for (;;) { n = readl(USB_USBSTS); writel(n, USB_USBSTS); if (n & STS_UI) /* finished transaction */ break; } /* USB Transaction is complete */ if (n & STS_UI) { n = readl(USB_ENDPTSETUPSTAT); if (n & EPT_RX(0)) handle_setup(ui); n = readl(USB_ENDPTCOMPLETE); writel(n, USB_ENDPTCOMPLETE); while (n) { unsigned bit = __ffs(n); act_ept = ui->ept + bit; if (ept == act_ept) { pr_debug("%s: recv'd right tx %d\n", __func__, bit); done = 1; } else { pr_debug("%s: recv'd extra tx from ept %d (exp %d)\n", __func__, bit, ept->bit); } /* always call the handler for KGDB and other usb functions. * this is to avoid hardware timeout, but can leave a bit * kernel code running when kgdb is invoked to stopped the * kernel. this works quite well with adb but might not * support usb mass storage devices very well. */ handle_endpoint(ui, bit); n = n & (~(1 << bit)); } } return done ? 0 : -EAGAIN; }
static irqreturn_t usb_interrupt(int irq, void *data) { struct usb_info *ui = data; unsigned n; n = readl(USB_USBSTS); writel(n, USB_USBSTS); /* somehow we got an IRQ while in the reset sequence: ignore it */ if (ui->running == 0) return IRQ_HANDLED; if (n & STS_PCI) { switch (readl(USB_PORTSC) & PORTSC_PSPD_MASK) { case PORTSC_PSPD_FS: INFO("msm72k_udc: portchange USB_SPEED_FULL\n"); ui->gadget.speed = USB_SPEED_FULL; break; case PORTSC_PSPD_LS: INFO("msm72k_udc: portchange USB_SPEED_LOW\n"); ui->gadget.speed = USB_SPEED_LOW; break; case PORTSC_PSPD_HS: INFO("msm72k_udc: portchange USB_SPEED_HIGH\n"); ui->gadget.speed = USB_SPEED_HIGH; break; } } if (n & STS_URI) { INFO("msm72k_udc: reset\n"); writel(readl(USB_ENDPTSETUPSTAT), USB_ENDPTSETUPSTAT); writel(readl(USB_ENDPTCOMPLETE), USB_ENDPTCOMPLETE); writel(0xffffffff, USB_ENDPTFLUSH); writel(0, USB_ENDPTCTRL(1)); if (ui->online != 0) { /* marking us offline will cause ept queue attempts ** to fail */ ui->online = 0; flush_all_endpoints(ui); /* XXX: we can't seem to detect going offline, * XXX: so deconfigure on reset for the time being */ if (ui->driver) { printk(KERN_INFO "usb: notify offline\n"); ui->driver->disconnect(&ui->gadget); } } } if (n & STS_SLI) INFO("msm72k_udc: suspend\n"); if (n & STS_UI) { n = readl(USB_ENDPTSETUPSTAT); if (n & EPT_RX(0)) handle_setup(ui); n = readl(USB_ENDPTCOMPLETE); writel(n, USB_ENDPTCOMPLETE); while (n) { unsigned bit = __ffs(n); handle_endpoint(ui, bit); n = n & (~(1 << bit)); } } return IRQ_HANDLED; }