From ffd0285613b1a44b6d25ce8389fa13e0a278d41e Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 5 Mar 2019 11:54:48 +0800 Subject: [PATCH] main: more work on fixing stuff Signed-off-by: Sean Cross --- sw/include/usb.h | 12 + sw/src/grainuum-phy.c | 243 ------------------ sw/src/grainuum-state.c | 348 -------------------------- sw/src/main.c | 8 +- sw/src/usb-epfifo.c | 531 +++++++--------------------------------- 5 files changed, 105 insertions(+), 1037 deletions(-) delete mode 100644 sw/src/grainuum-phy.c delete mode 100644 sw/src/grainuum-state.c diff --git a/sw/include/usb.h b/sw/include/usb.h index dc76772..38ad0cd 100644 --- a/sw/include/usb.h +++ b/sw/include/usb.h @@ -5,8 +5,20 @@ extern "C" { #endif +struct usb_device; +struct usb_setup_request; + void usb_isr(void); void usb_init(void); +void usb_connect(void); + +void usb_poll(void); +int usb_irq_happened(void); +void usb_setup(struct usb_device *dev, const struct usb_setup_request *setup); +int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count); +int usb_ack(struct usb_device *dev, int epnum); +int usb_err(struct usb_device *dev, int epnum); +int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len); #ifdef __cplusplus } diff --git a/sw/src/grainuum-phy.c b/sw/src/grainuum-phy.c deleted file mode 100644 index 9a6115a..0000000 --- a/sw/src/grainuum-phy.c +++ /dev/null @@ -1,243 +0,0 @@ -/**************************************************************************** - * Grainuum Software USB Stack * - * * - * MIT License: * - * Copyright (c) 2016 Sean Cross * - * * - * Permission is hereby granted, free of charge, to any person obtaining a * - * copy of this software and associated documentation files (the * - * "Software"), to deal in the Software without restriction, including * - * without limitation the rights to use, copy, modify, merge, publish, * - * distribute, distribute with modifications, sublicense, and/or sell * - * copies of the Software, and to permit persons to whom the Software is * - * furnished to do so, subject to the following conditions: * - * * - * The above copyright notice and this permission notice shall be included * - * in all copies or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * - * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * - * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - * * - * Except as contained in this notice, the name(s) of the above copyright * - * holders shall not be used in advertising or otherwise to promote the * - * sale, use or other dealings in this Software without prior written * - * authorization. * - ****************************************************************************/ - -#include -#include -#include - -__attribute__((weak)) void grainuumConnectPre(struct GrainuumUSB *usb) -{ - (void)usb; -} -__attribute__((weak)) void grainuumConnectPost(struct GrainuumUSB *usb) -{ - (void)usb; -} - -__attribute__((weak)) void grainuumDisconnectPre(struct GrainuumUSB *usb) -{ - (void)usb; -} -__attribute__((weak)) void grainuumDisconnectPost(struct GrainuumUSB *usb) -{ - (void)usb; -} - -__attribute__((weak)) void grainuumReceivePacket(struct GrainuumUSB *usb) -{ - (void)usb; -} - -__attribute__((weak)) void grainuumInitPre(struct GrainuumUSB *usb) -{ - (void)usb; -} - -__attribute__((weak)) void grainuumInitPost(struct GrainuumUSB *usb) -{ - (void)usb; -} - -/* --- */ - -void grainuum_receive_packet(struct GrainuumUSB *usb) -{ - grainuumReceivePacket(usb); -} - -int grainuumCaptureI(struct GrainuumUSB *usb, uint8_t samples[67]) -{ -#if 0 - int ret; - const uint8_t nak_pkt[] = {USB_PID_NAK}; - const uint8_t ack_pkt[] = {USB_PID_ACK}; - - ret = usbPhyReadI(usb, samples); - if (ret <= 0) { - if (ret != -1) - usbPhyWriteI(usb, nak_pkt, sizeof(nak_pkt)); - return 0; - } - - /* Save the byte counter for later inspection */ - samples[11] = ret; - - switch (samples[0]) { - case USB_PID_IN: - /* Make sure we have queued data, and that it's for this particular EP */ - if ((!usb->queued_size) - || (((((const uint16_t *)(samples+1))[0] >> 7) & 0xf) != usb->queued_epnum)) - { - usbPhyWriteI(usb, nak_pkt, sizeof(nak_pkt)); - break; - } - - usbPhyWriteI(usb, usb->queued_data, usb->queued_size); - break; - - case USB_PID_SETUP: - grainuum_receive_packet(usb); - break; - - case USB_PID_OUT: - grainuum_receive_packet(usb); - break; - - case USB_PID_ACK: - /* Allow the next byte to be sent */ - usb->queued_size = 0; - grainuum_receive_packet(usb); - break; - - case USB_PID_DATA0: - case USB_PID_DATA1: - usbPhyWriteI(usb, ack_pkt, sizeof(ack_pkt)); - grainuum_receive_packet(usb); - break; - - default: - usbPhyWriteI(usb, nak_pkt, sizeof(nak_pkt)); - break; - } - - return ret; -#endif - uint8_t obufbuf[128]; - uint32_t obufbuf_cnt = 0; - while (!usb_ep_0_out_obuf_empty_read()) - { - uint32_t obh = usb_ep_0_out_obuf_head_read(); - obufbuf[obufbuf_cnt++] = obh; - usb_ep_0_out_obuf_head_write(1); - } - - int i; - static int loops; - uint8_t last_tok = usb_ep_0_out_last_tok_read(); - printf("i: %d b: %d olt: %02x --", loops, obufbuf_cnt, last_tok); //obe: %d obh: %02x\n", i, obe, obh); - for (i = 0; i < obufbuf_cnt; i++) - { - printf(" %02x", obufbuf[i]); - } - printf("\n"); - - usb_ep_0_out_ev_pending_write((1 << 1)); - - // Response - if (!usb_ep_0_in_ibuf_empty_read()) - { - printf("USB ibuf still has data\n"); - return 0; - } - - uint32_t usb_in_pending = usb_ep_0_out_ev_pending_read(); - if (usb_in_pending) - { - printf("USB EP0 in pending is: %02x\n", usb_in_pending); - return 0; - } - - grainuumProcess(usb, last_tok, obufbuf, obufbuf_cnt); - - return 0; -} - -int grainuumInitialized(struct GrainuumUSB *usb) -{ - if (!usb) - return 0; - - return usb->initialized; -} - -enum usb_responses { - USB_STALL = 0b11, - USB_ACK = 0b00, - USB_NAK = 0b01, - USB_NONE = 0b10, -}; - -void grainuumWriteQueue(struct GrainuumUSB *usb, int epnum, - const void *buffer, int size) -{ - usb->queued_data = buffer; - usb->queued_epnum = epnum; - usb->queued_size = size; - - int i; - const uint8_t *buffer_u8 = buffer; - for (i = 0; i < size; i++) - { - usb_ep_0_in_ibuf_head_write(buffer_u8[i]); - } - // Indicate that we respond with an ACK - usb_ep_0_in_respond_write(USB_ACK); - usb_ep_0_in_ev_pending_write(0xff); -} - -void grainuumInit(struct GrainuumUSB *usb, - struct GrainuumConfig *cfg) -{ - - if (usb->initialized) - return; - - printf("Initializing USB to %08x, cfg to 0x%08x 0x%08x\n", usb, cfg, cfg->getDescriptor); - grainuumInitPre(usb); - - usb->cfg = cfg; - usb->state.usb = usb; - cfg->usb = usb; - - usb->initialized = 1; - - grainuumInitPost(usb); -} - -void grainuumDisconnect(struct GrainuumUSB *usb) -{ - - grainuumDisconnectPre(usb); - - usb_pullup_out_write(0); - - grainuumDisconnectPost(usb); -} - -void grainuumConnect(struct GrainuumUSB *usb) -{ - - grainuumConnectPre(usb); - - usb_pullup_out_write(1); - - grainuumConnectPost(usb); -} diff --git a/sw/src/grainuum-state.c b/sw/src/grainuum-state.c deleted file mode 100644 index c8cbe5a..0000000 --- a/sw/src/grainuum-state.c +++ /dev/null @@ -1,348 +0,0 @@ -/**************************************************************************** - * Grainuum Software USB Stack * - * * - * MIT License: * - * Copyright (c) 2016 Sean Cross * - * * - * Permission is hereby granted, free of charge, to any person obtaining a * - * copy of this software and associated documentation files (the * - * "Software"), to deal in the Software without restriction, including * - * without limitation the rights to use, copy, modify, merge, publish, * - * distribute, distribute with modifications, sublicense, and/or sell * - * copies of the Software, and to permit persons to whom the Software is * - * furnished to do so, subject to the following conditions: * - * * - * The above copyright notice and this permission notice shall be included * - * in all copies or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * - * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * - * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - * * - * Except as contained in this notice, the name(s) of the above copyright * - * holders shall not be used in advertising or otherwise to promote the * - * sale, use or other dealings in this Software without prior written * - * authorization. * - ****************************************************************************/ - #include "grainuum.h" - #include - #include - -#ifndef NULL -#define NULL ((void *)0) -#endif - -void *memcpy(void *dest, const void *src, unsigned int n); - -enum usb_state_packet_type { - packet_type_none, - packet_type_setup, - packet_type_setup_in, - packet_type_setup_out, - packet_type_in, - packet_type_out, -}; - -__attribute__((weak)) -void grainuumSendWait(struct GrainuumUSB *usb, int epnum, - const void *data, int size) -{ - (void)usb; - (void)epnum; - (void)data; - (void)size; -} - -static uint16_t crc16_add(uint16_t crc, uint8_t c, uint16_t poly) -{ - uint8_t i; - - for (i = 0; i < 8; i++) { - if ((crc ^ c) & 1) - crc = (crc >> 1) ^ poly; - else - crc >>= 1; - c >>= 1; - } - return crc; -} - -static uint16_t crc16(const uint8_t *data, uint32_t size, - uint16_t init, uint32_t poly) -{ - - while (size--) - init = crc16_add(init, *data++, poly); - - return init; -} - -static void grainuum_state_clear_tx(struct GrainuumState *state, int result) -{ - struct GrainuumUSB *usb = state->usb; - - /* If a thread is blocking, wake it up with a failure */ - if (usb->cfg->sendDataFinished && state->packet_queued) - usb->cfg->sendDataFinished(usb, result); - state->data_out_left = 0; - state->data_out_max = 0; - state->data_out = NULL; - state->packet_queued = 0; -} - -static void grainuum_state_process_tx(struct GrainuumState *state) -{ - - uint16_t crc; - struct GrainuumUSB *usb = state->usb; - - /* Don't allow us to re-prepare data */ - if (state->packet_queued) { - return; - } - state->packet_queued = 1; - - /* If there's no data to send, then don't send any */ - if (!state->data_out) { - state->packet_queued = 0; - return; - } - - /* If we've sent all of our data, then there's nothing else to send */ - if ((state->data_out_left < 0) || (state->data_out_max < 0)) { - grainuum_state_clear_tx(state, 0); - return; - } - - /* Pick the correct PID, DATA0 or DATA1 */ - // if (state->data_buffer & (1 << state->tok_epnum)) - // state->packet.pid = USB_PID_DATA1; - // else - // state->packet.pid = USB_PID_DATA0; - - /* If there's no data, prepare a special NULL packet */ - if ((state->data_out_left == 0) || (state->data_out_max == 0)) { - - /* The special-null thing only happens for EP0 */ - if (state->data_out_epnum != 0) { - grainuum_state_clear_tx(state, 0); - return; - } - state->packet.data[0] = 0; /* CRC16 for empty packets is 0 */ - state->packet.data[1] = 0; - state->packet.size = 2; - grainuumWriteQueue(usb, state->data_out_epnum, - &state->packet, state->packet.size + 1); - return; - } - - /* Keep the packet size to 8 bytes max */ - if (state->data_out_left > GRAINUUM_PACKET_SIZE_MAX) - state->packet.size = GRAINUUM_PACKET_SIZE_MAX; - else - state->packet.size = state->data_out_left; - - /* Limit the amount of data transferred to data_out_max */ - if (state->packet.size > state->data_out_max) - state->packet.size = state->data_out_max; - - /* Copy over data bytes */ - memcpy(state->packet.data, state->data_out, state->packet.size); - - /* Calculate and copy the crc16 */ - crc = ~crc16(state->packet.data, state->packet.size, 0xffff, 0xa001); - state->packet.data[state->packet.size++] = crc; - state->packet.data[state->packet.size++] = crc >> 8; - - /* Prepare the packet, including the PID at the end */ - grainuumWriteQueue(usb, state->data_out_epnum, - &state->packet, state->packet.size + 1); -} - -/* Called when a packet is ACKed. - * Updates the outgoing packet buffer. - */ -static void usbStateTransferSuccess(struct GrainuumState *state) -{ - - /* Reduce the amount of data left. - * If the packet is divisible by 8, this will cause one more call - * to this function with state->data_out_left == 0. This will send - * a NULL packet, which indicates end-of-transfer. - */ - state->data_out_left -= GRAINUUM_PACKET_SIZE_MAX; - state->data_out_max -= GRAINUUM_PACKET_SIZE_MAX; - state->data_out += GRAINUUM_PACKET_SIZE_MAX; - - if ((state->data_out_left < 0) || (state->data_out_max < 0)) { - grainuum_state_clear_tx(state, 0); - - /* End of a State setup packet */ - if (state->packet_type == packet_type_setup_out) - state->packet_type = packet_type_none; - if (state->packet_type == packet_type_setup_in) - state->packet_type = packet_type_none; - if (state->packet_type == packet_type_out) - state->packet_type = packet_type_none; - } - - state->packet_queued = 0; -} - -/* Send data down the wire, interrupting any existing - * data that may be queued. - */ -static int grainuum_state_send_data(struct GrainuumState *state, - int epnum, - const void *data, - int size, - int max) -{ - - /* De-queue any data that may already be queued. */ - grainuum_state_clear_tx(state, 1); - - state->data_out_epnum = epnum; - state->data_out_left = size; - state->data_out_max = max; - state->data_out = data; - - grainuum_state_process_tx(state); - return 0; -} - -void grainuumDropData(struct GrainuumUSB *usb) -{ - usb->state.packet_queued = 0; - usb->state.data_out = 0; - grainuumWriteQueue(usb, 0, NULL, 0); -} - -int grainuumDataQueued(struct GrainuumUSB *usb) -{ - return (usb->state.data_out || usb->state.packet_queued); -} - -int grainuumSendData(struct GrainuumUSB *usb, int epnum, - const void *data, int size) -{ - - struct GrainuumState *state = &usb->state; - int ret; - - if (state->data_out || !state->address || state->packet_queued) { - return -11; /* EAGAIN */ - } - - ret = grainuum_state_send_data(state, epnum, data, size, size); - if (ret) - return ret; - - grainuum_state_process_tx(state); - - if (usb->cfg->sendDataStarted) - usb->cfg->sendDataStarted(usb, epnum, data, size); - - return 0; -} - -static int grainuum_state_process_setup(struct GrainuumState *state, const uint8_t packet[10]) -{ - - const struct usb_setup_packet *setup; - const void *response = (void *)-1; - uint32_t response_len = 0; - struct GrainuumUSB *usb = state->usb; - struct GrainuumConfig *cfg = usb->cfg; - - setup = (const struct usb_setup_packet *)packet; - - if ((setup->bmRequestType == 0x00) && (setup->bRequest == SET_ADDRESS)) { - state->address = setup->wValue; - } - else if ((setup->bmRequestType == 0x00) && (setup->bRequest == SET_CONFIGURATION)) { - if (cfg->setConfigNum) - cfg->setConfigNum(usb, setup->wValue); - } - else { - printf("Going to get descriptor @ 0x%08x\n", cfg->getDescriptor); - response_len = cfg->getDescriptor(usb, setup, &response); - } - grainuum_state_send_data(state, state->tok_epnum, response, response_len, setup->wLength); - - return 0; -} - -static void grainuum_state_parse_data(struct GrainuumState *state, - const uint8_t packet[GRAINUUM_PACKET_SIZE_MAX + 2], - uint32_t size) -{ - (void)size; - struct GrainuumUSB *usb = state->usb; - - switch (state->packet_type) { - - case packet_type_setup: - grainuum_state_process_setup(state, packet); - grainuum_state_process_tx(state); - state->packet_type = packet_type_none; - break; - - case packet_type_out: - // XXX HACK: An OUT packet gets generated (on Windows at least) when - // terminating a SETUP sequence. This seems odd. - if (state->tok_epnum == 0) - break; - // Copy over the packet, minus the CRC16 - memcpy(state->tok_buf + state->tok_pos, packet, size - 2); - state->tok_pos += (size - 2); - if (!usb->cfg->receiveData(usb, state->tok_epnum, size - 2, packet)) - state->packet_type = packet_type_none; - break; - - case packet_type_in: - case packet_type_none: - default: - break; - } -} - -void grainuumProcess(struct GrainuumUSB *usb, - uint8_t pid, - const uint8_t packet[GRAINUUM_PACKET_SIZE_MAX + 3], - uint32_t size) -{ - - // uint32_t size = packet[GRAINUUM_PACKET_SIZE_MAX + 3]; - struct GrainuumState *state = &usb->state; - printf("Processing %d byte packet %x %08x (%02x)\n", size, pid, packet, packet[0]); - switch(pid) { - case VUSB_PID_SETUP: - printf("Setup packet!\n"); - state->packet_type = packet_type_setup; - grainuum_state_clear_tx(state, 1); - break; - - case USB_PID_OUT: - state->packet_type = packet_type_out; - state->tok_pos = 0; - state->tok_buf = usb->cfg->getReceiveBuffer(usb, state->tok_epnum, NULL); - break; - - default: - printf("Unrecognized PID: %02x\n", pid); - break; - } - - if (size == 0) { - usb_ep_0_in_respond_write(0); - usb_ep_0_in_ev_pending_write(0xff); - } - - //state->data_buffer |= (1 << state->tok_epnum); - grainuum_state_parse_data(state, packet, size); -} diff --git a/sw/src/main.c b/sw/src/main.c index a12b6e2..a5a5324 100644 --- a/sw/src/main.c +++ b/sw/src/main.c @@ -67,13 +67,12 @@ int main(int argc, char **argv) printf("\n\nUSB API: %s\n", usb_hw_api()); // printf("Press any key to enable USB...\n"); - usb_print_status(); + // usb_print_status(); // uart_read(); printf("Enabling USB\n"); usb_connect(); printf("USB enabled, waiting for packet...\n"); - // usb_wait(); - usb_print_status(); + // usb_print_status(); int last = 0; while (1) { @@ -81,8 +80,7 @@ int main(int argc, char **argv) last = usb_irq_happened(); printf("USB %d IRQ happened\n", last); } - // printf("x"); - usb_print_status(); + usb_poll(); } return 0; } \ No newline at end of file diff --git a/sw/src/usb-epfifo.c b/sw/src/usb-epfifo.c index eb4c73b..0e05f25 100644 --- a/sw/src/usb-epfifo.c +++ b/sw/src/usb-epfifo.c @@ -8,101 +8,22 @@ #ifdef CSR_USB_EP_0_OUT_EV_PENDING_ADDR +/* The state machine states of a control pipe */ +enum CONTROL_STATE +{ + WAIT_SETUP, + IN_DATA, + OUT_DATA, + LAST_IN_DATA, + WAIT_STATUS_IN, + WAIT_STATUS_OUT, + STALLED, +} control_state; + #define NUM_BUFFERS 4 #define BUFFER_SIZE 64 #define EP_INTERVAL_MS 6 -//static struct GrainuumUSB usb; -//static uint8_t usb_buf[67]; -static const uint8_t hid_report_descriptor[] = { - 0x06, 0x00, 0xFF, // (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined - 0x09, 0x00, // (LOCAL) USAGE 0xFF000000 - 0xA1, 0x01, // (MAIN) COLLECTION 0x01 Application (Usage=0xFF000000: Page=Vendor-defined, Usage=, Type=) - 0x26, 0xFF, 0x00, // (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255) - 0x75, 0x08, // (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field - 0x95, 0x08, // (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields - 0x06, 0xFF, 0xFF, // (GLOBAL) USAGE_PAGE 0xFFFF Vendor-defined - 0x09, 0x01, // (LOCAL) USAGE 0xFFFF0001 - 0x81, 0x02, // (MAIN) INPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap - 0x09, 0x01, // (LOCAL) USAGE 0xFFFF0001 - 0x91, 0x02, // (MAIN) OUTPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap - 0xC0, // (MAIN) END_COLLECTION Application -}; - -static const struct usb_device_descriptor device_descriptor = { - .bLength = 18, //sizeof(struct usb_device_descriptor), - .bDescriptorType = DT_DEVICE, /* DEVICE */ - .bcdUSB = 0x0200, /* USB 2.0 */ - .bDeviceClass = 0x00, - .bDeviceSubClass = 0x00, - .bDeviceProtocol = 0x00, - .bMaxPacketSize0 = 0x08, /* 8-byte packets max */ - .idVendor = 0x1209, - .idProduct = 0x9317, - .bcdDevice = 0x0114, /* Device release 1.14 */ - .iManufacturer = 0x02, /* No manufacturer string */ - .iProduct = 0x01, /* Product name in string #2 */ - .iSerialNumber = 0x03, /* No serial number */ - .bNumConfigurations = 0x01, -}; - -static const struct usb_configuration_descriptor configuration_descriptor = { - .bLength = 9, //sizeof(struct usb_configuration_descriptor), - .bDescriptorType = DT_CONFIGURATION, - .wTotalLength = (9 + /*9 + 9 + 7 +*/ 9 + 9 + 7 + 7) /* - (sizeof(struct usb_configuration_descriptor) - + sizeof(struct usb_interface_descriptor) - + sizeof(struct usb_hid_descriptor) - + sizeof(struct usb_endpoint_descriptor)*/, - .bNumInterfaces = 1, - .bConfigurationValue = 1, - .iConfiguration = 5, - .bmAttributes = 0x80, /* Remote wakeup not supported */ - .bMaxPower = 100 / 2, /* 100 mA (in 2-mA units) */ - .data = { - /* struct usb_interface_descriptor { */ - /* uint8_t bLength; */ 9, - /* uint8_t bDescriptorType; */ DT_INTERFACE, - /* uint8_t bInterfaceNumber; */ 0, - /* uint8_t bAlternateSetting; */ 0, - /* uint8_t bNumEndpoints; */ 2, /* Two extra EPs */ - /* uint8_t bInterfaceClass; */ 3, /* HID class */ - /* uint8_t bInterfaceSubclass; */ 0, /* Boot Device subclass */ - /* uint8_t bInterfaceProtocol; */ 0, /* 1 == keyboard, 2 == mouse */ - /* uint8_t iInterface; */ 4, /* String index #4 */ - /* }*/ - - /* struct usb_hid_descriptor { */ - /* uint8_t bLength; */ 9, - /* uint8_t bDescriptorType; */ DT_HID, - /* uint16_t bcdHID; */ 0x11, 0x01, - /* uint8_t bCountryCode; */ 0, - /* uint8_t bNumDescriptors; */ 1, /* We have only one REPORT */ - /* uint8_t bReportDescriptorType; */ DT_HID_REPORT, - /* uint16_t wReportDescriptorLength; */ sizeof(hid_report_descriptor), - sizeof(hid_report_descriptor) >> 8, - /* } */ - - /* struct usb_endpoint_descriptor { */ - /* uint8_t bLength; */ 7, - /* uint8_t bDescriptorType; */ DT_ENDPOINT, - /* uint8_t bEndpointAddress; */ 0x81, /* EP1 (IN) */ - /* uint8_t bmAttributes; */ 3, /* Interrupt */ - /* uint16_t wMaxPacketSize; */ 0x08, 0x00, - /* uint8_t bInterval; */ EP_INTERVAL_MS, /* Every 6 ms */ - /* } */ - - /* struct usb_endpoint_descriptor { */ - /* uint8_t bLength; */ 7, - /* uint8_t bDescriptorType; */ DT_ENDPOINT, - /* uint8_t bEndpointAddress; */ 0x01, /* EP1 (OUT) */ - /* uint8_t bmAttributes; */ 3, /* Interrupt */ - /* uint16_t wMaxPacketSize; */ 0x08, 0x00, - /* uint8_t bInterval; */ EP_INTERVAL_MS, /* Every 6 ms */ - /* } */ - }, -}; - enum epfifo_response { EPF_ACK = 0, EPF_NAK = 1, @@ -118,7 +39,7 @@ void usb_connect(void) { // By default, it wants to respond with NAK. usb_ep_0_out_respond_write(EPF_ACK); - usb_ep_0_in_respond_write(EPF_NAK); + usb_ep_0_in_respond_write(EPF_ACK); usb_ep_0_out_ev_pending_write(usb_ep_0_out_ev_enable_read()); usb_ep_0_in_ev_pending_write(usb_ep_0_in_ev_pending_read()); @@ -134,11 +55,12 @@ void usb_init(void) { volatile int irq_count = 0; -#define EP0OUT_BUFFERS 64 +#define EP0OUT_BUFFERS 4 +__attribute__((aligned(4))) static uint8_t usb_ep0out_buffer[EP0OUT_BUFFERS][128]; +static uint8_t usb_ep0out_buffer_len[EP0OUT_BUFFERS]; uint8_t usb_ep0out_wr_ptr; uint8_t usb_ep0out_rd_ptr; -int descriptor_ptr; int max_byte_length = 8; static const uint8_t *current_data; @@ -146,7 +68,7 @@ static int current_length; static int current_offset; static int current_to_send; -static int maybe_send_more_data(int epnum) { +static int queue_more_data(int epnum) { (void)epnum; // Don't allow requeueing if (usb_ep_0_in_respond_read() != EPF_NAK) @@ -157,22 +79,23 @@ static int maybe_send_more_data(int epnum) { if (current_to_send > max_byte_length) current_to_send = max_byte_length; - for (this_offset = current_offset; this_offset < current_offset + current_to_send; this_offset++) { + for (this_offset = current_offset; this_offset < (current_offset + current_to_send); this_offset++) { usb_ep_0_in_ibuf_head_write(current_data[this_offset]); } usb_ep_0_in_respond_write(EPF_ACK); - usb_ep_0_out_respond_write(EPF_ACK); return 0; } -static int send_data(int epnum, const void *data, int total_count) { +int usb_send(struct usb_device *dev, int epnum, const void *data, int total_count) { + (void)dev; // Don't allow requeueing if (usb_ep_0_in_respond_read() != EPF_NAK) return -1; current_data = (uint8_t *)data; current_length = total_count; current_offset = 0; - maybe_send_more_data(epnum); + control_state = IN_DATA; + queue_more_data(epnum); return 0; } @@ -182,56 +105,48 @@ void usb_isr(void) { uint8_t ep0o_pending = usb_ep_0_out_ev_pending_read(); uint8_t ep0i_pending = usb_ep_0_in_ev_pending_read(); + // We got an OUT or a SETUP packet. Copy it to usb_ep0out_buffer + // and clear the "pending" bit. if (ep0o_pending) { + int byte_count = 0; uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_wr_ptr]; - while (1) { - if (usb_ep_0_out_obuf_empty_read()) - break; - obuf[++byte_count] = usb_ep_0_out_obuf_head_read(); + while (!usb_ep_0_out_obuf_empty_read()) { + obuf[byte_count++] = usb_ep_0_out_obuf_head_read(); usb_ep_0_out_obuf_head_write(0); } usb_ep_0_out_ev_pending_write(ep0o_pending); if (byte_count) { - obuf[0] = byte_count; + printf("read %d bytes\n", byte_count); + usb_ep0out_buffer_len[usb_ep0out_wr_ptr] = byte_count; usb_ep0out_wr_ptr = (usb_ep0out_wr_ptr + 1) & (EP0OUT_BUFFERS-1); - - // usb_ep_0_in_dtb_write(1); - send_data(0, &device_descriptor, sizeof(device_descriptor)); } else { + printf("read no bytes\n"); usb_ep_0_out_respond_write(EPF_ACK); } } + // We just got an "IN" token. Send data if we have it. if (ep0i_pending) { - /* - uint8_t *descriptor = (uint8_t *)&device_descriptor; - if (descriptor_ptr < 0) { - usb_ep_0_in_respond_write(EPF_NAK); - } - else if (descriptor_ptr >= sizeof(device_descriptor)) { - descriptor_ptr = -1; - usb_ep_0_in_respond_write(EPF_ACK); - } - else { - usb_ep_0_in_respond_write(EPF_NAK); - for (descriptor_ptr; descriptor_ptr < sizeof(device_descriptor); descriptor_ptr++) { - usb_ep_0_in_ibuf_head_write(descriptor[descriptor_ptr]); - } - usb_ep_0_in_respond_write(EPF_ACK); - } - */ usb_ep_0_in_respond_write(EPF_NAK); current_offset += current_to_send; - maybe_send_more_data(0); + queue_more_data(0); usb_ep_0_in_ev_pending_write(ep0i_pending); - // Get ready to respond to the empty data byte - usb_ep_0_out_respond_write(EPF_ACK); + // Get ready to respond with an empty data byte + if (current_offset >= current_length) { + current_offset = 0; + current_length = 0; + current_data = NULL; + if (control_state == IN_DATA) { + usb_ep_0_out_respond_write(EPF_ACK); + } + } } + printf(">> %02x %02x <<\n", ep0o_pending, ep0i_pending); return; } @@ -241,338 +156,72 @@ void usb_wait(void) { } int usb_irq_happened(void) { - return irq_count; + return irq_count; +} + +int usb_ack(struct usb_device *dev, int epnum) { + usb_ep_0_out_respond_write(EPF_ACK); + usb_ep_0_in_respond_write(EPF_ACK); +} + +int usb_err(struct usb_device *dev, int epnum) { + usb_ep_0_out_respond_write(EPF_STALL); + usb_ep_0_in_respond_write(EPF_STALL); +} + +int usb_recv(struct usb_device *dev, void *buffer, unsigned int buffer_len) { + return; } static const char hex[] = "0123456789abcdef"; + +void usb_poll(void) { + // If some data was received, then process it. + if (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) { + const struct usb_setup_request *request = (const struct usb_setup_request *)(usb_ep0out_buffer[usb_ep0out_rd_ptr]); + + usb_setup(NULL, request); + usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0; + usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1); + } + // Cancel any pending transfers + if ((control_state == IN_DATA) && usb_ep_0_in_ibuf_empty_read()) { + printf("state is IN_DATA but ibuf is empty?\n"); + usb_ack(NULL, 0); + printf("and obuf_empty_read(): %d\n", usb_ep_0_out_obuf_empty_read()); + usb_ep_0_out_obuf_head_write(0); + control_state = WAIT_SETUP; + } + if (!usb_ep_0_out_obuf_empty_read()) { + printf("obuf not empty\n"); + } + // if (!usb_ep_0_in_ibuf_empty_read()) { + // usb_ep_0_in_ibuf_head_write(0); + // } + // usb_ack(NULL, 0); +} + void usb_print_status(void) { - /* - printf("EP0_OUT Status: %02x\n", usb_ep_0_out_ev_status_read()); - printf("EP0_OUT Pending: %02x\n", usb_ep_0_out_ev_pending_read()); - printf("EP0_OUT Enable: %02x\n", usb_ep_0_out_ev_enable_read()); - printf("EP0_OUT Last Tok: %02x\n", usb_ep_0_out_last_tok_read()); - printf("EP0_OUT Respond: %02x\n", usb_ep_0_out_respond_read()); - printf("EP0_OUT DTB: %02x\n", usb_ep_0_out_dtb_read()); - printf("EP0_OUT OBUF Head: %02x\n", usb_ep_0_out_obuf_head_read()); - printf("EP0_OUT OBUF Empty: %02x\n", usb_ep_0_out_obuf_empty_read()); - printf("EP0_IN Status: %02x\n", usb_ep_0_in_ev_status_read()); - printf("EP0_IN Pending: %02x\n", usb_ep_0_in_ev_pending_read()); - printf("EP0_IN Enable: %02x\n", usb_ep_0_in_ev_enable_read()); - printf("EP0_IN Last Tok: %02x\n", usb_ep_0_in_last_tok_read()); - printf("EP0_IN Respond: %02x\n", usb_ep_0_in_respond_read()); - printf("EP0_IN DTB: %02x\n", usb_ep_0_in_dtb_read()); - printf("EP0_IN IBUF Head: %02x\n", usb_ep_0_in_ibuf_head_read()); - printf("EP0_IN IBUF Empty: %02x\n", usb_ep_0_in_ibuf_empty_read()); - */ while (usb_ep0out_rd_ptr != usb_ep0out_wr_ptr) { - // printf("for (this_offset = current_offset; this_offset < this_offset + current_to_send; this_offset++) {\n"); - // printf("for (this_offset = %d; this_offset < %d; %d++) {\n", current_offset, this_offset, this_offset + current_to_send, this_offset); - printf("current_data: 0x%08x\n", current_data); - printf("current_length: %d\n", current_length); - printf("current_offset: %d\n", current_offset); - printf("current_to_send: %d\n", current_to_send); + // printf("current_data: 0x%08x\n", current_data); + // printf("current_length: %d\n", current_length); + // printf("current_offset: %d\n", current_offset); + // printf("current_to_send: %d\n", current_to_send); uint8_t *obuf = usb_ep0out_buffer[usb_ep0out_rd_ptr]; - uint8_t cnt = obuf[0]; + uint8_t cnt = usb_ep0out_buffer_len[usb_ep0out_rd_ptr]; unsigned int i; if (cnt) { for (i = 0; i < cnt; i++) { uart_write(' '); uart_write(hex[(obuf[i+1] >> 4) & 0xf]); uart_write(hex[obuf[i+1] & (0xf)]); - // printf(" %02x", obufbuf[i]); } uart_write('\r'); uart_write('\n'); } - // printf("\n"); + usb_ep0out_buffer_len[usb_ep0out_rd_ptr] = 0; usb_ep0out_rd_ptr = (usb_ep0out_rd_ptr + 1) & (EP0OUT_BUFFERS-1); } } - -// static inline unsigned char usb_pullup_out_read(void); -// static inline void usb_pullup_out_write(unsigned char value); - - -// static inline unsigned char usb_ep_0_out_ev_status_read(void); -// static inline void usb_ep_0_out_ev_status_write(unsigned char value); - -// static inline unsigned char usb_ep_0_out_ev_pending_read(void); -// static inline void usb_ep_0_out_ev_pending_write(unsigned char value); - -// static inline unsigned char usb_ep_0_out_ev_enable_read(void); -// static inline void usb_ep_0_out_ev_enable_write(unsigned char value); - -// static inline unsigned char usb_ep_0_out_last_tok_read(void); - -// static inline unsigned char usb_ep_0_out_respond_read(void); -// static inline void usb_ep_0_out_respond_write(unsigned char value); - -// static inline unsigned char usb_ep_0_out_dtb_read(void); -// static inline void usb_ep_0_out_dtb_write(unsigned char value); - -// static inline unsigned char usb_ep_0_out_obuf_head_read(void); -// static inline void usb_ep_0_out_obuf_head_write(unsigned char value); - -// static inline unsigned char usb_ep_0_out_obuf_empty_read(void); - - -// static inline unsigned char usb_ep_0_in_ev_status_read(void); -// static inline void usb_ep_0_in_ev_status_write(unsigned char value); - -// static inline unsigned char usb_ep_0_in_ev_pending_read(void); -// static inline void usb_ep_0_in_ev_pending_write(unsigned char value); - -// static inline unsigned char usb_ep_0_in_ev_enable_read(void); -// static inline void usb_ep_0_in_ev_enable_write(unsigned char value); - -// static inline unsigned char usb_ep_0_in_last_tok_read(void); - -// static inline unsigned char usb_ep_0_in_respond_read(void); -// static inline void usb_ep_0_in_respond_write(unsigned char value); - -// static inline unsigned char usb_ep_0_in_dtb_read(void); -// static inline void usb_ep_0_in_dtb_write(unsigned char value); - -// static inline unsigned char usb_ep_0_in_ibuf_head_read(void); -// static inline void usb_ep_0_in_ibuf_head_write(unsigned char value); - -// static inline unsigned char usb_ep_0_in_ibuf_empty_read(void); - - -#if 0 -static uint32_t rx_buffer[NUM_BUFFERS][BUFFER_SIZE / sizeof(uint32_t)]; -static uint8_t rx_buffer_head; -static uint8_t rx_buffer_tail; - -static uint32_t rx_buffer_queries = 0; -static void set_usb_config_num(struct GrainuumUSB *usb, int configNum) -{ - (void)usb; - (void)configNum; - ; -} - - -#define USB_STR_BUF_LEN 64 - -static uint32_t str_buf_storage[USB_STR_BUF_LEN / sizeof(uint32_t)]; -static int send_string_descriptor(const char *str, const void **data) -{ - int len; - int max_len; - uint8_t *str_buf = (uint8_t *)str_buf_storage; - uint8_t *str_offset = str_buf; - - len = strlen(str); - max_len = (USB_STR_BUF_LEN / 2) - 2; - - if (len > max_len) - len = max_len; - - *str_offset++ = (len * 2) + 2; // Two bytes for length count - *str_offset++ = DT_STRING; // Sending a string descriptor - - while (len--) - { - *str_offset++ = *str++; - *str_offset++ = 0; - } - - *data = str_buf; - - // Return the size, which is stored in the first byte of the output data. - return str_buf[0]; -} - -static int get_string_descriptor(struct GrainuumUSB *usb, - uint32_t num, - const void **data) -{ - - static const uint8_t en_us[] = {0x04, DT_STRING, 0x09, 0x04}; - - (void)usb; - - if (num == 0) - { - *data = en_us; - return sizeof(en_us); - } - - // Product - if (num == 1) - return send_string_descriptor("Palawan Bootloader", data); - - if (num == 2) - return send_string_descriptor("21", data); - - if (num == 3) - return send_string_descriptor("1236", data); - - if (num == 4) - return send_string_descriptor("12345", data); - - if (num == 5) - return send_string_descriptor("54", data); - - if (num == 6) - return send_string_descriptor("12345678901234", data); - - return 0; -} - -static int get_device_descriptor(struct GrainuumUSB *usb, - uint32_t num, - const void **data) -{ - - (void)usb; - - if (num == 0) - { - *data = &device_descriptor; - return sizeof(device_descriptor); - } - return 0; -} - -static int get_hid_report_descriptor(struct GrainuumUSB *usb, - uint32_t num, - const void **data) -{ - - (void)usb; - - if (num == 0) - { - *data = &hid_report_descriptor; - return sizeof(hid_report_descriptor); - } - - return 0; -} - -static int get_configuration_descriptor(struct GrainuumUSB *usb, - uint32_t num, - const void **data) -{ - - (void)usb; - - if (num == 0) - { - *data = &configuration_descriptor; - return configuration_descriptor.wTotalLength; - } - return 0; -} - -static int get_descriptor(struct GrainuumUSB *usb, - const void *packet, - const void **response) -{ - - const struct usb_setup_packet *setup = packet; - printf("In get_Descriptor()\n"); - switch (setup->wValueH) - { - case DT_DEVICE: - printf("Returning device descriptor %d\n", setup->wValueL); - return get_device_descriptor(usb, setup->wValueL, response); - - case DT_STRING: - printf("Returning string descriptor %d\n", setup->wValueL); - return get_string_descriptor(usb, setup->wValueL, response); - - case DT_CONFIGURATION: - printf("Returning configuration descriptor %d\n", setup->wValueL); - return get_configuration_descriptor(usb, setup->wValueL, response); - - case DT_HID_REPORT: - printf("Returning HID descriptor %d\n", setup->wValueL); - return get_hid_report_descriptor(usb, setup->wValueL, response); - } - - printf("Returning no descriptor %d\n", setup->wValueL); - - return 0; -} - -static void *get_usb_rx_buffer(struct GrainuumUSB *usb, - uint8_t epNum, - int32_t *size) -{ - (void)usb; - (void)epNum; - - if (size) - *size = sizeof(rx_buffer[0]); - rx_buffer_queries++; - return rx_buffer[rx_buffer_head]; -} - -static int received_data(struct GrainuumUSB *usb, - uint8_t epNum, - uint32_t bytes, - const void *data) -{ - (void)usb; - (void)epNum; - (void)bytes; - (void)data; - - if (epNum == 1) - { - rx_buffer_head = (rx_buffer_head + 1) & (NUM_BUFFERS - 1); - } - - /* Return 0, indicating this packet is complete. */ - return 0; -} - -static int send_data_finished(struct GrainuumUSB *usb, int result) -{ - (void)usb; - (void)result; - - return 0; -} - -static struct GrainuumConfig cfg = { - .getDescriptor = get_descriptor, - .getReceiveBuffer = get_usb_rx_buffer, - .receiveData = received_data, - .sendDataFinished = send_data_finished, - .setConfigNum = set_usb_config_num, -}; - -// void usb_isr(void) { -// // grainuumCaptureI(&usb, usb_buf); -// return; -// } - -// void usb_init(void) { -// // grainuumInit(&usb, &cfg); -// // grainuumConnect(&usb); -// return; -// } - -void usbPhyWriteI(const struct GrainuumUSB *usb, const void *buffer, uint32_t size) { - // (void)usb; - // const uint8_t *ubuffer = (const uint8_t *)buffer; - // uint32_t i = 0; - // while (i < size) - // usb_obuf_head_write(ubuffer[i]); -} - -int usbPhyReadI(const struct GrainuumUSB *usb, uint8_t *samples) { - (void)usb; - int count = 0; - // while (!usb_ibuf_empty_read()) { - // samples[count++] = usb_ibuf_head_read(); - // } - return count; -} -#endif #endif /* CSR_USB_EP_0_OUT_EV_PENDING_ADDR */ \ No newline at end of file