📄 usb-host.c
字号:
int i; DBFENTER; /* Read comment at zout_buffer declaration for an explanation to this. */ TxIntrSB_zout.sw_len = 1; TxIntrSB_zout.next = 0; TxIntrSB_zout.buf = virt_to_phys(&zout_buffer[0]); TxIntrSB_zout.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)); for (i = 0; i < (MAX_INTR_INTERVAL - 1); i++) { CHECK_ALIGN(&TxIntrEPList[i]); TxIntrEPList[i].hw_len = 0; TxIntrEPList[i].command = (IO_STATE(USB_EP_command, eof, yes) | IO_STATE(USB_EP_command, enable, yes) | IO_FIELD(USB_EP_command, epid, INVALID_EPID)); TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[i + 1]); } CHECK_ALIGN(&TxIntrEPList[i]); TxIntrEPList[i].hw_len = 0; TxIntrEPList[i].command = (IO_STATE(USB_EP_command, eof, yes) | IO_STATE(USB_EP_command, eol, yes) | IO_STATE(USB_EP_command, enable, yes) | IO_FIELD(USB_EP_command, epid, INVALID_EPID)); TxIntrEPList[i].sub = virt_to_phys(&TxIntrSB_zout); TxIntrEPList[i].next = virt_to_phys(&TxIntrEPList[0]); *R_DMA_CH8_SUB2_EP = virt_to_phys(&TxIntrEPList[0]); *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); DBFEXIT;}static void init_tx_isoc_ep(void){ int i; DBFENTER; /* Read comment at zout_buffer declaration for an explanation to this. */ TxIsocSB_zout.sw_len = 1; TxIsocSB_zout.next = 0; TxIsocSB_zout.buf = virt_to_phys(&zout_buffer[0]); TxIsocSB_zout.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)); /* The last isochronous EP descriptor is a dummy. */ for (i = 0; i < (NBR_OF_EPIDS - 1); i++) { CHECK_ALIGN(&TxIsocEPList[i]); TxIsocEPList[i].hw_len = 0; TxIsocEPList[i].command = IO_FIELD(USB_EP_command, epid, i); TxIsocEPList[i].sub = 0; TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[i + 1]); } CHECK_ALIGN(&TxIsocEPList[i]); TxIsocEPList[i].hw_len = 0; /* Must enable the last EP descr to get eof interrupt. */ TxIsocEPList[i].command = (IO_STATE(USB_EP_command, enable, yes) | IO_STATE(USB_EP_command, eof, yes) | IO_STATE(USB_EP_command, eol, yes) | IO_FIELD(USB_EP_command, epid, INVALID_EPID)); TxIsocEPList[i].sub = virt_to_phys(&TxIsocSB_zout); TxIsocEPList[i].next = virt_to_phys(&TxIsocEPList[0]); *R_DMA_CH8_SUB3_EP = virt_to_phys(&TxIsocEPList[0]); *R_DMA_CH8_SUB3_CMD = IO_STATE(R_DMA_CH8_SUB3_CMD, cmd, start); DBFEXIT;}static void etrax_usb_unlink_intr_urb(urb_t *urb){ volatile USB_EP_Desc_t *first_ep; /* First EP in the list. */ volatile USB_EP_Desc_t *curr_ep; /* Current EP, the iterator. */ volatile USB_EP_Desc_t *next_ep; /* The EP after current. */ volatile USB_EP_Desc_t *unlink_ep; /* The one we should remove from the list. */ int epid; /* Read 8.8.4 in Designer's Reference, "Removing an EP Descriptor from the List". */ DBFENTER; epid = ((etrax_urb_priv_t *)urb->hcpriv)->epid; first_ep = &TxIntrEPList[0]; curr_ep = first_ep; /* Note that this loop removes all EP descriptors with this epid. This assumes that all EP descriptors belong to the one and only urb for this epid. */ do { next_ep = (USB_EP_Desc_t *)phys_to_virt(curr_ep->next); if (IO_EXTRACT(USB_EP_command, epid, next_ep->command) == epid) { dbg_intr("Found EP to unlink for epid %d", epid); /* This is the one we should unlink. */ unlink_ep = next_ep; /* Actually unlink the EP from the DMA list. */ curr_ep->next = unlink_ep->next; /* Wait until the DMA is no longer at this descriptor. */ while (*R_DMA_CH8_SUB2_EP == virt_to_phys(unlink_ep)); /* Now we are free to remove it and its SB descriptor. Note that it is assumed here that there is only one sb in the sb list for this ep. */ kmem_cache_free(usb_desc_cache, phys_to_virt(unlink_ep->sub)); kmem_cache_free(usb_desc_cache, (USB_EP_Desc_t *)unlink_ep); } curr_ep = phys_to_virt(curr_ep->next); } while (curr_ep != first_ep);}void etrax_usb_do_intr_recover(int epid){ USB_EP_Desc_t *first_ep, *tmp_ep; DBFENTER; first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); tmp_ep = first_ep; /* What this does is simply to walk the list of interrupt ep descriptors and enable those that are disabled. */ do { if (IO_EXTRACT(USB_EP_command, epid, tmp_ep->command) == epid && !(tmp_ep->command & IO_MASK(USB_EP_command, enable))) { tmp_ep->command |= IO_STATE(USB_EP_command, enable, yes); } tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->next); } while (tmp_ep != first_ep); DBFEXIT;}static int etrax_rh_unlink_urb (urb_t *urb){ etrax_hc_t *hc; DBFENTER; hc = urb->dev->bus->hcpriv; if (hc->rh.urb == urb) { hc->rh.send = 0; del_timer(&hc->rh.rh_int_timer); } DBFEXIT; return 0;}static void etrax_rh_send_irq(urb_t *urb){ __u16 data = 0; etrax_hc_t *hc = urb->dev->bus->hcpriv;/* DBFENTER; *//* dbg_rh("R_USB_FM_NUMBER : 0x%08X", *R_USB_FM_NUMBER); dbg_rh("R_USB_FM_REMAINING: 0x%08X", *R_USB_FM_REMAINING);*/ data |= (hc->rh.wPortChange_1) ? (1 << 1) : 0; data |= (hc->rh.wPortChange_2) ? (1 << 2) : 0; *((__u16 *)urb->transfer_buffer) = cpu_to_le16(data); /* FIXME: Why is actual_length set to 1 when data is 2 bytes? Since only 1 byte is used, why not declare data as __u8? */ urb->actual_length = 1; urb->status = 0; if (data && hc->rh.send && urb->complete) { dbg_rh("wPortChange_1: 0x%04X", hc->rh.wPortChange_1); dbg_rh("wPortChange_2: 0x%04X", hc->rh.wPortChange_2); urb->complete(urb); } /* DBFEXIT; */}static void etrax_rh_init_int_timer(urb_t *urb){ etrax_hc_t *hc; /* DBFENTER; */ hc = urb->dev->bus->hcpriv; hc->rh.interval = urb->interval; init_timer(&hc->rh.rh_int_timer); hc->rh.rh_int_timer.function = etrax_rh_int_timer_do; hc->rh.rh_int_timer.data = (unsigned long)urb; /* FIXME: Is the jiffies resolution enough? All intervals < 10 ms will be mapped to 0, and the rest to the nearest lower 10 ms. */ hc->rh.rh_int_timer.expires = jiffies + ((HZ * hc->rh.interval) / 1000); add_timer(&hc->rh.rh_int_timer); /* DBFEXIT; */}static void etrax_rh_int_timer_do(unsigned long ptr){ urb_t *urb; etrax_hc_t *hc; /* DBFENTER; */ urb = (urb_t*)ptr; hc = urb->dev->bus->hcpriv; if (hc->rh.send) { etrax_rh_send_irq(urb); } etrax_rh_init_int_timer(urb); /* DBFEXIT; */}static int etrax_usb_setup_epid(urb_t *urb){ int epid; char devnum, endpoint, out_traffic, slow; int maxlen; unsigned long flags; DBFENTER; epid = etrax_usb_lookup_epid(urb); if ((epid != -1)){ /* An epid that fits this urb has been found. */ DBFEXIT; return epid; } /* We must find and initiate a new epid for this urb. */ epid = etrax_usb_allocate_epid(); if (epid == -1) { /* Failed to allocate a new epid. */ DBFEXIT; return epid; } /* We now have a new epid to use. Initiate it. */ set_bit(epid, (void *)&epid_usage_bitmask); 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)); if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { /* We want both IN and OUT control traffic to be put on the same EP/SB list. */ out_traffic = 1; } else { out_traffic = usb_pipeout(urb->pipe); } save_flags(flags); cli(); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { *R_USB_EPT_DATA_ISO = IO_STATE(R_USB_EPT_DATA_ISO, valid, yes) | /* FIXME: Change any to the actual port? */ IO_STATE(R_USB_EPT_DATA_ISO, port, any) | IO_FIELD(R_USB_EPT_DATA_ISO, max_len, maxlen) | IO_FIELD(R_USB_EPT_DATA_ISO, ep, endpoint) | IO_FIELD(R_USB_EPT_DATA_ISO, dev, devnum); } else { *R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) | IO_FIELD(R_USB_EPT_DATA, low_speed, slow) | /* FIXME: Change any to the actual port? */ IO_STATE(R_USB_EPT_DATA, port, any) | IO_FIELD(R_USB_EPT_DATA, max_len, maxlen) | IO_FIELD(R_USB_EPT_DATA, ep, endpoint) | IO_FIELD(R_USB_EPT_DATA, dev, devnum); } restore_flags(flags); if (out_traffic) { set_bit(epid, (void *)&epid_out_traffic); } else { clear_bit(epid, (void *)&epid_out_traffic); } dbg_epid("Setting up epid %d with devnum %d, endpoint %d and max_len %d (%s)", epid, devnum, endpoint, maxlen, out_traffic ? "OUT" : "IN"); DBFEXIT; return epid;}static void etrax_usb_free_epid(int epid){ unsigned long flags; DBFENTER; if (!test_bit(epid, (void *)&epid_usage_bitmask)) { warn("Trying to free unused epid %d", epid); DBFEXIT; return; } save_flags(flags); cli(); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); while (*R_USB_EPT_DATA & IO_MASK(R_USB_EPT_DATA, hold)); /* This will, among other things, set the valid field to 0. */ *R_USB_EPT_DATA = 0; restore_flags(flags); clear_bit(epid, (void *)&epid_usage_bitmask); dbg_epid("Freed epid %d", epid); DBFEXIT;}static int etrax_usb_lookup_epid(urb_t *urb){ int i; __u32 data; char devnum, endpoint, slow, out_traffic; int maxlen; unsigned long flags; DBFENTER; 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)); if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { /* We want both IN and OUT control traffic to be put on the same EP/SB list. */ out_traffic = 1; } else { out_traffic = usb_pipeout(urb->pipe); } /* Step through att epids. */ for (i = 0; i < NBR_OF_EPIDS; i++) { if (test_bit(i, (void *)&epid_usage_bitmask) && test_bit(i, (void *)&epid_out_traffic) == out_traffic) { save_flags(flags); cli(); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -