Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 8 commits
  • 1 file changed
  • 0 comments
  • 1 contributor
Nov 13, 2011
Werner Almesberger softusb-input: also accept 3 byte reports, e.g., from wheelless mice 6b83fa4
Werner Almesberger softusb-input: use symbolic constants for packet ID values 85b2d1c
Werner Almesberger softusb: use macro to construct (address, EP) value
0x81 meaning "address 1, endpoint 1" looks like the ubiquitous 0x81
meaning "direction IN, endpoint 1". This patch makes things a little
less misleading.
bd7d5e1
Werner Almesberger softusb: don't interrupt the host if we're ignoring the packet anyway 40404f9
Werner Almesberger softusb: renamed "fs" to "full_speed"
No need to be *that* tight-lipped ...
169c6a6
Werner Almesberger softusb: separate EP-specific state from port-specific state
This is made a little easier by the rest of the code ignoring the
data toggle in SETUP requests. Otherwise, EP0 would need some state
as well.
a2656a5
Werner Almesberger softusb: support composite USB devices
For this, we parse the entire configuration descriptor and look at
all interface descriptors. Furthermore, we set the endpoint number
according to the endpoint descriptor(s) following the interface
descriptor, instead of hard-coding it.

Here is a brief description of how composite devices are structured:
http://atmel.com/dyn/resources/prod_documents/doc7805.pdf

Note that this doesn't help with combi-devices that present
themselves as independent devices plus a hub.

We still bail out at the first interface descriptor we don't
understand, to avoid wandering into crazy things that may be lurking
at tne end of the configuration descriptor. (I did this on a whim.
Maybe we don't need that extra dose of paranoia.)
a26dc51
Werner Almesberger softusb: added hack for Rii RF mini-keyboard
Unlike the ACME rodent, the mouse pad of the Rii RF mini-keyboard
sends reports with report ID and 16 bit resolution. This patch just
identifies these reports by their sheer size and then rearranges the
packet content before further processing.
0b2d12a

Showing 1 changed file with 111 additions and 60 deletions. Show diff stats Hide diff stats

  1. 171  softusb-input/main.c
171  softusb-input/main.c
@@ -27,6 +27,16 @@
27 27
 #include "crc.h"
28 28
 
29 29
 enum {
  30
+	USB_PID_OUT	= 0xe1,
  31
+	USB_PID_IN	= 0x69,
  32
+	USB_PID_SETUP	= 0x2d,
  33
+	USB_PID_DATA0	= 0xc3,
  34
+	USB_PID_DATA1	= 0x4b,
  35
+	USB_PID_ACK	= 0xd2,
  36
+	USB_PID_NAK	= 0x5a,
  37
+};
  38
+
  39
+enum {
30 40
 	PORT_STATE_DISCONNECTED = 0,
31 41
 	PORT_STATE_BUS_RESET,
32 42
 	PORT_STATE_WARMUP,
@@ -38,14 +48,18 @@ enum {
38 48
 	PORT_STATE_UNSUPPORTED
39 49
 };
40 50
 
  51
+struct ep_status {
  52
+	char ep;
  53
+	unsigned char expected_data;
  54
+};
  55
+
41 56
 struct port_status {
42 57
 	char state;
43  
-	char fs;
44  
-	char keyboard;
  58
+	char full_speed;
45 59
 	char retry_count;
46 60
 	unsigned int unreset_frame;
47  
-
48  
-	unsigned char expected_data;
  61
+	struct ep_status keyboard;
  62
+	struct ep_status mouse;
49 63
 };
50 64
 
51 65
 static struct port_status port_a;
@@ -53,6 +67,8 @@ static struct port_status port_b;
53 67
 
54 68
 static unsigned int frame_nr;
55 69
 
  70
+#define	ADDR_EP(addr, ep)	((addr) | (ep) << 7)
  71
+
56 72
 static void make_usb_token(unsigned char pid, unsigned int elevenbits, unsigned char *out)
57 73
 {
58 74
 	out[0] = pid;
@@ -131,9 +147,9 @@ static inline unsigned char get_data_token(char *toggle)
131 147
 {
132 148
 	*toggle = !(*toggle);
133 149
 	if(*toggle)
134  
-		return 0xc3;
  150
+		return USB_PID_DATA0;
135 151
 	else
136  
-		return 0x4b;
  152
+		return USB_PID_DATA1;
137 153
 }
138 154
 
139 155
 static const char control_failed[] PROGMEM = "Control transfer failed:\n";
@@ -153,7 +169,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
153 169
 	toggle = 0;
154 170
 
155 171
 	/* send SETUP token */
156  
-	make_usb_token(0x2d, addr, usb_buffer);
  172
+	make_usb_token(USB_PID_SETUP, addr, usb_buffer);
157 173
 	usb_tx(usb_buffer, 3);
158 174
 	/* send setup packet */
159 175
 	usb_buffer[0] = get_data_token(&toggle);
@@ -162,7 +178,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
162 178
 	usb_tx(usb_buffer, 11);
163 179
 	/* get ACK token from device */
164 180
 	rxlen = usb_rx(usb_buffer, 11);
165  
-	if((rxlen != 1) || (usb_buffer[0] != 0xd2)) {
  181
+	if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
166 182
 		print_string(control_failed);
167 183
 		print_string(setup_reply);
168 184
 		dump_hex(usb_buffer, rxlen);
@@ -180,7 +196,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
180 196
 				chunklen = 8;
181 197
 
182 198
 			/* send OUT token */
183  
-			make_usb_token(0xe1, addr, usb_buffer);
  199
+			make_usb_token(USB_PID_OUT, addr, usb_buffer);
184 200
 			usb_tx(usb_buffer, 3);
185 201
 			/* send DATAx packet */
186 202
 			usb_buffer[0] = get_data_token(&toggle);
@@ -189,8 +205,9 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
189 205
 			usb_tx(usb_buffer, chunklen+3);
190 206
 			/* get ACK from device */
191 207
 			rxlen = usb_rx(usb_buffer, 11);
192  
-			if((rxlen != 1) || (usb_buffer[0] != 0xd2)) {
193  
-				if((rxlen > 0) && (usb_buffer[0] == 0x5a))
  208
+			if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
  209
+				if((rxlen > 0) &&
  210
+				    (usb_buffer[0] == USB_PID_NAK))
194 211
 					continue; /* NAK: retry */
195 212
 				print_string(control_failed);
196 213
 				print_string(out_reply);
@@ -206,12 +223,14 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
206 223
 	} else if(maxlen != 0) {
207 224
 		while(1) {
208 225
 			/* send IN token */
209  
-			make_usb_token(0x69, addr, usb_buffer);
  226
+			make_usb_token(USB_PID_IN, addr, usb_buffer);
210 227
 			usb_tx(usb_buffer, 3);
211 228
 			/* get DATAx packet */
212 229
 			rxlen = usb_rx(usb_buffer, 11);
213  
-			if((rxlen < 3) || ((usb_buffer[0] != 0xc3) && (usb_buffer[0] != 0x4b))) {
214  
-				if((rxlen > 0) && (usb_buffer[0] == 0x5a))
  230
+			if((rxlen < 3) || ((usb_buffer[0] != USB_PID_DATA0) &&
  231
+			    (usb_buffer[0] != USB_PID_DATA1))) {
  232
+				if((rxlen > 0) &&
  233
+				    (usb_buffer[0] == USB_PID_NAK))
215 234
 					continue; /* NAK: retry */
216 235
 				print_string(control_failed);
217 236
 				print_string(in_reply);
@@ -224,7 +243,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
224 243
 			memcpy(payload, &usb_buffer[1], chunklen);
225 244
 
226 245
 			/* send ACK token */
227  
-			usb_buffer[0] = 0xd2;
  246
+			usb_buffer[0] = USB_PID_ACK;
228 247
 			usb_tx(usb_buffer, 1);
229 248
 
230 249
 			transferred += chunklen;
@@ -236,13 +255,14 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
236 255
 
237 256
 	/* send IN/OUT token in the opposite direction to end transfer */
238 257
 retry:
239  
-	make_usb_token(out ? 0x69 : 0xe1, addr, usb_buffer);
  258
+	make_usb_token(out ? USB_PID_IN : USB_PID_OUT, addr, usb_buffer);
240 259
 	usb_tx(usb_buffer, 3);
241 260
 	if(out) {
242 261
 		/* get DATAx packet */
243 262
 		rxlen = usb_rx(usb_buffer, 11);
244  
-		if((rxlen != 3) || ((usb_buffer[0] != 0xc3) && (usb_buffer[0] != 0x4b))) {
245  
-			if((rxlen > 0) && (usb_buffer[0] == 0x5a))
  263
+		if((rxlen != 3) || ((usb_buffer[0] != USB_PID_DATA0) &&
  264
+		    (usb_buffer[0] != USB_PID_DATA1))) {
  265
+			if((rxlen > 0) && (usb_buffer[0] == USB_PID_NAK))
246 266
 				goto retry; /* NAK: retry */
247 267
 			print_string(control_failed);
248 268
 			print_string(termination);
@@ -251,7 +271,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
251 271
 			return -1;
252 272
 		}
253 273
 		/* send ACK token */
254  
-		usb_buffer[0] = 0xd2;
  274
+		usb_buffer[0] = USB_PID_ACK;
255 275
 		usb_tx(usb_buffer, 1);
256 276
 	} else {
257 277
 		/* send DATAx packet */
@@ -260,8 +280,8 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
260 280
 		usb_tx(usb_buffer, 3);
261 281
 		/* get ACK token from device */
262 282
 		rxlen = usb_rx(usb_buffer, 11);
263  
-		if((rxlen != 1) || (usb_buffer[0] != 0xd2)) {
264  
-			if((rxlen > 0) && (usb_buffer[0] == 0x5a))
  283
+		if((rxlen != 1) || (usb_buffer[0] != USB_PID_ACK)) {
  284
+			if((rxlen > 0) && (usb_buffer[0] == USB_PID_NAK))
265 285
 				goto retry; /* NAK: retry */
266 286
 			print_string(control_failed);
267 287
 			print_string(termination);
@@ -275,7 +295,7 @@ static char control_transfer(unsigned char addr, struct setup_packet *p, char ou
275 295
 }
276 296
 
277 297
 static const char datax_mismatch[] PROGMEM = "DATAx mismatch\n";
278  
-static void poll(struct port_status *p)
  298
+static void poll(struct ep_status *ep, char keyboard)
279 299
 {
280 300
 	unsigned char usb_buffer[11];
281 301
 	unsigned char len;
@@ -283,43 +303,60 @@ static void poll(struct port_status *p)
283 303
 	char i;
284 304
 
285 305
 	/* IN */
286  
-	make_usb_token(0x69, 0x081, usb_buffer);
  306
+	make_usb_token(USB_PID_IN, ADDR_EP(1, ep->ep), usb_buffer);
287 307
 	usb_tx(usb_buffer, 3);
288 308
 	/* DATAx */
289 309
 	len = usb_rx(usb_buffer, 11);
290  
-	if(len < 7)
  310
+	if(len < 6)
291 311
 		return;
292  
-	if(usb_buffer[0] != p->expected_data) {
293  
-		if((usb_buffer[0] == 0xc3) || (usb_buffer[0] == 0x4b)) {
  312
+	if(usb_buffer[0] != ep->expected_data) {
  313
+		if((usb_buffer[0] == USB_PID_DATA0) ||
  314
+		    (usb_buffer[0] == USB_PID_DATA1)) {
294 315
 			/* ACK */
295  
-			usb_buffer[0] = 0xd2;
  316
+			usb_buffer[0] = USB_PID_ACK;
296 317
 			usb_tx(usb_buffer, 1);
297 318
 			print_string(datax_mismatch);
298 319
 		}
299 320
 		return; /* drop */
300 321
 	}
301 322
 	/* ACK */
302  
-	usb_buffer[0] = 0xd2;
  323
+	usb_buffer[0] = USB_PID_ACK;
303 324
 	usb_tx(usb_buffer, 1);
304  
-	if(p->expected_data == 0xc3)
305  
-		p->expected_data = 0x4b;
  325
+	if(ep->expected_data == USB_PID_DATA0)
  326
+		ep->expected_data = USB_PID_DATA1;
306 327
 	else
307  
-		p->expected_data = 0xc3;
  328
+		ep->expected_data = USB_PID_DATA0;
308 329
 	/* send to host */
309  
-	if(p->keyboard) {
310  
-		if(len >= 9) {
311  
-			m = COMLOC_KEVT_PRODUCE;
312  
-			for(i=0;i<8;i++)
313  
-				COMLOC_KEVT(8*m+i) = usb_buffer[i+1];
314  
-			COMLOC_KEVT_PRODUCE = (m + 1) & 0x07;
315  
-		}
  330
+	if(keyboard) {
  331
+		if(len < 9)
  332
+			return;
  333
+		m = COMLOC_KEVT_PRODUCE;
  334
+		for(i=0;i<8;i++)
  335
+			COMLOC_KEVT(8*m+i) = usb_buffer[i+1];
  336
+		COMLOC_KEVT_PRODUCE = (m + 1) & 0x07;
316 337
 	} else {
317  
-		if(len >= 7) {
318  
-			m = COMLOC_MEVT_PRODUCE;
319  
-			for(i=0;i<4;i++)
320  
-				COMLOC_MEVT(4*m+i) = usb_buffer[i+1];
321  
-			COMLOC_MEVT_PRODUCE = (m + 1) & 0x0f;
  338
+		if(len < 6)
  339
+			return;
  340
+		/*
  341
+		 * HACK: The Rii RF mini-keyboard sends ten byte messages with
  342
+		 * a report ID and 16 bit coordinates. We're too lazy to parse
  343
+		 * report descriptors, so we just hard-code that report layout.
  344
+		 */
  345
+		if(len == 10) {
  346
+			usb_buffer[1] = usb_buffer[2];	/* buttons */
  347
+			usb_buffer[2] = usb_buffer[3];	/* X LSB */
  348
+			usb_buffer[3] = usb_buffer[5];	/* Y LSB */
322 349
 		}
  350
+		if(len > 7)
  351
+			len = 7;
  352
+		m = COMLOC_MEVT_PRODUCE;
  353
+		for(i=0;i<len-3;i++)
  354
+			COMLOC_MEVT(4*m+i) = usb_buffer[i+1];
  355
+		while(i < 4) {
  356
+			COMLOC_MEVT(4*m+i) = 0;
  357
+			i++;
  358
+		}
  359
+		COMLOC_MEVT_PRODUCE = (m + 1) & 0x0f;
323 360
 	}
324 361
 	/* trigger host IRQ */
325 362
 	wio8(HOST_IRQ, 1);
@@ -343,8 +380,10 @@ static void check_discon(struct port_status *p, char name)
343 380
 	}
344 381
 }
345 382
 
346  
-static char validate_configuration_descriptor(unsigned char *descriptor, char len, char *keyboard)
  383
+static char validate_configuration_descriptor(unsigned char *descriptor,
  384
+    char len, struct port_status *p)
347 385
 {
  386
+	struct ep_status *ep = NULL;
348 387
 	char offset;
349 388
 
350 389
 	offset = 0;
@@ -353,24 +392,30 @@ static char validate_configuration_descriptor(unsigned char *descriptor, char le
353 392
 			/* got an interface descriptor */
354 393
 			/* check for bInterfaceClass=3 and bInterfaceSubClass=1 (HID) */
355 394
 			if((descriptor[offset+5] != 0x03) || (descriptor[offset+6] != 0x01))
356  
-				return 0;
  395
+				break;
357 396
 			/* check bInterfaceProtocol */
358 397
 			switch(descriptor[offset+7]) {
359 398
 				case 0x01:
360  
-					*keyboard = 1;
361  
-					return 1;
  399
+					ep = &p->keyboard;
  400
+					break;
362 401
 				case 0x02:
363  
-					*keyboard = 0;
364  
-					return 1;
  402
+					ep = &p->mouse;
  403
+					break;
365 404
 				default:
366 405
 					/* unknown protocol, fail */
367  
-					return 0;
  406
+					ep = NULL;
  407
+					break;
368 408
 			}
  409
+		} else if(descriptor[offset+1] == 0x05 &&
  410
+		    (descriptor[offset+2] & 0x80) && ep) {
  411
+				ep->ep = descriptor[offset+2] & 0x7f;
  412
+				ep->expected_data = USB_PID_DATA0;
  413
+				    /* start with DATA0 */
  414
+				ep = NULL;
369 415
 		}
370 416
 		offset += descriptor[offset+0];
371 417
 	}
372  
-	/* no interface descriptor found, fail */
373  
-	return 0;
  418
+	return p->keyboard.ep || p->mouse.ep;
374 419
 }
375 420
 
376 421
 static const char retry_exceed[] PROGMEM = "Retry count exceeded, disabling device.\n";
@@ -406,12 +451,12 @@ static void port_service(struct port_status *p, char name)
406 451
 				linestat = rio8(SIE_LINE_STATUS_B);
407 452
 			if(linestat == 0x01) {
408 453
 				print_string(connect_fs); print_char(name); print_char('\n');
409  
-				p->fs = 1;
  454
+				p->full_speed = 1;
410 455
 				p->state = PORT_STATE_UNSUPPORTED;
411 456
 			}
412 457
 			if(linestat == 0x02) {
413 458
 				print_string(connect_ls); print_char(name); print_char('\n');
414  
-				p->fs = 0;
  459
+				p->full_speed = 0;
415 460
 				if(name == 'A')
416 461
 					wio8(SIE_TX_BUSRESET, rio8(SIE_TX_BUSRESET) | 0x01);
417 462
 				else
@@ -506,15 +551,19 @@ static void port_service(struct port_status *p, char name)
506 551
 			len = control_transfer(0x01, &packet, 0, configuration_descriptor, 127);
507 552
 			if(len >= 0) {
508 553
 				p->retry_count = 0;
509  
-				if(!validate_configuration_descriptor(configuration_descriptor, len, &p->keyboard)) {
  554
+				if(!validate_configuration_descriptor(
  555
+				    configuration_descriptor, len, p)) {
510 556
 					print_string(found); print_string(unsupported_device);
511 557
 					p->state = PORT_STATE_UNSUPPORTED;
512 558
 				} else {
513  
-					print_string(found);
514  
-					if(p->keyboard)
  559
+					if(p->keyboard.ep) {
  560
+						print_string(found);
515 561
 						print_string(keyboard);
516  
-					else
  562
+					}
  563
+					if(p->mouse.ep) {
  564
+						print_string(found);
517 565
 						print_string(mouse);
  566
+					}
518 567
 					p->state = PORT_STATE_SET_CONFIGURATION;
519 568
 				}
520 569
 			}
@@ -535,14 +584,16 @@ static void port_service(struct port_status *p, char name)
535 584
 
536 585
 			if(control_transfer(0x01, &packet, 1, NULL, 0) == 0) {
537 586
 				p->retry_count = 0;
538  
-				p->expected_data = 0xc3; /* start with DATA0 */
539 587
 				p->state = PORT_STATE_RUNNING;
540 588
 			}
541 589
 			check_retry(p);
542 590
 			break;
543 591
 		}
544 592
 		case PORT_STATE_RUNNING:
545  
-			poll(p);
  593
+			if(p->keyboard.ep)
  594
+				poll(&p->keyboard, 1);
  595
+			if(p->mouse.ep)
  596
+				poll(&p->mouse, 0);
546 597
 			break;
547 598
 		case PORT_STATE_UNSUPPORTED:
548 599
 			break;

No commit comments for this range

Something went wrong with that request. Please try again.