📄 usb-host.c
字号:
{ USB_SB_Desc_t *sb_desc_1; etrax_urb_priv_t *urb_priv; unsigned long flags; DBFENTER; urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL); sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); if (usb_pipeout(urb->pipe)) { dbg_bulk("Bulk transfer for epid %d is OUT", epid); dbg_bulk("transfer_buffer_length == %d", urb->transfer_buffer_length); dbg_bulk("actual_length == %d", urb->actual_length); if (urb->transfer_buffer_length > 0xffff) { panic(__FILE__ __FUNCTION__ ":urb->transfer_buffer_length > 0xffff\n"); } sb_desc_1->sw_len = urb->transfer_buffer_length; /* was actual_length */ sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | IO_STATE(USB_SB_command, tt, out) |#if 0 IO_STATE(USB_SB_command, full, no) |#else IO_STATE(USB_SB_command, full, yes) |#endif IO_STATE(USB_SB_command, eot, yes) | IO_STATE(USB_SB_command, eol, yes); dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); sb_desc_1->buf = virt_to_phys(urb->transfer_buffer); sb_desc_1->next = 0; } else if (usb_pipein(urb->pipe)) { dbg_bulk("Transfer for epid %d is IN", epid); dbg_bulk("transfer_buffer_length = %d", urb->transfer_buffer_length); dbg_bulk("rem is calculated to %d", urb->transfer_buffer_length % maxlen); sb_desc_1->sw_len = urb->transfer_buffer_length ? (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; dbg_bulk("sw_len got %d", sb_desc_1->sw_len); dbg_bulk("transfer_buffer is at 0x%08X", urb->transfer_buffer); sb_desc_1->command = IO_FIELD(USB_SB_command, rem, urb->transfer_buffer_length % maxlen) | IO_STATE(USB_SB_command, tt, in) | IO_STATE(USB_SB_command, eot, yes) | IO_STATE(USB_SB_command, eol, yes); sb_desc_1->buf = 0; sb_desc_1->next = 0; urb_priv->rx_offset = 0; urb_priv->eot = 0; } urb_priv->first_sb = sb_desc_1; urb->hcpriv = (void *)urb_priv; /* Reset toggle bits and reset error count, remeber to di and ei */ /* Warning: it is possible that this locking doesn't work with bottom-halves */ save_flags(flags); cli(); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { panic("Hold was set in %s\n", __FUNCTION__); } *R_USB_EPT_DATA &= ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | IO_MASK(R_USB_EPT_DATA, error_count_out)); if (usb_pipeout(urb->pipe)) { char toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_out); *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_out, toggle); } else { char toggle = usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)); *R_USB_EPT_DATA &= ~IO_MASK(R_USB_EPT_DATA, t_in); *R_USB_EPT_DATA |= IO_FIELD(R_USB_EPT_DATA, t_in, toggle); } /* Enable the EP descr. */ set_bit(epid, (void *)&ep_really_active); TxBulkEPList[epid].sub = virt_to_phys(sb_desc_1); TxBulkEPList[epid].hw_len = 0; TxBulkEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); restore_flags(flags); if (!(*R_DMA_CH8_SUB0_CMD & IO_MASK(R_DMA_CH8_SUB0_CMD, cmd))) { *R_DMA_CH8_SUB0_CMD = IO_STATE(R_DMA_CH8_SUB0_CMD, cmd, start); } DBFEXIT;}static void handle_bulk_transfer_attn(int epid, int status){ urb_t *old_urb; etrax_urb_priv_t *hc_priv; unsigned long flags; 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)) { 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; } else { if (urb_priv->rx_offset == 0) { status = 0; } else { status = -EPROTO; } old_urb->actual_length = 0; err("(BULK) No eot set in IN data!!! rx_offset is: %d", urb_priv->rx_offset); } restore_flags(flags); } save_flags(flags); cli(); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); if (usb_pipeout(old_urb->pipe)) { char toggle = IO_EXTRACT(R_USB_EPT_DATA, t_out, *R_USB_EPT_DATA); usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), usb_pipeout(old_urb->pipe), toggle); } else { char toggle = IO_EXTRACT(R_USB_EPT_DATA, t_in, *R_USB_EPT_DATA); usb_settoggle(old_urb->dev, usb_pipeendpoint(old_urb->pipe), usb_pipeout(old_urb->pipe), toggle); } 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_bulk_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 int etrax_usb_submit_ctrl_urb(urb_t *urb){ int epid; char devnum; char endpoint; char maxlen; char out_traffic; char slow; urb_t *tmp_urb; unsigned long flags; DBFENTER; devnum = usb_pipedevice(urb->pipe); endpoint = usb_pipeendpoint(urb->pipe); maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); out_traffic = usb_pipeout(urb->pipe); slow = usb_pipeslow(urb->pipe); epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen, out_traffic); if (epid == -1) { epid = etrax_usb_allocate_epid(); if (epid == -1) { /* We're out of endpoints, return some error */ err("We're out of endpoints"); return -ENOMEM; } /* Now we have to fill in this ep */ etrax_usb_setup_epid(epid, devnum, endpoint, maxlen, slow, out_traffic); } /* Ok, now we got valid endpoint, lets insert some traffic */ urb->status = -EINPROGRESS; save_flags(flags); cli(); if (URB_List[epid]) { /* Find end of list and add */ for (tmp_urb = URB_List[epid]; tmp_urb->next; tmp_urb = tmp_urb->next) dump_urb(tmp_urb); tmp_urb->next = urb; restore_flags(flags); } else { /* If this is the first URB, add the URB and do HW add */ URB_List[epid] = urb; restore_flags(flags); etrax_usb_do_ctrl_hw_add(urb, epid, maxlen); } DBFEXIT; return 0;}static void etrax_usb_do_ctrl_hw_add(urb_t *urb, int epid, char maxlen){ USB_SB_Desc_t *sb_desc_1; USB_SB_Desc_t *sb_desc_2; USB_SB_Desc_t *sb_desc_3; etrax_urb_priv_t *urb_priv; unsigned long flags; DBFENTER; urb_priv = kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL); sb_desc_1 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); sb_desc_2 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); if (!(sb_desc_1 && sb_desc_2)) { panic("kmem_cache_alloc in ctrl_hw_add gave NULL pointers !!!\n"); } sb_desc_1->sw_len = 8; sb_desc_1->command = IO_FIELD(USB_SB_command, rem, 0) | IO_STATE(USB_SB_command, tt, setup) | IO_STATE(USB_SB_command, full, yes) | IO_STATE(USB_SB_command, eot, yes); sb_desc_1->buf = virt_to_phys(urb->setup_packet); sb_desc_1->next = virt_to_phys(sb_desc_2); dump_sb_desc(sb_desc_1); if (usb_pipeout(urb->pipe)) { dbg_ctrl("Transfer for epid %d is OUT", epid); /* If this Control OUT transfer has an optional data stage we add an OUT token before the mandatory IN (status) token, hence the reordered SB list */ if (urb->transfer_buffer) { dbg_ctrl("This OUT transfer has an extra data stage"); sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); sb_desc_1->next = virt_to_phys(sb_desc_3); sb_desc_3->sw_len = urb->transfer_buffer_length; sb_desc_3->command = IO_STATE(USB_SB_command, tt, out) | IO_STATE(USB_SB_command, full, yes) | IO_STATE(USB_SB_command, eot, yes); sb_desc_3->buf = virt_to_phys(urb->transfer_buffer); sb_desc_3->next = virt_to_phys(sb_desc_2); } sb_desc_2->sw_len = 1; sb_desc_2->command = IO_FIELD(USB_SB_command, rem, 0) | IO_STATE(USB_SB_command, tt, in) | IO_STATE(USB_SB_command, eot, yes) | IO_STATE(USB_SB_command, eol, yes); sb_desc_2->buf = 0; sb_desc_2->next = 0; dump_sb_desc(sb_desc_2); } else if (usb_pipein(urb->pipe)) { dbg_ctrl("Transfer for epid %d is IN", epid); dbg_ctrl("transfer_buffer_length = %d", urb->transfer_buffer_length); dbg_ctrl("rem is calculated to %d", urb->transfer_buffer_length % maxlen); sb_desc_3 = (USB_SB_Desc_t*)kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); sb_desc_2->sw_len = urb->transfer_buffer_length ? (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; dbg_ctrl("sw_len got %d", sb_desc_2->sw_len); sb_desc_2->command = IO_FIELD(USB_SB_command, rem, urb->transfer_buffer_length % maxlen) | IO_STATE(USB_SB_command, tt, in) | IO_STATE(USB_SB_command, eot, yes); sb_desc_2->buf = 0; sb_desc_2->next = virt_to_phys(sb_desc_3); dump_sb_desc(sb_desc_2); sb_desc_3->sw_len = 1; sb_desc_3->command = IO_FIELD(USB_SB_command, rem, 0) | IO_STATE(USB_SB_command, tt, zout) | IO_STATE(USB_SB_command, full, yes) | IO_STATE(USB_SB_command, eot, yes) | IO_STATE(USB_SB_command, eol, yes); sb_desc_3->buf = 0; sb_desc_3->next = 0; dump_sb_desc(sb_desc_3); urb_priv->rx_offset = 0; urb_priv->eot = 0; } urb_priv->first_sb = sb_desc_1; urb->hcpriv = (void *)urb_priv; /* Reset toggle bits and reset error count, remeber to di and ei */ /* Warning: it is possible that this locking doesn't work with bottom-halves */ save_flags(flags); cli(); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); if (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)) { panic("Hold was set in %s\n", __FUNCTION__); } *R_USB_EPT_DATA &= ~(IO_MASK(R_USB_EPT_DATA, error_count_in) | IO_MASK(R_USB_EPT_DATA, error_count_out) | IO_MASK(R_USB_EPT_DATA, t_in) | IO_MASK(R_USB_EPT_DATA, t_out)); /* Enable the EP descr. */ set_bit(epid, (void *)&ep_really_active); TxCtrlEPList[epid].sub = virt_to_phys(sb_desc_1); TxCtrlEPList[epid].hw_len = 0; TxCtrlEPList[epid].command |= IO_STATE(USB_EP_command, enable, yes); restore_flags(flags); dump_ep_desc(&TxCtrlEPList[epid]); if (!(*R_DMA_CH8_SUB1_CMD & IO_MASK(R_DMA_CH8_SUB1_CMD, cmd))) { *R_DMA_CH8_SUB1_CMD = IO_STATE(R_DMA_CH8_SUB1_CMD, cmd, start); } DBFEXIT;}static int etrax_usb_submit_urb(urb_t *urb){ etrax_hc_t *hc; int rval = -EINVAL; DBFENTER; urb->next = NULL; dump_urb(urb); submit_urb_count++; hc = (etrax_hc_t*) urb->dev->bus->hcpriv; if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { /* This request if for the Virtual Root Hub */ rval = etrax_rh_submit_urb(urb); } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { rval = etrax_usb_submit_ctrl_urb(urb); } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { rval = etrax_usb_submit_bulk_urb(urb); } else if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) { int bustime; if (urb->bandwidth == 0) { bustime = usb_check_bandwidth(urb->dev, urb); if (bustime < 0) { rval = bustime; } else { usb_claim_bandwidth(urb->dev, urb, bustime, 0); rval = etrax_usb_submit_intr_urb(urb); } } } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { warn("Isochronous traffic is not supported !!!"); rval = -EINVAL; } DBFEXIT; return rval;}static int etrax_usb_unlink_urb(urb_t *urb){ etrax_hc_t *hc = urb->dev->bus->hcpriv; int epid; int devnum, endpoint, slow, maxlen, out_traffic; etrax_urb_priv_t *hc_priv; unsigned long flags; DBFENTER; dump_urb(urb); devnum = usb_pipedevice(urb->pipe); endpoint = usb_pipeendpoint(urb->pipe); slow = usb_pipeslow(urb->pipe); maxlen = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)); out_traffic = usb_pipeout(urb->pipe); epid = etrax_usb_lookup_epid(devnum, endpoint, slow, maxlen, out_traffic); if (epid == -1) return 0; if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { int ret; ret = etrax_rh_unlink_urb(urb); DBFEXIT; return ret; } else if (usb_pipetype(URB_List[epid]->pipe) == PIPE_INTERRUPT) { int ret; ret = etrax_usb_unlink_intr_urb(urb); urb->status = -ENOENT; if (urb->complete) { urb->complete(urb); } DBFEXIT; return ret; } info("Unlink of BULK or CTRL"); save_flags(flags); cli(); for (epid = 0; epid < 32; epid++) { urb_t *u = URB_List[epid];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -