📄 usb-host.c
字号:
{ struct usb_reg_context *reg; DBFENTER; reg = (struct usb_reg_context *)kmalloc(sizeof(struct usb_reg_context), GFP_ATOMIC); if (!(reg)) { panic("kmalloc failed in top_half\n"); } reg->hc = (etrax_hc_t *)vhc; reg->r_usb_irq_mask_read = *R_USB_IRQ_MASK_READ; reg->r_usb_status = *R_USB_STATUS;#if 0 if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { panic("r_usb_status said perror\n"); } if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { panic("r_usb_status said ourun !!!\n"); }#endif reg->r_usb_epid_attn = *R_USB_EPID_ATTN; reg->r_usb_rh_port_status_1 = *R_USB_RH_PORT_STATUS_1; reg->r_usb_rh_port_status_2 = *R_USB_RH_PORT_STATUS_2; reg->usb_bh.sync = 0; reg->usb_bh.routine = etrax_usb_hc_intr_bottom_half; reg->usb_bh.data = reg; queue_task(®->usb_bh, &tq_immediate); mark_bh(IMMEDIATE_BH); DBFEXIT;}static int etrax_rh_submit_urb(urb_t *urb){ struct usb_device *usb_dev = urb->dev; etrax_hc_t *hc = usb_dev->bus->hcpriv; unsigned int pipe = urb->pipe; devrequest *cmd = (devrequest *) urb->setup_packet; void *data = urb->transfer_buffer; int leni = urb->transfer_buffer_length; int len = 0; int stat = 0; __u16 bmRType_bReq; __u16 wValue; __u16 wIndex; __u16 wLength; DBFENTER; if (usb_pipetype (pipe) == PIPE_INTERRUPT) { dbg_rh("Root-Hub submit IRQ: every %d ms", urb->interval); hc->rh.urb = urb; hc->rh.send = 1; hc->rh.interval = urb->interval; etrax_rh_init_int_timer(urb); DBFEXIT; return 0; } bmRType_bReq = cmd->requesttype | cmd->request << 8; wValue = le16_to_cpu(cmd->value); wIndex = le16_to_cpu(cmd->index); wLength = le16_to_cpu(cmd->length); dbg_rh("bmRType_bReq : 0x%04X (%d)", bmRType_bReq, bmRType_bReq); dbg_rh("wValue : 0x%04X (%d)", wValue, wValue); dbg_rh("wIndex : 0x%04X (%d)", wIndex, wIndex); dbg_rh("wLength : 0x%04X (%d)", wLength, wLength); switch (bmRType_bReq) { /* Request Destination: without flags: Device, RH_INTERFACE: interface, RH_ENDPOINT: endpoint, RH_CLASS means HUB here, RH_OTHER | RH_CLASS almost ever means HUB_PORT here */ case RH_GET_STATUS: *(__u16 *) data = cpu_to_le16 (1); OK (2); case RH_GET_STATUS | RH_INTERFACE: *(__u16 *) data = cpu_to_le16 (0); OK (2); case RH_GET_STATUS | RH_ENDPOINT: *(__u16 *) data = cpu_to_le16 (0); OK (2); case RH_GET_STATUS | RH_CLASS: *(__u32 *) data = cpu_to_le32 (0); OK (4); /* hub power ** */ case RH_GET_STATUS | RH_OTHER | RH_CLASS: if (wIndex == 1) { *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_1); *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_1); } else if (wIndex == 2) { *((__u16*)data) = cpu_to_le16(hc->rh.prev_wPortStatus_2); *((__u16*)data + 1) = cpu_to_le16(hc->rh.wPortChange_2); } else { dbg_rh("RH_GET_STATUS whith invalid wIndex !!"); OK(0); } OK(4); case RH_CLEAR_FEATURE | RH_ENDPOINT: switch (wValue) { case (RH_ENDPOINT_STALL): OK (0); } break; case RH_CLEAR_FEATURE | RH_CLASS: switch (wValue) { case (RH_C_HUB_OVER_CURRENT): OK (0); /* hub power over current ** */ } break; case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS: switch (wValue) { case (RH_PORT_ENABLE): if (wIndex == 1) { dbg_rh("trying to do disable of port 1"); *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, yes); while (hc->rh.prev_wPortStatus_1 & IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes)); *R_USB_PORT1_DISABLE = IO_STATE(R_USB_PORT1_DISABLE, disable, no); dbg_rh("Port 1 is disabled"); } else if (wIndex == 2) { dbg_rh("trying to do disable of port 2"); *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, yes); while (hc->rh.prev_wPortStatus_2 & IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes)); *R_USB_PORT2_DISABLE = IO_STATE(R_USB_PORT2_DISABLE, disable, no); dbg_rh("Port 2 is disabled"); } else { dbg_rh("RH_CLEAR_FEATURE->RH_PORT_ENABLE " "with invalid wIndex == %d!!", wIndex); } OK (0); case (RH_PORT_SUSPEND): /* Opposite to suspend should be resume, so well do a resume */ if (wIndex == 1) { *R_USB_COMMAND = IO_STATE(R_USB_COMMAND, port_sel, port1) | IO_STATE(R_USB_COMMAND, port_cmd, resume)| IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); } else if (wIndex == 2) { *R_USB_COMMAND = IO_STATE(R_USB_COMMAND, port_sel, port2) | IO_STATE(R_USB_COMMAND, port_cmd, resume)| IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); } else { dbg_rh("RH_CLEAR_FEATURE->RH_PORT_SUSPEND " "with invalid wIndex == %d!!", wIndex); } OK (0); case (RH_PORT_POWER): OK (0); /* port power ** */ case (RH_C_PORT_CONNECTION): if (wIndex == 1) { hc->rh.wPortChange_1 &= ~(1 << RH_PORT_CONNECTION); } else if (wIndex == 2) { hc->rh.wPortChange_2 &= ~(1 << RH_PORT_CONNECTION); } else { dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_CONNECTION " "with invalid wIndex == %d!!", wIndex); } OK (0); case (RH_C_PORT_ENABLE): if (wIndex == 1) { hc->rh.wPortChange_1 &= ~(1 << RH_PORT_ENABLE); } else if (wIndex == 2) { hc->rh.wPortChange_2 &= ~(1 << RH_PORT_ENABLE); } else { dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_ENABLE " "with invalid wIndex == %d!!", wIndex); } OK (0); case (RH_C_PORT_SUSPEND):/*** WR_RH_PORTSTAT(RH_PS_PSSC); */ OK (0); case (RH_C_PORT_OVER_CURRENT): OK (0); /* port power over current ** */ case (RH_C_PORT_RESET): if (wIndex == 1) { hc->rh.wPortChange_1 &= ~(1 << RH_PORT_RESET); } else if (wIndex == 2) { dbg_rh("This is wPortChange before clear: 0x%04X", hc->rh.wPortChange_2); hc->rh.wPortChange_2 &= ~(1 << RH_PORT_RESET); dbg_rh("This is wPortChange after clear: 0x%04X", hc->rh.wPortChange_2); } else { dbg_rh("RH_CLEAR_FEATURE->RH_C_PORT_RESET " "with invalid index == %d!!", wIndex); } OK (0); } break; case RH_SET_FEATURE | RH_OTHER | RH_CLASS: switch (wValue) { case (RH_PORT_SUSPEND): if (wIndex == 1) { *R_USB_COMMAND = IO_STATE(R_USB_COMMAND, port_sel, port1) | IO_STATE(R_USB_COMMAND, port_cmd, suspend) | IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); } else if (wIndex == 2) { *R_USB_COMMAND = IO_STATE(R_USB_COMMAND, port_sel, port2) | IO_STATE(R_USB_COMMAND, port_cmd, suspend) | IO_STATE(R_USB_COMMAND, ctrl_cmd, nop); } else { dbg_rh("RH_SET_FEATURE->RH_C_PORT_SUSPEND " "with invalid wIndex == %d!!", wIndex); } OK (0); case (RH_PORT_RESET): if (wIndex == 1) { int port1_retry; port1_redo: dbg_rh("Doing reset of port 1"); *R_USB_COMMAND = IO_STATE(R_USB_COMMAND, port_cmd, reset) | IO_STATE(R_USB_COMMAND, port_sel, port1); /* We must once again wait at least 10ms for the device to recover */ port1_retry = 0; while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_1)) & IO_STATE(R_USB_RH_PORT_STATUS_1, enabled, yes))) { printk(""); if (port1_retry++ >= 10000) {goto port1_redo;} } /* This only seems to work if we use printk, not even schedule() works !!! WHY ?? */ udelay(15000); } else if (wIndex == 2) { int port2_retry; port2_redo: dbg_rh("Doing reset of port 2"); *R_USB_COMMAND = IO_STATE(R_USB_COMMAND, port_cmd, reset) | IO_STATE(R_USB_COMMAND, port_sel, port2); /* We must once again wait at least 10ms for the device to recover */ port2_retry = 0; while (!((*((volatile __u16 *)&hc->rh.prev_wPortStatus_2)) & IO_STATE(R_USB_RH_PORT_STATUS_2, enabled, yes))) { printk(""); if (port2_retry++ >= 10000) {goto port2_redo;} } /* This only seems to work if we use printk, not even schedule() works !!! WHY ?? */ udelay(15000); } /* Try to bring the HC into running state */ *R_USB_COMMAND = IO_STATE(R_USB_COMMAND, ctrl_cmd, host_run); nop(); while (*R_USB_COMMAND & IO_MASK(R_USB_COMMAND, busy)); dbg_rh("...Done"); OK(0); case (RH_PORT_POWER): OK (0); /* port power ** */ case (RH_PORT_ENABLE): /* There is no rh port enable command in the Etrax USB interface!!!! */ OK (0); } break; case RH_SET_ADDRESS: hc->rh.devnum = wValue; dbg_rh("RH address set to: %d", hc->rh.devnum); OK (0); case RH_GET_DESCRIPTOR: switch ((wValue & 0xff00) >> 8) { case (0x01): /* device descriptor */ len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_dev_des), wLength)); memcpy (data, root_hub_dev_des, len); OK (len); case (0x02): /* configuration descriptor */ len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_config_des), wLength)); memcpy (data, root_hub_config_des, len); OK (len); case (0x03): /* string descriptors */ len = usb_root_hub_string (wValue & 0xff, 0xff, "ETRAX 100LX", data, wLength); if (len > 0) { OK(min(leni, len)); } else stat = -EPIPE; } break; case RH_GET_DESCRIPTOR | RH_CLASS: root_hub_hub_des[2] = hc->rh.numports; len = min_t(unsigned int, leni, min_t(unsigned int, sizeof (root_hub_hub_des), wLength)); memcpy (data, root_hub_hub_des, len); OK (len); case RH_GET_CONFIGURATION: *(__u8 *) data = 0x01; OK (1); case RH_SET_CONFIGURATION: OK (0); default: stat = -EPIPE; } urb->actual_length = len; urb->status = stat; urb->dev = NULL; if (urb->complete) { urb->complete (urb); } DBFEXIT; return 0;}static int __init etrax_usb_hc_init(void){ static etrax_hc_t *hc; struct usb_bus *bus; struct usb_device *usb_rh; DBFENTER; info("ETRAX 100LX USB-HCD %s (c) 2001 Axis Communications AB\n", usb_hcd_version); hc = kmalloc(sizeof(etrax_hc_t), GFP_KERNEL); /* We use kmem_cache_* to make sure that all DMA desc. are dword aligned */ usb_desc_cache = kmem_cache_create("usb_desc_cache", sizeof(USB_EP_Desc_t), 0, 0, 0, 0); if (!usb_desc_cache) { panic("USB Desc Cache allocation failed !!!\n"); } etrax_usb_bus = bus = usb_alloc_bus(&etrax_usb_device_operations); hc->bus = bus; bus->hcpriv = hc; /* Initalize RH to the default address. And make sure that we have no status change indication */ hc->rh.numports = 2; /* The RH has two ports */ hc->rh.devnum = 0; hc->rh.wPortChange_1 = 0; hc->rh.wPortChange_2 = 0; /* Also initate the previous values to zero */ hc->rh.prev_wPortStatus_1 = 0; hc->rh.prev_wPortStatus_2 = 0; /* Initialize the intr-traffic flags */ hc->intr.sleeping = 0; hc->intr.wq = NULL; /* Initially all ep's are free except ep 0 */ ep_usage_bitmask = 0; set_bit(0, (void *)&ep_usage_bitmask); ep_really_active = 0; ep_out_traffic = 0; memset(URB_List, 0, sizeof(URB_List)); /* This code should really be moved */ if (request_dma(USB_TX_DMA_NBR, "ETRAX 100LX built-in USB (Tx)")) { err("Could not allocate DMA ch 8 for USB"); etrax_usb_hc_cleanup(); DBFEXIT; return -1; } if (request_dma(USB_RX_DMA_NBR, "ETRAX 100LX built-in USB (Rx)")) { err("Could not allocate DMA ch 9 for USB"); etrax_usb_hc_cleanup(); DBFEXIT; return -1; } #if 0 /* Moved to head.S */ *R_GEN_CONFIG = genconfig_shadow = (genconfig_shadow & ~(IO_MASK(R_GEN_CONFIG, usb1) | IO_MASK(R_GEN_CONFIG, usb2) | IO_MASK(R_GEN_CONFIG, dma8) | IO_MASK(R_GEN_CONFIG, dma9))) | IO_STATE(R_GEN_CONFIG, dma8, usb) | IO_STATE(R_GEN_CONFIG, dma9, usb)#ifdef CONFIG_ETRAX_USB_HOST_PORT1 | IO_STATE(R_GEN_CONFIG, usb1, select)#endif#ifdef CONFIG_ETRAX_USB_HOST_PORT2 | IO_STATE(R_GEN_CONFIG, usb2, select)#endif ;#endif usb_register_bus(hc->bus); /* We may have to set more bits, but these are the obvious ones */ *R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma8_sub0_descr, set) | IO_STATE(R_IRQ_MASK2_SET, dma8_sub1_descr, set) | IO_STATE(R_IRQ_MASK2_SET, dma8_sub2_descr, set) | IO_STATE(R_IRQ_MASK2_SET, dma8_sub3_descr, set); *R_IRQ_MASK2_SET = IO_STATE(R_IRQ_MASK2_SET, dma9_eop, set) | IO_STATE(R_IRQ_MASK2_SET, dma9_descr, set); *R_USB_IRQ_MASK_SET = IO_STATE(R_USB_IRQ_MASK_SET, ctl_status, set) | IO_STATE(R_USB_IRQ_MASK_SET, ctl_eot, set) | IO_STATE(R_USB_IRQ_MASK_SET, bulk_eot, set) |#ifdef ETRAX_USB_INTR_IRQ IO_STATE(R_USB_IRQ_MASK_SET, intr_eot, set) |#endif IO_STATE(R_USB_IRQ_MASK_SET, epid_attn, set) | IO_STATE(R_USB_IRQ_MASK_SET, port_status, set); if (request_irq(ETRAX_USB_HC_IRQ, etrax_usb_hc_intr_top_half, 0, "ETRAX 100LX built-in USB (HC)", hc)) { err("Could not allocate IRQ %d for USB", ETRAX_USB_HC_IRQ); etrax_usb_hc_cleanup(); DBFEXIT; return -1; } if (request_irq(ETRAX_USB_RX_IRQ, etrax_usb_rx_interrupt, 0, "ETRAX 100LX bu
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -