📄 usb-host.c
字号:
urb_t *prev = NULL; int pos = 0; for (; u; u = u->next) { pos++; if (u == urb) { if (!prev) { URB_List[epid] = u->next; } else { prev->next = u->next; } restore_flags(flags); if (!prev) { if (usb_pipetype(u->pipe) == PIPE_CONTROL) { if (TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable)) { /* The EP was enabled, disable it and wait */ TxCtrlEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); while (*R_DMA_CH8_SUB1_EP == virt_to_phys(&TxCtrlEPList[epid])); } } else if (usb_pipetype(u->pipe) == PIPE_BULK) { if (TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable)) { TxBulkEPList[epid].command &= ~IO_MASK(USB_EP_command, enable); while (*R_DMA_CH8_SUB0_EP == virt_to_phys(&TxBulkEPList[epid])); } } } info("Found urb at epid %d, pos %d", epid, pos); u->status = -ENOENT; if (u->complete) { u->complete(u); } hc_priv = (etrax_urb_priv_t *)u->hcpriv; cleanup_sb(hc_priv->first_sb); kfree(hc_priv); DBFEXIT; return 0; } prev = u; } } restore_flags(flags); DBFEXIT; return 0;}static int etrax_usb_get_frame_number(struct usb_device *usb_dev){ DBFENTER; DBFEXIT; return (*R_USB_FM_NUMBER);}static int etrax_usb_allocate_dev(struct usb_device *usb_dev){ DBFENTER; DBFEXIT; return 0;}static int etrax_usb_deallocate_dev(struct usb_device *usb_dev){ DBFENTER; DBFEXIT; return 0;}static void etrax_usb_tx_interrupt(int irq, void *vhc, struct pt_regs *regs){ DBFENTER; if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub0_descr)) { info("dma8_sub0_descr (BULK) intr."); *R_DMA_CH8_SUB0_CLR_INTR = IO_STATE(R_DMA_CH8_SUB0_CLR_INTR, clr_descr, do); } if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub1_descr)) { info("dma8_sub1_descr (CTRL) intr."); *R_DMA_CH8_SUB1_CLR_INTR = IO_STATE(R_DMA_CH8_SUB1_CLR_INTR, clr_descr, do); } if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub2_descr)) { info("dma8_sub2_descr (INT) intr."); *R_DMA_CH8_SUB2_CLR_INTR = IO_STATE(R_DMA_CH8_SUB2_CLR_INTR, clr_descr, do); } if (*R_IRQ_READ2 & IO_MASK(R_IRQ_READ2, dma8_sub3_descr)) { info("dma8_sub3_descr (ISO) intr."); *R_DMA_CH8_SUB3_CLR_INTR = IO_STATE(R_DMA_CH8_SUB3_CLR_INTR, clr_descr, do); } DBFEXIT;}static void etrax_usb_rx_interrupt(int irq, void *vhc, struct pt_regs *regs){ int epid = 0; urb_t *urb; etrax_urb_priv_t *urb_priv; *R_DMA_CH9_CLR_INTR = IO_STATE(R_DMA_CH9_CLR_INTR, clr_eop, do); while (myNextRxDesc->status & IO_MASK(USB_IN_status, eop)) { if (myNextRxDesc->status & IO_MASK(USB_IN_status, nodata)) { goto skip_out; } if (myNextRxDesc->status & IO_MASK(USB_IN_status, error)) { goto skip_out; } epid = IO_EXTRACT(USB_IN_status, epid, myNextRxDesc->status); urb = URB_List[epid]; if (urb && usb_pipein(urb->pipe)) { urb_priv = (etrax_urb_priv_t *)urb->hcpriv; if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { struct in_chunk *in; dbg_intr("Packet for epid %d in rx buffers", epid); in = kmalloc(sizeof(struct in_chunk), GFP_ATOMIC); in->length = myNextRxDesc->hw_len; in->data = kmalloc(in->length, GFP_ATOMIC); memcpy(in->data, phys_to_virt(myNextRxDesc->buf), in->length); list_add_tail(&in->list, &urb_priv->ep_in_list);#ifndef ETRAX_USB_INTR_IRQ etrax_usb_hc_intr_top_half(irq, vhc, regs);#endif } else { if ((urb_priv->rx_offset + myNextRxDesc->hw_len) > urb->transfer_buffer_length) { err("Packet (epid: %d) in RX buffer (%d) was bigger " "than the URB has room for (%d)!!!", epid, urb_priv->rx_offset + myNextRxDesc->hw_len, urb->transfer_buffer_length); goto skip_out; } memcpy(urb->transfer_buffer + urb_priv->rx_offset, phys_to_virt(myNextRxDesc->buf), myNextRxDesc->hw_len); urb_priv->rx_offset += myNextRxDesc->hw_len; } if (myNextRxDesc->status & IO_MASK(USB_IN_status, eot)) { urb_priv->eot = 1; } } else { err("This is almost fatal, inpacket for epid %d which does not exist " " or is out!!!\nURB was at 0x%08lX", epid, (unsigned long)urb); goto skip_out; } skip_out: myPrevRxDesc = myNextRxDesc; myPrevRxDesc->command |= IO_MASK(USB_IN_command, eol); myLastRxDesc->command &= ~IO_MASK(USB_IN_command, eol); myLastRxDesc = myPrevRxDesc; myNextRxDesc->status = 0; myNextRxDesc = phys_to_virt(myNextRxDesc->next); }}static void cleanup_sb(USB_SB_Desc_t *sb){ USB_SB_Desc_t *next_sb; DBFENTER; if (sb == NULL) { err("cleanup_sb was given a NULL pointer"); return; } while (!(sb->command & IO_MASK(USB_SB_command, eol))) { next_sb = (USB_SB_Desc_t *)phys_to_virt(sb->next); kmem_cache_free(usb_desc_cache, sb); sb = next_sb; } kmem_cache_free(usb_desc_cache, sb); DBFEXIT;}static void handle_control_transfer_attn(int epid, int status){ urb_t *old_urb; etrax_urb_priv_t *hc_priv; DBFENTER; clear_bit(epid, (void *)&ep_really_active); old_urb = URB_List[epid]; URB_List[epid] = old_urb->next; /* if (status == 0 && IN) find data and copy to urb */ if (status == 0 && usb_pipein(old_urb->pipe)) { unsigned long flags; etrax_urb_priv_t *urb_priv; urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; save_flags(flags); cli(); if (urb_priv->eot == 1) { old_urb->actual_length = urb_priv->rx_offset; dbg_ctrl("urb_priv->rx_offset: %d in handle_control_attn", urb_priv->rx_offset); } else { status = -EPROTO; old_urb->actual_length = 0; err("(CTRL) No eot set in IN data!!! rx_offset: %d", urb_priv->rx_offset); } restore_flags(flags); } /* If there are any more URB's in the list we'd better start sending */ if (URB_List[epid]) { etrax_usb_do_ctrl_hw_add(URB_List[epid], epid, usb_maxpacket(URB_List[epid]->dev, URB_List[epid]->pipe, usb_pipeout(URB_List[epid]->pipe))); }#if 1 else { /* This means that this EP is now free, deconfigure it */ etrax_usb_free_epid(epid); }#endif /* Remember to free the SB's */ hc_priv = (etrax_urb_priv_t *)old_urb->hcpriv; cleanup_sb(hc_priv->first_sb); kfree(hc_priv); old_urb->status = status; if (old_urb->complete) { old_urb->complete(old_urb); } DBFEXIT;}static void etrax_usb_hc_intr_bottom_half(void *data){ struct usb_reg_context *reg = (struct usb_reg_context *)data; int error_code; int epid; __u32 r_usb_ept_data; etrax_hc_t *hc = reg->hc; __u16 r_usb_rh_port_status_1; __u16 r_usb_rh_port_status_2; DBFENTER; if (reg->r_usb_irq_mask_read & IO_MASK(R_USB_IRQ_MASK_READ, port_status)) { /* The Etrax RH does not include a wPortChange register, so this has to be handled in software. See section 11.16.2.6.2 in USB 1.1 spec for details. */ r_usb_rh_port_status_1 = reg->r_usb_rh_port_status_1; r_usb_rh_port_status_2 = reg->r_usb_rh_port_status_2; dbg_rh("port_status pending"); dbg_rh("r_usb_rh_port_status_1: 0x%04X", r_usb_rh_port_status_1); dbg_rh("r_usb_rh_port_status_2: 0x%04X", r_usb_rh_port_status_2); /* C_PORT_CONNECTION is set on any transition */ hc->rh.wPortChange_1 |= ((r_usb_rh_port_status_1 & (1 << RH_PORT_CONNECTION)) != (hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_CONNECTION))) ? (1 << RH_PORT_CONNECTION) : 0; hc->rh.wPortChange_2 |= ((r_usb_rh_port_status_2 & (1 << RH_PORT_CONNECTION)) != (hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_CONNECTION))) ? (1 << RH_PORT_CONNECTION) : 0; /* C_PORT_ENABLE is _only_ set on a one to zero transition */ hc->rh.wPortChange_1 |= ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_ENABLE)) && !(r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? (1 << RH_PORT_ENABLE) : 0; hc->rh.wPortChange_2 |= ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_ENABLE)) && !(r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? (1 << RH_PORT_ENABLE) : 0; /* C_PORT_SUSPEND seems difficult, lets ignore it.. (for now) */ /* C_PORT_RESET is _only_ set on a transition from the resetting state to the enabled state */ hc->rh.wPortChange_1 |= ((hc->rh.prev_wPortStatus_1 & (1 << RH_PORT_RESET)) && (r_usb_rh_port_status_1 & (1 << RH_PORT_ENABLE))) ? (1 << RH_PORT_RESET) : 0; hc->rh.wPortChange_2 |= ((hc->rh.prev_wPortStatus_2 & (1 << RH_PORT_RESET)) && (r_usb_rh_port_status_2 & (1 << RH_PORT_ENABLE))) ? (1 << RH_PORT_RESET) : 0; hc->rh.prev_wPortStatus_1 = r_usb_rh_port_status_1; hc->rh.prev_wPortStatus_2 = r_usb_rh_port_status_2; } for (epid = 0; epid < 32; epid++) { unsigned long flags; save_flags(flags); cli(); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); r_usb_ept_data = *R_USB_EPT_DATA; restore_flags(flags); if (r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, hold)) { warn("Was hold for epid %d", epid); continue; } if (!(r_usb_ept_data & IO_MASK(R_USB_EPT_DATA, valid))) { continue; } if (test_bit(epid, (void *)®->r_usb_epid_attn)) { if (URB_List[epid] == NULL) { err("R_USB_EPT_DATA is 0x%08X", r_usb_ept_data); err("submit urb has been called %lu times..", submit_urb_count); err("EPID_ATTN for epid %d, with NULL entry in list", epid); return; } dbg_ep("r_usb_ept_data [%d] == 0x%08X", epid, r_usb_ept_data); error_code = IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data); if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { /* no_error means that this urb was sucessfully sent or that we have some undefinde error*/ if (IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data) == 3 || IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data) == 3) { /* Actually there were transmission errors */ warn("Undefined error for epid %d", epid); if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { handle_control_transfer_attn(epid, -EPROTO); } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { handle_bulk_transfer_attn(epid, -EPROTO); } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { handle_intr_transfer_attn(epid, -EPROTO); } } else { if (reg->r_usb_status & IO_MASK(R_USB_STATUS, perror)) { if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { etrax_usb_do_intr_recover(epid); } else { panic("Epid attention for epid %d (none INTR), with no errors and no " "exessive retry r_usb_status is 0x%02X\n", epid, reg->r_usb_status); } } else if (reg->r_usb_status & IO_MASK(R_USB_STATUS, ourun)) { panic("Epid attention for epid %d, with no errors and no " "exessive retry r_usb_status is 0x%02X\n", epid, reg->r_usb_status); } warn("Epid attention for epid %d, with no errors and no " "exessive retry r_usb_status is 0x%02X", epid, reg->r_usb_status); warn("OUT error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_out, r_usb_ept_data)); warn("IN error count: %d", IO_EXTRACT(R_USB_EPT_DATA, error_count_in, r_usb_ept_data)); } } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, stall)) { warn("Stall for epid %d", epid); if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { handle_control_transfer_attn(epid, -EPIPE); } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { handle_bulk_transfer_attn(epid, -EPIPE); } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { handle_intr_transfer_attn(epid, -EPIPE); } } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, bus_error)) { panic("USB bus error for epid %d\n", epid); } else if (error_code == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, buffer_error)) { warn("Buffer error for epid %d", epid); if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { handle_control_transfer_attn(epid, -EPROTO); } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { handle_bulk_transfer_attn(epid, -EPROTO); } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { handle_intr_transfer_attn(epid, -EPROTO); } } } else if (test_bit(epid, (void *)&ep_really_active)) { /* Should really be else if (testbit(really active)) */ if (usb_pipetype(URB_List[epid]->pipe) == PIPE_CONTROL) { if (!(TxCtrlEPList[epid].command & IO_MASK(USB_EP_command, enable))) { /* Now we have to verify that this CTRL endpoint got disabled cause it reached end of list with no error */ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { /* This means that the endpoint has no error, is disabled and had inserted traffic, i.e. transfer sucessfully completed */ dbg_ctrl("Last SB for CTRL %d sent sucessfully", epid); handle_control_transfer_attn(epid, 0); } } } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_BULK) { if (!(TxBulkEPList[epid].command & IO_MASK(USB_EP_command, enable))) { /* Now we have to verify that this BULK endpoint go disabled cause it reached end of list with no error */ if (IO_EXTRACT(R_USB_EPT_DATA, error_code, r_usb_ept_data) == IO_STATE_VALUE(R_USB_EPT_DATA, error_code, no_error)) { /* This means that the endpoint has no error, is disabled and had inserted traffic, i.e. transfer sucessfully completed */ dbg_bulk("Last SB for BULK %d sent sucessfully", epid); handle_bulk_transfer_attn(epid, 0); } } } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { handle_intr_transfer_attn(epid, 0); } } } kfree(reg); DBFEXIT;}static void etrax_usb_hc_intr_top_half(int irq, void *vhc, struct pt_regs *regs)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -