📄 usb-host.c
字号:
clear_bit(epid, (void *)&ep_really_active); URB_List[epid] = NULL; etrax_usb_free_epid(epid); DBFEXIT; return 0;}void etrax_usb_do_intr_recover(int epid){ USB_EP_Desc_t *first_ep, *tmp_ep; first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP); tmp_ep = first_ep; 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->nep); } while (tmp_ep != first_ep);}static int etrax_usb_submit_intr_urb(urb_t *urb){ USB_EP_Desc_t *tmp_ep; USB_EP_Desc_t *first_ep; int epid; char devnum; char endpoint; char maxlen; char out_traffic; char slow; int interval; int i; etrax_urb_priv_t *urb_priv; 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); interval = urb->interval; dbg_intr("Intr traffic for dev %d, endpoint %d, maxlen %d, slow %d", devnum, endpoint, maxlen, slow); 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_priv = (etrax_urb_priv_t *)kmalloc(sizeof(etrax_urb_priv_t), GFP_KERNEL); urb_priv->first_sb = 0; urb_priv->rx_offset = 0; urb_priv->eot = 0; INIT_LIST_HEAD(&urb_priv->ep_in_list); urb->hcpriv = urb_priv; /* This is safe since there cannot be any other URB's for this epid */ URB_List[epid] = urb;#if 0 first_ep = (USB_EP_Desc_t *)phys_to_virt(*R_DMA_CH8_SUB2_EP);#else first_ep = &TxIntrEPList[0];#endif /* Round of the interval to 2^n, it is obvious that this code favours smaller numbers, but that is actually a good thing */ for (i = 0; interval; i++) { interval = interval >> 1; } urb->interval = interval = 1 << (i - 1); dbg_intr("Interval rounded to %d", interval); tmp_ep = first_ep; i = 0; do { if (tmp_ep->command & IO_MASK(USB_EP_command, eof)) { if ((i % interval) == 0) { /* Insert the traffic ep after tmp_ep */ USB_EP_Desc_t *traffic_ep; USB_SB_Desc_t *traffic_sb; traffic_ep = (USB_EP_Desc_t *) kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); traffic_sb = (USB_SB_Desc_t *) kmem_cache_alloc(usb_desc_cache, GFP_KERNEL); traffic_ep->hw_len = 0; traffic_ep->command = IO_FIELD(USB_EP_command, epid, epid) | IO_STATE(USB_EP_command, enable, yes); traffic_ep->sub = virt_to_phys(traffic_sb); if (usb_pipein(urb->pipe)) { traffic_sb->sw_len = urb->transfer_buffer_length ? (urb->transfer_buffer_length - 1) / maxlen + 1 : 0; traffic_sb->next = 0; traffic_sb->buf = 0; traffic_sb->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); } else if (usb_pipeout(urb->pipe)) { traffic_sb->sw_len = urb->transfer_buffer_length; traffic_sb->next = 0; traffic_sb->buf = virt_to_phys(urb->transfer_buffer); traffic_sb->command = IO_FIELD(USB_SB_command, rem, 0) | IO_STATE(USB_SB_command, tt, out) | IO_STATE(USB_SB_command, eot, yes) | IO_STATE(USB_SB_command, eol, yes) | IO_STATE(USB_SB_command, full, yes); } traffic_ep->nep = tmp_ep->nep; tmp_ep->nep = virt_to_phys(traffic_ep); dbg_intr("One ep sucessfully inserted"); } i++; } tmp_ep = (USB_EP_Desc_t *)phys_to_virt(tmp_ep->nep); } while (tmp_ep != first_ep); set_bit(epid, (void *)&ep_really_active); *R_DMA_CH8_SUB2_CMD = IO_STATE(R_DMA_CH8_SUB2_CMD, cmd, start); DBFEXIT; return 0;}static void handle_intr_transfer_attn(int epid, int status){ urb_t *old_urb; DBFENTER; old_urb = URB_List[epid]; /* 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; struct list_head *entry; struct in_chunk *in; urb_priv = (etrax_urb_priv_t *)old_urb->hcpriv; save_flags(flags); cli(); list_for_each(entry, &urb_priv->ep_in_list) { in = list_entry(entry, struct in_chunk, list); memcpy(old_urb->transfer_buffer, in->data, in->length); old_urb->actual_length = in->length; old_urb->status = status; if (old_urb->complete) { old_urb->complete(old_urb); } list_del(entry); kfree(in->data); kfree(in); } restore_flags(flags); } else if (status != 0) { warn("Some sort of error for INTR EP !!!!");#ifdef ETRAX_USB_INTR_ERROR_FATAL /* This means that an INTR error is fatal for that endpoint */ etrax_usb_unlink_intr_urb(old_urb); old_urb->status = status; if (old_urb->complete) { old_urb->complete(old_urb); }#else /* In this case we reenable the disabled endpoint(s) */ etrax_usb_do_intr_recover(epid);#endif } 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;// static prev_wPortStatus_1 = 0;// static prev_wPortStatus_2 = 0; /* 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); 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; 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 void etrax_usb_setup_epid(int epid, char devnum, char endpoint, char packsize, char slow, char out_traffic){ unsigned long flags; DBFENTER; save_flags(flags); cli(); if (test_bit(epid, (void *)&ep_usage_bitmask)) { restore_flags(flags); warn("Trying to setup used epid %d", epid); DBFEXIT; return; } set_bit(epid, (void *)&ep_usage_bitmask); *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, epid); nop(); *R_USB_EPT_DATA = IO_STATE(R_USB_EPT_DATA, valid, yes) | IO_FIELD(R_USB_EPT_DATA, ep, endpoint) | IO_FIELD(R_USB_EPT_DATA, dev, devnum) | IO_FIELD(R_USB_EPT_DATA, max_len, packsize) | IO_FIELD(R_USB_EPT_DATA, low_speed, slow); if (out_traffic) set_bit(epid, (void *)&ep_out_traffic); else clear_bit(epid, (void *)&ep_out_traffic); restore_flags(flags); dbg_ep("Setting up ep_id %d with devnum %d, endpoint %d and max_len %d (%s)", epid, devnum, endpoint, packsize, out_traffic ? "OUT" : "IN"); DBFEXIT;}static void etrax_usb_free_epid(int epid){ unsigned long flags; DBFENTER; if (!test_bit(epid, (void *)&ep_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)) printk("+"); *R_USB_EPT_DATA = 0; clear_bit(epid, (void *)&ep_usage_bitmask); restore_flags(flags); dbg_ep("epid: %d freed", epid); DBFEXIT;}static int etrax_usb_lookup_epid(unsigned char devnum, char endpoint, char slow, int maxp, char out_traffic){ int i; unsigned long flags; __u32 data; DBFENTER; save_flags(flags); cli(); /* Skip first ep_id since it is reserved when intr. or iso traffic is used */ for (i = 0; i < NBR_OF_EP_DESC; i++) { if (test_bit(i, (void *)&ep_usage_bitmask) && test_bit(i, (void *)&ep_out_traffic) == out_traffic) { *R_USB_EPT_INDEX = IO_FIELD(R_USB_EPT_INDEX, value, i); nop(); data = *R_USB_EPT_DATA; 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) == maxp)) { restore_flags(flags); dbg_ep("Found ep_id %d for devnum %d, endpoint %d (%s)", i, devnum, endpoint, out_traffic ? "OUT" : "IN"); DBFEXIT; return i; } } } restore_flags(flags); dbg_ep("Found no ep_id for devnum %d, endpoint %d (%s)", devnum, endpoint, out_traffic ? "OUT" : "IN"); DBFEXIT; return -1;}static int etrax_usb_allocate_epid(void){ int i; DBFENTER; for (i = 0; i < NBR_OF_EP_DESC; i++) { if (!test_bit(i, (void *)&ep_usage_bitmask)) { dbg_ep("Found free ep_id at %d", i); DBFEXIT; return i; } } dbg_ep("Found no free ep_id's"); DBFEXIT; return -1;}static int etrax_usb_submit_bulk_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_bulk_hw_add(urb, epid, maxlen); } DBFEXIT; return 0;}static void etrax_usb_do_bulk_hw_add(urb_t *urb, int epid, char maxlen)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -