Esempio n. 1
0
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;
}
Esempio n. 2
0
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;
}