static int ftdi_elan_check_controller()

in misc/ftdi-elan.c [2193:2393]


static int ftdi_elan_check_controller(struct usb_ftdi *ftdi, int quirk)
{
	int devices = 0;
	int retval;
	u32 hc_control;
	int num_ports;
	u32 control;
	u32 rh_a = -1;
	u32 status;
	u32 fminterval;
	u32 hc_fminterval;
	u32 periodicstart;
	u32 cmdstatus;
	u32 roothub_a;
	int mask = OHCI_INTR_INIT;
	int sleep_time = 0;
	int reset_timeout = 30;        /* ... allow extra time */
	int temp;
	retval = ftdi_write_pcimem(ftdi, intrdisable, OHCI_INTR_MIE);
	if (retval)
		return retval;
	retval = ftdi_read_pcimem(ftdi, control, &control);
	if (retval)
		return retval;
	retval = ftdi_read_pcimem(ftdi, roothub.a, &rh_a);
	if (retval)
		return retval;
	num_ports = rh_a & RH_A_NDP;
	retval = ftdi_read_pcimem(ftdi, fminterval, &hc_fminterval);
	if (retval)
		return retval;
	hc_fminterval &= 0x3fff;
	if (hc_fminterval != FI) {
	}
	hc_fminterval |= FSMP(hc_fminterval) << 16;
	retval = ftdi_read_pcimem(ftdi, control, &hc_control);
	if (retval)
		return retval;
	switch (hc_control & OHCI_CTRL_HCFS) {
	case OHCI_USB_OPER:
		sleep_time = 0;
		break;
	case OHCI_USB_SUSPEND:
	case OHCI_USB_RESUME:
		hc_control &= OHCI_CTRL_RWC;
		hc_control |= OHCI_USB_RESUME;
		sleep_time = 10;
		break;
	default:
		hc_control &= OHCI_CTRL_RWC;
		hc_control |= OHCI_USB_RESET;
		sleep_time = 50;
		break;
	}
	retval = ftdi_write_pcimem(ftdi, control, hc_control);
	if (retval)
		return retval;
	retval = ftdi_read_pcimem(ftdi, control, &control);
	if (retval)
		return retval;
	msleep(sleep_time);
	retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
	if (retval)
		return retval;
	if (!(roothub_a & RH_A_NPS)) {        /* power down each port */
		for (temp = 0; temp < num_ports; temp++) {
			retval = ftdi_write_pcimem(ftdi,
						   roothub.portstatus[temp], RH_PS_LSDA);
			if (retval)
				return retval;
		}
	}
	retval = ftdi_read_pcimem(ftdi, control, &control);
	if (retval)
		return retval;
retry:retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_HCR);
	if (retval)
		return retval;
extra:{
		retval = ftdi_read_pcimem(ftdi, cmdstatus, &status);
		if (retval)
			return retval;
		if (0 != (status & OHCI_HCR)) {
			if (--reset_timeout == 0) {
				dev_err(&ftdi->udev->dev, "USB HC reset timed out!\n");
				return -ENODEV;
			} else {
				msleep(5);
				goto extra;
			}
		}
	}
	if (quirk & OHCI_QUIRK_INITRESET) {
		retval = ftdi_write_pcimem(ftdi, control, hc_control);
		if (retval)
			return retval;
		retval = ftdi_read_pcimem(ftdi, control, &control);
		if (retval)
			return retval;
	}
	retval = ftdi_write_pcimem(ftdi, ed_controlhead, 0x00000000);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, ed_bulkhead, 0x11000000);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, hcca, 0x00000000);
	if (retval)
		return retval;
	retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, fminterval,
				   ((fminterval & FIT) ^ FIT) | hc_fminterval);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, periodicstart,
				   ((9 *hc_fminterval) / 10) & 0x3fff);
	if (retval)
		return retval;
	retval = ftdi_read_pcimem(ftdi, fminterval, &fminterval);
	if (retval)
		return retval;
	retval = ftdi_read_pcimem(ftdi, periodicstart, &periodicstart);
	if (retval)
		return retval;
	if (0 == (fminterval & 0x3fff0000) || 0 == periodicstart) {
		if (!(quirk & OHCI_QUIRK_INITRESET)) {
			quirk |= OHCI_QUIRK_INITRESET;
			goto retry;
		} else
			dev_err(&ftdi->udev->dev, "init err(%08x %04x)\n",
				fminterval, periodicstart);
	}                        /* start controller operations */
	hc_control &= OHCI_CTRL_RWC;
	hc_control |= OHCI_CONTROL_INIT | OHCI_CTRL_BLE | OHCI_USB_OPER;
	retval = ftdi_write_pcimem(ftdi, control, hc_control);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, cmdstatus, OHCI_BLF);
	if (retval)
		return retval;
	retval = ftdi_read_pcimem(ftdi, cmdstatus, &cmdstatus);
	if (retval)
		return retval;
	retval = ftdi_read_pcimem(ftdi, control, &control);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_DRWE);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, intrstatus, mask);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, intrdisable,
				   OHCI_INTR_MIE | OHCI_INTR_OC | OHCI_INTR_RHSC | OHCI_INTR_FNO |
				   OHCI_INTR_UE | OHCI_INTR_RD | OHCI_INTR_SF | OHCI_INTR_WDH |
				   OHCI_INTR_SO);
	if (retval)
		return retval;        /* handle root hub init quirks ... */
	retval = ftdi_read_pcimem(ftdi, roothub.a, &roothub_a);
	if (retval)
		return retval;
	roothub_a &= ~(RH_A_PSM | RH_A_OCPM);
	if (quirk & OHCI_QUIRK_SUPERIO) {
		roothub_a |= RH_A_NOCP;
		roothub_a &= ~(RH_A_POTPGT | RH_A_NPS);
		retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
		if (retval)
			return retval;
	} else if ((quirk & OHCI_QUIRK_AMD756) || distrust_firmware) {
		roothub_a |= RH_A_NPS;
		retval = ftdi_write_pcimem(ftdi, roothub.a, roothub_a);
		if (retval)
			return retval;
	}
	retval = ftdi_write_pcimem(ftdi, roothub.status, RH_HS_LPSC);
	if (retval)
		return retval;
	retval = ftdi_write_pcimem(ftdi, roothub.b,
				   (roothub_a & RH_A_NPS) ? 0 : RH_B_PPCM);
	if (retval)
		return retval;
	retval = ftdi_read_pcimem(ftdi, control, &control);
	if (retval)
		return retval;
	mdelay((roothub_a >> 23) & 0x1fe);
	for (temp = 0; temp < num_ports; temp++) {
		u32 portstatus;
		retval = ftdi_read_pcimem(ftdi, roothub.portstatus[temp],
					  &portstatus);
		if (retval)
			return retval;
		if (1 & portstatus)
			devices += 1;
	}
	return devices;
}