diff options
Diffstat (limited to 'usb')
-rw-r--r-- | usb/bdt.h | 3 | ||||
-rw-r--r-- | usb/descriptors.h | 80 | ||||
-rw-r--r-- | usb/endpt0.c | 59 | ||||
-rw-r--r-- | usb/endpt1.c | 37 | ||||
-rw-r--r-- | usb/hid.h | 87 | ||||
-rw-r--r-- | usb/usb.c | 10 |
6 files changed, 201 insertions, 75 deletions
@@ -3,9 +3,8 @@ #include <reg/usbotg.h> -extern volatile struct usb0_bd usb_bdt[4 * 16]; +extern volatile struct usb0_bd usb_bdt[2][2][2]; -#define BDT_ENDPT(n, tx, odd) (usb_bdt[(n) << 2 | (tx & 1) << 1 | (odd & 1)]) #define BDT_RX 0 #define BDT_TX 1 #define BDT_EVEN 0 diff --git a/usb/descriptors.h b/usb/descriptors.h index f60ed86..b1b143d 100644 --- a/usb/descriptors.h +++ b/usb/descriptors.h @@ -1,23 +1,27 @@ #ifndef USB_DESCRIPTORS_H #define USB_DESCRIPTORS_H +#include "hid.h" + /* * TODO: Move into a source file and use extern so there's only ever one copy * LTO should take care of the rest. */ +#define U16LE(d) ((d) & 0xff), (((uint16_t)(d) >> 8) & 0xff) + /* Device descriptor */ unsigned char ds_dev[] = { 18, // Length 1, // Descriptor type - 0x00, 0x02, // USB Release - 0xff, // Device class + U16LE(0x0200), // USB Release + 0x00, // Device class 0x00, // Device sub class 0x00, // Device protocol 64, // Max packet size - 0xc0, 0x16, // VID - 0xdc, 0x05, // PID - 0x01, 0x00, // Device relase + U16LE(0x16c0), // VID + U16LE(0x05dc), // PID + U16LE(0x0001), // Device relase 1, // Manufacturer string 0, // Product string 0, // Serial number string @@ -25,11 +29,12 @@ unsigned char ds_dev[] = { }; /* Configuration descriptor */ +#define DS_CONF_SIZE 34 unsigned char ds_conf[] = { /* Configuration */ 9, // Length 2, // Descriptor type - 0x22, 0x00, // Total length + U16LE(DS_CONF_SIZE), // Total length 1, // Number of interfaces 1, // Configuration value 0, // Configuration string @@ -50,20 +55,54 @@ unsigned char ds_conf[] = { /* HID */ 9, // Length 33, // Descriptor type - 0x11, 0x01, // HID Class spec version + U16LE(0x0111), // HID Class spec version 0, // Country code 1, // Number of descriptors 34, // Descriptor type - 0x34, 0x00, // Descriptor length + U16LE(52), // Descriptor length /* Endpoint */ 7, // Length 5, // Descriptor type 0x81, // Endpoint address (D000NNNN, D - Direction (0 OUT, 1 IN), N - Endpoint No.) 0x03, // Attributes (00UUSSTT, U - Usage type, S - Synch type, T - Transfer type) - 0x08, 0x00, // Max packet size + U16LE(64), // Max packet size 64, // Interval (1ms Frames) }; +_Static_assert(sizeof ds_conf == DS_CONF_SIZE, "sizeof ds_conf != DS_CONF_SIZE"); + +/* HID Report descriptor */ +#define DS_HIDREP_SIZE 52 +unsigned char ds_hidrep[] = { + HR_USAGE_PAGE(1), HR_GENERIC_DESKTOP, + HR_USAGE(1), HR_MOUSE, + HR_COLLECTION(1), HR_APPLICATION, + HR_USAGE(1), HR_POINTER, + HR_COLLECTION(1), HR_PHYSICAL, + HR_USAGE_PAGE(1), HR_BUTTON, + HR_USAGE_MINIMUM(1), 1, + HR_USAGE_MAXIMUM(1), 5, + HR_LOGICAL_MINIMUM(1), 0, + HR_LOGICAL_MAXIMUM(1), 1, + HR_REPORT_COUNT(1), 5, + HR_REPORT_SIZE(1), 1, + HR_INPUT(1), HR_DATA | HR_VARIABLE | HR_ABSOLUTE | HR_BIT_FIELD, + HR_REPORT_COUNT(1), 1, + HR_REPORT_SIZE(1), 3, + HR_INPUT(1), HR_CONSTANT | HR_ARRAY | HR_ABSOLUTE | HR_BIT_FIELD, + HR_USAGE_PAGE(1), HR_GENERIC_DESKTOP, + HR_USAGE(1), HR_X, + HR_USAGE(1), HR_Y, + HR_USAGE(1), HR_WHEEL, + HR_LOGICAL_MINIMUM(1), -127, + HR_LOGICAL_MAXIMUM(1), 127, + HR_REPORT_SIZE(1), 8, + HR_REPORT_COUNT(1), 3, + HR_INPUT(1), HR_DATA | HR_VARIABLE | HR_RELATIVE | HR_BIT_FIELD, + HR_END_COLLECTION(0), + HR_END_COLLECTION(0), +}; +_Static_assert(sizeof ds_hidrep == DS_HIDREP_SIZE, "sizeof ds_hidrep != DS_HIDREP_SIZE"); /* Language descriptor */ unsigned char ds_lang[] = { @@ -71,21 +110,24 @@ unsigned char ds_lang[] = { 3, // Descriptor type 0x09, 0x04 // Language ID }; +_Static_assert(sizeof ds_lang == 4, "sizeof ds_lang != 4"); /* String descriptor 1 */ +#define DS_STR1_SIZE 22 unsigned char ds_str1[] = { 22, // Length 3, // Descriptor type - 0x74, 0x00, // t - 0x68, 0x00, // h - 0x65, 0x00, // e - 0x2d, 0x00, // - - 0x74, 0x00, // t - 0x6b, 0x00, // k - 0x2e, 0x00, // . - 0x63, 0x00, // c - 0x6f, 0x00, // o - 0x6d, 0x00, // m + U16LE(0x74), // t + U16LE(0x68), // h + U16LE(0x65), // e + U16LE(0x2d), // - + U16LE(0x74), // t + U16LE(0x6b), // k + U16LE(0x2e), // . + U16LE(0x63), // c + U16LE(0x6f), // o + U16LE(0x6d), // m }; +_Static_assert(sizeof ds_str1 == DS_STR1_SIZE, "sizeof ds_str1 != DS_STR1_SIZE"); #endif /* USB_DESCRIPTORS_H */ diff --git a/usb/endpt0.c b/usb/endpt0.c index 485e464..c4c3360 100644 --- a/usb/endpt0.c +++ b/usb/endpt0.c @@ -7,10 +7,9 @@ #include <reg/gpio.h> -#include "../uart/uart.h" - #include "bdt.h" #include "endpt0.h" +#include "endpt1.h" #include "descriptors.h" @@ -21,7 +20,7 @@ static bool tx_data01; static volatile unsigned int nextaddr; -static const void *tx_data; +static void *tx_data; static size_t tx_size; struct tok_setup { @@ -49,12 +48,12 @@ static void read_setup(struct tok_setup *setup, const void *_data) /* puttx: place data in the current buffer descriptor */ static bool puttx(void *data, size_t size) { - if (GET_BIT(BDT_ENDPT(0, BDT_TX, tx_odd).desc, BD_OWN)) + if (GET_BIT(usb_bdt[0][BDT_TX][tx_odd].desc, BD_OWN)) return false; /* TODO: Just stop bothering with const */ - BDT_ENDPT(0, BDT_TX, tx_odd).addr = data; - BDT_ENDPT(0, BDT_TX, tx_odd).desc = USB0_BD_INIT(size, tx_data01); + usb_bdt[0][BDT_TX][tx_odd].addr = data; + usb_bdt[0][BDT_TX][tx_odd].desc = USB0_BD_INIT(size, tx_data01); tx_odd = !tx_odd; tx_data01 = !tx_data01; @@ -102,17 +101,17 @@ void usb_endpt0_disable(void) /* usb_endpt0_enable: Enable and reset endpoint 0 */ void usb_endpt0_enable(void) { - BDT_ENDPT(0, BDT_RX, BDT_EVEN).addr = buf[0]; - BDT_ENDPT(0, BDT_RX, BDT_EVEN).desc = USB0_BD_INIT(sizeof buf[0], 0); + usb_bdt[0][BDT_RX][BDT_EVEN].addr = buf[0]; + usb_bdt[0][BDT_RX][BDT_EVEN].desc = USB0_BD_INIT(sizeof buf[0], 0); - BDT_ENDPT(0, BDT_RX, BDT_ODD).addr = buf[1]; - BDT_ENDPT(0, BDT_RX, BDT_ODD).desc = USB0_BD_INIT(sizeof buf[1], 0); + usb_bdt[0][BDT_RX][BDT_ODD].addr = buf[1]; + usb_bdt[0][BDT_RX][BDT_ODD].desc = USB0_BD_INIT(sizeof buf[1], 0); - BDT_ENDPT(0, BDT_TX, BDT_EVEN).addr = NULL; - BDT_ENDPT(0, BDT_TX, BDT_EVEN).desc = 0; + usb_bdt[0][BDT_TX][BDT_EVEN].addr = NULL; + usb_bdt[0][BDT_TX][BDT_EVEN].desc = 0; - BDT_ENDPT(0, BDT_TX, BDT_ODD).addr = NULL; - BDT_ENDPT(0, BDT_TX, BDT_ODD).desc = 0; + usb_bdt[0][BDT_TX][BDT_ODD].addr = NULL; + usb_bdt[0][BDT_TX][BDT_ODD].desc = 0; USB0_ENDPT(0) = BV(ENDPT_EPRXEN) | BV(ENDPT_EPTXEN) | BV(ENDPT_EPHSHK); nextaddr = 0; @@ -134,39 +133,38 @@ static void tok_setup(struct tok_setup *setup) { switch (setup->reqtyp << 8 | setup->req) { case 0x0005: /* SET ADDRESS */ - uart_printf(" SET ADDRESS (%u)\n", (unsigned)setup->value); nextaddr = setup->value; puttx(NULL, 0); break; case 0x0009: /* SET CONFIGURATION */ - uart_puts(" SET CONFIGURATION"); + usb_endpt1_enable(); + puttx(NULL, 0); + break; + case 0x210a: /* SET IDLE */ puttx(NULL, 0); break; + case 0x8106: /* GET INTERFACE */ case 0x8006: /* GET DESCRIPTOR */ - uart_printf(" GET DESCRIPTOR (0x%x)", (unsigned)setup->value); switch (setup->value) { case 0x0100: /* DEVICE */ - uart_puts(" DEVICE"); quetx(ds_dev, trunc(ARRLEN(ds_dev), setup->length)); return; case 0x0200: /* CONFIGURATION */ - uart_puts(" CONFIGURATION"); quetx(ds_conf, trunc(ARRLEN(ds_conf), setup->length)); return; case 0x0300: /* STRING 0 */ - uart_puts(" STRING 0"); quetx(ds_lang, trunc(ARRLEN(ds_lang), setup->length)); return; case 0x0301: /* STRING 1 */ - uart_puts(" STRING 1"); quetx(ds_str1, trunc(ARRLEN(ds_str1), setup->length)); return; + case 0x2200: + quetx(ds_hidrep, trunc(ARRLEN(ds_hidrep), setup->length)); + return; } /* fall through */ default: /* We received an unexpected SETUP so we STALL the endpoint */ - printf("Unexpected SETUP: RT: 0x%x R: 0x%x V: 0x%x\n", - setup->reqtyp, setup->req, setup->value); SET_BIT(USB0_ENDPT(0), ENDPT_EPSTALL); break; } @@ -174,31 +172,27 @@ static void tok_setup(struct tok_setup *setup) void usb_endpt0_token(uint8_t state) { - struct usb0_bd *bd; + volatile struct usb0_bd *bd; struct tok_setup setup; - bd = &BDT_ENDPT(0, GET_BIT(state, STAT_TX), GET_BIT(state, STAT_ODD)); + bd = &usb_bdt[0][GET_BIT(state, STAT_TX)][GET_BIT(state, STAT_ODD)]; switch (GET_BITS(bd->desc, BD_TOK_PID)) { case BD_TOK_PID_OUT: - uart_puts(" PID_OUT"); bd->desc = USB0_BD_INIT(sizeof buf[0], 1); break; case BD_TOK_PID_IN: - uart_puts(" PID_IN"); - uart_printf(" pushtx: %d\n", (int)pushtx()); if (nextaddr) { USB0_ADDR = nextaddr; nextaddr = 0; } break; case BD_TOK_PID_SETUP: - uart_puts(" PID_SETUP"); read_setup(&setup, bd->addr); bd->desc = USB0_BD_INIT(sizeof buf[0], 1); - BDT_ENDPT(0, BDT_TX, BDT_EVEN).desc = 0; - BDT_ENDPT(0, BDT_TX, BDT_ODD).desc = 0; + usb_bdt[0][BDT_TX][BDT_EVEN].desc = 0; + usb_bdt[0][BDT_TX][BDT_ODD].desc = 0; tx_data = NULL; tx_data01 = 1; @@ -206,8 +200,7 @@ void usb_endpt0_token(uint8_t state) tok_setup(&setup); /* SETUP sets CTL_TXSUSPENDTOKENBUSY to suspend TX */ - uart_printf("Clearing USB0_CTL, was: 0x%x", (unsigned)USB0_CTL); - USB0_CTL = 0; + USB0_CTL = BV(CTL_USBENSOFEN); break; } diff --git a/usb/endpt1.c b/usb/endpt1.c index ca954fc..4358221 100644 --- a/usb/endpt1.c +++ b/usb/endpt1.c @@ -1,4 +1,5 @@ #include <reg/usbotg.h> +#include <stddef.h> #include <stdint.h> #include "../uart/uart.h" @@ -8,33 +9,45 @@ #define MAX_PACKET 64 -static unsigned char buf[2][MAX_PACKET]; +static unsigned char report[4][4] = { + { 0x00, 0x01, 0x00, 0x00, }, + { 0x00, 0x00, 0x01, 0x00, }, + { 0x00, 0xff, 0x00, 0x00, }, + { 0x00, 0x00, 0xff, 0x00, }, +}; +static int nextrep; void usb_endpt1_enable(void) { + nextrep = 0; + + usb_bdt[1][BDT_TX][BDT_EVEN].addr = &report[0]; + usb_bdt[1][BDT_TX][BDT_EVEN].desc = USB0_BD_INIT(4, nextrep % 2); + nextrep++; + + usb_bdt[1][BDT_TX][BDT_ODD].addr = &report[1]; + usb_bdt[1][BDT_TX][BDT_ODD].desc = USB0_BD_INIT(4, nextrep % 2); + nextrep++; + + USB0_ENDPT(1) = BV(ENDPT_EPTXEN) | BV(ENDPT_EPHSHK); } void usb_endpt1_disable(void) { + USB0_ENDPT(1) = 0; } void usb_endpt1_token(uint8_t state) { - struct usb0_bd *bd; + volatile struct usb0_bd *bd; - uart_puts(" endpt1 token"); - - bd = &BDT_ENDPT(1, GET_BIT(state, STAT_TX), GET_BIT(state, STAT_ODD)); + bd = &usb_bdt[1][GET_BIT(state, STAT_TX)][GET_BIT(state, STAT_ODD)]; switch (GET_BITS(bd->desc, BD_TOK_PID)) { - case BD_TOK_PID_OUT: - bd->desc = USB0_BD_INIT(sizeof buf[0], 1); - /* should never happen */ - break; case BD_TOK_PID_IN: - /*pushtx();*/ + bd->addr = &report[nextrep]; + bd->desc = USB0_BD_INIT(4, nextrep % 2); + nextrep = (nextrep + 1) % 4; break; } - - /*USB0_CTL = BV(CTL_USBENSOFEN);*/ } diff --git a/usb/hid.h b/usb/hid.h new file mode 100644 index 0000000..949cf8e --- /dev/null +++ b/usb/hid.h @@ -0,0 +1,87 @@ +#ifndef USB_HID_H +#define USB_HID_H + +#define SHORT_ITEM(tag, type, size) (((tag) & 0xf) << 4 | \ + ((type) & 0x3) << 2 | \ + ((size) & 0x3) << 0) + +#define HR_MAIN_ITEM(tag, size) SHORT_ITEM(tag, 0, size) +#define HR_GLOBAL_ITEM(tag, size) SHORT_ITEM(tag, 1, size) +#define HR_LOCAL_ITEM(tag, size) SHORT_ITEM(tag, 2, size) + +#define HR_INPUT(size) HR_MAIN_ITEM(8, size) +#define HR_OUTPUT(size) HR_MAIN_ITEM(9, size) +#define HR_FEATURE(size) HR_MAIN_ITEM(11, size) +#define HR_COLLECTION(size) HR_MAIN_ITEM(10, size) +#define HR_END_COLLECTION(size) HR_MAIN_ITEM(12, size) + +#define HR_USAGE_PAGE(size) HR_GLOBAL_ITEM(0, size) +#define HR_LOGICAL_MINIMUM(size) HR_GLOBAL_ITEM(1, size) +#define HR_LOGICAL_MAXIMUM(size) HR_GLOBAL_ITEM(2, size) +#define HR_PHYSICAL_MINIMUM(size) HR_GLOBAL_ITEM(3, size) +#define HR_PHYSICAL_MAXIMUM(size) HR_GLOBAL_ITEM(4, size) +#define HR_UNIT_EXPONENT(size) HR_GLOBAL_ITEM(5, size) +#define HR_UNIT(size) HR_GLOBAL_ITEM(6, size) +#define HR_REPORT_SIZE(size) HR_GLOBAL_ITEM(7, size) +#define HR_REPORT_ID(size) HR_GLOBAL_ITEM(8, size) +#define HR_REPORT_COUNT(size) HR_GLOBAL_ITEM(9, size) +#define HR_PUSH(size) HR_GLOBAL_ITEM(10, size) +#define HR_POP(size) HR_GLOBAL_ITEM(11, size) + +#define HR_USAGE(size) HR_LOCAL_ITEM(0, size) +#define HR_USAGE_MINIMUM(size) HR_LOCAL_ITEM(0, size) +#define HR_USAGE_MAXIMUM(size) HR_LOCAL_ITEM(0, size) +#define HR_DESIGNATOR_INDEX(size) HR_LOCAL_ITEM(0, size) +#define HR_DESIGNATOR_MINIMUM(size) HR_LOCAL_ITEM(0, size) +#define HR_DESIGNATOR_MAXIMUM(size) HR_LOCAL_ITEM(0, size) +#define HR_STRING_INDEX(size) HR_LOCAL_ITEM(0, size) +#define HR_STRING_MINIMUM(size) HR_LOCAL_ITEM(0, size) +#define HR_STRING_MAXIMUM(size) HR_LOCAL_ITEM(0, size) +#define HR_DELIMITER(size) HR_LOCAL_ITEM(0, size) + +#define HR_PHYSICAL 0x00 +#define HR_APPLICATION 0x01 +#define HR_LOGICAL 0x02 +#define HR_REPORT 0x03 +#define HR_NAMED_ARRAY 0x04 +#define HR_USAGE_SWITCH 0x05 +#define HR_USAGE_MODIFIER 0x06 + +#define HR_GENERIC_DESKTOP 0x01 +#define HR_POINTER 0x01 +#define HR_MOUSE 0x02 +#define HR_KEYBOARD 0x06 +#define HR_X 0x30 +#define HR_Y 0x31 +#define HR_WHEEL 0x38 + +#define HR_BUTTON 0x09 + +#define HR_DATA (0) +#define HR_CONSTANT (1 << 0) + +#define HR_ARRAY (0) +#define HR_VARIABLE (1 << 1) + +#define HR_ABSOLUTE (0) +#define HR_RELATIVE (1 << 2) + +#define HR_NO_WRAP (0) +#define HR_WRAP (1 << 3) + +#define HR_LINEAR (0) +#define HR_NON_LINEAR (1 << 4) + +#define HR_PREFERRED_STATE (0) +#define HR_NO_PREFERRED (1 << 5) + +#define HR_NO_NULL_POSITION (0) +#define HR_NULL_STATE (1 << 6) + +#define HR_NON_VOLATILE (0) +#define HR_VOLATILE (1 << 7) + +#define HR_BIT_FIELD (0) +#define HR_BUFFERED_BYTES (1 << 8) + +#endif /* USB_HID_H */ @@ -13,11 +13,8 @@ #define USBFRAC_VAL 1 /* 72 MHz * 2 = 144 MHz (Top of Fraction) */ #define USBDIV_VAL 2 /* 144 MHz / 3 = 48 MHz (Bottom of Fraction) */ -/* TODO: Only use the number of endpoints that are needed */ -/* TODO: Try using static */ -/* TODO: Try [16][2][2] since everything is contiguous. */ __attribute__ ((aligned(512))) -volatile struct usb0_bd usb_bdt[16 * 4]; +volatile struct usb0_bd usb_bdt[2][2][2]; /* usb_setup: Setup function for USB subsystem */ void usb_setup(void) @@ -87,20 +84,16 @@ void usb_isr(void) USB0_ISTAT = BV(ISTAT_STALL); } if (GET_BIT(stat, ISTAT_RESUME)) { - uart_puts("INT: resume"); USB0_ISTAT = BV(ISTAT_RESUME); } if (GET_BIT(stat, ISTAT_SLEEP)) { - uart_puts("INT: sleep"); USB0_ISTAT = BV(ISTAT_SLEEP); } if (GET_BIT(stat, ISTAT_TOKDNE)) { - uart_puts("INT: tokdne"); i_tokdne(); USB0_ISTAT = BV(ISTAT_TOKDNE); } if (GET_BIT(stat, ISTAT_SOFTOK)) { - /*uart_puts("INT: softok");*/ USB0_ISTAT = BV(ISTAT_SOFTOK); } if (GET_BIT(stat, ISTAT_ERROR)) { @@ -109,7 +102,6 @@ void usb_isr(void) USB0_ISTAT = BV(ISTAT_ERROR); } if (GET_BIT(stat, ISTAT_USBRST)) { - uart_puts("INT: usbrst"); i_usbrst(); USB0_ISTAT = BV(ISTAT_USBRST); } |