Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
  • 9 commits
  • 2 files changed
  • 0 comments
  • 1 contributor
Nov 30, 2011
Werner Almesberger softusb: use symbolic names for various USB constants 4923a9d
Werner Almesberger softusb: move protocol identification (interface descriptor) to separ…
…ate function
4d9920b
Werner Almesberger softusb: remove trailing whitespace
Some lines had trailing tabs. Those can sometimes trip patch.
dae5ff5
Werner Almesberger softusb: minimize time between SETUP/OUT and DATAx
By not waiting until the transmitter is idle, we can reduce the
time between the end of the SE0 indicating EOP of SETUP or OUT
and the first transition of the following DATAx to a mere two
bit times (as oppose to ~6 bit times before).

While I haven't been able to find anything in the USB standard
that would require such tight timing, AVR USB chips (i.e., the
ATmega32U2 of atusb and the AT90USB162 of the Faderfox LV3)
flat out ignore any transfers with longer delays.
6ca46c2
Werner Almesberger softusb: clean up device reporting
Moved reporting of the device(s) detected out of port_service, making
it a bit less cluttered and providing a more comfortable basis for
future additions.
b553999
Werner Almesberger softusb: added detection of MIDI devices (WIP) 0294551
Werner Almesberger softusb: move protocol-specfic data processing to separate functions
This will prevent "poll" from getting too cluttered when MIDI is added.
98be89d
Werner Almesberger softusb: protect macro arguments in comloc.h
This change is purely cosmetic.
b452f54
Werner Almesberger softusb: poll MIDI EPs and pass control changes to the LM32
Adding other events should be easy, but one step at a time.
9e05e46
8  softusb-input/comloc.h
@@ -22,10 +22,12 @@
22 22
 #define COMLOCV(x)	(*(volatile unsigned char *)(x))
23 23
 
24 24
 #define COMLOC_DEBUG_PRODUCE	COMLOC(0x1000)
25  
-#define COMLOC_DEBUG(offset)	COMLOC(0x1001+offset)
  25
+#define COMLOC_DEBUG(offset)	COMLOC(0x1001+(offset))
26 26
 #define COMLOC_MEVT_PRODUCE	COMLOC(0x1101)
27  
-#define COMLOC_MEVT(offset)	COMLOC(0x1102+offset)
  27
+#define COMLOC_MEVT(offset)	COMLOC(0x1102+(offset))
28 28
 #define COMLOC_KEVT_PRODUCE	COMLOC(0x1142)
29  
-#define COMLOC_KEVT(offset)	COMLOC(0x1143+offset)
  29
+#define COMLOC_KEVT(offset)	COMLOC(0x1143+(offset))
  30
+#define COMLOC_MIDI_PRODUCE	COMLOC(0x1183)
  31
+#define COMLOC_MIDI(offset)	COMLOC(0x1184+(offset))
30 32
 
31 33
 #endif /* __COMLOC_H */
266  softusb-input/main.c
@@ -53,6 +53,31 @@ enum {
53 53
 };
54 54
 
55 55
 enum {
  56
+	USB_DT_DEVICE		= 1,
  57
+	USB_DT_CONFIG		= 2,
  58
+	USB_DT_INTERFACE	= 4,
  59
+	USB_DT_ENDPOINT		= 5,
  60
+};
  61
+
  62
+enum {
  63
+	USB_CLASS_AUDIO		= 1,
  64
+	USB_CLASS_HID		= 3,
  65
+};
  66
+
  67
+enum {
  68
+	USB_SUBCLASS_BOOT	= 1,	/* HID */
  69
+};
  70
+
  71
+enum {
  72
+	USB_SUBCLASS_MIDISTREAMING = 3,	/* AUDIO */
  73
+};
  74
+
  75
+enum {
  76
+	USB_PROTO_KEYBOARD	= 1,	/* HID */
  77
+	USB_PROTO_MOUSE		= 2,
  78
+};
  79
+
  80
+enum {
56 81
 	PORT_STATE_DISCONNECTED = 0,
57 82
 	PORT_STATE_BUS_RESET,
58 83
 	PORT_STATE_RESET_WAIT,
@@ -80,6 +105,7 @@ struct port_status {
80 105
 	unsigned char ep0_size;
81 106
 	struct ep_status keyboard;
82 107
 	struct ep_status mouse;
  108
+	struct ep_status midi;
83 109
 };
84 110
 
85 111
 static struct port_status port_a;
@@ -99,7 +125,7 @@ static void make_usb_token(unsigned char pid, unsigned int elevenbits, unsigned
99 125
 	out[2] |= usb_crc5(out[1], out[2]) << 3;
100 126
 }
101 127
 
102  
-static void usb_tx(const unsigned char *buf, unsigned char len)
  128
+static void usb_tx_nowait(const unsigned char *buf, unsigned char len)
103 129
 {
104 130
 	unsigned char i;
105 131
 
@@ -110,9 +136,15 @@ static void usb_tx(const unsigned char *buf, unsigned char len)
110 136
 	}
111 137
 	while(rio8(SIE_TX_PENDING));
112 138
 	wio8(SIE_TX_VALID, 0);
  139
+}
  140
+
  141
+static void usb_tx(const unsigned char *buf, unsigned char len)
  142
+{
  143
+	usb_tx_nowait(buf, len);
113 144
 	while(rio8(SIE_TX_BUSY));
114 145
 }
115 146
 
  147
+
116 148
 static inline void usb_ack(void)
117 149
 {
118 150
 	wio8(SIE_TX_DATA, 0x80); /* send SYNC */
@@ -282,7 +314,7 @@ static char usb_out(unsigned addr, const unsigned char *buf, unsigned char len)
282 314
 
283 315
 	/* send OUT */
284 316
 	make_usb_token(USB_PID_OUT, addr, out);
285  
-	usb_tx(out, 3);
  317
+	usb_tx_nowait(out, 3);
286 318
 
287 319
 	/* send DATAx */
288 320
 	usb_tx(buf, len);
@@ -326,7 +358,7 @@ static int control_transfer(unsigned char addr, struct setup_packet *p,
326 358
 	TRIGGER_ON();
327 359
 
328 360
 	/* send them back-to-back */
329  
-	usb_tx(setup, 3);
  361
+	usb_tx_nowait(setup, 3);
330 362
 	usb_tx(usb_buffer, 11);
331 363
 
332 364
 	TRIGGER_OFF();
@@ -407,52 +439,79 @@ static int control_transfer(unsigned char addr, struct setup_packet *p,
407 439
 	return transferred;
408 440
 }
409 441
 
410  
-static void poll(struct ep_status *ep, char keyboard)
  442
+static char process_keyboard(unsigned char *buf, unsigned char len)
  443
+{
  444
+	unsigned char m, i;
  445
+
  446
+	if(len < 6)
  447
+		return 0;
  448
+	m = COMLOC_KEVT_PRODUCE;
  449
+	for(i = 0; i < 8; i++)
  450
+		COMLOC_KEVT(8*m+i) = buf[i];
  451
+	COMLOC_KEVT_PRODUCE = (m + 1) & 0x07;
  452
+	return 1;
  453
+}
  454
+
  455
+static char process_mouse(unsigned char *buf, unsigned char len)
  456
+{
  457
+	unsigned char m, i;
  458
+
  459
+	if(len < 3)
  460
+		return 0;
  461
+	/*
  462
+	 * HACK: The Rii RF mini-keyboard sends ten byte messages with
  463
+	 * a report ID and 16 bit coordinates. We're too lazy to parse
  464
+	 * report descriptors, so we just hard-code that report layout.
  465
+	 */
  466
+	if(len == 7) {
  467
+		buf[0] = buf[1];	/* buttons */
  468
+		buf[1] = buf[2];	/* X LSB */
  469
+		buf[2] = buf[4];	/* Y LSB */
  470
+	}
  471
+	if(len > 4)
  472
+		len = 4;
  473
+	m = COMLOC_MEVT_PRODUCE;
  474
+	for(i = 0; i < len; i++)
  475
+		COMLOC_MEVT(4*m+i) = buf[i];
  476
+	while(i < 4) {
  477
+		COMLOC_MEVT(4*m+i) = 0;
  478
+		i++;
  479
+	}
  480
+	COMLOC_MEVT_PRODUCE = (m + 1) & 0x0f;
  481
+	return 1;
  482
+}
  483
+
  484
+static char process_midi(unsigned char *buf, unsigned char len)
  485
+{
  486
+	unsigned char end = len & ~3;
  487
+	unsigned char i, m, j;
  488
+
  489
+	for(i = 0; i != end; i += 4) {
  490
+		if((buf[i] & 0xf) != 0xb) /* not a control change */
  491
+			continue;
  492
+		m = COMLOC_MIDI_PRODUCE;
  493
+		for(j = 0; j != 4; j++)
  494
+			COMLOC_MIDI(4*m+j) = buf[i+j];
  495
+		COMLOC_MIDI_PRODUCE = (m + 1) & 15;
  496
+	}
  497
+	return 0;
  498
+}
  499
+
  500
+static void poll(struct ep_status *ep,
  501
+    char (*process)(unsigned char *buf, unsigned char len))
411 502
 {
412  
-	unsigned char usb_buffer[11];
  503
+	unsigned char usb_buffer[1+64+2]; /* DATAx + payload + CRC */
413 504
 	int len;
414  
-	unsigned char m;
415  
-	char i;
416 505
 
417 506
 	len = usb_in(ADDR_EP(ADDR, ep->ep), ep->expected_data, usb_buffer, 11);
418 507
 	if(len <= 0)
419 508
 		return;
420 509
 	ep->expected_data = toggle(ep->expected_data);
421 510
 
422  
-	/* send to host */
423  
-	if(keyboard) {
424  
-		if(len < 9)
425  
-			return;
426  
-		m = COMLOC_KEVT_PRODUCE;
427  
-		for(i=0;i<8;i++)
428  
-			COMLOC_KEVT(8*m+i) = usb_buffer[i+1];
429  
-		COMLOC_KEVT_PRODUCE = (m + 1) & 0x07;
430  
-	} else {
431  
-		if(len < 6)
432  
-			return;
433  
-		/*
434  
-		 * HACK: The Rii RF mini-keyboard sends ten byte messages with
435  
-		 * a report ID and 16 bit coordinates. We're too lazy to parse
436  
-		 * report descriptors, so we just hard-code that report layout.
437  
-		 */
438  
-		if(len == 10) {
439  
-			usb_buffer[1] = usb_buffer[2];	/* buttons */
440  
-			usb_buffer[2] = usb_buffer[3];	/* X LSB */
441  
-			usb_buffer[3] = usb_buffer[5];	/* Y LSB */
442  
-		}
443  
-		if(len > 7)
444  
-			len = 7;
445  
-		m = COMLOC_MEVT_PRODUCE;
446  
-		for(i=0;i<len-3;i++)
447  
-			COMLOC_MEVT(4*m+i) = usb_buffer[i+1];
448  
-		while(i < 4) {
449  
-			COMLOC_MEVT(4*m+i) = 0;
450  
-			i++;
451  
-		}
452  
-		COMLOC_MEVT_PRODUCE = (m + 1) & 0x0f;
453  
-	}
454  
-	/* trigger host IRQ */
455  
-	wio8(HOST_IRQ, 1);
  511
+	if(len <= 3)
  512
+		return;
  513
+	if(process(usb_buffer+1, len-3))	/* send to host */
  514
+		wio8(HOST_IRQ, 1);		/* trigger host IRQ */
456 515
 }
457 516
 
458 517
 static const char connect_fs[] PROGMEM = "Full speed device on port ";
@@ -470,11 +529,37 @@ static void check_discon(struct port_status *p, char name)
470 529
 	if(discon) {
471 530
 		print_string(disconnect); print_char(name); print_char('\n');
472 531
 		p->state = PORT_STATE_DISCONNECTED;
473  
-		p->keyboard.ep = p->mouse.ep = 0;
  532
+		p->keyboard.ep = p->mouse.ep = p->midi.ep = 0;
474 533
 	}
475 534
 }
476 535
 
477  
-static char validate_configuration_descriptor(unsigned char *descriptor,
  536
+static struct ep_status *identify_protocol(const unsigned char *itf,
  537
+    struct port_status *p)
  538
+{
  539
+	/* check for bInterfaceClass=3 and bInterfaceSubClass=1 (HID) */
  540
+	if (itf[5] == USB_CLASS_HID && itf[6] == USB_SUBCLASS_BOOT)
  541
+		switch(itf[7]) { /* check bInterfaceProtocol */
  542
+			case USB_PROTO_KEYBOARD:
  543
+				return &p->keyboard;
  544
+			case USB_PROTO_MOUSE:
  545
+				return &p->mouse;
  546
+			default:
  547
+				/* unknown protocol, fail */
  548
+				return NULL;
  549
+		}
  550
+	if (itf[5] == USB_CLASS_AUDIO && itf[6] == USB_SUBCLASS_MIDISTREAMING)
  551
+		return &p->midi;
  552
+
  553
+	return NULL;
  554
+}
  555
+
  556
+static const char found[] PROGMEM = "Found ";
  557
+static const char unsupported_device[] PROGMEM = "unsupported device\n";
  558
+static const char mouse[] PROGMEM = "mouse\n";
  559
+static const char keyboard[] PROGMEM = "keyboard\n";
  560
+static const char midi[] PROGMEM = "MIDI\n";
  561
+
  562
+static char validate_configuration_descriptor(const unsigned char *descriptor,
478 563
     char len, struct port_status *p)
479 564
 {
480 565
 	struct ep_status *ep = NULL;
@@ -482,25 +567,9 @@ static char validate_configuration_descriptor(unsigned char *descriptor,
482 567
 
483 568
 	offset = 0;
484 569
 	while(offset < len) {
485  
-		if(descriptor[offset+1] == 0x04) {
486  
-			/* got an interface descriptor */
487  
-			/* check for bInterfaceClass=3 and bInterfaceSubClass=1 (HID) */
488  
-			if((descriptor[offset+5] != 0x03) || (descriptor[offset+6] != 0x01))
489  
-				break;
490  
-			/* check bInterfaceProtocol */
491  
-			switch(descriptor[offset+7]) {
492  
-				case 0x01:
493  
-					ep = &p->keyboard;
494  
-					break;
495  
-				case 0x02:
496  
-					ep = &p->mouse;
497  
-					break;
498  
-				default:
499  
-					/* unknown protocol, fail */
500  
-					ep = NULL;
501  
-					break;
502  
-			}
503  
-		} else if(descriptor[offset+1] == 0x05 &&
  570
+		if(descriptor[offset+1] == USB_DT_INTERFACE) {
  571
+			ep = identify_protocol(descriptor+offset, p);
  572
+		} else if(descriptor[offset+1] == USB_DT_ENDPOINT &&
504 573
 		    (descriptor[offset+2] & 0x80) && ep) {
505 574
 				ep->ep = descriptor[offset+2] & 0x7f;
506 575
 				ep->expected_data = USB_PID_DATA0;
@@ -509,7 +578,26 @@ static char validate_configuration_descriptor(unsigned char *descriptor,
509 578
 		}
510 579
 		offset += descriptor[offset+0];
511 580
 	}
512  
-	return p->keyboard.ep || p->mouse.ep;
  581
+	if(p->keyboard.ep) {
  582
+		print_string(found);
  583
+		print_string(keyboard);
  584
+	}
  585
+	if(p->mouse.ep) {
  586
+		print_string(found);
  587
+		print_string(mouse);
  588
+	}
  589
+	if(p->midi.ep) {
  590
+		print_string(found);
  591
+		print_string(midi);
  592
+	}
  593
+	return p->keyboard.ep || p->mouse.ep || p->midi.ep;
  594
+}
  595
+
  596
+static void unsupported(struct port_status *p)
  597
+{
  598
+	print_string(found);
  599
+	print_string(unsupported_device);
  600
+	p->state = PORT_STATE_UNSUPPORTED;
513 601
 }
514 602
 
515 603
 static const char retry_exceed[] PROGMEM = "Retry count exceeded, disabling device.\n";
@@ -524,20 +612,15 @@ static void check_retry(struct port_status *p)
524 612
 static const char vid[] PROGMEM = "VID: ";
525 613
 static const char pid[] PROGMEM = ", PID: ";
526 614
 
527  
-static const char found[] PROGMEM = "Found ";
528  
-static const char unsupported_device[] PROGMEM = "unsupported device\n";
529  
-static const char mouse[] PROGMEM = "mouse\n";
530  
-static const char keyboard[] PROGMEM = "keyboard\n";
531  
-
532 615
 static int get_device_descriptor(unsigned char *buf, int size,
533 616
     unsigned char ep0_size)
534 617
 {
535 618
 	struct setup_packet packet;
536  
-			
  619
+
537 620
 	packet.bmRequestType = 0x80;
538 621
 	packet.bRequest = 0x06;
539 622
 	packet.wValue[0] = 0x00;
540  
-	packet.wValue[1] = 0x01;
  623
+	packet.wValue[1] = USB_DT_DEVICE;
541 624
 	packet.wIndex[0] = 0x00;
542 625
 	packet.wIndex[1] = 0x00;
543 626
 	packet.wLength[0] = size;
@@ -646,7 +729,7 @@ static void port_service(struct port_status *p, char name)
646 729
 			break;
647 730
 		case PORT_STATE_GET_DEVICE_DESCRIPTOR: {
648 731
 			unsigned char device_descriptor[18];
649  
-			
  732
+
650 733
 			if(get_device_descriptor(device_descriptor, 18,
651 734
 			    p->ep0_size) >= 0) {
652 735
 				p->retry_count = 0;
@@ -660,10 +743,9 @@ static void port_service(struct port_status *p, char name)
660 743
 				/* check for bDeviceClass=0 and bDeviceSubClass=0.
661 744
 				 * HID devices have those.
662 745
 				 */
663  
-				if((device_descriptor[4] != 0) || (device_descriptor[5] != 0)) {
664  
-					print_string(found); print_string(unsupported_device);
665  
-					p->state = PORT_STATE_UNSUPPORTED;
666  
-				} else
  746
+				if((device_descriptor[4] != 0) || (device_descriptor[5] != 0))
  747
+					unsupported(p);
  748
+				else
667 749
 					p->state = PORT_STATE_GET_CONFIGURATION_DESCRIPTOR;
668 750
 			}
669 751
 			check_retry(p);
@@ -677,7 +759,7 @@ static void port_service(struct port_status *p, char name)
677 759
 			packet.bmRequestType = 0x80;
678 760
 			packet.bRequest = 0x06;
679 761
 			packet.wValue[0] = 0x00;
680  
-			packet.wValue[1] = 0x02;
  762
+			packet.wValue[1] = USB_DT_CONFIG;
681 763
 			packet.wIndex[0] = 0x00;
682 764
 			packet.wIndex[1] = 0x00;
683 765
 			packet.wLength[0] = 127;
@@ -688,20 +770,10 @@ static void port_service(struct port_status *p, char name)
688 770
 			if(len >= 0) {
689 771
 				p->retry_count = 0;
690 772
 				if(!validate_configuration_descriptor(
691  
-				    configuration_descriptor, len, p)) {
692  
-					print_string(found); print_string(unsupported_device);
693  
-					p->state = PORT_STATE_UNSUPPORTED;
694  
-				} else {
695  
-					if(p->keyboard.ep) {
696  
-						print_string(found);
697  
-						print_string(keyboard);
698  
-					}
699  
-					if(p->mouse.ep) {
700  
-						print_string(found);
701  
-						print_string(mouse);
702  
-					}
  773
+				    configuration_descriptor, len, p))
  774
+					unsupported(p);
  775
+				else
703 776
 					p->state = PORT_STATE_SET_CONFIGURATION;
704  
-				}
705 777
 			}
706 778
 			check_retry(p);
707 779
 			break;
@@ -728,9 +800,11 @@ static void port_service(struct port_status *p, char name)
728 800
 		}
729 801
 		case PORT_STATE_RUNNING:
730 802
 			if(p->keyboard.ep)
731  
-				poll(&p->keyboard, 1);
  803
+				poll(&p->keyboard, process_keyboard);
732 804
 			if(p->mouse.ep)
733  
-				poll(&p->mouse, 0);
  805
+				poll(&p->mouse, process_mouse);
  806
+			if(p->midi.ep)
  807
+				poll(&p->midi, process_midi);
734 808
 			break;
735 809
 		case PORT_STATE_UNSUPPORTED:
736 810
 			break;
@@ -744,7 +818,7 @@ static void sof()
744 818
 {
745 819
 	unsigned char mask;
746 820
 	unsigned char usb_buffer[3];
747  
-	
  821
+
748 822
 	mask = 0;
749 823
 #ifndef TRIGGER
750 824
 	if(port_a.full_speed && (port_a.state > PORT_STATE_BUS_RESET))
@@ -763,7 +837,7 @@ static void sof()
763 837
 static void keepalive()
764 838
 {
765 839
 	unsigned char mask;
766  
-	
  840
+
767 841
 	mask = 0;
768 842
 #ifndef TRIGGER
769 843
 	if(!port_a.full_speed && (port_a.state == PORT_STATE_RESET_WAIT))
@@ -782,7 +856,7 @@ static void keepalive()
782 856
 static void set_rx_speed()
783 857
 {
784 858
 	unsigned char mask;
785  
-	
  859
+
786 860
 	mask = 0;
787 861
 	if(!port_a.full_speed) mask |= 0x01;
788 862
 	if(!port_b.full_speed) mask |= 0x02;
@@ -811,7 +885,7 @@ int main()
811 885
 		 */
812 886
 		for(i=0;i<128;i++)
813 887
 			asm("nop");
814  
-		
  888
+
815 889
 #ifndef TRIGGER
816 890
 		wio8(SIE_SEL_RX, 0);
817 891
 		wio8(SIE_SEL_TX, 0x01);
@@ -821,7 +895,7 @@ int main()
821 895
 		wio8(SIE_SEL_RX, 1);
822 896
 		wio8(SIE_SEL_TX, 0x02);
823 897
 		port_service(&port_b, 'B');
824  
-		
  898
+
825 899
 		/* set RX speed for new detected devices */
826 900
 		set_rx_speed();
827 901
 

No commit comments for this range

Something went wrong with that request. Please try again.