📄 isp116x-hcd.c
字号:
isp116x_show_regs(isp116x); break; case RH_SET_FEATURE | RH_OTHER | RH_CLASS: DBG("RH_SET_FEATURE | RH_OTHER | RH_CLASS"); switch (wValue) { case RH_PORT_SUSPEND: isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, RH_PS_PSS); len = 0; break; case RH_PORT_RESET: /* Spin until any current reset finishes */ while (1) { tmp = isp116x_read_reg32(isp116x, HCRHPORT1 + wIndex - 1); if (!(tmp & RH_PS_PRS)) break; wait_ms(1); } isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, RH_PS_PRS); wait_ms(10); len = 0; break; case RH_PORT_POWER: isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, RH_PS_PPS); len = 0; break; case RH_PORT_ENABLE: isp116x_write_reg32(isp116x, HCRHPORT1 + wIndex - 1, RH_PS_PES); len = 0; break; default: ERR("invalid wValue"); stat = USB_ST_STALLED; } isp116x_show_regs(isp116x); break; case RH_SET_ADDRESS: DBG("RH_SET_ADDRESS"); rh_devnum = wValue; len = 0; break; case RH_GET_DESCRIPTOR: DBG("RH_GET_DESCRIPTOR: %x, %d", wValue, wLength); switch (wValue) { case (USB_DT_DEVICE << 8): /* device descriptor */ len = min_t(unsigned int, leni, min_t(unsigned int, sizeof(root_hub_dev_des), wLength)); data_buf = root_hub_dev_des; break; case (USB_DT_CONFIG << 8): /* configuration descriptor */ len = min_t(unsigned int, leni, min_t(unsigned int, sizeof(root_hub_config_des), wLength)); data_buf = root_hub_config_des; break; case ((USB_DT_STRING << 8) | 0x00): /* string 0 descriptors */ len = min_t(unsigned int, leni, min_t(unsigned int, sizeof(root_hub_str_index0), wLength)); data_buf = root_hub_str_index0; break; case ((USB_DT_STRING << 8) | 0x01): /* string 1 descriptors */ len = min_t(unsigned int, leni, min_t(unsigned int, sizeof(root_hub_str_index1), wLength)); data_buf = root_hub_str_index1; break; default: ERR("invalid wValue"); stat = USB_ST_STALLED; } break; case RH_GET_DESCRIPTOR | RH_CLASS: DBG("RH_GET_DESCRIPTOR | RH_CLASS"); tmp = isp116x_read_reg32(isp116x, HCRHDESCA); data_buf[0] = 0x09; /* min length; */ data_buf[1] = 0x29; data_buf[2] = tmp & RH_A_NDP; data_buf[3] = 0; if (tmp & RH_A_PSM) /* per-port power switching? */ data_buf[3] |= 0x01; if (tmp & RH_A_NOCP) /* no overcurrent reporting? */ data_buf[3] |= 0x10; else if (tmp & RH_A_OCPM) /* per-port overcurrent rep? */ data_buf[3] |= 0x08; /* Corresponds to data_buf[4-7] */ datab[1] = 0; data_buf[5] = (tmp & RH_A_POTPGT) >> 24; tmp = isp116x_read_reg32(isp116x, HCRHDESCB); data_buf[7] = tmp & RH_B_DR; if (data_buf[2] < 7) data_buf[8] = 0xff; else { data_buf[0] += 2; data_buf[8] = (tmp & RH_B_DR) >> 8; data_buf[10] = data_buf[9] = 0xff; } len = min_t(unsigned int, leni, min_t(unsigned int, data_buf[0], wLength)); break; case RH_GET_CONFIGURATION: DBG("RH_GET_CONFIGURATION"); *(__u8 *) data_buf = 0x01; len = 1; break; case RH_SET_CONFIGURATION: DBG("RH_SET_CONFIGURATION"); isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPSC); len = 0; break; default: ERR("*** *** *** unsupported root hub command *** *** ***"); stat = USB_ST_STALLED; } len = min_t(int, len, leni); if (buffer != data_buf) memcpy(buffer, data_buf, len); dev->act_len = len; dev->status = stat; DBG("dev act_len %d, status %d", dev->act_len, dev->status); dump_msg(dev, pipe, buffer, transfer_len, "RH(ret)"); return stat;}/* --- Transfer functions -------------------------------------------------- */int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len, int interval){ DBG("dev=%p pipe=%#lx buf=%p size=%d int=%d", dev, pipe, buffer, len, interval); return -1;}int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len, struct devrequest *setup){ int devnum = usb_pipedevice(pipe); int epnum = usb_pipeendpoint(pipe); int max = max_transfer_len(dev, pipe); int dir_in = usb_pipein(pipe); int done, ret; /* Control message is for the HUB? */ if (devnum == rh_devnum) return isp116x_submit_rh_msg(dev, pipe, buffer, len, setup); /* Ok, no HUB message so send the message to the device */ /* Setup phase */ DBG("--- SETUP PHASE --------------------------------"); usb_settoggle(dev, epnum, 1, 0); ret = isp116x_submit_job(dev, pipe, PTD_DIR_SETUP, setup, sizeof(struct devrequest)); if (ret < 0) { DBG("control setup phase error (ret = %d", ret); return -1; } /* Data phase */ DBG("--- DATA PHASE ---------------------------------"); done = 0; usb_settoggle(dev, epnum, !dir_in, 1); while (done < len) { ret = isp116x_submit_job(dev, pipe, dir_in ? PTD_DIR_IN : PTD_DIR_OUT, (__u8 *) buffer + done, max > len - done ? len - done : max); if (ret < 0) { DBG("control data phase error (ret = %d)", ret); return -1; } done += ret; if (dir_in && ret < max) /* short packet */ break; } /* Status phase */ DBG("--- STATUS PHASE -------------------------------"); usb_settoggle(dev, epnum, !dir_in, 1); ret = isp116x_submit_job(dev, pipe, !dir_in ? PTD_DIR_IN : PTD_DIR_OUT, NULL, 0); if (ret < 0) { DBG("control status phase error (ret = %d", ret); return -1; } dev->act_len = done; dump_msg(dev, pipe, buffer, len, "DEV(ret)"); return done;}int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer, int len){ int dir_out = usb_pipeout(pipe); int max = max_transfer_len(dev, pipe); int done, ret; DBG("--- BULK ---------------------------------------"); DBG("dev=%ld pipe=%ld buf=%p size=%d dir_out=%d", usb_pipedevice(pipe), usb_pipeendpoint(pipe), buffer, len, dir_out); done = 0; while (done < len) { ret = isp116x_submit_job(dev, pipe, !dir_out ? PTD_DIR_IN : PTD_DIR_OUT, (__u8 *) buffer + done, max > len - done ? len - done : max); if (ret < 0) { DBG("error on bulk message (ret = %d)", ret); return -1; } done += ret; if (!dir_out && ret < max) /* short packet */ break; } dev->act_len = done; return 0;}/* --- Basic functions ----------------------------------------------------- */static int isp116x_sw_reset(struct isp116x *isp116x){ int retries = 15; int ret = 0; DBG(""); isp116x->disabled = 1; isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC); isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR); while (--retries) { /* It usually resets within 1 ms */ wait_ms(1); if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR)) break; } if (!retries) { ERR("software reset timeout"); ret = -1; } return ret;}static int isp116x_reset(struct isp116x *isp116x){ unsigned long t; u16 clkrdy = 0; int ret, timeout = 15 /* ms */ ; DBG(""); ret = isp116x_sw_reset(isp116x); if (ret) return ret; for (t = 0; t < timeout; t++) { clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY; if (clkrdy) break; wait_ms(1); } if (!clkrdy) { ERR("clock not ready after %dms", timeout); /* After sw_reset the clock won't report to be ready, if H_WAKEUP pin is high. */ ERR("please make sure that the H_WAKEUP pin is pulled low!"); ret = -1; } return ret;}static void isp116x_stop(struct isp116x *isp116x){ u32 val; DBG(""); isp116x_write_reg16(isp116x, HCuPINTENB, 0); /* Switch off ports' power, some devices don't come up after next 'start' without this */ val = isp116x_read_reg32(isp116x, HCRHDESCA); val &= ~(RH_A_NPS | RH_A_PSM); isp116x_write_reg32(isp116x, HCRHDESCA, val); isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS); isp116x_sw_reset(isp116x);}/* * Configure the chip. The chip must be successfully reset by now. */static int isp116x_start(struct isp116x *isp116x){ struct isp116x_platform_data *board = isp116x->board; u32 val; DBG(""); /* Clear interrupt status and disable all interrupt sources */ isp116x_write_reg16(isp116x, HCuPINT, 0xff); isp116x_write_reg16(isp116x, HCuPINTENB, 0); isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE); isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE); /* Hardware configuration */ val = HCHWCFG_DBWIDTH(1); if (board->sel15Kres) val |= HCHWCFG_15KRSEL; /* Remote wakeup won't work without working clock */ if (board->remote_wakeup_enable) val |= HCHWCFG_CLKNOTSTOP; if (board->oc_enable) val |= HCHWCFG_ANALOG_OC; isp116x_write_reg16(isp116x, HCHWCFG, val); /* --- Root hub configuration */ val = (25 << 24) & RH_A_POTPGT; /* AN10003_1.pdf recommends RH_A_NPS (no power switching) to be always set. Yet, instead, we request individual port power switching. */ val |= RH_A_PSM; /* Report overcurrent per port */ val |= RH_A_OCPM; isp116x_write_reg32(isp116x, HCRHDESCA, val); isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA); val = RH_B_PPCM; isp116x_write_reg32(isp116x, HCRHDESCB, val); isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB); val = 0; if (board->remote_wakeup_enable) val |= RH_HS_DRWE; isp116x_write_reg32(isp116x, HCRHSTATUS, val); isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS); isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf); /* Go operational */ val = HCCONTROL_USB_OPER; if (board->remote_wakeup_enable) val |= HCCONTROL_RWE; isp116x_write_reg32(isp116x, HCCONTROL, val); /* Disable ports to avoid race in device enumeration */ isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS); isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS); isp116x_show_regs(isp116x); isp116x->disabled = 0; return 0;}/* --- Init functions ------------------------------------------------------ */int isp116x_check_id(struct isp116x *isp116x){ int val; val = isp116x_read_reg16(isp116x, HCCHIPID); if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) { ERR("invalid chip ID %04x", val); return -1; } return 0;}int usb_lowlevel_init(void){ struct isp116x *isp116x = &isp116x_dev; DBG(""); got_rhsc = rh_devnum = 0; /* Init device registers addr */ isp116x->addr_reg = (u16 *) ISP116X_HCD_ADDR; isp116x->data_reg = (u16 *) ISP116X_HCD_DATA; /* Setup specific board settings */#ifdef ISP116X_HCD_SEL15kRES isp116x_board.sel15Kres = 1;#endif#ifdef ISP116X_HCD_OC_ENABLE isp116x_board.oc_enable = 1;#endif#ifdef ISP116X_HCD_REMOTE_WAKEUP_ENABLE isp116x_board.remote_wakeup_enable = 1;#endif isp116x->board = &isp116x_board; /* Try to get ISP116x silicon chip ID */ if (isp116x_check_id(isp116x) < 0) return -1; isp116x->disabled = 1; isp116x->sleeping = 0; isp116x_reset(isp116x); isp116x_start(isp116x); return 0;}int usb_lowlevel_stop(void){ struct isp116x *isp116x = &isp116x_dev; DBG(""); if (!isp116x->disabled) isp116x_stop(isp116x); return 0;}#endif /* CONFIG_USB_ISP116X_HCD */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -