/** * @brief submit bulk urb * @param host struct uhci_host * @param device struct usb_device * @param endpoint u8 * @param data void * * @param size u16 * @param callback int * * @param arg void * * @param ioc int */ struct usb_request_block * uhci_submit_bulk(struct usb_host *usbhc, 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 uhci_host *host = (struct uhci_host *)usbhc->private; if (USB_EP_TRANSTYPE(epdesc) != USB_ENDPOINT_TYPE_BULK) { dprintft(2, "%04x: %s: wrong endpoint(%02x).\n", host->iobase, __FUNCTION__, USB_EP_TRANSTYPE(epdesc)); return (struct usb_request_block *)NULL; } return uhci_submit_async(host, device, epdesc, data, size, callback, arg, ioc); }
/** * @brief submit bulk urb * @param host struct uhci_host * @param device struct usb_device * @param endpoint u8 * @param data void * * @param size u16 * @param callback int * * @param arg void * * @param ioc int */ struct usb_request_block * uhci_submit_bulk(struct uhci_host *host, struct usb_device *device, u8 endpoint, void *data, u16 size, int (*callback)(struct usb_host *, struct usb_request_block *, void *), void *arg, int ioc) { struct usb_endpoint_descriptor *epdesc; epdesc = usb_epdesc(device, endpoint); if (!epdesc || (USB_EP_TRANSTYPE(epdesc) != USB_ENDPOINT_TYPE_BULK)) { if (!epdesc) dprintft(2, "%04x: %s: no endpoint(%02x) found.\n", host->iobase, __FUNCTION__, endpoint); else dprintft(2, "%04x: %s: wrong endpoint(%02x).\n", host->iobase, __FUNCTION__, USB_EP_TRANSTYPE(epdesc)); return (struct usb_request_block *)NULL; } return uhci_submit_async(host, device, epdesc, data, size, callback, arg, ioc); }
/** * @brief activate urb * @param host struct uhci_host *host * @param urb struct usb_request_block */ u8 uhci_activate_urb(struct uhci_host *host, struct usb_request_block *urb) { u8 status, type; int n; type = (urb->endpoint) ? USB_EP_TRANSTYPE(urb->endpoint) : USB_ENDPOINT_TYPE_CONTROL; spinlock_lock(&host->lock_hfl); switch (type) { case USB_ENDPOINT_TYPE_INTERRUPT: n = __ffs(urb->endpoint->bInterval | (1 << (UHCI_NUM_SKELTYPES - 1))); /* MEMO: a new interrupt urb must be inserted just after a skelton anytime. */ urb->link_prev = host->host_skelton[n]; if (host->host_skelton[n] == host->tailurb[URB_TAIL_CONTROL]) host->tailurb[URB_TAIL_CONTROL] = urb; if (host->host_skelton[n] == host->tailurb[URB_TAIL_BULK]) host->tailurb[URB_TAIL_BULK] = urb; break; case USB_ENDPOINT_TYPE_CONTROL: urb->link_prev = host->tailurb[URB_TAIL_CONTROL]; if (host->tailurb[URB_TAIL_CONTROL] == host->tailurb[URB_TAIL_BULK]) host->tailurb[URB_TAIL_BULK] = urb; host->tailurb[URB_TAIL_CONTROL] = urb; break; case USB_ENDPOINT_TYPE_BULK: urb->link_prev = host->tailurb[URB_TAIL_BULK]; host->tailurb[URB_TAIL_BULK] = urb; break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: default: printf("%s: transfer type(%02x) unsupported.\n", __FUNCTION__, type); status = urb->status; return status; } /* initialize qh_element_copy for detecting advance after NAK */ URB_UHCI(urb)->qh_element_copy = URB_UHCI(urb)->qh->element; /* urb link */ urb->link_next = urb->link_prev->link_next; urb->link_prev->link_next = urb; if (urb->link_next) { /* make a backward pointer */ urb->link_next->link_prev = urb; } else if (type == USB_ENDPOINT_TYPE_BULK) { if (host->fsbr) { dprintft(2, "%04x: %s: append it to the " "FSBR loopback.\n", host->iobase, __FUNCTION__); host->fsbr_loop_tail = urb; } else { dprintft(2, "%04x: %s: make a FSBR loopback.\n", host->iobase, __FUNCTION__); host->fsbr = 1; host->fsbr_loop_head = urb; host->fsbr_loop_tail = urb; } } /* record the current frame number */ URB_UHCI(urb)->frnum_issued = uhci_current_frame_number(host); /* qh link */ URB_UHCI(urb)->qh->link = URB_UHCI(urb->link_prev)->qh->link; if (host->fsbr_loop_tail) URB_UHCI(host->fsbr_loop_tail)->qh->link = (phys32_t) URB_UHCI(host->fsbr_loop_head)->qh_phys | UHCI_QH_LINK_QH; URB_UHCI(urb->link_prev)->qh->link = URB_UHCI(urb)->qh_phys | UHCI_QH_LINK_QH; urb->status = URB_STATUS_RUN; dprintft(3, "%s: The urb link is %p <- %p -> %p.\n", __FUNCTION__, urb->link_prev, urb, urb->link_next); status = urb->status; LIST4_PUSH (host->inproc_urbs, list, urb); spinlock_unlock(&host->lock_hfl); return status; }
/** * @brief deactivates the urb * @param host struct uhci_host * @param urb struct usb_request_block */ u8 uhci_deactivate_urb(struct usb_host *usbhc, struct usb_request_block *urb) { struct uhci_host *host = (struct uhci_host *)usbhc->private; u8 status, type; /* nothing to do if already unlinked */ if (urb->status == URB_STATUS_UNLINKED) return urb->status; dprintft(5, "%s: The urb link is %p <- %p -> %p.\n", __FUNCTION__, urb->link_prev, urb, urb->link_next); spinlock_lock(&host->lock_hfl); if (urb->prevent_del) { urb->deferred_del = true; spinlock_unlock(&host->lock_hfl); return 0U; } /* urb link */ if ((urb == host->fsbr_loop_head) && (urb == host->fsbr_loop_tail)) { dprintft(2, "%04x: %s: FSBR unlooped \n", host->iobase, __FUNCTION__); host->fsbr = 0; host->fsbr_loop_head = host->fsbr_loop_tail = (struct usb_request_block *)NULL; /* qh */ URB_UHCI(urb->link_prev)->qh->link = UHCI_QH_LINK_TE; } else if (urb == host->fsbr_loop_tail) { /* tail of a FSBR loopback */ dprintft(2, "%04x: %s: the tail of a FSBR loopback\n", host->iobase, __FUNCTION__); host->fsbr_loop_tail = urb->link_prev; /* qh */ URB_UHCI(host->fsbr_loop_tail)->qh->link = (phys32_t)URB_UHCI(host->fsbr_loop_head)->qh_phys | UHCI_QH_LINK_QH; } else if (host->fsbr_loop_head == urb) { /* head of a FSBR loopback */ dprintft(2, "%04x: %s: the head of a FSBR loopback\n", host->iobase, __FUNCTION__); host->fsbr_loop_head = urb->link_next; /* qh */ URB_UHCI(host->fsbr_loop_tail)->qh->link = (phys32_t)URB_UHCI(host->fsbr_loop_head)->qh_phys | UHCI_QH_LINK_QH; URB_UHCI(urb->link_prev)->qh->link = URB_UHCI(urb)->qh->link; } else { /* qh */ URB_UHCI(urb->link_prev)->qh->link = URB_UHCI(urb)->qh->link; } URB_UHCI(urb)->qh->link = UHCI_QH_LINK_TE; /* MEMO: There must exist urb->link_prev because of the skelton. */ urb->link_prev->link_next = urb->link_next; if (urb->link_next) urb->link_next->link_prev = urb->link_prev; urb->status = URB_STATUS_UNLINKED; type = (urb->endpoint) ? USB_EP_TRANSTYPE(urb->endpoint) : USB_ENDPOINT_TYPE_CONTROL; switch (type) { case USB_ENDPOINT_TYPE_INTERRUPT: /* through */ case USB_ENDPOINT_TYPE_CONTROL: if (host->tailurb[URB_TAIL_CONTROL] == urb) host->tailurb[URB_TAIL_CONTROL] = urb->link_prev; /* through */ case USB_ENDPOINT_TYPE_BULK: if (host->tailurb[URB_TAIL_BULK] == urb) host->tailurb[URB_TAIL_BULK] = urb->link_prev; break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: default: printf("%s: transfer type(%02x) unsupported.\n", __FUNCTION__, type); } status = urb->status; LIST4_DEL (host->inproc_urbs, list, urb); LIST4_ADD (host->unlinked_urbs[host->unlinked_urbs_index], list, urb); spinlock_unlock(&host->lock_hfl); return status; }