📄 hc_crisv10.c
字号:
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(struct urb *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); urb->hcpriv = NULL;}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 (struct urb *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(struct urb *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 (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, NULL); } DBFEXIT;}static void etrax_rh_init_int_timer(struct urb *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){ struct urb *urb; etrax_hc_t *hc; DBFENTER; urb = (struct urb*)ptr; hc = urb->dev->bus->hcpriv; if (hc->rh.send) { etrax_rh_send_irq(urb); } DBFEXIT;}static int etrax_usb_setup_epid(struct urb *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(struct urb *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); nop(); if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { data = *R_USB_EPT_DATA_ISO; restore_flags(flags); if ((IO_MASK(R_USB_EPT_DATA_ISO, valid) & data) && (IO_EXTRACT(R_USB_EPT_DATA_ISO, dev, data) == devnum) && (IO_EXTRACT(R_USB_EPT_DATA_ISO, ep, data) == endpoint) && (IO_EXTRACT(R_USB_EPT_DATA_ISO, max_len, data) == maxlen)) { dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)", i, devnum, endpoint, out_traffic ? "OUT" : "IN"); DBFEXIT; return i; } } else { data = *R_USB_EPT_DATA; restore_flags(flags); if ((IO_MASK(R_USB_EPT_DATA, valid) & data) && (IO_EXTRACT(R_USB_EPT_DATA, dev, data) == devnum) && (IO_EXTRACT(R_USB_EPT_DATA, ep, data) == endpoint) && (IO_EXTRACT(R_USB_EPT_DATA, low_speed, data) == slow) && (IO_EXTRACT(R_USB_EPT_DATA, max_len, data) == maxlen)) { dbg_epid("Found epid %d for devnum %d, endpoint %d (%s)", i, devnum, endpoint, out_traffic ? "OUT" : "IN"); DBFEXIT; return i; } } } } DBFEXIT; return -1;}static int etrax_usb_allocate_epid(void){ int i; DBFENTER; for (i = 0; i < NBR_OF_EPIDS; i++) { if (!test_bit(i, (void *)&epid_usage_bitmask)) { dbg_epid("Found free epid %d", i); DBFEXIT; return i; } } dbg_epid("Found no free epids"); DBFEXIT; return -1;}static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags){ etrax_hc_t *hc; int ret = -EINVAL; DBFENTER; if (!urb->dev || !urb->dev->bus) { return -ENODEV; } if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) <= 0) { info("Submit urb to pipe with maxpacketlen 0, pipe 0x%X\n", urb->pipe); return -EMSGSIZE; } if (urb->timeout) { /* FIXME. */ warn("urb->timeout specified, ignoring."); } hc = (etrax_hc_t*)urb->dev->bus->hcpriv; if (usb_pipedevice(urb->pipe) == hc->rh.devnum) { /* This request is for the Virtual Root Hub. */ ret = etrax_rh_submit_urb(urb); } else if (usb_pipetype(urb->pipe) == PIPE_BULK) { ret = etrax_usb_submit_bulk_urb(urb); } else if (usb_pipetype(urb->pipe) == PIPE_CONTROL) { ret = etrax_usb_submit_ctrl_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) { ret = bustime; } else { ret = etrax_usb_submit_intr_urb(urb); if (ret == 0) usb_claim_bandwidth(urb->dev, urb, bustime, 0); } } else { /* Bandwidth already set. */ ret = etrax_usb_submit_intr_urb(urb); } } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) { int bustime;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -