aboutsummaryrefslogtreecommitdiff
path: root/src/usb/dev.c
blob: fb28e43e4aecffc7892108431a5e475bd32a7c13 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#include "CH58x_common.h"

#include "utils.h"
#include "debug.h"

extern uint8_t *cfg_desc;

void usb_set_address(uint8_t ad);

USB_DEV_DESCR dev_desc = {
	.bLength = sizeof(USB_DEV_DESCR),
	.bDescriptorType = 0x01,
	.bcdUSB = 0x0110,

	.bDeviceClass = 0x00,
	.bDeviceSubClass = 0x00,
	.bDeviceProtocol = 0x00,

	.bMaxPacketSize0 = MAX_PACKET_SIZE,

	.idVendor = 0x0416,
	.idProduct = 0x5020,
	.bcdDevice = 0x0000,
	.iManufacturer = 1,
	.iProduct = 2,
	.iSerialNumber = 3,
	.bNumConfigurations = 0x01
};

/* String Descriptor Zero, Specifying Languages Supported by the Device */
static uint8_t lang_desc[] = {
	0x04,       /* bLength */
	0x03,       /* bDescriptorType */
	0x09, 0x04  /* wLANGID - en-US */
};

static uint16_t vendor_info[] = {
	36 | /* bLength */
	0x03 << 8, /* bDescriptorType */

	/* bString */
	'F', 'O', 'S', 'S', 'A', 'S', 'I', 'A', ' ',
	'W', 'A', 'S', ' ', 'H', 'E', 'R', 'E'
};

static uint16_t product_info[] = {
	32 | /* bLength */
	0x03 << 8, /* bDescriptorType */

	/* bString */
	'L', 'E', 'D', ' ',
	'B', 'a', 'd', 'g', 'e', ' ',
	'M', 'a', 'g', 'i', 'c'
};

// TODO: auto update firmware version by CI here
static uint16_t serial_number[] = {
	47 * 2 | /* bLength */
	0x03 << 8, /* bDescriptorType */

	/* bString */
	'N', 'o', 't', ' ', 'y', 'e', 't', ' ',
	'i', 'm', 'p', 'l', 'e', 'm', 'e', 'n', 't', 'e', 'd', '\n',
	'P', 'R', 'E', 'S', 'S', ' ', 'A', 'L', 'T', '+', 'F', '4', ' ',
	'T', 'O', ' ', 'C', 'O', 'N', 'T', 'I', 'N', 'U', 'E', '.'
};

static void desc_dev(USB_SETUP_REQ *request)
{
	ctrl_start_load_block(&dev_desc, dev_desc.bLength);
}

static void desc_config(USB_SETUP_REQ *request)
{
	ctrl_start_load_block(cfg_desc, request->wLength);
}

static void desc_string(USB_SETUP_REQ *request)
{
	uint8_t *string_index[32] = {
		lang_desc,
		vendor_info,
		product_info,
		serial_number
	};
	uint8_t index = request->wValue & 0xff;
	if (index <= sizeof(string_index))
		ctrl_start_load_block(string_index[index], string_index[index][0]);
}

static void dev_getDesc(USB_SETUP_REQ *request)
{
	_TRACE();
	uint8_t type = request->wValue >> 8;
	
	PRINT("Descriptor type: 0x%02x\n", type);

	static const void (*desc_type_handlers[4])(USB_SETUP_REQ *request) = {
		NULL,
		desc_dev,
		desc_config,
		desc_string
	};
	if (type <= 3 && desc_type_handlers[type])
		desc_type_handlers[type](request);
}

static void dev_getStatus(USB_SETUP_REQ *request)
{
	_TRACE();
	// Remote Wakeup disabled | Bus powered, hardcoded for now
	uint8_t buf[] = {0, 0};
	ctrl_start_load_block(buf, 2);
}

static void dev_clearFeature(USB_SETUP_REQ *request)
{
	_TRACE();
	// DEVICE_REMOTE_WAKEUP and TEST_MODE are not available, ignore.
}

static void dev_setFeature(USB_SETUP_REQ *request)
{
	_TRACE();
	// DEVICE_REMOTE_WAKEUP and TEST_MODE are not available, ignore.
}

static void dev_setAddress(USB_SETUP_REQ *request)
{
	_TRACE();
	/* new address will be loadled in the next IN poll,
	so here just sending a ACK */
	usb_set_address(request->wValue & 0xff);
	ctrl_ack();
}

// For now, multiple configuration is not supported
static uint8_t devcfg;

static void dev_getConfig(USB_SETUP_REQ *request)
{
	_TRACE();
	ctrl_start_load_block(&devcfg, 1);
}

static void dev_setConfig(USB_SETUP_REQ *request)
{
	_TRACE();
	devcfg = (request->wValue) & 0xff;
	ctrl_ack();
}

void handle_devreq(USB_SETUP_REQ *request)
{
	_TRACE();

	static const void (*dev_req_handlers[13])(USB_SETUP_REQ *request) = {
		dev_getStatus,
		dev_clearFeature,
		NULL, // Reserved
		dev_setFeature,
		NULL, // Reserved
		dev_setAddress,
		dev_getDesc,
		NULL, // set desc
		dev_getConfig,
		dev_setConfig,
		NULL, // get interface
		NULL, // set interface
		NULL, // sync frame
	};

	uint8_t req = request->bRequest;
	if (req <= 12 && dev_req_handlers[req])
		dev_req_handlers[req](request);
}