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 }
/* Windows 7 fails to configure device unless this is implemented */ static int cdc_handle_control(struct usb_ctrl_req_t *req, void *data) { struct cdc_ctx *ctx = data; switch ((enum cdc_ctrl_req_code)req->bRequest) { case USB_CTRL_REQ_CDC_SET_LINE_CODING: { if (req->wLength != sizeof(struct cdc_line_coding)) { usb_handle_control_status(1); } else { usb_ep0_rx(&ctx->line_coding, req->wLength, cdc_handle_control_set_line_coding, ctx); return 1; } break; } case USB_CTRL_REQ_CDC_GET_LINE_CODING: { usb_ep0_tx_cp(&ctx->line_coding, sizeof(struct cdc_line_coding), req->wLength, NULL, NULL); usb_handle_control_status(0); break; } case USB_CTRL_REQ_CDC_SET_CTRL_LINE_STATE: { /* * We should remain inactive unless there is a terminal on the other end of the link, * indicated by the first two bits of wValue */ ctx->control_lines = req->wValue; usb_handle_control_status(0); break; } default: return 0; } return 0; }
int dfu_handle_control(struct usb_ctrl_req_t *req, void *data) { struct dfu_ctx *ctx = data; int fail = 1; /* XXX check for std vs class request */ switch ((uint8_t)req->bRequest) { case USB_CTRL_REQ_SET_INTERFACE: if (req->wValue >= ctx->dfuf->segment_count) goto out; ctx->segment = req->wValue; ctx->state = DFU_STATE_dfuIDLE; break; case USB_CTRL_REQ_GET_INTERFACE: usb_ep0_tx_cp(&ctx->segment, 1, req->wLength, NULL, NULL); break; case USB_CTRL_REQ_DFU_DNLOAD: { void *buf; switch (ctx->state) { case DFU_STATE_dfuIDLE: ctx->off = 0; break; case DFU_STATE_dfuDNLOAD_IDLE: break; default: goto err; } /** * XXX we are not allowed to STALL here, and we need to eat all transferred data. * better not allow setup_write to break the protocol. */ ctx->status = ctx->dfuf->segment[ctx->segment].setup_write(ctx, ctx->off, req->wLength, &buf); if (ctx->status != DFU_STATUS_OK) { ctx->state = DFU_STATE_dfuERROR; goto err_have_status; } if (req->wLength > 0) { ctx->state = DFU_STATE_dfuDNLOAD_SYNC; usb_ep0_rx(buf, req->wLength, dfu_dnload_complete, ctx); } else { ctx->state = DFU_STATE_dfuMANIFEST_SYNC; dfu_dnload_complete(NULL, 0, ctx); } goto out_no_status; } case USB_CTRL_REQ_DFU_GETSTATUS: { struct dfu_status_t st; st.bState = ctx->state; st.bStatus = ctx->status; st.bwPollTimeout = 1; /* XXX allow setting in desc? */ /** * If we're in DFU_STATE_dfuMANIFEST, we just finished * the download, and we're just about to send our last * status report. Once the report has been sent, go * and reset the system to put the new firmware into * effect. */ usb_ep0_tx_cp(&st, sizeof(st), req->wLength, NULL, NULL); break; } case USB_CTRL_REQ_DFU_CLRSTATUS: if (ctx->state != DFU_STATE_dfuERROR) goto err; ctx->state = DFU_STATE_dfuIDLE; ctx->status = DFU_STATUS_OK; break; case USB_CTRL_REQ_DFU_GETSTATE: { uint8_t st = ctx->state; usb_ep0_tx_cp(&st, sizeof(st), req->wLength, NULL, NULL); break; } case USB_CTRL_REQ_DFU_ABORT: switch (ctx->state) { case DFU_STATE_dfuIDLE: case DFU_STATE_dfuDNLOAD_IDLE: /* case DFU_STATE_dfuUPLOAD_IDLE: */ ctx->state = DFU_STATE_dfuIDLE; break; default: goto err; } break; /* case USB_CTRL_REQ_DFU_UPLOAD: */ default: return (0); } fail = 0; goto out; err: ctx->status = DFU_STATUS_errSTALLEDPKT; err_have_status: ctx->state = DFU_STATE_dfuERROR; out: usb_handle_control_status(fail); out_no_status: return (1); }
/* * Handle class (HID) specific calls. * * see hid_handle_control() */ static int hid_handle_control_class(struct usb_ctrl_req_t *req, struct hid_ctx *ctx) { size_t len = 0; /* XXX maintain state for all report descriptors */ switch ((enum hid_ctrl_req_code)req->bRequest) { case USB_CTRL_REQ_HID_GET_REPORT: { enum hid_report_type report_type = req->wValue >> 8; uint8_t report_id = req->wValue & 0xff; int ret = -1; ctx->get_report_outstanding_length = req->wLength; if (ctx->hidf->get_report) ret = ctx->hidf->get_report(ctx, report_type, report_id); if (ret <= 0) { ctx->get_report_outstanding_length = 0; usb_handle_control_status(1); } return (1); } case USB_CTRL_REQ_HID_SET_REPORT: { int ret = -1; void *buf = NULL; ctx->set_report_length = req->wLength; ctx->set_report_type = req->wValue >> 8; ctx->set_report_id = req->wValue & 0xff; if (ctx->hidf->set_report) ret = ctx->hidf->set_report(ctx->set_report_type, ctx->set_report_id, &buf, ctx->set_report_length); if (ret > 0) usb_ep0_rx(buf, ctx->set_report_length, hid_set_report_done, ctx); else usb_handle_control_status(1); return (1); } case USB_CTRL_REQ_HID_GET_IDLE: /* XXX implement */ usb_ep0_tx_cp(&len, 1, req->wLength, NULL, NULL); usb_handle_control_status(0); return (1); case USB_CTRL_REQ_HID_SET_IDLE: /* XXX implement */ usb_handle_control_status(0); return (1); case USB_CTRL_REQ_HID_GET_PROTOCOL: /* XXX implement */ /* usb_ep0_tx_cp(&len, 1, req->wLength, NULL, NULL); */ /* usb_handle_control_status(0); */ return (0); case USB_CTRL_REQ_HID_SET_PROTOCOL: /* XXX implement */ usb_handle_control_status(0); return (1); default: return (0); } }