コード例 #1
0
ファイル: adm5120-hub.c プロジェクト: cilynx/dd-wrt
/* hcd->hub_irq_enable() */
static void admhc_rhsc_enable(struct usb_hcd *hcd)
{
	struct admhcd	*ahcd = hcd_to_admhcd(hcd);

	spin_lock_irq(&ahcd->lock);
	if (!ahcd->autostop)
		del_timer(&hcd->rh_timer);	/* Prevent next poll */
	admhc_intr_enable(ahcd, ADMHC_INTR_INSM);
	spin_unlock_irq(&ahcd->lock);
}
コード例 #2
0
ファイル: adm5120-hcd.c プロジェクト: Cribstone/linino
static irqreturn_t admhc_irq(struct usb_hcd *hcd)
{
	struct admhcd *ahcd = hcd_to_admhcd(hcd);
	struct admhcd_regs __iomem *regs = ahcd->regs;
 	u32 ints;

	ints = admhc_readl(ahcd, &regs->int_status);
	if ((ints & ADMHC_INTR_INTA) == 0) {
		/* no unmasked interrupt status is set */
		return IRQ_NONE;
	}

	ints &= admhc_readl(ahcd, &regs->int_enable);

	if (ints & ADMHC_INTR_FATI) {
		/* e.g. due to PCI Master/Target Abort */
		admhc_disable(ahcd);
		admhc_err(ahcd, "Fatal Error, controller disabled\n");
		admhc_dump(ahcd, 1);
		admhc_usb_reset(ahcd);
	}

	if (ints & ADMHC_INTR_BABI) {
		admhc_intr_disable(ahcd, ADMHC_INTR_BABI);
		admhc_intr_ack(ahcd, ADMHC_INTR_BABI);
		admhc_err(ahcd, "Babble Detected\n");
	}

	if (ints & ADMHC_INTR_INSM) {
		admhc_vdbg(ahcd, "Root Hub Status Change\n");
		ahcd->next_statechange = jiffies + STATECHANGE_DELAY;
		admhc_intr_ack(ahcd, ADMHC_INTR_RESI | ADMHC_INTR_INSM);

		/* NOTE: Vendors didn't always make the same implementation
		 * choices for RHSC.  Many followed the spec; RHSC triggers
		 * on an edge, like setting and maybe clearing a port status
		 * change bit.  With others it's level-triggered, active
		 * until khubd clears all the port status change bits.  We'll
		 * always disable it here and rely on polling until khubd
		 * re-enables it.
		 */
		admhc_intr_disable(ahcd, ADMHC_INTR_INSM);
		usb_hcd_poll_rh_status(hcd);
	} else if (ints & ADMHC_INTR_RESI) {
		/* For connect and disconnect events, we expect the controller
		 * to turn on RHSC along with RD.  But for remote wakeup events
		 * this might not happen.
		 */
		admhc_vdbg(ahcd, "Resume Detect\n");
		admhc_intr_ack(ahcd, ADMHC_INTR_RESI);
		hcd->poll_rh = 1;
		if (ahcd->autostop) {
			spin_lock(&ahcd->lock);
			admhc_rh_resume(ahcd);
			spin_unlock(&ahcd->lock);
		} else
			usb_hcd_resume_root_hub(hcd);
	}

	if (ints & ADMHC_INTR_TDC) {
		admhc_vdbg(ahcd, "Transfer Descriptor Complete\n");
		admhc_intr_ack(ahcd, ADMHC_INTR_TDC);
		if (HC_IS_RUNNING(hcd->state))
			admhc_intr_disable(ahcd, ADMHC_INTR_TDC);
		spin_lock(&ahcd->lock);
		admhc_td_complete(ahcd);
		spin_unlock(&ahcd->lock);
		if (HC_IS_RUNNING(hcd->state))
			admhc_intr_enable(ahcd, ADMHC_INTR_TDC);
	}

	if (ints & ADMHC_INTR_SO) {
		/* could track INTR_SO to reduce available PCI/... bandwidth */
		admhc_vdbg(ahcd, "Schedule Overrun\n");
	}

#if 1
	spin_lock(&ahcd->lock);
	if (ahcd->ed_rm_list)
		finish_unlinks(ahcd, admhc_frame_no(ahcd));

	if ((ints & ADMHC_INTR_SOFI) != 0 && !ahcd->ed_rm_list
			&& HC_IS_RUNNING(hcd->state))
		admhc_intr_disable(ahcd, ADMHC_INTR_SOFI);
	spin_unlock(&ahcd->lock);
#else
	if (ints & ADMHC_INTR_SOFI) {
		admhc_vdbg(ahcd, "Start Of Frame\n");
		spin_lock(&ahcd->lock);

		/* handle any pending ED removes */
		finish_unlinks(ahcd, admhc_frameno(ahcd));

		/* leaving INTR_SOFI enabled when there's still unlinking
		 * to be done in the (next frame).
		 */
		if ((ahcd->ed_rm_list == NULL) ||
			HC_IS_RUNNING(hcd->state) == 0)
			/*
			 * disable INTR_SOFI if there are no unlinking to be
			 * done (in the next frame)
			 */
			admhc_intr_disable(ahcd, ADMHC_INTR_SOFI);

		spin_unlock(&ahcd->lock);
	}
#endif

	if (HC_IS_RUNNING(hcd->state)) {
		admhc_intr_ack(ahcd, ints);
		admhc_intr_enable(ahcd, ADMHC_INTR_MIE);
		admhc_writel_flush(ahcd);
	}

	return IRQ_HANDLED;
}
コード例 #3
0
ファイル: adm5120-hcd.c プロジェクト: Cribstone/linino
/* Start an OHCI controller, set the BUS operational
 * resets USB and controller
 * enable interrupts
 */
static int admhc_run(struct admhcd *ahcd)
{
	u32			temp;
	int			first = ahcd->fminterval == 0;
	struct usb_hcd		*hcd = admhcd_to_hcd(ahcd);

	admhc_disable(ahcd);

	/* boot firmware should have set this up (5.1.1.3.1) */
	if (first) {
		temp = admhc_readl(ahcd, &ahcd->regs->fminterval);
		ahcd->fminterval = temp & ADMHC_SFI_FI_MASK;
		if (ahcd->fminterval != FI)
			admhc_dbg(ahcd, "fminterval delta %d\n",
				ahcd->fminterval - FI);
		ahcd->fminterval |=
			(FSLDP(ahcd->fminterval) << ADMHC_SFI_FSLDP_SHIFT);
		/* also: power/overcurrent flags in rhdesc */
	}

#if 0	/* TODO: not applicable */
	/* Reset USB nearly "by the book".  RemoteWakeupConnected was
	 * saved if boot firmware (BIOS/SMM/...) told us it's connected,
	 * or if bus glue did the same (e.g. for PCI add-in cards with
	 * PCI PM support).
	 */
	if ((ahcd->hc_control & OHCI_CTRL_RWC) != 0
			&& !device_may_wakeup(hcd->self.controller))
		device_init_wakeup(hcd->self.controller, 1);
#endif

	switch (ahcd->host_control & ADMHC_HC_BUSS) {
	case ADMHC_BUSS_OPER:
		temp = 0;
		break;
	case ADMHC_BUSS_SUSPEND:
		/* FALLTHROUGH ? */
	case ADMHC_BUSS_RESUME:
		ahcd->host_control = ADMHC_BUSS_RESUME;
		temp = 10 /* msec wait */;
		break;
	/* case ADMHC_BUSS_RESET: */
	default:
		ahcd->host_control = ADMHC_BUSS_RESET;
		temp = 50 /* msec wait */;
		break;
	}
	admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control);

	/* flush the writes */
	admhc_writel_flush(ahcd);

	msleep(temp);
	temp = admhc_read_rhdesc(ahcd);
	if (!(temp & ADMHC_RH_NPS)) {
		/* power down each port */
		for (temp = 0; temp < ahcd->num_ports; temp++)
			admhc_write_portstatus(ahcd, temp, ADMHC_PS_CPP);
	}
	/* flush those writes */
	admhc_writel_flush(ahcd);

	/* 2msec timelimit here means no irqs/preempt */
	spin_lock_irq(&ahcd->lock);

	admhc_writel(ahcd, ADMHC_CTRL_SR,  &ahcd->regs->gencontrol);
	temp = 30;	/* ... allow extra time */
	while ((admhc_readl(ahcd, &ahcd->regs->gencontrol) & ADMHC_CTRL_SR) != 0) {
		if (--temp == 0) {
			spin_unlock_irq(&ahcd->lock);
			admhc_err(ahcd, "USB HC reset timed out!\n");
			return -1;
		}
		udelay(1);
	}

	/* enable HOST mode, before access any host specific register */
	admhc_writel(ahcd, ADMHC_CTRL_UHFE,  &ahcd->regs->gencontrol);

	/* Tell the controller where the descriptor list is */
	admhc_writel(ahcd, (u32)ahcd->ed_head->dma, &ahcd->regs->hosthead);

	periodic_reinit(ahcd);

	/* use rhsc irqs after khubd is fully initialized */
	hcd->poll_rh = 1;
	hcd->uses_new_polling = 1;

#if 0
	/* wake on ConnectStatusChange, matching external hubs */
	admhc_writel(ahcd, RH_HS_DRWE, &ahcd->regs->roothub.status);
#else
	/* FIXME roothub_write_status (ahcd, ADMHC_RH_DRWE); */
#endif

	/* Choose the interrupts we care about now, others later on demand */
	admhc_intr_ack(ahcd, ~0);
	admhc_intr_enable(ahcd, ADMHC_INTR_INIT);

	admhc_writel(ahcd, ADMHC_RH_NPS | ADMHC_RH_LPSC, &ahcd->regs->rhdesc);

	/* flush those writes */
	admhc_writel_flush(ahcd);

	/* start controller operations */
	ahcd->host_control = ADMHC_BUSS_OPER;
	admhc_writel(ahcd, ahcd->host_control, &ahcd->regs->host_control);

	temp = 20;
	while ((admhc_readl(ahcd, &ahcd->regs->host_control)
			& ADMHC_HC_BUSS) != ADMHC_BUSS_OPER) {
		if (--temp == 0) {
			spin_unlock_irq(&ahcd->lock);
			admhc_err(ahcd, "unable to setup operational mode!\n");
			return -1;
		}
		mdelay(1);
	}

	hcd->state = HC_STATE_RUNNING;

	ahcd->next_statechange = jiffies + STATECHANGE_DELAY;

#if 0
	/* FIXME: enabling DMA is always failed here for an unknown reason */
	admhc_dma_enable(ahcd);

	temp = 200;
	while ((admhc_readl(ahcd, &ahcd->regs->host_control)
			& ADMHC_HC_DMAE) != ADMHC_HC_DMAE) {
		if (--temp == 0) {
			spin_unlock_irq(&ahcd->lock);
			admhc_err(ahcd, "unable to enable DMA!\n");
			admhc_dump(ahcd, 1);
			return -1;
		}
		mdelay(1);
	}

#endif

	spin_unlock_irq(&ahcd->lock);

	mdelay(ADMHC_POTPGT);

	return 0;
}