void usb_handle_irq(void) { unsigned n; USB_IRQ_COUNT++; // P("usb %x\n", USB_IRQ_COUNT); n = readl(USB_INT_STATUS); //writel(n & (USB_INT_EP0 | USB_INT_EP1), USB_INT_CLEAR); writel(n, USB_INT_CLEAR); if (n & USB_INT_FRAME) msec_counter++; if (n & USB_INT_EP0) usb_ep0_rx(); if (n & USB_INT_EP1) usb_ep0_tx(); /* ignore masked interrupts */ n &= readl(USB_INT_ENABLE); if (n & ~(USB_INT_FRAME)) { // P("usb n 0x%x\n", n); } if ((n & USB_INT_EP2) && usb_ep1_rx_full_cb) usb_ep1_rx_full_cb(); if ((n & USB_INT_EP3) && usb_ep1_tx_empty_cb) usb_ep1_tx_empty_cb(); #if CONFIG_USB_2ND_IFC if ((n & USB_INT_EP4) && usb_ep2_rx_full_cb) usb_ep2_rx_full_cb(); if ((n & USB_INT_EP5) && usb_ep2_tx_empty_cb) usb_ep2_tx_empty_cb(); #endif }
static int usb_tx_config_desc(int idx, int reqlen) { const struct usb_desc_config_t *d = usb.identity->configs[idx]->desc; usb_ep0_tx(d, d->wTotalLength, reqlen, NULL, NULL); return (0); }
void hid_update_data(struct hid_ctx *ctx, uint8_t report_id, const void *data, size_t len) { if (ctx->get_report_outstanding_length != 0) { usb_ep0_tx(data, len, ctx->get_report_outstanding_length, NULL, NULL); ctx->get_report_outstanding_length = 0; usb_handle_control_status(0); } else if (ctx->hidf->report_max_size > 0) { usb_tx(ctx->tx_pipe, data, len, ctx->hidf->report_max_size, NULL, NULL); } }
int wcid_handle_control(const struct usbd_global *f, struct usb_ctrl_req_t *req) { const struct wcid_function *wcid = (const void *)f; if (req->bRequest != WCID_REQ_ID) return (0); size_t pos, len; const struct wcid_generic_header *desc; switch (req->wIndex) { case WCID_DESC_COMPAT_OS: desc = wcid->compat_id; break; case WCID_DESC_EXTENDED_PROP: { static const struct wcid_extended_prop_header ex_prop = { .dwLength = sizeof(ex_prop), .bcdVersion = { .raw = 0x0100 }, .wIndex = WCID_DESC_EXTENDED_PROP, .wCount = 0, }; desc = &ex_prop; break; } default: return (0); } pos = (req->wValue & 0xff00) << 8; len = req->wLength; if (pos > desc->dwLength) return (0); if (pos + len > desc->dwLength) len = desc->dwLength - pos; usb_ep0_tx((uint8_t *)desc + pos, len, req->wLength, NULL, NULL); usb_handle_control_status(0); return (1); }
static int usb_tx_string_desc(int idx, int reqlen) { const struct usbd_string_entry *d; for (d = usb.identity->string_descs; d->string != NULL; ++d) if (d->index == idx) break; if (!d->string) return (-1); switch ((uintptr_t)d->string) { case (uintptr_t)NULL: return (-1); case (uintptr_t)USB_DESC_STRING_SERIALNO: return (usb_tx_serialno(reqlen)); default: usb_ep0_tx(d->string, d->string->bLength, reqlen, NULL, NULL); return (0); } }
static void usb_handle_control(void *data, ssize_t len, void *cbdata) { struct usb_ctrl_req_t *req = data; uint16_t zero16 = 0; int fail = 1; usb.ctrl_dir = req->in; /** * Pass control to our handlers for non standard * or non device (interface/class/other) requests. */ if (req->type != USB_CTRL_REQ_STD || req->recp != USB_CTRL_REQ_DEV) { if (usb_handle_control_nonstddev(req) != 0) return; } /* Only STD requests here */ switch (req->bRequest) { case USB_CTRL_REQ_GET_STATUS: /** * Because we don't support remote wakeup or * self-powered operation, and we are specialized to * only EP 0 so far, all GET_STATUS replies are just * empty. */ usb_ep0_tx_cp(&zero16, sizeof(zero16), req->wLength, NULL, NULL); break; case USB_CTRL_REQ_CLEAR_FEATURE: case USB_CTRL_REQ_SET_FEATURE: /** * Nothing to do. Maybe return STALLs on illegal * accesses? */ break; case USB_CTRL_REQ_SET_ADDRESS: /** * We must keep our previous address until the end of * the status stage; therefore we can't set the * address right now. Since this is a special case, * the EP 0 handler will take care of this later on. */ usb.address = req->wValue & 0x7f; usb.state = USBD_STATE_SETTING_ADDRESS; break; case USB_CTRL_REQ_GET_DESCRIPTOR: switch (req->wValue >> 8) { case USB_DESC_DEV: usb_ep0_tx(usb.identity->dev_desc, usb.identity->dev_desc->bLength, req->wLength, NULL, NULL); fail = 0; break; case USB_DESC_CONFIG: fail = usb_tx_config_desc(req->wValue & 0xff, req->wLength); break; case USB_DESC_STRING: fail = usb_tx_string_desc(req->wValue & 0xff, req->wLength); break; default: fail = -1; break; } /* we set fail already, so we can go directly to `err' */ goto err; case USB_CTRL_REQ_GET_CONFIGURATION: usb_ep0_tx(&usb.config, 1, req->wLength, NULL, NULL); /* XXX implicit LE */ break; case USB_CTRL_REQ_SET_CONFIGURATION: if (usb_set_config(req->wValue) < 0) goto err; break; default: goto err; } fail = 0; err: usb_handle_control_status(fail); }