summaryrefslogtreecommitdiffstats
path: root/usb
diff options
context:
space:
mode:
Diffstat (limited to 'usb')
-rw-r--r--usb/bdt.h3
-rw-r--r--usb/descriptors.h80
-rw-r--r--usb/endpt0.c59
-rw-r--r--usb/endpt1.c37
-rw-r--r--usb/hid.h87
-rw-r--r--usb/usb.c10
6 files changed, 201 insertions, 75 deletions
diff --git a/usb/bdt.h b/usb/bdt.h
index 2945e2b..f4bc57d 100644
--- a/usb/bdt.h
+++ b/usb/bdt.h
@@ -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 */
diff --git a/usb/usb.c b/usb/usb.c
index 977e7a5..2749e16 100644
--- a/usb/usb.c
+++ b/usb/usb.c
@@ -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);
}