#include #include #include #include static uint8_t reply_buffer[8]; static uint8_t usb_configuration = 0; void usb_setup(const struct usb_setup_request *setup) { const uint8_t *data = NULL; uint32_t datalen = 0; const usb_descriptor_list_t *list; switch (setup->wRequestAndType) { case 0x0500: // SET_ADDRESS case 0x0b01: // SET_INTERFACE break; case 0x0900: // SET_CONFIGURATION usb_configuration = setup->wValue; break; case 0x0880: // GET_CONFIGURATION reply_buffer[0] = usb_configuration; datalen = 1; data = reply_buffer; break; case 0x0080: // GET_STATUS (device) reply_buffer[0] = 0; reply_buffer[1] = 0; datalen = 2; data = reply_buffer; break; case 0x0082: // GET_STATUS (endpoint) if (setup->wIndex > 0) { usb_err(); return; } reply_buffer[0] = 0; reply_buffer[1] = 0; // XXX handle endpoint stall here data = reply_buffer; datalen = 2; break; case 0x0102: // CLEAR_FEATURE (endpoint) if (setup->wIndex > 0 || setup->wValue != 0) { // TODO: do we need to handle IN vs OUT here? usb_err(); return; } break; case 0x0302: // SET_FEATURE (endpoint) if (setup->wIndex > 0 || setup->wValue != 0) { // TODO: do we need to handle IN vs OUT here? usb_err(); return; } // XXX: Should we set the stall bit? // USB->DIEP0CTL |= USB_DIEP_CTL_STALL; // TODO: do we need to clear the data toggle here? break; case 0x0680: // GET_DESCRIPTOR case 0x0681: for (list = usb_descriptor_list; 1; list++) { if (list->addr == NULL) break; if (setup->wValue == list->wValue) { data = list->addr; if ((setup->wValue >> 8) == 3) { // for string descriptors, use the descriptor's // length field, allowing runtime configured // length. datalen = *(list->addr); } else { datalen = list->length; } goto send; } } usb_err(); return; default: usb_err(); return; } send: if (data && datalen) { if (datalen > setup->wLength) datalen = setup->wLength; usb_send(data, datalen); } else usb_ack_in(); return; }