static inline u32 uhci_pid_from_ep(struct usb_endpoint_descriptor *epdesc) { if ((epdesc->bEndpointAddress == 0x00) || USB_EP_DIRECT(epdesc)) return UHCI_TD_TOKEN_PID_IN; else return UHCI_TD_TOKEN_PID_OUT; }
/** * @brief submit asynchronous urb * @param host struct uhci_host * @param device struct usb_device * @param epdesc struct usb_endpoint_descriptor * @param data void * * @param size u16 * @param callback int * * @param arg void* * @param ioc int */ static struct usb_request_block * uhci_submit_async(struct uhci_host *host, struct usb_device *device, struct usb_endpoint_descriptor *epdesc, void *data, u16 size, int (*callback)(struct usb_host *, struct usb_request_block *, void *), void *arg, int ioc) { struct usb_request_block *urb; size_t pktsize; u32 lospeed = 0; urb = uhci_create_urb(host); if (!urb) return (struct usb_request_block *)NULL; if (device) { spinlock_lock(&device->lock_dev); init_urb(urb, device->devnum, epdesc, callback, arg); spinlock_unlock(&device->lock_dev); } /* determine if we are dealing with a low speed device or not */ if (device) { if (device->speed == UD_SPEED_UNDEF) { u16 portsc; ASSERT (device->portno <= UHCI_NUM_PORTS_HC); portsc = host->portsc[(device->portno-1)]; device->speed = (portsc & UHCI_PORTSC_LOSPEED) ? UD_SPEED_LOW : UD_SPEED_FULL; } lospeed = (device->speed == UD_SPEED_LOW) ? UHCI_TD_STAT_LS : 0; } /* create a QH */ URB_UHCI(urb)->qh = uhci_alloc_qh(host, &URB_UHCI(urb)->qh_phys); if (!URB_UHCI(urb)->qh) goto fail_submit_async; URB_UHCI(urb)->qh->link = UHCI_QH_LINK_TE; pktsize = epdesc->wMaxPacketSize; /* buffer and TD */ if (size > 0) { struct usb_buffer_list *b; b = zalloc_usb_buffer_list(); b->pid = USB_PID_IN; b->len = size; b->vadr = (virt_t)alloc2_aligned(b->len, &b->padr); if (!b->vadr) { free(b); goto fail_submit_async; } /* copy data if OUT direction */ if (!USB_EP_DIRECT(epdesc)) { b->pid = USB_PID_OUT; memcpy((void *)b->vadr, data, b->len); } urb->buffers = b; } if (device) { spinlock_lock(&device->lock_dev); URB_UHCI(urb)->tdm_head = prepare_buffer_tds(host, (urb->buffers) ? (phys32_t)urb->buffers->padr : 0U, size, device->devnum, epdesc, (size_t)pktsize, UHCI_TD_STAT_AC | UHCI_TD_STAT_SP | lospeed | uhci_td_maxerr(3)); spinlock_unlock(&device->lock_dev); } if (!URB_UHCI(urb)->tdm_head) goto fail_submit_async; /* link the TDs into the QH */ URB_UHCI(urb)->qh->element = URB_UHCI(urb)->tdm_head->td_phys; /* set IOC */ if (ioc) URB_UHCI(urb)->tdm_head->td->status |= UHCI_TD_STAT_IC; /* set up toggles in TDs */ epdesc->toggle = uhci_fixup_toggles(URB_UHCI(urb)->tdm_head, epdesc->toggle); /* link the QH into the frame list */ if (uhci_activate_urb(host, urb) != URB_STATUS_RUN) goto fail_submit_async; URB_UHCI(urb)->tdm_acttail = NULL; return urb; fail_submit_async: uhci_destroy_urb(host, urb); return (struct usb_request_block *)NULL; }
/** * @brief submit asynchronous urb * @param host struct uhci_host * @param device struct usb_device * @param epdesc struct usb_endpoint_descriptor * @param data void * * @param size u16 * @param callback int * * @param arg void* * @param ioc int */ static struct usb_request_block * uhci_submit_async(struct uhci_host *host, struct usb_device *device, struct usb_endpoint_descriptor *epdesc, void *data, u16 size, int (*callback)(struct usb_host *, struct usb_request_block *, void *), void *arg, int ioc) { struct usb_request_block *urb; size_t pktsize; urb = create_urb(host); if (!urb) return (struct usb_request_block *)NULL; if (device){ spinlock_lock(&device->lock_dev); init_urb(urb, device->devnum, epdesc, callback, arg); spinlock_unlock(&device->lock_dev); } /* create a QH */ URB_UHCI(urb)->qh = uhci_alloc_qh(host, &URB_UHCI(urb)->qh_phys); if (!URB_UHCI(urb)->qh) goto fail_submit_async; URB_UHCI(urb)->qh->link = UHCI_QH_LINK_TE; pktsize = epdesc->wMaxPacketSize; /* buffer and TD */ if (size > 0) { struct usb_buffer_list *b; b = zalloc_usb_buffer_list(); b->len = size; b->vadr = malloc_from_pool(host->pool, b->len, &b->padr); if (!b->vadr) { free(b); goto fail_submit_async; } /* copy data if OUT direction */ if (!USB_EP_DIRECT(epdesc)) memcpy((void *)b->vadr, data, b->len); urb->buffers = b; } if (device){ spinlock_lock(&device->lock_dev); URB_UHCI(urb)->tdm_head = prepare_buffer_tds(host, (urb->buffers) ? (phys32_t)urb->buffers->padr : 0U, size, device->devnum, epdesc, UHCI_TD_STAT_AC | UHCI_TD_STAT_SP | uhci_td_maxerr(3)); spinlock_unlock(&device->lock_dev); } if (!URB_UHCI(urb)->tdm_head) goto fail_submit_async; /* link the TDs into the QH */ URB_UHCI(urb)->qh->element = URB_UHCI(urb)->tdm_head->td_phys; /* set IOC */ if (ioc) URB_UHCI(urb)->tdm_head->td->status |= UHCI_TD_STAT_IC; /* set up toggles in TDs */ epdesc->toggle = uhci_fixup_toggles(URB_UHCI(urb)->tdm_head, epdesc->toggle); /* link the QH into the frame list */ if (uhci_activate_urb(host, urb) != URB_STATUS_RUN) goto fail_submit_async; link_urb(&host->inproc_urbs, urb); return urb; fail_submit_async: destroy_urb(host, urb); return (struct usb_request_block *)NULL; }