Browse Source

Plan 9 from Bell Labs 2004-07-31

David du Colombier 19 years ago
parent
commit
2df216c076
39 changed files with 2813 additions and 3496 deletions
  1. 35 44
      dist/replica/_plan9.db
  2. 27 32
      dist/replica/plan9.db
  3. 43 0
      dist/replica/plan9.log
  4. 1 0
      lib/ndb/common
  5. 0 253
      sys/src/cmd/usb/audio/audioclass.h
  6. 44 70
      sys/src/cmd/usb/audio/audiofs.c
  7. 234 0
      sys/src/cmd/usb/audio/audiosub.c
  8. 0 334
      sys/src/cmd/usb/audio/config.c
  9. 0 660
      sys/src/cmd/usb/audio/controls.c
  10. 0 183
      sys/src/cmd/usb/audio/dat.h
  11. 0 260
      sys/src/cmd/usb/audio/dump.c
  12. 0 19
      sys/src/cmd/usb/audio/fns.h
  13. 0 429
      sys/src/cmd/usb/audio/main.c
  14. 11 14
      sys/src/cmd/usb/audio/mkfile
  15. 397 0
      sys/src/cmd/usb/audio/usbaudio.c
  16. 72 0
      sys/src/cmd/usb/audio/usbaudio.h
  17. 660 0
      sys/src/cmd/usb/audio/usbaudioctl.c
  18. 29 0
      sys/src/cmd/usb/audio/usbaudioctl.h
  19. 0 288
      sys/src/cmd/usb/lib/config.c
  20. 84 17
      sys/src/cmd/usb/lib/device.c
  21. 497 73
      sys/src/cmd/usb/lib/dump.c
  22. 6 3
      sys/src/cmd/usb/lib/mkfile
  23. 81 50
      sys/src/cmd/usb/lib/setup.c
  24. 327 102
      sys/src/cmd/usb/lib/usb.h
  25. 0 153
      sys/src/cmd/usb/lib/usbproto.h
  26. 18 5
      sys/src/cmd/usb/lib/util.c
  27. 8 1
      sys/src/cmd/usb/misc/mkfile
  28. 12 0
      sys/src/cmd/usb/misc/usbprint
  29. 14 4
      sys/src/cmd/usb/mkfile
  30. 0 179
      sys/src/cmd/usb/mouse/usbmouse.c
  31. 0 12
      sys/src/cmd/usb/printer/mkfile
  32. 0 13
      sys/src/cmd/usb/printer/usbprinter
  33. 1 1
      sys/src/cmd/usb/usbd/dat.h
  34. 0 131
      sys/src/cmd/usb/usbd/device.c
  35. 5 6
      sys/src/cmd/usb/usbd/fns.h
  36. 39 33
      sys/src/cmd/usb/usbd/hub.c
  37. 7 2
      sys/src/cmd/usb/usbd/mkfile
  38. 56 0
      sys/src/cmd/usb/usbd/setup.c
  39. 105 125
      sys/src/cmd/usb/usbd/usbd.c

+ 35 - 44
dist/replica/_plan9.db

@@ -1,15 +1,15 @@
 386 - 20000000775 sys sys 1010957353 0
 386/9load - 775 sys sys 1088798345 188040
-386/9loaddebug - 775 sys sys 1089402462 270242
+386/9loaddebug - 775 sys sys 1091156989 270242
 386/9loadlite - 775 sys sys 1088798346 125004
 386/9loadlitedebug - 775 sys sys 1089402462 183654
-386/9pc - 775 sys sys 1090688306 1808618
+386/9pc - 775 sys sys 1091156992 1808630
 386/9pc.gz - 664 sys sys 1077049336 635727
-386/9pccpu - 775 sys sys 1089402468 1464770
+386/9pccpu - 775 sys sys 1091156995 1464782
 386/9pccpu.gz - 664 sys sys 1077049387 519909
-386/9pcdisk - 775 sys sys 1090688310 2011224
+386/9pcdisk - 775 sys sys 1091156999 2011236
 386/9pcdisk.gz - 664 sys sys 1040006345 703136
-386/9pcf - 775 sys sys 1090688315 2342867
+386/9pcf - 775 sys sys 1091157003 2342879
 386/9pcf.gz - 664 sys sys 1077049490 872650
 386/9pxeload - 775 sys sys 1088798346 188040
 386/_9pcdisk.gz - 664 sys sys 1039764191 695837
@@ -249,7 +249,7 @@
 386/bin/gview - 775 sys sys 1087873351 235313
 386/bin/gzip - 775 sys sys 1085077061 82899
 386/bin/hayes - 775 sys sys 1085077062 62579
-386/bin/hget - 775 sys sys 1089257531 224015
+386/bin/hget - 775 sys sys 1091156987 230376
 386/bin/history - 775 sys sys 1085077062 72883
 386/bin/hoc - 775 sys sys 1085077062 97889
 386/bin/html2ms - 775 sys sys 1085077063 64059
@@ -445,7 +445,7 @@
 386/bin/upas/scanmail - 775 sys sys 1085077115 126758
 386/bin/upas/send - 775 sys sys 1085077116 189534
 386/bin/upas/smtp - 775 sys sys 1085077116 271187
-386/bin/upas/smtpd - 775 sys sys 1089257540 324203
+386/bin/upas/smtpd - 775 sys sys 1091156988 324025
 386/bin/upas/spam - 775 sys sys 1064598366 36
 386/bin/upas/testscan - 775 sys sys 1085077117 81626
 386/bin/upas/token - 775 sys sys 1085077117 75518
@@ -2764,7 +2764,7 @@ lib/namespace.ftp - 664 sys sys 1020313578 373
 lib/namespace.httpd - 664 sys sys 984695868 1209
 lib/ndb - 20000000775 sys sys 959260770 0
 lib/ndb/auth - 664 sys sys 959260674 586
-lib/ndb/common - 664 sys sys 1065569740 5261
+lib/ndb/common - 664 sys sys 1091203571 5285
 lib/ndb/consoledb - 664 sys sys 960222421 95
 lib/ndb/dhcp - 20000000775 sys sys 959260749 0
 lib/ndb/dnsdump - 664 sys sys 1032057649 61
@@ -10889,39 +10889,34 @@ sys/src/cmd/upas/vf/mkfile - 664 sys sys 1064393881 241
 sys/src/cmd/upas/vf/vf.c - 664 sys sys 1087829630 17442
 sys/src/cmd/usb - 20000000775 sys sys 1017802022 0
 sys/src/cmd/usb/audio - 20000000775 sys sys 1017802021 0
-sys/src/cmd/usb/audio/audioclass.h - 664 sys sys 1017802021 5463
-sys/src/cmd/usb/audio/config.c - 664 sys sys 1045503797 8526
-sys/src/cmd/usb/audio/controls.c - 664 sys sys 1072729649 13371
-sys/src/cmd/usb/audio/dat.h - 664 sys sys 1045503798 3603
-sys/src/cmd/usb/audio/dump.c - 664 sys sys 1045503798 7065
-sys/src/cmd/usb/audio/fns.h - 664 sys sys 1018387004 474
-sys/src/cmd/usb/audio/fs.c - 664 sys sys 1045503799 18550
-sys/src/cmd/usb/audio/main.c - 664 sys sys 1091021907 9533
-sys/src/cmd/usb/audio/mkfile - 664 sys sys 1045503800 351
+sys/src/cmd/usb/audio/audiofs.c - 664 sys sys 1091204980 18166
+sys/src/cmd/usb/audio/audiosub.c - 664 sys sys 1091204980 6967
+sys/src/cmd/usb/audio/mkfile - 664 sys sys 1091204980 349
+sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1091204980 10178
+sys/src/cmd/usb/audio/usbaudio.h - 664 sys sys 1091204979 1861
+sys/src/cmd/usb/audio/usbaudioctl.c - 664 sys sys 1091204980 17278
+sys/src/cmd/usb/audio/usbaudioctl.h - 664 sys sys 1091204980 600
 sys/src/cmd/usb/lib - 20000000775 sys sys 1018369393 0
-sys/src/cmd/usb/lib/config.c - 664 sys sys 1018462834 6210
-sys/src/cmd/usb/lib/device.c - 664 sys sys 1018387003 1479
-sys/src/cmd/usb/lib/dump.c - 664 sys sys 1018387002 2720
-sys/src/cmd/usb/lib/fmt.c - 664 sys sys 1017802020 291
-sys/src/cmd/usb/lib/mkfile - 664 sys sys 1018462834 191
-sys/src/cmd/usb/lib/setup.c - 664 sys sys 1018387003 1256
-sys/src/cmd/usb/lib/usb.h - 664 sys sys 1032060786 3367
-sys/src/cmd/usb/lib/usbproto.h - 664 sys sys 1017802021 2813
-sys/src/cmd/usb/lib/util.c - 664 sys sys 1017802020 339
-sys/src/cmd/usb/mkfile - 664 sys sys 1089299190 221
+sys/src/cmd/usb/lib/device.c - 664 sys sys 1091204978 2854
+sys/src/cmd/usb/lib/dump.c - 664 sys sys 1091204978 12457
+sys/src/cmd/usb/lib/fmt.c - 664 sys sys 1091204978 291
+sys/src/cmd/usb/lib/mkfile - 664 sys sys 1091204979 204
+sys/src/cmd/usb/lib/setup.c - 664 sys sys 1091204978 1953
+sys/src/cmd/usb/lib/usb.h - 664 sys sys 1091204978 6703
+sys/src/cmd/usb/lib/util.c - 664 sys sys 1091204978 523
+sys/src/cmd/usb/misc - 20000000775 sys sys 1091205037 0
+sys/src/cmd/usb/misc/mkfile - 664 sys sys 1091205037 274
+sys/src/cmd/usb/misc/usbprint - 775 sys sys 1091205037 234
+sys/src/cmd/usb/mkfile - 664 sys sys 1091204978 323
 sys/src/cmd/usb/mouse - 20000000775 sys sys 1017802022 0
-sys/src/cmd/usb/mouse/mkfile - 664 sys sys 1017802022 211
-sys/src/cmd/usb/mouse/usbmouse.c - 664 sys sys 1017802022 3074
 sys/src/cmd/usb/printer - 20000000775 sys sys 1073007760 0
-sys/src/cmd/usb/printer/mkfile - 664 sys sys 1089396828 199
-sys/src/cmd/usb/printer/usbprinter - 775 sys sys 1073007760 222
 sys/src/cmd/usb/usbd - 20000000775 sys sys 1017802021 0
-sys/src/cmd/usb/usbd/dat.h - 664 sys sys 1017802021 682
-sys/src/cmd/usb/usbd/device.c - 664 sys sys 1018387004 2955
-sys/src/cmd/usb/usbd/fns.h - 664 sys sys 1018387004 507
-sys/src/cmd/usb/usbd/hub.c - 664 sys sys 1018387003 4085
-sys/src/cmd/usb/usbd/mkfile - 664 sys sys 1017802021 258
-sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1055699682 5493
+sys/src/cmd/usb/usbd/dat.h - 664 sys sys 1091204979 675
+sys/src/cmd/usb/usbd/fns.h - 664 sys sys 1091204979 495
+sys/src/cmd/usb/usbd/hub.c - 664 sys sys 1091204979 4296
+sys/src/cmd/usb/usbd/mkfile - 664 sys sys 1091204979 304
+sys/src/cmd/usb/usbd/setup.c - 664 sys sys 1091204979 1192
+sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1091204979 5188
 sys/src/cmd/va - 20000000775 sys sys 954038374 0
 sys/src/cmd/va/a.h - 664 sys sys 1089299166 2915
 sys/src/cmd/va/a.y - 664 sys sys 944961340 7211
@@ -12339,10 +12334,6 @@ usr/glenda/lib/profile - 664 glenda glenda 1021580005 847
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
-386/9loaddebug - 775 sys sys 1091156989 270242
-386/9pc - 775 sys sys 1091156992 1808630
-386/9pccpu - 775 sys sys 1091156995 1464782
-386/9pcdisk - 775 sys sys 1091156999 2011236
-386/9pcf - 775 sys sys 1091157003 2342879
-386/bin/hget - 775 sys sys 1091156987 230376
-386/bin/upas/smtpd - 775 sys sys 1091156988 324025
+386/bin/usb/usbaudio - 775 sys sys 1091242967 183443
+386/bin/usb/usbd - 775 sys sys 1091242967 127455
+sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1091243258 9824

+ 27 - 32
dist/replica/plan9.db

@@ -453,8 +453,8 @@
 386/bin/upas/unspam - 775 sys sys 1064598367 38
 386/bin/upas/vf - 775 sys sys 1087873352 90619
 386/bin/usb - 20000000775 sys sys 1019538890 0
-386/bin/usb/usbaudio - 775 sys sys 1091071249 172909
-386/bin/usb/usbd - 775 sys sys 1085077118 122174
+386/bin/usb/usbaudio - 775 sys sys 1091242967 183443
+386/bin/usb/usbd - 775 sys sys 1091242967 127455
 386/bin/usb/usbmouse - 775 sys sys 1085077119 138047
 386/bin/usb/usbprinter - 775 sys sys 1089408719 222
 386/bin/vac - 775 sys sys 1085077119 167554
@@ -2764,7 +2764,7 @@ lib/namespace.ftp - 664 sys sys 1020313578 373
 lib/namespace.httpd - 664 sys sys 984695868 1209
 lib/ndb - 20000000775 sys sys 959260770 0
 lib/ndb/auth - 664 sys sys 959260674 586
-lib/ndb/common - 664 sys sys 1065569740 5261
+lib/ndb/common - 664 sys sys 1091203571 5285
 lib/ndb/consoledb - 664 sys sys 960222421 95
 lib/ndb/dhcp - 20000000775 sys sys 959260749 0
 lib/ndb/dnsdump - 664 sys sys 1032057649 61
@@ -10889,39 +10889,34 @@ sys/src/cmd/upas/vf/mkfile - 664 sys sys 1064393881 241
 sys/src/cmd/upas/vf/vf.c - 664 sys sys 1087829630 17442
 sys/src/cmd/usb - 20000000775 sys sys 1017802022 0
 sys/src/cmd/usb/audio - 20000000775 sys sys 1017802021 0
-sys/src/cmd/usb/audio/audioclass.h - 664 sys sys 1017802021 5463
-sys/src/cmd/usb/audio/config.c - 664 sys sys 1045503797 8526
-sys/src/cmd/usb/audio/controls.c - 664 sys sys 1072729649 13371
-sys/src/cmd/usb/audio/dat.h - 664 sys sys 1045503798 3603
-sys/src/cmd/usb/audio/dump.c - 664 sys sys 1045503798 7065
-sys/src/cmd/usb/audio/fns.h - 664 sys sys 1018387004 474
-sys/src/cmd/usb/audio/fs.c - 664 sys sys 1045503799 18550
-sys/src/cmd/usb/audio/main.c - 664 sys sys 1091021907 9533
-sys/src/cmd/usb/audio/mkfile - 664 sys sys 1045503800 351
+sys/src/cmd/usb/audio/audiofs.c - 664 sys sys 1091204980 18166
+sys/src/cmd/usb/audio/audiosub.c - 664 sys sys 1091204980 6967
+sys/src/cmd/usb/audio/mkfile - 664 sys sys 1091204980 349
+sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1091243258 9824
+sys/src/cmd/usb/audio/usbaudio.h - 664 sys sys 1091204979 1861
+sys/src/cmd/usb/audio/usbaudioctl.c - 664 sys sys 1091204980 17278
+sys/src/cmd/usb/audio/usbaudioctl.h - 664 sys sys 1091204980 600
 sys/src/cmd/usb/lib - 20000000775 sys sys 1018369393 0
-sys/src/cmd/usb/lib/config.c - 664 sys sys 1018462834 6210
-sys/src/cmd/usb/lib/device.c - 664 sys sys 1018387003 1479
-sys/src/cmd/usb/lib/dump.c - 664 sys sys 1018387002 2720
-sys/src/cmd/usb/lib/fmt.c - 664 sys sys 1017802020 291
-sys/src/cmd/usb/lib/mkfile - 664 sys sys 1018462834 191
-sys/src/cmd/usb/lib/setup.c - 664 sys sys 1018387003 1256
-sys/src/cmd/usb/lib/usb.h - 664 sys sys 1032060786 3367
-sys/src/cmd/usb/lib/usbproto.h - 664 sys sys 1017802021 2813
-sys/src/cmd/usb/lib/util.c - 664 sys sys 1017802020 339
-sys/src/cmd/usb/mkfile - 664 sys sys 1089299190 221
+sys/src/cmd/usb/lib/device.c - 664 sys sys 1091204978 2854
+sys/src/cmd/usb/lib/dump.c - 664 sys sys 1091204978 12457
+sys/src/cmd/usb/lib/fmt.c - 664 sys sys 1091204978 291
+sys/src/cmd/usb/lib/mkfile - 664 sys sys 1091204979 204
+sys/src/cmd/usb/lib/setup.c - 664 sys sys 1091204978 1953
+sys/src/cmd/usb/lib/usb.h - 664 sys sys 1091204978 6703
+sys/src/cmd/usb/lib/util.c - 664 sys sys 1091204978 523
+sys/src/cmd/usb/misc - 20000000775 sys sys 1091205037 0
+sys/src/cmd/usb/misc/mkfile - 664 sys sys 1091205037 274
+sys/src/cmd/usb/misc/usbprint - 775 sys sys 1091205037 234
+sys/src/cmd/usb/mkfile - 664 sys sys 1091204978 323
 sys/src/cmd/usb/mouse - 20000000775 sys sys 1017802022 0
-sys/src/cmd/usb/mouse/mkfile - 664 sys sys 1017802022 211
-sys/src/cmd/usb/mouse/usbmouse.c - 664 sys sys 1017802022 3074
 sys/src/cmd/usb/printer - 20000000775 sys sys 1073007760 0
-sys/src/cmd/usb/printer/mkfile - 664 sys sys 1089396828 199
-sys/src/cmd/usb/printer/usbprinter - 775 sys sys 1073007760 222
 sys/src/cmd/usb/usbd - 20000000775 sys sys 1017802021 0
-sys/src/cmd/usb/usbd/dat.h - 664 sys sys 1017802021 682
-sys/src/cmd/usb/usbd/device.c - 664 sys sys 1018387004 2955
-sys/src/cmd/usb/usbd/fns.h - 664 sys sys 1018387004 507
-sys/src/cmd/usb/usbd/hub.c - 664 sys sys 1018387003 4085
-sys/src/cmd/usb/usbd/mkfile - 664 sys sys 1017802021 258
-sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1055699682 5493
+sys/src/cmd/usb/usbd/dat.h - 664 sys sys 1091204979 675
+sys/src/cmd/usb/usbd/fns.h - 664 sys sys 1091204979 495
+sys/src/cmd/usb/usbd/hub.c - 664 sys sys 1091204979 4296
+sys/src/cmd/usb/usbd/mkfile - 664 sys sys 1091204979 304
+sys/src/cmd/usb/usbd/setup.c - 664 sys sys 1091204979 1192
+sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1091204979 5188
 sys/src/cmd/va - 20000000775 sys sys 954038374 0
 sys/src/cmd/va/a.h - 664 sys sys 1089299166 2915
 sys/src/cmd/va/a.y - 664 sys sys 944961340 7211

+ 43 - 0
dist/replica/plan9.log

@@ -16346,3 +16346,46 @@
 1091158290 4 c 386/9pcf - 775 sys sys 1091157003 2342879
 1091158290 5 c 386/bin/hget - 775 sys sys 1091156987 230376
 1091158290 6 c 386/bin/upas/smtpd - 775 sys sys 1091156988 324025
+1091205099 0 c lib/ndb/common - 664 sys sys 1091203571 5285
+1091205099 1 a sys/src/cmd/usb/audio/audiofs.c - 664 sys sys 1091204980 18166
+1091205099 2 a sys/src/cmd/usb/audio/audiosub.c - 664 sys sys 1091204980 6967
+1091205099 3 c sys/src/cmd/usb/audio/mkfile - 664 sys sys 1091204980 349
+1091205099 4 a sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1091204980 10178
+1091205099 5 a sys/src/cmd/usb/audio/usbaudio.h - 664 sys sys 1091204979 1861
+1091205099 6 a sys/src/cmd/usb/audio/usbaudioctl.c - 664 sys sys 1091204980 17278
+1091205099 7 a sys/src/cmd/usb/audio/usbaudioctl.h - 664 sys sys 1091204980 600
+1091205099 8 c sys/src/cmd/usb/lib/device.c - 664 sys sys 1091204978 2854
+1091205099 9 c sys/src/cmd/usb/lib/dump.c - 664 sys sys 1091204978 12457
+1091205099 10 c sys/src/cmd/usb/lib/fmt.c - 664 sys sys 1091204978 291
+1091205099 11 c sys/src/cmd/usb/lib/mkfile - 664 sys sys 1091204979 204
+1091205099 12 c sys/src/cmd/usb/lib/setup.c - 664 sys sys 1091204978 1953
+1091205099 13 c sys/src/cmd/usb/lib/usb.h - 664 sys sys 1091204978 6703
+1091205099 14 c sys/src/cmd/usb/lib/util.c - 664 sys sys 1091204978 523
+1091205099 15 a sys/src/cmd/usb/misc - 20000000775 sys sys 1091205037 0
+1091205099 16 a sys/src/cmd/usb/misc/mkfile - 664 sys sys 1091205037 274
+1091205099 17 a sys/src/cmd/usb/misc/usbprint - 775 sys sys 1091205037 234
+1091205099 18 c sys/src/cmd/usb/mkfile - 664 sys sys 1091204978 323
+1091205099 19 c sys/src/cmd/usb/usbd/dat.h - 664 sys sys 1091204979 675
+1091205099 20 c sys/src/cmd/usb/usbd/fns.h - 664 sys sys 1091204979 495
+1091205099 21 c sys/src/cmd/usb/usbd/hub.c - 664 sys sys 1091204979 4296
+1091205099 22 c sys/src/cmd/usb/usbd/mkfile - 664 sys sys 1091204979 304
+1091205099 23 a sys/src/cmd/usb/usbd/setup.c - 664 sys sys 1091204979 1192
+1091205099 24 c sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1091204979 5188
+1091205099 25 d sys/src/cmd/usb/usbd/device.c - 664 sys sys 1018387004 0
+1091205099 26 d sys/src/cmd/usb/printer/usbprinter - 775 sys sys 1073007760 0
+1091205099 27 d sys/src/cmd/usb/printer/mkfile - 664 sys sys 1089396828 0
+1091205099 28 d sys/src/cmd/usb/mouse/usbmouse.c - 664 sys sys 1017802022 0
+1091205099 29 d sys/src/cmd/usb/mouse/mkfile - 664 sys sys 1017802022 0
+1091205099 30 d sys/src/cmd/usb/lib/usbproto.h - 664 sys sys 1017802021 0
+1091205099 31 d sys/src/cmd/usb/lib/config.c - 664 sys sys 1018462834 0
+1091205099 32 d sys/src/cmd/usb/audio/main.c - 664 sys sys 1091021907 0
+1091205099 33 d sys/src/cmd/usb/audio/fs.c - 664 sys sys 1045503799 0
+1091205099 34 d sys/src/cmd/usb/audio/fns.h - 664 sys sys 1018387004 0
+1091205099 35 d sys/src/cmd/usb/audio/dump.c - 664 sys sys 1045503798 0
+1091205099 36 d sys/src/cmd/usb/audio/dat.h - 664 sys sys 1045503798 0
+1091205099 37 d sys/src/cmd/usb/audio/controls.c - 664 sys sys 1072729649 0
+1091205099 38 d sys/src/cmd/usb/audio/config.c - 664 sys sys 1045503797 0
+1091205099 39 d sys/src/cmd/usb/audio/audioclass.h - 664 sys sys 1017802021 0
+1091244706 0 c 386/bin/usb/usbaudio - 775 sys sys 1091242967 183443
+1091244706 1 c 386/bin/usb/usbd - 775 sys sys 1091242967 127455
+1091244706 2 c sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1091243258 9824

+ 1 - 0
lib/ndb/common

@@ -212,6 +212,7 @@ udp=bootp port=67
 udp=domain port=53
 udp=dns port=53
 udp=portmap port=111
+udp=netbios-ns port=137
 udp=ntp port=123
 udp=snmp port=161
 udp=rip port=520

+ 0 - 253
sys/src/cmd/usb/audio/audioclass.h

@@ -1,253 +0,0 @@
-/*
- *	Audio Control Class
- */
-enum
-{
-	/* subclass codes */
-	AUDIOCONTROL = 0x01,
-	AUDIOSTREAMING = 0x02,
-	MIDISTREAMING = 0x03,
-
-	/* class-specific descriptor types */
-	CS_UNDEFINED = 0x20,
-	CS_DEVICE = 0x21,
-	CS_CONFIG = 0x22,
-	CS_STRING = 0x23,
-	CS_INTERFACE = 0x24,
-	CS_ENDPOINT = 0x25,
-
-	/* audiocontrol descriptor subtypes */
-	HEADER = 0x01,
-	INPUT_TERMINAL = 0x02,
-	OUTPUT_TERMINAL = 0x03,
-	MIXER_UNIT = 0x04,
-	SELECTOR_UNIT = 0x05,
-	FEATURE_UNIT = 0x06,
-	PROCESSING_UNIT = 0x07,
-	EXTENSION_UNIT = 0x08,
-
-	/* audiostreaming descriptor subtypes */
-	AS_GENERAL = 0x01,
-	FORMAT_TYPE = 0x02,
-	FORMAT_SPECIFIC = 0x03,
-
-	/* processing unit process types */
-	UPDOWNMIX_PROCESS = 0x01,
-	DOLBY_PROLOGIC_PROCESS = 0x02,
-	STEREO_3D_PROCESS = 0x03,
-	REVERB_PROCESS = 0x04,
-	CHORUS_PROCESS = 0x05,
-	DYN_RANGE_COMP_PROCESS = 0x06,
-
-	/* endpoint descriptor subtypes */
-	EP_GENERAL = 0x01,
-
-	/* class-specific request codes */
-	GET_CUR = 0x81,
-	GET_MIN = 0x82,
-	GET_MAX = 0x83,
-	GET_RES = 0x84,
-	GET_MEM = 0x85,
-	GET_STAT = 0xff,
-	SET_CUR = 0x01,
-	SET_MIN = 0x02,
-	SET_MAX = 0x03,
-	SET_RES = 0x04,
-	SET_MEM = 0x05,
-
-	/* feature unit control selectors */
-	MUTE_CONTROL = 0x01,
-	VOLUME_CONTROL = 0x02,
-	BASS_CONTROL = 0x03,
-	MID_CONTROL = 0x04,
-	TREBLE_CONTROL = 0x05,
-	EQUALIZER_CONTROL = 0x06,
-	AGC_CONTROL = 0x07,
-	DELAY_CONTROL = 0x08,
-	BASS_BOOST_CONTROL = 0x09,
-	LOUDNESS_CONTROL = 0x0a,
-
-	/* up/down-mix processing unit control selectors */
-	UD_ENABLE_CONTROL = 0x01,
-	UD_MODE_SELECT_CONTROL = 0x02,
-
-	/* dolby pro-logic processing unit control selectors */
-	DP_ENABLE_CONTROL = 0x01,
-	DP_MODE_SELECT_CONTROL = 0x02,
-
-	/* 3D stereo expander processing unit control selectors */
-	STEREO_3D_ENABLE_CONTROL = 0x01,
-	SPACIOUSNESS_CONTROL = 0x03,
-
-	/* reverb processing unit control selectors */
-	REVERB_ENABLE_CONTROL = 0x01,
-	REVERB_LEVEL_CONTROL = 0x02,
-	REVERB_TIME_CONTROL = 0x03,
-	REVERB_FEEDBACK_CONTROL = 0x04,
-
-	/* chorus processing unit control selectors */
-	CHORUS_ENABLE_CONTROL = 0x01,
-	CHORUS_LEVEL_CONTROL = 0x02,
-	CHORUS_RATE_CONTROL = 0x03,
-	CHORUS_DEPTH_CONTROL = 0x04,
-
-	/* dynamic range compressor processing unit control selectors */
-	DR_ENABLE_CONTROL = 0x01,
-	COMPRESSION_RATE_CONTROL = 0x02,
-	MAXAMPL_CONTROL = 0x03,
-	THRESHOLD_CONTROL = 0x04,
-	ATTACK_TIME = 0x05,
-	RELEASE_TIME = 0x06,
-
-	/* extension unit control selectors */
-	XU_ENABLE_CONTROL = 0x01,
-
-	/* endpoint control selectors */
-	SAMPLING_FREQ_CONTROL = 0x01,
-	PITCH_CONTROL = 0x01,
-};
-
-/*
- *	Audio Format Types
- */
-enum
-{
-	/* type 1 format codes */
-	PCM = 0x0001,
-	PCM8 = 0x0002,
-	IEEE_FLOAT = 0x0003,
-	ALAW = 0x0004,
-	MULAW = 0x0005,
-
-	/* type 2 format codes */
-	MPEG = 0x1001,
-	AC_3 = 0x1002,
-
-	/* type 3 format codes */
-	IEC1937_AC_3 = 0x2001,
-	IEC1937_MPEG1_L1 = 0x2002,
-	IEC1937_MPEG1_L2_3 = 0x2003,
-	IEC1937_MPEG2_NOEXT= 0x2003,
-	IEC1937_MPEG2_EXT = 0x2004,
-	IEC1937_MPEG2_L1_LS = 0x2005,
-	IEC1937_MPEG2_L2_3_LS = 0x2006,
-
-	/* format type codes */
-	FORMAT_TYPE_UNDEF = 0x00,
-	FORMAT_TYPE_I = 0x01,
-	FORMAT_TYPE_II = 0x02,
-	FORMAT_TYPE_III = 0x03,
-
-	/* mpeg control selectors */
-	MP_DUAL_CHANNEL_CONTROL = 0x01,
-	MP_SECOND_STEREO_CONTROL = 0x02,
-	MP_MULTILINGUAL_CONTROL = 0x03,
-	MP_DYN_RANGE_CONTROL = 0x04,
-	MP_SCALING_CONTROL = 0x05,
-	MP_HILO_SCALING_CONTROL = 0x06,
-
-	/* AC-3 control selectors */
-	AC_MODE_CONTROL = 0x01,
-	AC_DYN_RANGE_CONTROL = 0x02,
-	AC_SCALING_CONTROL = 0x03,
-	AC_HILO_SCALING_CONTROL = 0x04,
-};
-
-/*
- *	Audio Terminal Types
- */
-enum
-{
-	/* USB terminal types */
-	USB_UNDEFINED = 0x0100,
-	USB_STREAMING = 0x0101,
-	USB_VENDOR = 0x01FF,
-
-	/* Input terminal types */
-	INPUT_UNDEFINED = 0x0200,
-	MICROPHONE = 0x0201,
-	DESK_MICROPHONE = 0x0202,
-	PERSONAL_MICROPHONE = 0x0203,
-	OMNI_MICROPHONE = 0x0204,
-	MICROPHONE_ARRAY = 0x0205,
-	PROC_MICROPHONE_ARRAY = 0x0205,
-
-	/* Output terminal types */
-	OUTPUT_UNDEFINED = 0x0300,
-	SPEAKER = 0x0301,
-	HEADPHONES = 0x0302,
-	HMD_AUDIO = 0x0303,
-	DESK_SPEAKER = 0x0304,
-	ROOM_SPEAKER = 0x0305,
-	COMM_SPEAKER = 0x0306,
-	LFE_SPEAKER = 0x0307,
-
-	/* Bidirectional terminal types */
-	BIDIRECTIONAL_UNDEFINED = 0x0400,
-	HANDSET = 0x0401,
-	HEADSET = 0x0402,
-	SPEAKERPHONE = 0x0403,
-	ECHO_SUPP_SPEAKERPHONE = 0x0404,
-	ECHO_CANC_SPEAKERPHONE = 0x0405,
-
-	/* Telephony terminal types */
-	TELEPHONY_UNDEFINED = 0x0500,
-	PHONELINE = 0x0501,
-	TELEPHONE = 0x0502,
-	DOWN_LINE_PHONE = 0x0503,
-
-	/* External terminal types */
-	EXTERNAL_UNDEFINED = 0x0600,
-	ANALOG_CONNECTOR = 0x0601,
-	DIGITAL_AUDIO = 0x0602,
-	LINE_CONNECTOR = 0x0603,
-	LEGACY_AUDIO = 0x0604,
-	SPDIF_INTERFACE = 0x0605,
-	I1394_DA = 0x0606,
-	I1394_DV = 0x0607,
-
-	/* Embedded function terminal types */
-	EMBEDDED_UNDEFINED = 0x0700,
-	LEVEL_CALIBRATION_NOICE_SOURCE = 0x0701,
-	EQUALIZATION_NOISE = 0x0702,
-	CD_PLAYER = 0x0703,
-	DAT = 0x0704,
-	DCC = 0x0705,
-	MINIDISK = 0x0706,
-	ANALOG_TAPE = 0x0707,
-	PHONOGRAPH = 0x0708,
-	VCR_AUDIO = 0x0709,
-	VIDEODISC_AUDIO = 0x070A,
-	DVD_AUDIO = 0x070B,
-	TVTUNER_AUDIO = 0x070C,
-	SATELLITE_AUDIO = 0x070D,
-	CABLETUNER_AUDIO = 0x070E,
-	DSS_AUDIO = 0x070F,
-	RADIO_RECEIVER = 0x0710,
-	RADIO_TRANSMITTER = 0x0711,
-	MULTITRACK_RECORDER = 0x0712,
-	SYNTHESIZER = 0x0713,
-};
-
-/*
- *	MIDI Streaming Subclass Definitions
- */
-enum
-{
-	/* interface descriptor subtypes */
-	MS_HEADER = 0x01,
-	MIDI_IN_JACK = 0x02,
-	MIDI_OUT_JACK = 0x03,
-	ELEMENT = 0x03,
-
-	/* endpoint descriptor subtypes */
-	MS_GENERAL= 0x01,
-
-	/* jack types */
-	JACKTYPE_UNDEFINED = 0x00,
-	EMBEDDED = 0x01,
-	EXTERNAL = 0x02,
-
-	/* endpoint control selectors */
-	ASSOCIATION_CONTROL = 0x01,
-};

+ 44 - 70
sys/src/cmd/usb/audio/fs.c → sys/src/cmd/usb/audio/audiofs.c

@@ -5,10 +5,8 @@
 #include <fcall.h>
 #include <libsec.h>
 #include "usb.h"
-#include "usbproto.h"
-#include "dat.h"
-#include "fns.h"
-#include "audioclass.h"
+#include "usbaudio.h"
+#include "usbaudioctl.h"
 
 #define STACKSIZE 16*1024
 
@@ -91,7 +89,7 @@ Fcall	thdr;
 Fcall	rhdr;
 Worker *workers;
 
-char srvfile[64], mntdir[64];
+char srvfile[64], mntdir[64], epdata[64], audiofile[64];
 int mfd[2], p[2];
 char user[32];
 char *srvpost;
@@ -132,7 +130,7 @@ char 	*(*fcalls[])(Fid*) = {
 
 char	Eperm[] =		"permission denied";
 char	Enotdir[] =	"not a directory";
-char	Enoauth[] =	"usbaudio: authentication not required";
+char	Enoauth[] =	"no authentication in ramfs";
 char	Enotexist[] =	"file does not exist";
 char	Einuse[] =		"file in use";
 char	Eexist[] =		"file exists";
@@ -166,30 +164,6 @@ post(char *name, char *envname, int srvfd)
 	putenv(envname, name);
 }
 
-static void
-dobind(Nexus *nx, char *mntpt, char *file)
-{
-	Stream *s;
-	Device *d;
-	Endpt *ep;
-	Streamalt *sa;
-	char epdata[64], audiofile[64];
-
-	if(nx == nil)
-		return;
-	s = nx->s;
-	d = s->intf->d;
-	for(sa = s->salt; sa != nil; sa = sa->next) {
-		if(sa->dalt->npt != 0)
-			break;
-	}
-	ep = &sa->dalt->ep[0];
-	sprint(epdata, "#U/usb%d/%d/ep%ddata", d->ctlrno, d->id, ep->addr);
-	sprint(audiofile, "%s/%s", mntpt, file);
-	if(bind(epdata, audiofile, MREPL) < 0)
-		sysfatal("bind failed");
-}
-
 void
 serve(void *)
 {
@@ -229,8 +203,18 @@ serve(void *)
 	}
 	if(mount(p[1], -1, mntpt, MBEFORE, "") < 0)
 		sysfatal("mount failed");
-	dobind(nexus[Play], mntpt, "audio");
-	dobind(nexus[Record], mntpt, "audioin");
+	if (endpt[Play] >= 0){
+		sprint(epdata, "#U/usb%d/%d/ep%ddata", ad->ctlrno, ad->id, endpt[Play]);
+		sprint(audiofile, "%s/audio", mntpt);
+		if(bind(epdata, audiofile, MREPL) < 0)
+			sysfatal("bind failed");
+	}
+	if (endpt[Record] >= 0){
+		sprint(epdata, "#U/usb%d/%d/ep%ddata", ad->ctlrno, ad->id, endpt[Record]);
+		sprint(audiofile, "%s/audioin", mntpt);
+		if(bind(epdata, audiofile, MREPL) < 0)
+			sysfatal("bind failed");
+	}
 	threadexits(nil);
 }
 
@@ -257,7 +241,7 @@ rversion(Fid*)
 char*
 rauth(Fid*)
 {
-	return Enoauth;
+	return "usbaudio: no authentication required";
 }
 
 char*
@@ -320,9 +304,9 @@ dowalk(Fid *f, char *name)
 	if(f->dir != &dirs[Qdir])
 		return Enotexist;
 	for (t = 1; t < Nqid; t++){
-		if (t == Qaudio && nexus[Play] == nil)
+		if (t == Qaudio && endpt[Play] < 0)
 			continue;
-		if (t == Qaudioin && nexus[Record] == nil)
+		if (t == Qaudioin && endpt[Record] < 0)
 			continue;
 		if(strcmp(name, dirs[t].name) == 0){
 			f->dir = &dirs[t];
@@ -430,9 +414,9 @@ readtopdir(Fid*, uchar *buf, long off, int cnt, int blen)
 	n = 0;
 	pos = 0;
 	for (i = 1; i < Nqid; i++){
-		if (nexus[Play] == nil && i == Qaudio)
+		if (endpt[Play] < 0 && i == Qaudio)
 			continue;
-		if (nexus[Record] == nil && i == Qaudioin)
+		if (endpt[Record] < 0 && i == Qaudioin)
 			continue;
 		m = convD2M(&dirs[i], &buf[n], blen-n);
 		if(off <= pos){
@@ -453,7 +437,6 @@ makeaudioctldata(Fid *f)
 	char *p, *e;
 	Audiocontrol *c;
 	Audioctldata *a;
-	Nexus *nx;
 
 	if ((a = f->fiddata) == nil)
 		sysfatal("fiddata");
@@ -462,12 +445,9 @@ makeaudioctldata(Fid *f)
 		a->s = p;
 	}
 	e = p + 1024;
-	for(rec = 0; rec < 2; rec++) {
-		nx = nexus[rec];
-		if(nx == nil)
-			continue;
-		for(ctl = 0; ctl < Ncontrol; ctl++) {
-			c = &nx->control[ctl];
+	for (rec = 0; rec < 2; rec++)
+		for (ctl = 0; ctl < Ncontrol; ctl++) {
+			c = &controls[rec][ctl];
 			different = 0;
 			if (c->chans){
 				for (i = 1; i < 8; i++)
@@ -477,7 +457,7 @@ makeaudioctldata(Fid *f)
 				if (c->value[0] != a->values[rec][ctl][0])
 					different = 1;
 			if (different){
-				p = seprint(p, e, "%s %s %A", controlname[ctl], rec?"in":"out", c);
+				p = seprint(p, e, "%s %s %A", c->name, rec?"in":"out", c);
 				memmove(a->values[rec][ctl], c->value, sizeof c->value);
 				if (c->min != Undef){
 					p = seprint(p, e, " %ld %ld", c->min, c->max);
@@ -487,7 +467,6 @@ makeaudioctldata(Fid *f)
 				p = seprint(p, e, "\n");
 			}
 		}
-	}
 	assert(strlen(a->s) < 1024);
 	a->ns = p - a->s;
 	return a->ns;
@@ -576,7 +555,6 @@ rread(Fid *f)
 	Audiocontrol *c;
 	Audioctldata *a;
 	Worker *w;
-	Nexus *nx;
 
 	rhdr.count = 0;
 	off = thdr.offset;
@@ -596,35 +574,26 @@ rread(Fid *f)
 	if(f->dir == &dirs[Qvolume]){
 		p = buf;
 		n = sizeof buf;
-		for (rec = 0; rec < 2; rec++) {
-			nx = nexus[rec];
-			if(nx == nil)
-				continue;
-			c = &nx->control[Volume_control];
+		for (rec = 0; rec < 2; rec++){
+			c = &controls[rec][Volume_control];
 			if (c->readable){
 				i = snprint(p, n, "audio %s %ld\n", rec?"in":"out", (c->min != Undef) ?
 					100*(c->value[0]-c->min)/(c->max-c->min) : c->value[0]);
 				p+=i; n-=i;
 			}
-			c = &nx->control[Mixer_control];
-			if (c->readable){
-				i = snprint(p, n, "mixer %s %ld\n", rec?"in":"out", (c->min != Undef) ?
-					100*(c->value[0]-c->min)/(c->max-c->min) : c->value[0]);
-				p+=i; n-=i;
-			}
-			c = &nx->control[Treble_control];
+			c = &controls[rec][Treble_control];
 			if (c->readable){
 				i = snprint(p, n, "treb %s %ld\n", rec?"in":"out", (c->min != Undef) ?
 					100*(c->value[0]-c->min)/(c->max-c->min) : c->value[0]);
 				p+=i; n-=i;
 			}
-			c = &nx->control[Bass_control];
+			c = &controls[rec][Bass_control];
 			if (c->readable){
 				i = snprint(p, n, "bass %s %ld\n", rec?"in":"out", (c->min != Undef) ?
 					100*(c->value[0]-c->min)/(c->max-c->min) : c->value[0]);
 				p+=i; n-=i;
 			}
-			c = &nx->control[Speed_control];
+			c = &controls[rec][Speed_control];
 			if (c->readable){
 				i = snprint(p, n, "speed %s %ld\n", rec?"in":"out", c->value[0]);
 				p+=i; n-=i;
@@ -703,7 +672,7 @@ rwrite(Fid *f)
 {
 	long cnt, value;
 	char *lines[2*Ncontrol], *fields[4], *subfields[9], *err, *p;
-	int nlines, i, nf, nnf, rec;
+	int nlines, i, nf, nnf, rec, ctl;
 	Audiocontrol *c;
 	Worker *w;
 	static char buf[256];
@@ -738,10 +707,15 @@ rwrite(Fid *f)
 				if (debug) fprint(2, "bad2 %d\n", nf);
 				return Ebadctl;
 			}
+			c = nil;
 			if (strcmp(fields[0], "audio") == 0)	/* special case */
 				fields[0] = "volume";
-			c = findcontrol(nexus[rec], fields[0]);
-			if (c == nil){
+			for (ctl = 0; ctl < Ncontrol; ctl++){
+				c = &controls[rec][ctl];
+				if (strcmp(fields[0], c->name) == 0)
+					break;
+			}
+			if (ctl == Ncontrol){
 				if (debug) fprint(2, "bad3\n");
 				return Ebadctl;
 			}
@@ -758,13 +732,13 @@ rwrite(Fid *f)
 					if (debug) {
 						if (p == buf)
 							fprint(2, "rwrite: %s %s '%ld",
-								fields[0], rec?"record":"playback", value);
+								c->name, rec?"record":"playback", value);
 						else
 							fprint(2, " %ld", value);
 					}
 					if (p == buf)
 						p = seprint(p, buf+sizeof buf, "0x%p %s %s '%ld",
-							replchan, fields[0], rec?"record":"playback", value);
+							replchan, c->name, rec?"record":"playback", value);
 					else
 						p = seprint(p, buf+sizeof buf, " %ld", value);
 				}
@@ -772,8 +746,8 @@ rwrite(Fid *f)
 				seprint(p, buf+sizeof buf, "'");
 				chanprint(controlchan, buf);
 			} else {
-				if (debug) fprint(2, "rwrite: %s %s %q", fields[0], rec?"record":"playback", fields[nf-1]);
-				chanprint(controlchan, "0x%p %s %s %q", replchan, fields[0], rec?"record":"playback", fields[nf-1]);
+				if (debug) fprint(2, "rwrite: %s %s %q", c->name, rec?"record":"playback", fields[nf-1]);
+				chanprint(controlchan, "0x%p %s %s %q", replchan, c->name, rec?"record":"playback", fields[nf-1]);
 			}
 			p = recvp(replchan);
 			if (p){
@@ -823,9 +797,9 @@ rstat(Fid *f)
 {
 	Audioctldata *a;
 
-	if (f->dir == &dirs[Qaudio] && nexus[Play] == nil)
+	if (f->dir == &dirs[Qaudio] && endpt[Play] < 0)
 			return Enotexist;
-	if (f->dir == &dirs[Qaudioin] && nexus[Record] == nil)
+	if (f->dir == &dirs[Qaudioin] && endpt[Record] < 0)
 			return Enotexist;
 	if (f->dir == &dirs[Qaudioctl]){
 		qlock(f);

+ 234 - 0
sys/src/cmd/usb/audio/audiosub.c

@@ -0,0 +1,234 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "usb.h"
+#include "usbaudio.h"
+#include "usbaudioctl.h"
+
+Namelist terminal_types[] = {
+	{	0x100, "USB Terminal, undefined type"},
+	{	0x101, "USB Streaming"},
+	{	0x301, "Speaker"},
+	{	0x603, "Line connector"},
+	{	0, nil }
+};
+
+units[2][8];	/* rec and play units */
+nunits[2];		/* number in use */
+
+static int
+findunit(int nr)
+{
+	int rec, i;
+	for (rec = 0; rec < 2; rec++)
+		for (i = 0; i < nunits[rec]; i++)
+			if (units[rec][i] == nr)
+				return rec;
+	return -1;
+}
+
+void
+audio_interface(Device *d, int n, ulong csp, void *bb, int nb) {
+	byte *b = bb;
+	int ctl, ch, u, x;
+	byte *p;
+	int class, subclass, ifc, dalt;
+	Audioalt *aa;
+
+	if ((dalt = (csp >> 24) & 0xff) == 0xff) dalt = -1;
+	if ((ifc = (csp >> 16) & 0xff) == 0xff) ifc = -1;
+	class = Class(csp);
+	subclass = Subclass(csp);
+
+	if (debug & Dbginfo) fprint(2, "%d.%d: ", class, subclass);
+	switch (subclass) {
+	case 1:	// control
+		switch (b[2]) {
+		case 0x01:
+			if (debug & Dbginfo){
+				fprint(2, "Class-Specific AC Interface Header Descriptor\n");
+				fprint(2, "\tAudioDeviceClass release (bcd)%c%c%c%c, TotalLength %d, InCollection %d aInterfaceNr %d\n",
+					'0'+((b[4]>>4)&0xf), '0'+(b[4]&0xf),
+					'0'+((b[3]>>4)&0xf), '0'+(b[3]&0xf),
+					b[5]|(b[6]<<8), b[7], b[8]);
+			}
+			break;
+		case 0x02:	// input
+			if (debug & Dbginfo){
+				fprint(2, "Audio Input Terminal Descriptor\n");
+				fprint(2, "\tbTerminalId %d, wTerminalType 0x%x (%s), bAssocTerminal %d bNrChannels %d, wChannelConfig %d, iChannelNames %d iTerminal %d\n",
+					b[3], b[4]|(b[5]<<8),
+					namefor(terminal_types, b[4]|(b[5]<<8)),
+					b[6], b[7], b[8]|(b[9]<<8), b[10], b[11]);
+			}
+			if ((b[4]|b[5]<<8) == 0x101){
+				if (verbose)
+					fprint(2, "Audio output unit %d\n", b[3]);
+				/* USB streaming input: play interface */
+				units[Play][nunits[Play]++] = b[3];
+			}else{
+				if (verbose)
+					fprint(2, "Device can record from %s\n",
+						namefor(terminal_types, b[4]|(b[5]<<8)));
+				/* Non-USB input: record interface */
+				units[Record][nunits[Record]++] = b[3];
+			}
+			break;
+		case 0x03:	// output
+			if (debug & Dbginfo){
+				fprint(2, "Audio Output Terminal Descriptor\n");
+				fprint(2, "\tbTerminalId %d, wTerminalType 0x%x (%s), bAssocTerminal %d bSourceId %d, iTerminal %d\n",
+					b[3], b[4]|(b[5]<<8),
+					namefor(terminal_types, b[4]|(b[5]<<8)),
+					b[6], b[7], b[8]);
+			}
+			if ((b[4]|b[5]<<8) == 0x101){
+				if (verbose)
+					fprint(2, "Audio input unit %d\n", b[3]);
+				/* USB streaming output: record interface */
+				units[Record][nunits[Record]++] = b[3];
+				if (verbose)
+					fprint(2, "Device can play to %s\n",
+						namefor(terminal_types, b[4]|(b[5]<<8)));
+				/* Non-USB output: play interface */
+				units[Play][nunits[Play]++] = b[3];
+			}
+			break;
+		case 0x04:
+			if (verbose)
+				fprint(2, "Audio Mixer Unit %d\n", b[3]);
+			break;
+		case 0x05:
+			if (verbose)
+				fprint(2, "Audio Selector Unit %d\n", b[3]);
+			if (debug & Dbginfo)
+				fprint(2, "\tbUnitId %d, bNrInPins %d", b[3], b[4]);
+			if (b[4]){
+				if (debug & Dbginfo) fprint(2, ", baSourceIDs: [%d", b[5]);
+				u = findunit(b[5]);
+				for (ctl = 1; ctl < b[4]; ctl++){
+					if (u < 0)
+						u = findunit(b[5+ctl]);
+					else if ((x = findunit(b[5+ctl])) >= 0 && u != x && verbose)
+						fprint(2, "\tSelector %d for output AND input\n", b[3]);
+					if (debug & Dbginfo) fprint(2, ", %d", b[5+ctl]);
+				}
+				if (debug & Dbginfo) fprint(2, "]\n");
+				if (u >= 0){
+					units[u][nunits[u]++] = b[3];
+					if (selectorid[u] >= 0)
+						fprint(2, "Second selector (%d, %d) on %s\n", selectorid[u], b[3], u?"record":"playback");
+					selectorid[u] = b[3];
+				}
+			}
+			break;
+		case 0x06:	// feature
+			if (verbose) fprint(2, "Audio Feature Unit %d", b[3]);
+			if (debug & Dbginfo)
+				fprint(2, "\tbUnitId %d, bSourceId %d, bControlSize %d\n",
+					b[3], b[4], b[5]);
+			u = findunit(b[4]);
+			if (u >= 0){
+				if (verbose) fprint(2, " for %s\n", u?"Record":"Playback");
+				units[u][nunits[u]++] = b[3];
+				if (featureid[u] >= 0)
+					if (verbose) fprint(2, "Second feature unit (%d, %d) on %s\n", featureid[u], b[3], u?"record":"playback");
+				featureid[u] = b[3];
+			}else
+				if (verbose) fprint(2, ", not known what for\n");
+			p = b + 6;
+			for (ctl = 1; ctl < 0x0b; ctl++)
+				if ((1<<(ctl-1)) & (b[6] | ((b[5]>1)?(b[7]<<8):0))) {
+					if (verbose)
+						fprint(2, "\t%s control on master channel\n",
+							controls[0][ctl].name);
+					if (u >= 0){
+						controls[u][ctl].readable = 1;
+						controls[u][ctl].settable = 1;
+						controls[u][ctl].chans = 0;
+					}
+				}
+			p += (b[5]>1)?2:1;
+			for (ch = 0; ch < (nb - 8)/b[5]; ch++) {
+				for (ctl = 1; ctl < 0x0b; ctl++)
+					if ((1<<(ctl-1)) & (p[0] | ((b[5]>1)?(p[1]<<8):0))) {
+						if (verbose)
+							fprint(2, "\t%s control on channel %d\n",
+								controls[0][ctl].name, ch+1);
+						if (u >= 0){
+							controls[u][ctl].readable = 1;
+							controls[u][ctl].settable = 1;
+							controls[u][ctl].chans |= 1 <<(ch+1);
+						}
+					}
+				p += (b[5]>1)?2:1;
+			}
+			break;
+		default:
+			pcs_raw("audio control unknown", bb, nb);
+		}
+		break;
+	case 2: // stream
+		switch (b[2]) {
+		case 0x01:
+			if (debug & Dbginfo)
+				fprint(2, "Audio stream for TerminalID %d, delay %d, format_tag %#ux\n",
+					b[3], b[4], b[5] | (b[6]<<8));
+			break;
+		case 0x02:
+			if (d->config[n]->iface[ifc]->dalt[dalt] == nil)
+				d->config[n]->iface[ifc]->dalt[dalt] = mallocz(sizeof(Dalt),1);
+			aa = (Audioalt *)d->config[n]->iface[ifc]->dalt[dalt]->devspec;
+			if (aa == nil) {
+				aa = mallocz(sizeof(Audioalt), 1);
+				d->config[n]->iface[ifc]->dalt[dalt]->devspec = aa;
+			}
+			if (verbose){
+				if (b[4] <= 2)
+					fprint(2, "Interface %d, alt %d: %s, %d bits, ",
+						ifc, dalt, (b[4] == 1)?"mono":"stereo", b[6]);
+				else
+					fprint(2, "Interface %d, alt %d: %d channels, %d bits, ",
+						ifc, dalt, b[4], b[6]);
+			}
+			if(b[7] == 0){
+				if (verbose)
+					fprint(2, "frequency variable between %d and %d\n",
+						b[8] | b[9]<<8 | b[10]<<16, b[11] | b[12]<<8 | b[13]<<16);
+				aa->minfreq = b[8] | b[9]<<8 | b[10]<<16;
+				aa->maxfreq = b[11] | b[12]<<8 | b[13]<<16;
+				aa->caps |= has_contfreq;
+			}else{
+				if (verbose)
+					fprint(2, "discrete frequencies are:");
+				for (ch = 0; ch < b[7] && ch < 8; ch++){
+					aa->freqs[ch] = b[8+3*ch] | b[9+3*ch]<<8 | b[10+3*ch]<<16;
+					if (verbose)
+						fprint(2, " %d", b[8+3*ch] | b[9+3*ch]<<8 | b[10+3*ch]<<16);
+				}
+				if (ch < 8)
+					aa->freqs[ch] = -1;
+				if (verbose)
+					fprint(2, "\n");
+				if (ch > 1)
+					aa->caps |= has_discfreq;	/* more than one frequency */
+				else
+					aa->caps |= onefreq;		/* only one frequency */
+			}
+			aa->nchan = b[4];
+			aa->res = b[6];
+			aa->subframesize = b[5];
+			break;
+		default:
+			if (debug & Dbginfo)
+				pcs_raw("audio stream unknown", bb, nb);
+		}
+		break;
+	case 3: // midi
+	default:
+		if (debug & Dbginfo){
+			fprint(2, "Unknown audio stream type: ");
+			pcs_raw("CS_INTERFACE", bb, nb);
+		}
+	}
+}

+ 0 - 334
sys/src/cmd/usb/audio/config.c

@@ -1,334 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include "usb.h"
-#include "usbproto.h"
-#include "dat.h"
-#include "fns.h"
-#include "audioclass.h"
-
-char reversebits[256] = {
-0,	128,	64,	192,	32,	160,	96,	224,	16,	144,	80,	208,	48,	176,	112,	240,	8,	136,	72,	200,
-40,	168,	104,	232,	24,	152,	88,	216,	56,	184,	120,	248,	4,	132,	68,	196,	36,	164,	100,
-228,	20,	148,	84,	212,	52,	180,	116,	244,	12,	140,	76,	204,	44,	172,	108,	236,	28,	156,
-92,	220,	60,	188,	124,	252,	2,	130,	66,	194,	34,	162,	98,	226,	18,	146,	82,	210,	50,	178,
-114,	242,	10,	138,	74,	202,	42,	170,	106,	234,	26,	154,	90,	218,	58,	186,	122,	250,	6,
-134,	70,	198,	38,	166,	102,	230,	22,	150,	86,	214,	54,	182,	118,	246,	14,	142,	78,	206,
-46,	174,	110,	238,	30,	158,	94,	222,	62,	190,	126,	254,	1,	129,	65,	193,	33,	161,	97,	225,
-17,	145,	81,	209,	49,	177,	113,	241,	9,	137,	73,	201,	41,	169,	105,	233,	25,	153,	89,	217,
-57,	185,	121,	249,	5,	133,	69,	197,	37,	165,	101,	229,	21,	149,	85,	213,	53,	181,	117,
-245,	13,	141,	77,	205,	45,	173,	109,	237,	29,	157,	93,	221,	61,	189,	125,	253,	3,	131,	67,
-195,	35,	163,	99,	227,	19,	147,	83,	211,	51,	179,	115,	243,	11,	139,	75,	203,	43,	171,
-107,	235,	27,	155,	91,	219,	59,	187,	123,	251,	7,	135,	71,	199,	39,	167,	103,	231,	23,
-151,	87,	215,	55,	183,	119,	247,	15,	143,	79,	207,	47,	175,	111,	239,	31,	159,	95,	223,
-63,	191,	127,	255,
-};
-
-static Stream *
-getstream(Audiofunc *af, int i)
-{
-	int j;
-	Dalt *alt;
-	Dconf *c;
-	Dinf *intf;
-	Stream *s;
-	Endpt *ep;
-	uchar *p, *pe, *q;
-	Streamalt *salt, *salttail;
-
-	for(s = af->streams; s != nil; s = s->next)
-		if(s->intf->x == i)
-			return s;
-
-	c = af->intf->conf;
-	intf = &c->iface[i];
-
-	s = emallocz(sizeof(Stream), 1);
-	s->intf = intf;
-	salttail = nil;
-	for(alt = intf->alt; alt != nil; alt = alt->next) {
-		salt = emallocz(sizeof(Streamalt), 1);
-		salt->dalt = alt;
-		salt->next = nil;
-		if(salttail == nil)
-			s->salt = salt;
-		else
-			salttail->next = salt;
-		salttail = salt;
-		p = alt->desc.data;
-		pe = p + alt->desc.bytes;
-		while(p < pe) {
-			if(p[1] == CS_INTERFACE) {
-				switch(p[2]) {
-				case AS_GENERAL:
-					s->id = p[3];
-					salt->delay = p[4];
-					salt->format = GET2(&p[5]);
-					break;
-				case FORMAT_TYPE:
-					switch(p[3]) {
-					case FORMAT_TYPE_I:
-						salt->nchan = p[4];
-						salt->subframe = p[5];
-						salt->res = p[6];
-						salt->nf = p[7];
-						if(salt->nf == 0) {
-							salt->minf = p[8]|(p[9]<<8)|(p[10]<<16);
-							salt->maxf = p[11]|(p[12]<<8)|(p[13]<<16);
-						}
-						else {
-							salt->f = emalloc(salt->nf*sizeof(int));
-							for(j = 0; j < salt->nf; j++) {
-								q = p+8+3*j;
-								salt->f[j] = q[0]|(q[1]<<8)|(q[2]<<16);
-							}
-						}
-						break;
-					default:
-						// werrstr("format type %d not handled", p[3]);
-						salt->unsup = 1;
-						break;
-					}
-					break;
-				case FORMAT_SPECIFIC:
-					break;
-				}
-			}
-			p += p[0];
-		}
-		if(alt->npt > 0) {
-			ep = &alt->ep[0];
-			p = ep->desc.data;
-			pe = p + ep->desc.bytes;
-			while(p < pe) {
-				if(p[1] = CS_ENDPOINT && p[2] == EP_GENERAL) {
-					salt->attr = p[3];
-					salt->lockunits = p[4];
-					salt->lockdelay = GET2(&p[5]);
-				}
-				p += p[0];
-			}
-		}
-	}
-	s->next = af->streams;
-	af->streams = s;
-	return s;
-}
-
-static Stream *
-findstream(Funcalt *falt, int id)
-{
-	int i;
-	Stream *s;
-
-	for(i = 0; i < falt->nstream; i++) {
-		s = falt->stream[i];
-		if(s->id == id)
-			return s;
-	}
-	return nil;
-}
-
-Audiofunc *
-getaudiofunc(Dinf *intf)
-{
-	Dalt *alt;
-	int len, i, j, sz;
-	Audiofunc *af;
-	uchar *p, *pe, *q;
-	Unit *u, *utail, *src;
-	Funcalt *falt, *falttail;
-
-	af = emallocz(sizeof(Audiofunc), 1);
-	af->intf = intf;
-
-	falttail = nil;
-	for(alt = intf->alt; alt != nil; alt = alt->next) {
-		/* scan for audiocontrol ``header'' descriptor */
-		p = alt->desc.data;
-		pe = p + alt->desc.bytes;
-		while(p < pe) {
-			if(p[1] == CS_INTERFACE && p[2] == HEADER)
-				break;
-			p += p[0];
-		}
-		if(p >= pe)
-			continue;
-		len = GET2(&p[5]);
-		if(len > pe-p)
-			len = pe-p;
-		if(p[0] > len || 8+p[7] > p[0]) {
-			werrstr("truncated descriptor");
-			/* BUG: memory leak */
-			return nil;
-		}
-
-		falt = emallocz(sizeof(Funcalt), 1);
-		falt->dalt = alt;
-		falt->next = nil;
-		if(falttail == nil)
-			af->falt = falt;
-		else
-			falttail->next = falt;
-		falttail = falt;
-		falt->nstream = p[7];
-		falt->stream = emallocz(falt->nstream*sizeof(Stream*), 1);
-		for(i = 0; i < falt->nstream; i++) {
-			if((falt->stream[i] = getstream(af, p[8+i])) == nil) {
-				werrstr("getstream: %r");
-				return nil;
-			}
-		}
-		pe = p+len;
-		p += p[0];
-		utail = nil;
-		for(; p < pe; p += p[0]) {
-			if(p[1] != CS_INTERFACE)
-				continue;
-			/* value doesn't appear in standard...
-			if(p[2] == ASSOC_INTERFACE) {
-				if(utail != nil)
-					utail->associf = p[3];
-				continue;
-			}
-			*/
-			u = emallocz(sizeof(Unit), 1);
-			u->type = p[2];
-			u->id = p[3];
-			if(utail == nil)
-				falt->unit = u;
-			else
-				utail->next = u;
-			utail = u;
-			switch(u->type) {
-			case INPUT_TERMINAL:
-				u->termtype = GET2(&p[4]);
-				u->assoc = p[6];
-				u->nchan = p[7];
-				u->chanmask = GET2(&p[8]);
-				break;
-			case OUTPUT_TERMINAL:
-				u->termtype = GET2(&p[4]);
-				u->assoc = p[6];
-				u->nsource = 1;
-				u->sourceid = emalloc(sizeof(int));
-				u->sourceid[0] = p[7];
-				break;
-			case MIXER_UNIT:
-				u->nsource = p[4];
-				u->sourceid = emalloc(u->nsource*sizeof(int));
-				for(i = 0; i < u->nsource; i++)
-					u->sourceid[i] = p[5+i];
-				q = p+5+u->nsource;
-				u->nchan = q[0];
-				u->chanmask = GET2(&q[1]);
-				j = (u->nsource * u->nchan + 7) >> 3;	/* # of bytes */
-				u->hascontrol = emalloc((j + 3) & ~3);	/* rounded up to word boundary */
-				for(i = 0; i < j; i++){
-					if ((i & 3) == 0)
-						u->hascontrol[i >> 2] = 0;
-					/* reverse bits in byte so that bit 0 is input 1 * channel 1*/
-					u->hascontrol[i >> 2] |= reversebits[q[4+i]] << (i & 3);
-				}
-				break;
-			case SELECTOR_UNIT:
-				u->nsource = p[4];
-				u->sourceid = emalloc(u->nsource*sizeof(int));
-				for(i = 0; i < u->nsource; i++)
-					u->sourceid[i] = p[5+i];
-				break;
-			case FEATURE_UNIT:
-				u->nsource = 1;
-				u->sourceid = emalloc(sizeof(int));
-				u->sourceid[0] = p[4];
-				/* need nchan before we can decode bitmaps, defer to later pass */
-				u->fdesc = p;
-				break;
-			case PROCESSING_UNIT:
-				u->proctype = GET2(&p[4]);
-				u->nsource = p[6];
-				u->sourceid = emalloc(u->nsource*sizeof(int));
-				for(i = 0; i < u->nsource; i++)
-					u->sourceid[i] = p[7+i];
-				q = p+7+u->nsource;
-				u->nchan = q[0];
-				u->chanmask = GET2(&q[1]);
-				/* TODO: decode bmControls bitmap and processing-specific section */
-				break;
-			case EXTENSION_UNIT:
-				u->exttype = GET2(&p[4]);
-				u->nsource = p[6];
-				u->sourceid = emalloc(u->nsource*sizeof(int));
-				for(i = 0; i < u->nsource; i++)
-					u->sourceid[i] = p[7+i];
-				q = p+7+u->nsource;
-				u->nchan = q[0];
-				u->chanmask = GET2(&q[1]);
-				/* TODO: decode bmControls bitmap */
-				break;
-			}
-		}
-		/* resolve source references */
-		for(u = falt->unit; u != nil; u = u->next) {
-			if(u->type == INPUT_TERMINAL || u->type == OUTPUT_TERMINAL) {
-				if(u->termtype == USB_STREAMING) {
-					if((u->stream = findstream(falt, u->id)) == nil) {
-						werrstr("stream for terminal id %d not found", u->id);
-						return nil;
-					}
-				}
-			}
-			if(u->nsource == 0)
-				continue;
-			u->source = emallocz(u->nsource*sizeof(Unit*), 1);
-			for(i = 0; i < u->nsource; i++) {
-				for(src = falt->unit; src != nil; src = src->next)
-					if(src->id == u->sourceid[i])
-						break;
-				if(src == nil) {
-					werrstr("source id %d missing", u->sourceid[i]);
-					return nil;
-				}
-				u->source[i] = src;
-			}
-		}
-		/* fill in nchan and chanmask for units which derive it from upstream */
-		for(u = falt->unit; u != nil; u = u->next) {
-			src = u;
-			for(;;) {
-				if(src == nil)
-					break;
-				switch(src->type) {
-				case OUTPUT_TERMINAL:
-				case FEATURE_UNIT:
-				case SELECTOR_UNIT:
-					if(src->nsource == 0) {
-						werrstr("unit id %d (type %d) needs a source", src->id, src->type);
-						return nil;
-					}
-					src = src->source[0];
-					break;
-				default:
-					if(src != u) {
-						u->nchan = src->nchan;
-						u->chanmask = src->chanmask;
-					}
-					goto break2;
-				}
-			}
-			break2:;
-		}
-		/* finish decoding feature units */
-		for(u = falt->unit; u != nil; u = u->next) {
-			if(u->type == FEATURE_UNIT) {
-				q = u->fdesc+5;
-				u->hascontrol = emallocz((u->nchan+1)*sizeof(int), 1);
-				sz = *q++;
-				for(i = 0; i <= u->nchan; i++)
-					for(j = 0; j < sz; j++)
-						u->hascontrol[i] |= *q++ << (j*8);
-			}
-		}
-	}
-	return af;
-}

+ 0 - 660
sys/src/cmd/usb/audio/controls.c

@@ -1,660 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include "usb.h"
-#include "usbproto.h"
-#include "dat.h"
-#include "fns.h"
-#include "audioclass.h"
-
-int buttonendpt =	-1;
-Nexus *nexus[2];
-
-char *controlname[Ncontrol] =
-{
-	[Speed_control]	"speed",
-	[Mute_control]		"mute",
-	[Volume_control]	"volume",
-	[Bass_control]		"bass",
-	[Mid_control]		"mid",
-	[Treble_control]	"treble",
-	[Equalizer_control]	"equalizer",
-	[Agc_control]		"agc",
-	[Delay_control]	"delay",
-	[Bassboost_control]	"bassboost",
-	[Loudness_control]	"loudness",
-	[Mixer_control]	"mixer",
-	[Channel_control]	"channels",
-	[Resolution_control]	"resolution",
-};
-
-Nexus *
-findnexus(char *name)
-{
-	if(strcmp(name, "playback") == 0)
-		return nexus[Play];
-	else if(strcmp(name, "record") == 0)
-		return nexus[Record];
-	else
-		return nil;
-}
-
-int
-controlnum(char *name)
-{
-	int i;
-
-	for(i = 0; i < Ncontrol; i++)
-		if(strcmp(controlname[i], name) == 0)
-			return i;
-	return Undef;
-}
-
-Audiocontrol *
-findcontrol(Nexus *nx, char *name)
-{
-	int i;
-
-	i = controlnum(name);
-	if(i == Undef)
-		return nil;
-	return &nx->control[i];
-}
-
-static void
-resetcontrol(Nexus *nx, int i)
-{
-	Audiocontrol *c;
-
-	c = &nx->control[i];
-	c->min = 1000000;
-	c->max = 0;
-	c->step = Undef;
-}
-
-static void
-controlval(Nexus *nx, int i, int val)
-{
-	Audiocontrol *c;
-
-	c = &nx->control[i];
-	c->value[0] = val;
-	if(val < c->min)
-		c->min = val;
-	if(val > c->max)
-		c->max = val;
-	c->settable = (c->min < c->max);
-	c->readable = 1;
-}
-
-void
-calcbounds(Nexus *nx)
-{
-	int i;
-	Stream *s;
-	Streamalt *sa;
-
-	s = nx->s;
-	if(s == nil)
-		return;
-	resetcontrol(nx, Channel_control);
-	resetcontrol(nx, Resolution_control);
-	resetcontrol(nx, Speed_control);
-	for(sa = s->salt; sa != nil; sa = sa->next) {
-		if(sa->nchan == 0)
-			continue;
-		controlval(nx, Channel_control, sa->nchan);
-		controlval(nx, Resolution_control, sa->res);
-		if(sa->nf == 0) {
-			controlval(nx, Speed_control, sa->minf);
-			controlval(nx, Speed_control, sa->maxf);
-		}
-		else {
-			for(i = 0; i < sa->nf; i++)
-				controlval(nx, Speed_control, sa->f[i]);
-		}
-	}
-}
-
-static Streamalt *
-findalt(Nexus *nx, int nchan, int res, int speed, int *newspeed, int *newi)
-{
-	Stream *s;
-	Streamalt *sa, *bestalt;
-	int i, guess, err, besti, bestguess, besterr;
-
-	s = nx->s;
-	if(s == nil)
-		return nil;
-	bestalt = nil;
-	besti = -1;
-	bestguess = 0;
-	besterr = 0x7fffffff;
-	for(sa = s->salt; sa != nil; sa = sa->next) {
-		if(sa->nchan != nchan || sa->res != res)
-			continue;
-		if(sa->nf == 0) {
-			if(speed < sa->minf)
-				guess = sa->minf;
-			else if(speed > sa->maxf)
-				guess = sa->maxf;
-			else
-				guess = speed;
-			err = abs(speed - guess);
-			if(err < besterr) {
-				bestguess = guess;
-				besti = -1;
-				bestalt = sa;
-				besterr = err;
-			}
-		}
-		else {
-			for(i = 0; i < sa->nf; i++) {
-				err = abs(speed - sa->f[i]);
-				if(err < besterr) {
-					bestguess = sa->f[i];
-					besti = i;
-					bestalt = sa;
-					besterr = err;
-				}
-			}
-		}
-	}
-	*newspeed = bestguess;
-	*newi = besti;
-	return bestalt;
-}
-
-static int
-altctl(Nexus *nx, int ctl, int val)
-{
-	Endpt *ep;
-	Dalt *dalt;
-	Device *d;
-	uchar buf[3];
-	Streamalt *sa;
-	char cmdbuf[32];
-	int ps, speed, newspeed, ind, nchan, res;
-
-	nchan = nx->control[Channel_control].value[0];
-	res = nx->control[Resolution_control].value[0];
-	speed = nx->control[Speed_control].value[0];
-	switch(ctl) {
-	case Channel_control:
-		nchan = val;
-		break;
-	case Resolution_control:
-		res = val;
-		break;
-	case Speed_control:
-		speed = val;
-		break;
-	}
-	sa = findalt(nx, nchan, res, speed, &newspeed, &ind);
-	if(sa == nil) {
-		fprint(2, "cannot find alt: nchan %d res %d speed %d\n", nchan, res, speed);
-		return Undef;
-	}
-	dalt = sa->dalt;
-	if(dalt->npt == 0) {
-		fprint(2, "no endpoint!\n");
-		return Undef;
-	}
-	d = dalt->intf->d;
-	if(setupreq(d, RH2D, SET_INTERFACE, dalt->alt, dalt->intf->x, nil, 0) < 0)
-		return -1;
-	ep = &dalt->ep[0];
-	if(sa->attr & Asampfreq) {
-		if(debug & Dbgcontrol)
-			fprint(2, "Setting speed to %d Hz;", speed);
-		if(ind >= 0) {
-			buf[0] = ind;
-			buf[1] = 0;
-			buf[2] = 0;
-		}
-		else {
-			buf[0] = newspeed;
-			buf[1] = newspeed >> 8;
-			buf[2] = newspeed >> 16;
-		}
-		if(setupreq(d, RH2D|Rclass|Rendpt, SET_CUR, sampling_freq_control<<8, ep->addr, buf, 3) < 0)
-			return Undef;
-		if(setupreq(d, RD2H|Rclass|Rendpt, GET_CUR, sampling_freq_control<<8, ep->addr, buf, 3) != 3)
-			return Undef;
-		if(buf[2]) {
-			if (debug & Dbgcontrol)
-				fprint(2, "Speed out of bounds %d (0x%x)\n",
-					buf[0] | buf[1] << 8 | buf[2] << 16,
-					buf[0] | buf[1] << 8 | buf[2] << 16);
-		}
-		else
-			speed = buf[0] | buf[1] << 8 | buf[2] << 16;
-		if (debug & Dbgcontrol)
-			fprint(2, " speed now %d Hz;", speed);
-	}
-	else
-		speed = newspeed;
-	ps = ((speed * ep->pollms + 999) / 1000) * nchan * res/8;
-	if(ps > ep->maxpkt){
-		fprint(2, "packet size %d > maximum packet size %d", ps, ep->maxpkt);
-		return Undef;
-	}
-	if(debug & Dbgcontrol)
-		fprint(2, "Configuring %s endpoint for %d Hz\n", nx->name, speed);
-	sprint(cmdbuf, "ep %d %d %c %d %d", ep->addr, ep->pollms, ep->dir == Ein ? 'r' : 'w', 
-		nchan*res/8, speed);
-	if(write(d->ctl, cmdbuf, strlen(cmdbuf)) != strlen(cmdbuf)){
-		fprint(2, "writing %s to #U/usb%d/%d/ctl: %r\n", cmdbuf, d->ctlrno, d->id);
-		return Undef;
-	}
-	if (debug & Dbgcontrol) fprint(2, "sent `%s' to /dev/usb%d/%d/ctl\n", cmdbuf, d->ctlrno, d->id);
-	if(ctl == Speed_control)
-		return speed;
-	return val;
-}
-
-static int
-set1(Nexus *nx, int ctl, int req, int i, int val)
-{
-	Device *d;
-	byte buf[2];
-	int type, count, id;
-
-	if(nx->s == nil)
-		return Undef;
-	d = nx->s->intf->d;
-	if(ctl == Mixer_control){
-		if (nx->mixer == nil)
-			return Undef;
-		id = nx->mixer->id<<8;
-	}else{
-		if (nx->feat == nil)
-			return Undef;
-		id = nx->feat->id<<8;
-	}
-	type = RH2D|Rclass|Rinterface;
-	switch(ctl) {
-	case Speed_control:
-	case Channel_control:
-	case Resolution_control:
-		return Undef;
-	case Mixer_control:
-		ctl = 1;	/* hack */
-	case Volume_control:
-	case Delay_control:
-		count = 2;
-		break;
-	default:
-		count = 1;
-		break;
-	}
-	buf[0] = val;
-	buf[1] = val>>8;
-	if(setupreq(d, type, req, (ctl<<8) | i, id, buf, count) < 0)
-		return Undef;
-	return 0;
-}
-
-static int
-set2(Nexus *nx, int ctl, int req, int i, int val)
-{
-	Device *d;
-	byte buf[2];
-	int type, id;
-
-	if(nx->mixer == nil || nx->s == nil)
-		return Undef;
-	d = nx->s->intf->d;
-	id = nx->mixer->id<<8;
-	type = RH2D|Rclass|Rinterface;
-	if (ctl != Mixer_control)
-		return Undef;
-	buf[0] = val;
-	buf[1] = val>>8;
-	if(setupreq(d, type, req, (1<<8) | i, id, buf, 2) < 0)
-		return Undef;
-	return 0;
-}
-
-int
-setcontrol(Nexus *nx, char *name, long *value)
-{
-	int i, ctl, m, req;
-	Audiocontrol *c;
-
-	ctl = controlnum(name);
-	if (ctl == Undef){
-		if (debug & Dbgcontrol) fprint(2, "setcontrol: control not found\n");
-		return -1;
-	}
-	c = &nx->control[ctl];
-	if(c->settable == 0) {
-		if(debug & Dbgcontrol)
-			fprint(2, "setcontrol: control %s.%d not settable\n", nx->name, ctl);
-		if(c->chans) {
-			for(i = 0; i < 8; i++)
-				if((c->chans & 1 << i) && c->value[i] != value[i])
-					return -1;
-			return 0;
-		}
-		if(c->value[0] != value[0])
-			return -1;
-		return 0;
-	}
-	if(c->chans) {
-		value[0] = 0;	// set to average
-		m = 0;
-		for(i = 1; i < 8; i++)
-			if(c->chans & (1 << i)) {
-				if(c->min != Undef && value[i] < c->min)
-					value[i] = c->min;
-				if(c->max != Undef && value[i] > c->max)
-					value[i] = c->max;
-				value[0] += value[i];
-				m++;
-			}
-			else
-				value[i] = Undef;
-		if(m)
-			value[0] /= m;
-	}
-	else {
-		if(c->min != Undef && value[0] < c->min)
-			value[0] = c->min;
-		if(c->max != Undef && value[0] > c->max)
-			value[0] = c->max;
-	}
-	req = SET_CUR;
-	switch(ctl) {
-	default:
-		if(debug & Dbgcontrol)
-			fprint(2, "setcontrol: can't happen\n");
-		return -1;
-	case Speed_control:
-	case Resolution_control:
-	case Channel_control:
-		if((value[0] = altctl(nx, ctl, value[0])) < 0)
-			return -1;
-		c->value[0] = value[0];
-		return 0;
-	case Equalizer_control:
-		/* not implemented */
-		return -1;
-	case Volume_control:
-	case Mixer_control:
-	case Delay_control:
-	case Mute_control:
-	case Bass_control:
-	case Mid_control:
-	case Treble_control:
-	case Agc_control:
-	case Bassboost_control:
-	case Loudness_control:
-		break;
-	}
-	if(c->chans) {
-		for(i = 1; i < 8; i++)
-			if(c->chans & 1 << i) {
-				if(set1(nx, ctl, req, i, value[i]) < 0) {
-					if(debug & Dbgcontrol)
-						fprint(2, "setcontrol: setupcmd %s failed\n",
-							controlname[ctl]);
-					return -1;
-				}
-				c->value[i] = value[i];
-			}
-	}
-	else {
-		if(set1(nx, ctl, req, 0, value[0]) < 0) {
-			if(debug & Dbgcontrol)
-				fprint(2, "setcontrol: setupcmd %s failed\n",
-					controlname[ctl]);
-			return -1;
-		}
-	}
-	c->value[0] = value[0];
-	return 0;
-}
-
-static int
-get1(Nexus *nx, int ctl, int req, int i)
-{
-	Device *d;
-	byte buf[2];
-	int type, count, id;
-
-	if(nx->s == nil)
-		return Undef;
-	d = nx->s->intf->d;
-	if(ctl == Mixer_control){
-		if (nx->mixer == nil)
-			return Undef;
-		id = nx->mixer->id<<8;
-	}else{
-		if (nx->feat == nil)
-			return Undef;
-		id = nx->feat->id<<8;
-	}
-	type = RD2H|Rclass|Rinterface;
-	switch(ctl) {
-	default:
-		count = 1;
-		break;
-	case Mixer_control:
-		ctl = 1;	/* see set1() */
-		/* fall through */
-	case Volume_control:
-	case Delay_control:
-		count = 2;
-		break;
-	case Speed_control:
-	case Channel_control:
-	case Resolution_control:
-		return Undef;
-	}
-	if(setupreq(d, type, req, (ctl<<8) | i, id, buf, count) != count){
-		return Undef;
-	}
-	switch(count) {
-	case 1:
-		return buf[0];
-	case 2:
-		return (short) (buf[0] | (buf[1]<<8));
-	}
-}
-
-static int
-getspecialcontrol(Nexus *nx, int ctl, int req, long *value)
-{
-	int m, i, val;
-	Audiocontrol *c;
-
-	c = &nx->control[ctl];
-	switch(ctl) {
-	default:
-		return Undef;
-	case Speed_control:
-	case Channel_control:
-	case Resolution_control:
-		if(req == GET_MIN)
-			value[0] = c->min;
-		else if(req == GET_MAX)
-			value[0] = c->max;
-		else if(req == GET_RES)
-			value[0] = c->step;
-		else if(req == GET_CUR)
-			value[0] = c->value[0];
-		else
-			value[0] = Undef;
-		return 0;
-	case Mixer_control:
-	case Volume_control:
-	case Delay_control:
-	case Mute_control:
-	case Bass_control:
-	case Mid_control:
-	case Treble_control:
-	case Equalizer_control:
-	case Agc_control:
-	case Bassboost_control:
-	case Loudness_control:
-		break;
-	}
-	if(c->chans) {
-		m = 0;
-		value[0] = 0; // set to average
-		for (i = 1; i < 8; i++){
-			value[i] = Undef;
-			if(c->chans & (1 << i)) {
-				val = get1(nx, ctl, req, i);
-				if(val == Undef)
-					return Undef;
-				if(req == GET_CUR) {
-					value[i] = val;
-					value[0] += val;
-					m++;
-				}
-				else
-					value[0] = val;
-			}
-		}
-		if(m != 0)
-			value[0] /= m;
-		return 0;
-	}
-	value[0] = Undef;
-	val = get1(nx, ctl, req, 0);
-	if(val == Undef)
-		return Undef;
-	value[0] = val;
-	return 0;
-}
-
-int
-getcontrol(Nexus *nx, char *name, long *value)
-{
-	int i;
-	Audiocontrol *c;
-
-	i = controlnum(name);
-	if(i == Undef)
-		return -1;
-	c = &nx->control[i];
-	if(!c->readable)
-		return -1;
-	if(getspecialcontrol(nx, i, GET_CUR, value) < 0)
-		return -1;
-	memmove(c->value, value, sizeof c->value);
-	return 0;
-}
-
-void
-getcontrols(Nexus *nx)
-{
-	int ctl, i;
-	Audiocontrol *c;
-	long v[8];
-
-	for(ctl = 0; ctl < Ncontrol; ctl++) {
-		c = &nx->control[ctl];
-		if(c->readable) {
-			if(verbose)
-				fprint(2, "%s %s control", nx->name, controlname[ctl]);
-			c->min = (getspecialcontrol(nx, ctl, GET_MIN, v) < 0) ? Undef : v[0];
-			if(verbose && c->min != Undef)
-				fprint(2, ", min %ld", c->min);
-			c->max = (getspecialcontrol(nx, ctl, GET_MAX, v) < 0) ? Undef : v[0];
-			if(verbose && c->max != Undef)
-				fprint(2, ", max %ld", c->max);
-			c->step = (getspecialcontrol(nx, ctl, GET_RES, v) < 0) ? Undef : v[0];
-			if(verbose && c->step != Undef)
-				fprint(2, ", step %ld", c->step);
-			if(getspecialcontrol(nx, ctl, GET_CUR, c->value) == 0) {
-				if(verbose) {
-					if(c->chans) {
-						fprint(2, ", values");
-						for(i = 1; i < 8; i++)
-							if(c->chans & (1 << i))
-								fprint(2, "[%d] %ld  ", i, c->value[i]);
-					}
-					else
-						fprint(2, ", value %ld", c->value[0]);
-				}
-			}
-			if(verbose)
-				fprint(2, "\n");
-		}
-		else {
-			c->min = Undef;
-			c->max = Undef;
-			c->step = Undef;
-			c->value[0] = Undef;
-			if (debug & Dbgcontrol)
-				fprint(2, "%s %s control not settable\n", nx->name, controlname[ctl]);
-		}
-	}
-}
-
-int
-ctlparse(char *s, Audiocontrol *c, long *v)
-{
-	int i, j, nf, m;
-	char *vals[9];
-	char *p;
-	long val;
-
-	nf = tokenize(s, vals, nelem(vals));
-	if (nf <= 0)
-		return -1;
-	if (c->chans){
-		j = 0;
-		m = 0;
-		SET(val);
-		v[0] = 0;	// will compute average of v[i]
-		for (i = 1; i < 8; i++)
-			if (c->chans & 1 << i) {
-				if (j < nf){
-					val = strtol(vals[j], &p, 0);
-					if (val == 0 && *p != '\0' && *p != '%')
-						return -1;
-					if (*p == '%' && c->min != Undef)
-						val = (val*c->max + (100-val)*c->min)/100;
-					j++;
-				}
-				v[i] = val;
-				v[0] += val;
-				m++;
-			} else
-				v[i] = Undef;
-		if (m) v[0] /= m;
-	} else {
-		val = strtol(vals[0], &p, 0);
-		if (*p == '%' && c->min != Undef)
-			val = (val*c->max + (100-val)*c->min)/100;
-		v[0] = val;
-	}
-	return 0;
-}
-
-int
-Aconv(Fmt *fp)
-{
-	char str[256];
-	Audiocontrol *c;
-	int fst, i;
-	char *p;
-
-	c = va_arg(fp->args, Audiocontrol*);
-	p = str;
-	if (c->chans) {
-		fst = 1;
-		for (i = 1; i < 8; i++)
-			if (c->chans & 1 << i){
-				p = seprint(p, str+sizeof str, "%s%ld", fst?"'":" ", c->value[i]);
-				fst = 0;
-			}
-		seprint(p, str+sizeof str, "'");
-	} else
-		seprint(p, str+sizeof str, "%ld", c->value[0]);
-	return fmtstrcpy(fp, str);
-}

+ 0 - 183
sys/src/cmd/usb/audio/dat.h

@@ -1,183 +0,0 @@
-typedef struct Audiocontrol Audiocontrol;
-typedef struct Audiofunc Audiofunc;
-typedef struct Funcalt Funcalt;
-typedef struct Nexus Nexus;
-typedef struct Stream Stream;
-typedef struct Streamalt Streamalt;
-typedef struct Unit Unit;
-
-enum
-{
-	master_chan				= 0x00,
-	Speed_control				= 0x00,
-	/* Items below are  defined by USB standard: */
-	Mute_control				= 0x01,
-	Volume_control			= 0x02,
-	Bass_control				= 0x03,
-	Mid_control				= 0x04,
-	Treble_control				= 0x05,
-	Equalizer_control			= 0x06,
-	Agc_control				= 0x07,
-	Delay_control				= 0x08,
-	Bassboost_control			= 0x09,
-	Loudness_control			= 0x0a,
-	Mixer_control				= 0x0b,
-	/* Items below are defined by implementation: */
-	Channel_control			= 0x0c,
-	Resolution_control			= 0x0d,
-	Ncontrol,
-	sampling_freq_control		= 0x01,
-};
-
-enum
-{
-	Undef = 0x80000000,
-	Play = 0,
-	Record = 1,
-};
-
-struct Audiocontrol
-{
-	uchar	readable;
-	uchar	settable;
-	uchar	chans;		/* 0 is master, non-zero is bitmap */
-	long		value[8];		/* 0 is master; value[0] == Undef -> all values Undef */
-	long		min, max, step;
-};
-
-struct Audiofunc
-{
-	Dinf			*intf;
-	Funcalt		*falt;
-	Stream		*streams;	/* cache */
-};
-
-struct Funcalt
-{
-	Dalt			*dalt;		/* interface (alternative) for audiocontrol interface */
-	int			nstream;	/* number of additional interfaces in collection */
-	Stream		**stream;	/* array of audio and midi streams */
-	Unit			*unit;	/* linked list of Units */
-	Funcalt		*next;
-};
-
-struct Stream
-{
-	Dinf			*intf;
-	int			id;		/* associated terminal id */
-	Streamalt		*salt;		/* list of alternates for this stream */
-	Stream		*next;	/* next in cache */
-};
-
-struct Streamalt
-{
-	Dalt			*dalt;		/* interface alternative for this stream alternative */
-	uchar		unsup;		/* set if format type is unknown/unsupported */
-	uchar		delay;
-	ushort		format;
-	uchar		nchan;
-	uchar		subframe;
-	uchar		res;
-	uchar		attr;
-	uchar		lockunits;
-	int			lockdelay;
-	int			minf;
-	int			maxf;
-	uchar		nf;
-	int			*f;
-	Streamalt		*next;	/* in list of alternates */
-};
-
-enum
-{
-	// Streamalt.attr
-	Asampfreq = (1<<0),
-	Apitch = (1<<1),
-	Amaxpkt = (1<<7),
-
-	// Streamalt.lockunits
-	Lundef = 0,
-	Lmillisec = 1,
-	Lsamp = 2,
-};
-
-struct Unit
-{
-	uchar		type;			/* from descriptor subtype */
-	uchar		id;
-	uchar		associf;		/* # of associated interface */
-	uchar		nchan;		/* number of logical channels */
-	ushort		chanmask;	/* spatial location of channels */
-
-	int			nsource;		/* number of inputs (sources) */
-	int			*sourceid;		/* ids of inputs */
-	Unit			**source;		/* pointers to actual Unit structures of inputs */
-
-	union {
-		/* for terminals: */
-		struct {
-			uchar		assoc;		/* id of associated terminal, if any */
-			int			termtype;		/* terminal type */
-			Stream		*stream;		/* associated stream */
-		};
-
-		/* for feature and mixer units: */
-		struct {
-			int			*hascontrol;	/* per-channel bitmasks */
-			uchar		*fdesc;		/* saved descriptor for second pass */
-		};
-
-		/* for processing units: */
-		struct {
-			int			proctype;
-		};
-
-		/* for extension units: */
-		struct {
-			int			exttype;
-		};
-	};
-	Unit			*next;		/* in list of all Units/Terminals */
-};
-
-struct Nexus
-{
-	char			*name;
-	int			id;
-	int			dir;
-	Audiofunc	*af;
-	Funcalt		*alt;
-	Stream		*s;
-	Unit			*input;
-	Unit			*feat;
-	Unit			*mixer;
-	Unit			*output;
-	Audiocontrol	control[Ncontrol];
-	Nexus		*next;
-};
-
-enum
-{
-	/* Nexus.dir */
-	Nin,
-	Nout,
-};
-
-extern Channel *controlchan;
-
-extern int buttonendpt;
-extern Nexus *nexus[2];
-extern char *controlname[Ncontrol];
-
-extern int debug;
-extern int debugdebug;
-extern int verbose;
-
-enum {
-	Dbginfo = 0x01,
-	Dbgfs = 0x02,
-	Dbgproc = 0x04,
-	Dbgcontrol = 0x08,
-};
-
-#pragma	varargck	type	"A"	Audiocontrol*

+ 0 - 260
sys/src/cmd/usb/audio/dump.c

@@ -1,260 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include "usb.h"
-#include "usbproto.h"
-#include "dat.h"
-#include "fns.h"
-#include "audioclass.h"
-
-static char *unittype[] =
-{
-	[INPUT_TERMINAL]		"Input Terminal",
-	[OUTPUT_TERMINAL]	"Output Terminal",
-	[MIXER_UNIT]			"Mixer Unit",
-	[SELECTOR_UNIT]		"Selector Unit",
-	[FEATURE_UNIT]		"Feature Unit",
-	[PROCESSING_UNIT]		"Processing Unit",
-	[EXTENSION_UNIT]		"Extension Unit",
-};
-
-typedef struct Namelist Namelist;
-struct Namelist
-{
-	short	index;
-	char		*name;
-};
-
-static Namelist termtypes[] =
-{
-	{ USB_UNDEFINED, "USB Terminal, undefined type"},
-	{ USB_STREAMING, "USB Streaming"},
-	{ USB_VENDOR, "USB Vendor-Specific"},
-
-	{ INPUT_UNDEFINED, "Input, undefined type"},
-	{ MICROPHONE, "Microphone"},
-	{ DESK_MICROPHONE, "Desk Microphone"},
-	{ PERSONAL_MICROPHONE, "Personal Microphone"},
-	{ OMNI_MICROPHONE, "Omni-directional Microphone"},
-	{ MICROPHONE_ARRAY, "Microphone Array"},
-	{ PROC_MICROPHONE_ARRAY, "Processing Microphone Array"},
-
-	{ OUTPUT_UNDEFINED, "Output Undefined"},
-	{ SPEAKER, "Speaker"},
-	{ HEADPHONES, "Headphones"},
-	{ HMD_AUDIO, "Head Mounted Display Audio"},
-	{ DESK_SPEAKER, "Desk Speaker"},
-	{ ROOM_SPEAKER, "Room Speaker"},
-	{ COMM_SPEAKER, "Communication Speaker"},
-	{ LFE_SPEAKER, "Low Frequency Effects Speaker"},
-
-	{ BIDIRECTIONAL_UNDEFINED, "Bi-directional Undefined"},
-	{ HANDSET, "Handset"},
-	{ HEADSET, "Headset"},
-	{ SPEAKERPHONE, "Speakerphone"},
-	{ ECHO_SUPP_SPEAKERPHONE, "Echo-suppressing Speakerphone"},
-	{ ECHO_CANC_SPEAKERPHONE, "Echo-cancelling Speakerphone"},
-
-	{ TELEPHONY_UNDEFINED, "Telephony Undefined"},
-	{ PHONELINE, "Phone Line"},
-	{ TELEPHONE, "Telephone"},
-	{ DOWN_LINE_PHONE, "Down Line Phone"},
-
-	{ EXTERNAL_UNDEFINED, "External Undefined"},
-	{ ANALOG_CONNECTOR, "Analog Connector"},
-	{ DIGITAL_AUDIO, "Digital Audio Interface"},
-	{ LINE_CONNECTOR, "Line Connector"},
-	{ LEGACY_AUDIO, "Legacy Audio Connector"},
-	{ SPDIF_INTERFACE, "S/PDIF Interface"},
-	{ I1394_DA, "1394 DA Stream"},
-	{ I1394_DV, "1394 DV Stream Soundtrack"},
-
-	{ EMBEDDED_UNDEFINED, "Embedded Undefined"},
-	{ LEVEL_CALIBRATION_NOICE_SOURCE, "Level Calibration Noise Source"},
-	{ EQUALIZATION_NOISE, "Equalization Noise"},
-	{ CD_PLAYER, "CD Player"},
-	{ DAT, "DAT"},
-	{ DCC, "DCC"},
-	{ MINIDISK, "MiniDisk"},
-	{ ANALOG_TAPE, "Analog Tape"},
-	{ PHONOGRAPH, "Phonograph"},
-	{ VCR_AUDIO, "VCR Audio"},
-	{ VIDEODISC_AUDIO, "Video Disc Audio"},
-	{ DVD_AUDIO, "DVD Audio"},
-	{ TVTUNER_AUDIO, "TV Tuner Audio"},
-	{ SATELLITE_AUDIO, "Satellite Receiver Audio"},
-	{ CABLETUNER_AUDIO, "Cable Tuner Audio"},
-	{ DSS_AUDIO, "DSS Audio"},
-	{ RADIO_RECEIVER, "Radio Receiver"},
-	{ RADIO_TRANSMITTER, "Radio Transmitter"},
-	{ MULTITRACK_RECORDER, "Multi-track Recorder"},
-	{ SYNTHESIZER, "Synthesizer"},
-
-	{ 0, nil }
-};
-
-static Namelist featcontrols[] =
-{
-	{ MUTE_CONTROL-1, "Mute"},
-	{ VOLUME_CONTROL-1, "Volume"},
-	{ BASS_CONTROL-1, "Bass"},
-	{ MID_CONTROL-1, "Mid"},
-	{ TREBLE_CONTROL-1, "Treble"},
-	{ EQUALIZER_CONTROL-1, "Equalizer"},
-	{ AGC_CONTROL-1, "AGC"},
-	{ DELAY_CONTROL-1, "Delay"},
-	{ BASS_BOOST_CONTROL-1, "Bass Boost"},
-	{ LOUDNESS_CONTROL-1, "Loudness"},
-
-	{ 0, nil }
-};
-
-static Namelist formats[] =
-{
-	/* type 1 */
-	{ PCM, "PCM"},
-	{ PCM8, "PCM8"},
-	{ IEEE_FLOAT, "IEEE_FLOAT"},
-	{ ALAW, "ALAW"},
-	{ MULAW, "MULAW"},
-
-	/* type 2 */
-	{ MPEG, "MPEG"},
-	{ AC_3, "AC-3"},
-
-	/* type 3 */
-	{ IEC1937_AC_3, "IEC1937 AC-3"},
-	{ IEC1937_MPEG1_L1, "IEC1937 MPEG-1 Layer 1"},
-	{ IEC1937_MPEG1_L2_3, "IEC1937 MPEG-1 Layer 2/3"},
-	{ IEC1937_MPEG2_NOEXT, "IEC1937 MPEG-2 NOEXT"},
-	{ IEC1937_MPEG2_EXT, "IEC1937 MPEG-2 EXT"},
-	{ IEC1937_MPEG2_L1_LS, "IEC1937 MPEG-2 Layer 1_LS"},
-	{ IEC1937_MPEG2_L2_3_LS, "IEC1937 MPEG-2 Layer 2/3_LS"},
-
-	{ 0, nil }
-};
-
-static Namelist spatials[] =
-{
-	{ 0, "Left Front"},
-	{ 1, "Right Front"},
-	{ 2, "Center Front"},
-	{ 3, "Low Frequency Enhancement"},
-	{ 4, "Left Surround"},
-	{ 5, "Right Surround"},
-	{ 6, "Left of Center"},
-	{ 7, "Right of Center"},
-	{ 8, "Surround"},
-	{ 9, "Side Left"},
-	{ 10, "Side Right"},
-	{ 11, "Top"},
-
-	{ 0, nil }
-};
-
-static char *
-namefor(Namelist *list, int item)
-{
-	while (list->name){
-		if (list->index == item)
-			return list->name;
-		list++;
-	}
-	return "<unnamed>";
-}
-
-static void
-dumpbits(Namelist *list, int bits)
-{
-	int i, spoke;
-
-	fprint(2, "{");
-	spoke = 0;
-	for(i = 0; i < 8*sizeof(int); i++) {
-		if(bits & (1<<i)) {
-			fprint(2, "%s%s", spoke ? ", " : " ", namefor(list, i));
-			spoke = 1;
-		}
-	}
-	fprint(2, " }\n");
-}
-
-void
-dumpaudiofunc(Audiofunc *af)
-{
-	int i;
-	Unit *u;
-	Dalt *dalt;
-	Dinf *intf;
-	Stream *s;
-	Funcalt *falt;
-	Streamalt *salt;
-
-	intf = af->intf;
-	fprint(2, "audio function on %D config %d interface %d\n", intf->d, intf->conf->x, intf->x);
-	for(falt = af->falt; falt != nil; falt = falt->next) {
-		fprint(2, "\tcontrol alt %d, %d streams\n", falt->dalt->alt, falt->nstream);
-		for(u = falt->unit; u != nil; u = u->next) {
-			fprint(2, "\t\tunit id %d: %s\n", u->id, unittype[u->type]);
-			fprint(2, "\t\t\t%d channels, spatial location mask %.4x\n", u->nchan, u->chanmask);
-			fprint(2, "\t\t\t");
-			dumpbits(spatials, u->chanmask);
-			switch(u->type) {
-			case INPUT_TERMINAL:
-			case OUTPUT_TERMINAL:
-				fprint(2, "\t\t\tterminal type %.4x: %s\n", u->termtype, namefor(termtypes, u->termtype));
-				if(u->assoc != 0)
-					fprint(2, "\t\t\tassociated terminal id %d\n", u->assoc);
-				break;
-			case MIXER_UNIT:
-				fprint(2, "\t\t\tmixer controls (sources × channels = %d × %d)",
-					u->nsource, u->nchan);
-				for(i = 0; i < (u->nsource*u->nchan+31) >> 5; i++)
-					fprint(2, " %.8ux", u->hascontrol[i]);
-				fprint(2, "\n");
-				break;
-			case FEATURE_UNIT:
-				fprint(2, "\t\t\tmaster hascontrol %.4x ", u->hascontrol[0]);
-				dumpbits(featcontrols, u->hascontrol[0]);
-				for(i = 1; i <= u->nchan; i++) {
-					fprint(2, "\t\t\tchannel %d hascontrol %.4x ", i, u->hascontrol[i]);
-					dumpbits(featcontrols, u->hascontrol[i]);
-				}
-				break;
-			case PROCESSING_UNIT:
-				fprint(2, "\t\t\tprocessing type %.4x\n", u->proctype);
-				break;
-			case EXTENSION_UNIT:
-				fprint(2, "\t\t\textension type %.4x\n", u->exttype);
-				break;
-			}
-			for(i = 0; i < u->nsource; i++)
-				fprint(2, "\t\t\tsource id %d\n", u->sourceid[i]);
-		}
-		for(i = 0; i < falt->nstream; i++) {
-			s = falt->stream[i];
-			fprint(2, "\t\tstream %d\n", s->id);
-		}
-	}
-	for(s = af->streams; s != nil; s = s->next) {
-		fprint(2, "\tstream id %d on interface %d\n", s->id, s->intf->x);
-		for(salt = s->salt; salt != nil; salt = salt->next) {
-			dalt = salt->dalt;
-			fprint(2, "\t\talt %d: ", dalt->alt);
-			if(dalt->npt == 0 || dalt->ep[0].maxpkt == 0) {
-				fprint(2, "disabled\n");
-				continue;
-			}
-			fprint(2, "delay %dms format %.4x (%s) channel %d subframe %d res %d\n",
-				salt->delay, salt->format, namefor(formats, salt->format), salt->nchan, salt->subframe, salt->res);
-			if(salt->nf == 0)
-				fprint(2, "\t\t\tfrequency range %d-%d\n", salt->minf, salt->maxf);
-			else {
-				fprint(2, "\t\t\tfrequencies:");
-				for(i = 0; i < salt->nf; i++)
-					fprint(2, " %d", salt->f[i]);
-				fprint(2, "\n");
-			}
-		}
-	}
-}

+ 0 - 19
sys/src/cmd/usb/audio/fns.h

@@ -1,19 +0,0 @@
-/* config.c */
-Audiofunc *getaudiofunc(Dinf*);
-
-/* controls.c */
-Nexus *findnexus(char *name);
-Audiocontrol *findcontrol(Nexus *nx, char *name);
-void	calcbounds(Nexus *nx);
-int	setcontrol(Nexus *nx, char *name, long *value);
-int	getcontrol(Nexus *nx, char *name, long *value);
-void	getcontrols(Nexus *nx);
-int	ctlparse(char *s, Audiocontrol *c, long *v);
-int	Aconv(Fmt *fp);
-
-/* dump.c */
-void dumpaudiofunc(Audiofunc*);
-
-/* fs.c */
-void	serve(void *);
-void	ctlevent(void);

+ 0 - 429
sys/src/cmd/usb/audio/main.c

@@ -1,429 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include "usb.h"
-#include "usbproto.h"
-#include "dat.h"
-#include "fns.h"
-#include "audioclass.h"
-
-#define STACKSIZE 16*1024
-
-extern char *srvpost;
-char * mntpt;
-int debug;
-int debugdebug;
-int verbose;
-
-Channel *controlchan;
-
-char audstr[]		= "Enabled 0x000101\n";	/* audio.control.0 */
-
-Nexus *nexushd;
-Nexus *nexustl;
-
-void
-makenexus(Audiofunc *af, Funcalt *alt, Unit *output)
-{
-	int i, ch;
-	Nexus *nx;
-	Unit *u, *feat;
-	static int idgen;
-	Audiocontrol *c;
-	Stream *ins, *outs;
-
-	nx = emallocz(sizeof(Nexus), 1);
-	nx->af = af;
-	nx->alt = alt;
-	nx->output = output;
-	nx->id = idgen++;
-	for(u = output; u != nil; u = u->source[0]) {
-		switch(u->type) {
-		case INPUT_TERMINAL:
-			nx->input = u;
-			break;
-		case MIXER_UNIT:
-			nx->mixer = u;
-			break;
-		case FEATURE_UNIT:
-			nx->feat = u;
-			break;
-		}
-		if(u->nsource == 0)
-			break;
-	}
-	if(nx->input == nil) {
-		free(nx);
-		return;
-	}
-	ins = nx->output->stream;
-	outs = nx->input->stream;
-	if(ins == nil && outs == nil || ins != nil && outs != nil) {
-		free(nx);
-		return;
-	}
-	if(ins != nil) {
-		nx->s = ins;
-		nx->dir = Nin;
-	}
-	else {
-		nx->s = outs;
-		nx->dir = Nout;
-	}
-
-	memset(nx->control, 0, sizeof(nx->control));
-	for(i = 0; i < Ncontrol; i++) {
-		c = &nx->control[i];
-		c->step = Undef;
-	}
-	calcbounds(nx);
-	feat = nx->feat;
-	if(feat != nil) {
-		for(i = Mute_control; i < Mixer_control; i++) {
-			c = &nx->control[i];
-			for(ch = 0; ch <= feat->nchan; ch++) {
-				if((feat->hascontrol[ch] & (1<<(i-1))) == 0)
-					continue;
-				c->readable = 1;
-				c->settable = 1;
-				if(ch > 0)
-					c->chans |= (1<<ch);
-			}
-		}
-	}
-	feat = nx->mixer;
-	if(feat != nil) {
-		c = &nx->control[Mixer_control];
-		for(ch = 1; ch <= feat->nchan; ch++) {
-			if((feat->hascontrol[((ch-1)*feat->nsource)>>5] & (1 << (((ch-1)*feat->nsource) & 31))) == 0)
-				continue;
-			c->readable = 1;
-			c->settable = 1;
-			c->chans |= (1<<ch);
-		}
-	}
-
-	if(nexushd == nil)
-		nexushd = nx;
-	else
-		nexustl->next = nx;
-	nexustl = nx;
-}
-
-int
-adddevice(Device *d)
-{
-	int i;
-	Unit *u;
-	Dconf *c;
-	Dinf *intf;
-	ulong csp;
-	Audiofunc *af;
-
-	if(d->nconf < 1)
-		sysfatal("no configurations???");
-
-	/* we only handle first config for now -- most devices only have 1 anyway */
-	c = &d->config[0];
-	for(i = 0; i < c->nif; i++) {
-		intf = &c->iface[i];
-		if(intf == nil)
-			continue;
-		csp = intf->csp;
-		if(Class(csp) == CL_AUDIO && Subclass(csp) == AUDIOCONTROL) {
-			if((af = getaudiofunc(intf)) == nil)
-				return -1;
-			if(debug)
-				dumpaudiofunc(af);
-			for(u = af->falt->unit; u != nil; u = u->next)
-				if(u->type == OUTPUT_TERMINAL)
-					makenexus(af, af->falt, u);
-		}
-		if(Class(csp) == CL_HID && Subclass(csp) == 0) {
-			if (verbose)
-				fprint(2, "Buttons on endpoint %d\n", i);
-			if(intf->alt->npt == 1)
-				buttonendpt = intf->alt->ep[0].addr;
-		}
-	}
-	return 0;
-}
-
-void
-controlproc(void *)
-{
-	/* Proc that looks after /dev/usb/%d/ctl */
-	int nf;
-	Nexus *nx;
-	long value[8];
-	Audiocontrol *c;
-	char *req, *args[8];
-	Channel *replchan;
-
-	while(req = recvp(controlchan)) {
-		nf = tokenize(req, args, nelem(args));
-		if (nf < 3)
-			sysfatal("controlproc: not enough arguments");
-		replchan = (Channel*)strtol(args[0], nil, 0);
-		nx = findnexus(args[2]);
-		if(nx == nil) {
-			/* illegal request */
-			if (debug) fprint(2, "%s must be record or playback", args[2]);
-			if (replchan) chanprint(replchan, "%s must be record or playback", args[2]);
-			free(req);
-			continue;
-		}
-		c = findcontrol(nx, args[1]);
-		if (c == nil){
-			if (debug) fprint(2, "Illegal control name: %s", args[1]);
-			if (replchan) chanprint(replchan, "Illegal control name: %s", args[1]);
-		}else if (!c->settable){
-			if (debug & Dbginfo) fprint(2, "%s %s is not settable", args[1], args[2]);
-			if (replchan)
-				chanprint(replchan, "%s %s is not settable", args[1], args[2]);
-		}else if (nf < 4){
-			if (debug & Dbginfo) fprint(2, "insufficient arguments for %s %s",
-					args[1], args[2]);
-			if (replchan)
-				chanprint(replchan, "insufficient arguments for %s %s",
-					args[1], args[2]);
-		}else if (ctlparse(args[3], c, value) < 0) {
-			if (replchan)
-				chanprint(replchan, "parse error in %s %s", args[1], args[2]);
-		} else {
-			if (debug & Dbginfo)
-				fprint(2, "controlproc: setcontrol %s %s %s\n", nx->name, args[1], args[3]);
-			if (setcontrol(nx, args[1], value) < 0){
-				if (replchan)
-					chanprint(replchan, "setting %s %s failed", args[1], args[2]);
-			}else{
-				if (replchan) chanprint(replchan, "ok");
-			}
-			ctlevent();
-		}
-		free(req);
-	}
-}
-
-void
-buttonproc(void *x)
-{
-	int i, fd, b;
-	Device *d;
-	uchar buf[1];
-	Audiocontrol *c;
-	char fname[64], err[32];
-
-	d = x;
-	sprint(fname, "/dev/usb%d/%d/ep%ddata", d->ctlrno, d->id, buttonendpt);
-	if (debug & Dbginfo) fprint(2, "buttonproc opening %s\n", fname);
-	if ((fd = open(fname, OREAD)) < 0)
-		sysfatal("Can't open %s: %r", fname);
-
-	c = &nexus[Play]->control[Volume_control];
-	for (;;) {
-		if ((b = read(fd, buf, 1)) < 0){
-			rerrstr(err, sizeof err);
-			if (strcmp(err, "interrupted") == 0){
-				if (debug & Dbginfo) fprint(2, "read interrupted\n");
-				continue;
-			}
-			sysfatal("read %s: %r", fname);
-		}
-		if (b == 0 || buf[0] == 0){
-			continue;
-		}else if (buf[0] == 1){
-			if (c->chans == 0)
-				c->value[0] += c->step;
-			else
-				for (i = 1; i < 8; i++)
-					if (c->chans & 1 << i)
-						c->value[i] += c->step;
-			chanprint(controlchan, "0 volume playback %A", c);
-		}else if (buf[0] == 2){
-			if (c->chans == 0)
-				c->value[0] -= c->step;
-			else
-				for (i = 1; i < 8; i++)
-					if (c->chans & 1 << i)
-						c->value[i] -= c->step;
-			chanprint(controlchan, "0 volume playback %A", c);
-		}else if (debug & Dbginfo){
-			fprint(2, "button");
-			for (i = 0; i < b; i++)
-				fprint(2, " %#2.2x", buf[i]);
-			fprint(2, "\n");
-		}
-	}
-}
-
-void
-findendpoints(void)
-{
-	Nexus *nx;
-
-	for(nx = nexushd; nx != nil; nx = nx->next) {
-		switch(nx->dir) {
-		case Nin:
-			nx->name = "record";
-			nexus[Record] = nx;
-			break;
-		case Nout:
-			nx->name = "play";
-			nexus[Play] = nx;
-			break;
-		}
-	}
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: usbaudio [-d] [-v volume[%%]] [-s srvname] [-m mountpoint] [ctrlno id]\n");
-	threadexitsall("usage");
-}
-
-void
-threadmain(int argc, char **argv)
-{
-	Device *d;
-	Nexus *nx;
-	long value[8];
-	long volume[8];
-	Audiocontrol *c;
-	int ctlrno, id, i, sfd;
-	char buf[32], *p, line[256];
-
-	ctlrno = -1;
-	id = -1;
-	volume[0] = Undef;
-	for (i = 0; i<8; i++)
-		value[i] = 0;
-	fmtinstall('A', Aconv);
-	quotefmtinstall();
-	usbfmtinit();
-
-	ARGBEGIN{
-	case 'd':
-		debug = strtol(ARGF(), nil, 0);
-		if (debug == -1) debugdebug++;
-		verbose++;
-		break;
-	case 'v':
-		volume[0] = strtol(ARGF(), &p, 0);
-		for(i = 1; i < 8; i++)
-			volume[i] = volume[0];
-		break;
-	case 'm':
-		mntpt = ARGF();
-		break;
-	case 's':
-		srvpost = ARGF();
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	switch (argc) {
-	case 0:
-		for (ctlrno = 0; ctlrno < 16; ctlrno++) {
-			for (i = 1; i < 128; i++) {
-				sprint(buf, "/dev/usb%d/%d/status", ctlrno, i);
-				sfd = open(buf, OREAD);
-				if (sfd < 0)
-					break;
-				if (read(sfd, line, strlen(audstr)) == strlen(audstr)
-				 && strncmp(audstr, line, strlen(audstr)) == 0) {
-					id = i;
-					goto found;
-				}
-				close(sfd);
-			}
-		}
-		if (verbose) fprint(2, "No usb audio\n");
-		threadexitsall("usbaudio not found");
-	found:
-		break;
-	case 2:
-		ctlrno = atoi(argv[0]);
-		id = atoi(argv[1]);
-		break;
-	default:
-		usage();
-	}
-
-	d = opendev(ctlrno, id);
-
-	if(describedevice(d) < 0)
-		sysfatal("usbaudio: %r");
-
-	if(adddevice(d) < 0)
-		sysfatal("usbaudio: adddevice: %r");
-
-	controlchan = chancreate(sizeof(char*), 8);
-
-	findendpoints();
-
-	nx = nexus[Play];
-	if(nx != nil) {
-		value[0] = 2;
-		if(setcontrol(nx, "channels", value) == Undef)
-			sysfatal("Can't set play channels");
-		value[0] = 16;
-		if(setcontrol(nx, "resolution", value) == Undef)
-			sysfatal("Can't set play resolution");
-		getcontrols(nx);	/* Get the initial value of all controls */
-		value[0] = 44100;
-		if(setcontrol(nx, "speed", value) < 0){
-			fprint(2, "warning: Can't set play speed to %d\n", value[0]);
-			value[0] = 48000;
-			if(setcontrol(nx, "speed", value) < 0)
-				fprint(2, "warning: Can't set play speed to %d\n", value[0]);
-			else
-				fprint(2, "warning: Play speed set to %d\n", value[0]);
-		}
-		value[0] = 0;
-		setcontrol(nx, "mute", value);
-		if(volume[0] != Undef) {
-			c = &nx->control[Volume_control];
-			if(*p == '%' && c->min != Undef)
-				for (i = 0; i < 8; i++)
-					volume[i] = (volume[i]*c->max + (100-volume[i])*c->min)/100;
-			if(c->settable)
-				setcontrol(nx, "volume", volume);
-		}
-	}
-
-	nx = nexus[Record];
-	if(nx != nil) {
-		value[0] = 2;
-		if(setcontrol(nx, "channels", value) == Undef)
-			sysfatal("Can't set record channels");
-		value[0] = 16;
-		if(setcontrol(nx, "resolution", value) == Undef)
-			sysfatal("Can't set record resolution");
-		getcontrols(nx);	/* Get the initial value of all controls */
-		value[0] = 44100;
-		if(setcontrol(nx, "speed", value) < 0)
-			fprint(2, "Can't set record speed\n");
-		if(volume[0] != Undef) {
-			c = &nx->control[Volume_control];
-			if(c->settable)
-				setcontrol(nx, "volume", volume);
-		}
-	}
-
-	nx = nexus[Play];
-	if(buttonendpt > 0 && nx != nil) {
-		sprint(buf, "ep %d bulk r 1 1", buttonendpt);
-		if(debug) fprint(2, "sending `%s' to /dev/usb/%d/ctl\n", buf, id);
-		if(write(d->ctl, buf, strlen(buf)) > 0)
-			proccreate(buttonproc, nx->s->intf->d, STACKSIZE);
-		else
-			fprint(2, "Could not configure button endpoint: %r\n");
-	}
-	proccreate(controlproc, nil, STACKSIZE);
-	proccreate(serve, nil, STACKSIZE);
-
-	threadexits(nil);
-}

+ 11 - 14
sys/src/cmd/usb/audio/mkfile

@@ -2,28 +2,25 @@
 
 TARG=usbaudio
 OFILES=\
-	config.$O\
-	dump.$O\
-	controls.$O\
-	fs.$O\
-	main.$O\
+	audiofs.$O\
+	audiosub.$O\
+	usbaudio.$O\
+	usbaudioctl.$O\
 
 HFILES=\
-	dat.h\
-	fns.h\
-	audioclass.h\
+	usbaudio.h\
+	usbaudioctl.h\
 	../lib/usb.h\
-	../lib/usbproto.h\
-
-LIB=../lib/usb.a$O
-
-BIN=/$objtype/bin/usb
 
 UPDATE=\
-	mkfile\
 	$HFILES\
 	${OFILES:%.$O=%.c}\
+	mkfile\
+	/sys/man/3/usb\
+
+LIB=../lib/usb.a$O
 
+BIN=/$objtype/bin/usb
 </sys/src/cmd/mkone
 
 CFLAGS=-I../lib $CFLAGS

+ 397 - 0
sys/src/cmd/usb/audio/usbaudio.c

@@ -0,0 +1,397 @@
+/*
+ * USB audio driver for Plan 9
+ */
+
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "usb.h"
+#include "usbaudio.h"
+#include "usbaudioctl.h"
+
+#define STACKSIZE 16*1024
+
+extern char* srvpost;
+char * mntpt;
+
+Channel *controlchan;
+
+char audstr[]		= "Enabled 0x000101\n";	/* audio.control.0 */
+
+int defaultspeed[2] = {44100, 44100};
+
+static void
+audio_endpoint(Device *d, int c, ulong csp, void *bb, int n)
+{
+	int ifc;
+	int dalt;
+	byte *b = bb;
+
+	if (c >= nelem(d->config)) {
+		fprint(2, "Too many interfaces (%d of %d)\n",
+			c, nelem(d->config));
+		return;
+	}
+	dalt=csp>>24;
+	ifc = csp>>16 & 0xff;
+
+	switch(b[2]) {
+	case 0x01:
+		if (debug){
+			fprint(2, "CS_ENDPOINT for attributes 0x%x, lockdelayunits %d, lockdelay %#ux, ",
+				b[3], b[4], b[5] | (b[6]<<8));
+			if (b[3] & has_setspeed)
+				fprint(2, "has sampling-frequency control");
+			else
+				fprint(2, "does not have sampling-frequency control");
+			if (b[3] & 0x1<<1)
+				fprint(2, ", has pitch control");
+			else
+				fprint(2, ", does not have pitch control");
+			if (b[3] & 0x1<<7)
+				fprint(2, ", max packets only");
+			fprint(2, "\n");
+		}
+		if (d->config[c] == nil)
+			sysfatal("d->config[%d] == nil", c);
+		if (d->config[c]->iface[ifc] == nil)
+			sysfatal("d->config[%d]->iface[%d] == nil", c, ifc);
+		if (d->config[c]->iface[ifc]->dalt[dalt] == nil)
+			d->config[c]->iface[ifc]->dalt[dalt] = mallocz(sizeof(Dalt),1);
+		if (d->config[c]->iface[ifc]->dalt[dalt]->devspec == nil)
+			d->config[c]->iface[ifc]->dalt[dalt]->devspec= mallocz(sizeof(Audioalt),1);
+		((Audioalt*)d->config[c]->iface[ifc]->dalt[dalt]->devspec)->caps |= b[3];
+		break;
+	case 0x02:
+		if (debug){
+			fprint(2, "CS_INTERFACE FORMAT_TYPE %d, channels %d, subframesize %d, resolution %d, freqtype %d, ",
+				b[3], b[4], b[5], b[6], b[7]);
+			fprint(2, "freq0 %d, freq1 %d\n",
+				b[8] | (b[9]<<8) | (b[10]<<16), b[11] | (b[12]<<8) | (b[13]<<16));
+		}
+		break;
+	default:
+		if (debug) pcs_raw("CS_INTERFACE", bb, n);
+	}
+}
+
+void (*dprinter[])(Device *, int, ulong, void *b, int n) = {
+	[STRING] pstring,
+	[DEVICE] pdevice,
+	[0x21] phid,
+	[0x24] audio_interface,
+	[0x25] audio_endpoint,
+};
+
+enum {
+	None,
+	Volumeset,
+	Volumeget,
+	Altset,
+	Altget,
+	Speedget,
+};
+
+void
+controlproc(void *)
+{
+	/* Proc that looks after /dev/usb/%d/ctl */
+	int i, nf;
+	char *req, *args[8];
+	Audiocontrol *c;
+	long value[8];
+	Channel *replchan;
+
+	while(req = recvp(controlchan)){
+		int rec;
+
+		nf = tokenize(req, args, nelem(args));
+		if (nf < 3)
+			sysfatal("controlproc: not enough arguments");
+		replchan = (Channel*)strtol(args[0], nil, 0);
+		if (strcmp(args[2], "playback") == 0)
+			rec = Play;
+		else if (strcmp(args[2], "record") == 0)
+			rec = Record;
+		else{
+			/* illegal request */
+			if (debug) fprint(2, "%s must be record or playback", args[2]);
+			if (replchan) chanprint(replchan, "%s must be record or playback", args[2]);
+			free(req);
+			continue;
+		}
+		c = nil;
+		for (i = 0; i < Ncontrol; i++){
+			c = &controls[rec][i];
+			if (strcmp(args[1], c->name) == 0)
+				break;
+		}
+		if (i == Ncontrol){
+			if (debug) fprint(2, "Illegal control name: %s", args[1]);
+			if (replchan) chanprint(replchan, "Illegal control name: %s", args[1]);
+		}else if (!c->settable){
+			if (debug & Dbginfo) fprint(2, "%s %s is not settable", args[1], args[2]);
+			if (replchan)
+				chanprint(replchan, "%s %s is not settable", args[1], args[2]);
+		}else if (nf < 4){
+			if (debug & Dbginfo) fprint(2, "insufficient arguments for %s %s",
+					args[1], args[2]);
+			if (replchan)
+				chanprint(replchan, "insufficient arguments for %s %s",
+					args[1], args[2]);
+		}else if (ctlparse(args[3], c, value) < 0) {
+			if (replchan)
+				chanprint(replchan, "parse error in %s %s", args[1], args[2]);
+		} else {
+			if (debug & Dbginfo)
+				fprint(2, "controlproc: setcontrol %s %s %s\n",
+					rec?"in":"out", args[1], args[3]);
+			if (setcontrol(rec, args[1], value) < 0){
+				if (replchan)
+					chanprint(replchan, "setting %s %s failed", args[1], args[2]);
+			}else{
+				if (replchan) chanprint(replchan, "ok");
+			}
+			ctlevent();
+		}
+		free(req);
+	}
+}
+
+void
+buttonproc(void *) {
+	int	i, fd, b;
+	char fname[64], err[32];
+	byte buf[1];
+	Audiocontrol *c;
+
+	sprint(fname, "/dev/usb%d/%d/ep%ddata", ad->ctlrno, ad->id, buttonendpt);
+	if (debug & Dbginfo) fprint(2, "buttonproc opening %s\n", fname);
+	if ((fd = open(fname, OREAD)) < 0)
+		sysfatal("Can't open %s: %r", fname);
+
+	c = &controls[Play][Volume_control];
+	for (;;) {
+		if ((b = read(fd, buf, 1)) < 0){
+			rerrstr(err, sizeof err);
+			if (strcmp(err, "interrupted") == 0){
+				if (debug & Dbginfo) fprint(2, "read interrupted\n");
+				continue;
+			}
+			sysfatal("read %s: %r", fname);
+		}
+		if (b == 0 || buf[0] == 0){
+			continue;
+		}else if (buf[0] == 1){
+			if (c->chans == 0)
+				c->value[0] += c->step;
+			else
+				for (i = 1; i < 8; i++)
+					if (c->chans & 1 << i)
+						c->value[i] += c->step;
+			chanprint(controlchan, "0 volume playback %A", c);
+		}else if (buf[0] == 2){
+			if (c->chans == 0)
+				c->value[0] -= c->step;
+			else
+				for (i = 1; i < 8; i++)
+					if (c->chans & 1 << i)
+						c->value[i] -= c->step;
+			chanprint(controlchan, "0 volume playback %A", c);
+		}else if (debug & Dbginfo){
+			fprint(2, "button");
+			for (i = 0; i < b; i++)
+				fprint(2, " %#2.2x", buf[i]);
+			fprint(2, "\n");
+		}
+	}
+}
+
+void
+findendpoints(void)
+{
+	Endpt *ep;
+	int i, rec;
+
+	for (i = 0; i < Nendpt; i++) {
+		if ((ep = ad->ep[i]) == nil)
+			continue;
+		switch(ep->csp){
+		default:
+			break;
+		case CSP(CL_AUDIO, 2, 0):
+			if (ep->iface == nil)
+				break;
+			rec = (ep->iface->addr &  0x80)?1:0;
+			if (verbose)
+				fprint(2, "%s on endpoint %d\n", rec?"Record":"Playback", i);
+			endpt[rec] = i;
+			interface[rec] = ep->iface->interface;
+			break;
+		case CSP(CL_HID, 0, 0):
+			if (verbose)
+				fprint(2, "Buttons on endpoint %d\n", i);
+			buttonendpt = i;
+			break;
+		}
+	}
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: usbaudio [-V] [-v volume[%%]] [-m mountpoint] [-s srvname] [ctrlno id]\n");
+	threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	int ctlrno, id, i, sfd;
+	long value[8];
+	long volume[8];
+	Audiocontrol *c;
+	char buf[32], *p, line[256];
+
+	ctlrno = -1;
+	id = -1;
+	volume[0] = Undef;
+	for (i = 0; i<8; i++)
+		value[i] = 0;
+	fmtinstall('A', Aconv);
+	quotefmtinstall();
+
+	ARGBEGIN{
+	case 'V':
+		verbose++;
+		break;
+	case 'd':
+		debug = strtol(ARGF(), nil, 0);
+		if (debug == -1) debugdebug++;
+		verbose++;
+		break;
+	case 'v':
+		volume[0] = strtol(ARGF(), &p, 0);
+		for(i = 1; i < 8; i++)
+			volume[i] = volume[0];
+		break;
+	case 'm':
+		mntpt = ARGF();
+		break;
+	case 's':
+		srvpost = ARGF();
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	switch (argc) {
+	case 0:
+		for (ctlrno = 0; ctlrno < 16; ctlrno++) {
+			for (i = 1; i < 128; i++) {
+				sprint(buf, "/dev/usb%d/%d/status", ctlrno, i);
+				sfd = open(buf, OREAD);
+				if (sfd < 0)
+					break;
+				if (read(sfd, line, strlen(audstr)) == strlen(audstr)
+				 && strncmp(audstr, line, strlen(audstr)) == 0) {
+					id = i;
+					goto found;
+				}
+				close(sfd);
+			}
+		}
+		if (verbose) fprint(2, "No usb audio\n");
+		threadexitsall("usbaudio not found");
+	found:
+		break;
+	case 2:
+		ctlrno = atoi(argv[0]);
+		id = atoi(argv[1]);
+		break;
+	default:
+		usage();
+	}
+
+	ad = opendev(ctlrno, id);
+
+	if (describedevice(ad) < 0)
+		sysfatal("describedevice");
+
+	for(i=0; i<ad->nconf; i++) {
+		if (ad->config[i] == nil)
+			ad->config[i] = mallocz(sizeof(*ad->config[i]),1);
+		loadconfig(ad, i);
+	}
+
+	controlchan = chancreate(sizeof(char*), 8);
+
+	findendpoints();
+
+	if (endpt[Play] >= 0){
+		if(findalt(Play, 2, 16, defaultspeed[Play]) < 0){
+			if(findalt(Play, 2, 16, 48000) < 0)
+				sysfatal("Can't configure playout for %d or %d Hz", defaultspeed[Play], 48000);
+			fprint(2, "Warning, can't configure playout for %d Hz, configuring for %d Hz instead\n",
+				defaultspeed[Play], 48000);
+			defaultspeed[Play] = 48000;
+		}
+		value[0] = 2;
+		if (setcontrol(Play, "channels", value) == Undef)
+			sysfatal("Can't set play channels\n");
+		value[0] = 16;
+		if (setcontrol(Play, "resolution", value) == Undef)
+			sysfatal("Can't set play resolution\n");
+	}
+
+	if (endpt[Record] >= 0){
+		if(findalt(Record, 2, 16, defaultspeed[Record]) < 0){
+			if(findalt(Record, 2, 16, 48000) < 0)
+				sysfatal("Can't configure record for %d or %d Hz", defaultspeed[Record], 48000);
+			fprint(2, "Warning, can't configure record for %d Hz, configuring for %d Hz instead\n",
+				defaultspeed[Record], 48000);
+			defaultspeed[Record] = 48000;
+		}
+		value[0] = 2;
+		if (setcontrol(Record, "channels", value) == Undef)
+			sysfatal("Can't set record channels\n");
+		value[0] = 16;
+		if (setcontrol(Record, "resolution", value) == Undef)
+			sysfatal("Can't set record resolution\n");
+	}
+
+	getcontrols();	/* Get the initial value of all controls */
+	value[0] = defaultspeed[Play];
+	if (endpt[Play] >= 0 && setcontrol(Play, "speed", value) < 0)
+		sysfatal("Can't set play speed\n");
+	value[0] = defaultspeed[Record];
+	if (endpt[Record] >= 0 && setcontrol(Record, "speed", value) < 0)
+		sysfatal("Can't set record speed\n");
+	value[0] = 0;
+	setcontrol(Play, "mute", value);
+
+	if (volume[0] != Undef){
+		c = &controls[Play][Volume_control];
+		if (*p == '%' && c->min != Undef)
+			for (i = 0; i < 8; i++)
+				volume[i] = (volume[i]*c->max + (100-volume[i])*c->min)/100;
+		if (c->settable)
+			setcontrol(Play, "volume", volume);
+		c = &controls[Record][Volume_control];
+		if (c->settable)
+			setcontrol(Record, "volume", volume);
+	}
+
+	if (buttonendpt > 0){
+		sprint(buf, "ep %d bulk r 1 1", buttonendpt);
+		if (debug) fprint(2, "sending `%s' to /dev/usb/%d/ctl\n", buf, id);
+		if (write(ad->ctl, buf, strlen(buf)) > 0)
+			proccreate(buttonproc, nil, STACKSIZE);
+		else
+			fprint(2, "Could not configure button endpoint: %r\n");
+	}
+	proccreate(controlproc, nil, STACKSIZE);
+	proccreate(serve, nil, STACKSIZE);
+
+	threadexits(nil);
+}

+ 72 - 0
sys/src/cmd/usb/audio/usbaudio.h

@@ -0,0 +1,72 @@
+
+enum {
+	master_chan		= 0x00,
+	Speed_control		= 0x00,
+	/* Items below are  defined by USB standard: */
+	Mute_control		= 0x01,
+	Volume_control		= 0x02,
+	Bass_control		= 0x03,
+	Mid_control		= 0x04,
+	Treble_control		= 0x05,
+	Equalizer_control	= 0x06,
+	Agc_control		= 0x07,
+	Delay_control		= 0x08,
+	Bassboost_control	= 0x09,
+	Loudness_control	= 0x0a,
+	/* Items below are define by implementation: */
+	Channel_control		= 0x0b,
+	Resolution_control	= 0x0c,
+	Ncontrol,
+	sampling_freq_control	= 0x01,
+};
+
+
+#define AS_GENERAL 1
+#define FORMAT_TYPE 2
+#define FORMAT_SPECIFIC 3
+
+#define PCM 1
+#define PCM8 2
+#define IEEE_FLOAT 3
+#define ALAW 4
+#define MULAW 5
+
+#define SAMPLING_FREQ_CONTROL 0x01
+
+typedef struct Audioalt Audioalt;
+
+struct Audioalt {
+	int		nchan;
+	int		res;
+	int		subframesize;
+	int		minfreq, maxfreq;	/* continuous freqs */
+	int		freqs[8];		/* discrete freqs */
+	int		caps;		/* see below for meanings */
+};
+
+enum {
+	/* Audioalt->caps bits */
+	has_setspeed = 0x1,		/* has a speed_set command */
+	has_pitchset = 0x2,		/* has a pitch_set command */
+	has_contfreq = 0x4,		/* frequency continuously variable */
+	has_discfreq = 0x8,		/* discrete set of frequencies */
+	onefreq = 0x10,		/* only one frequency */
+	maxpkt_only = 0x80,	/* packets must be padded to max size */
+};
+
+extern int defaultspeed[2];
+extern Device *ad;
+extern Channel *controlchan;
+
+void	audio_interface(Device *d, int n, ulong csp, void *bb, int nb);
+void	setalt(Device *d, int endpt, int value);
+int	getalt(Device *d, int endpt);
+int	setspeed(int rec, int speed);
+int	setcontrol(int rec, char *name, long *value);
+int	getspecialcontrol(int rec, int ctl, int req, long *value);
+int	getcontrol(int rec, char *name, long *value);
+int	findalt(int rec, int nchan, int res, int speed);
+void	getcontrols(void);
+void	serve(void *);
+int	nbchanprint(Channel *c, char *fmt, ...);
+int	Aconv(Fmt *fp);

+ 660 - 0
sys/src/cmd/usb/audio/usbaudioctl.c

@@ -0,0 +1,660 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "usb.h"
+#include "usbaudio.h"
+#include "usbaudioctl.h"
+
+int endpt[2] =		{-1, -1};
+int interface[2] =	{-1, -1};
+int featureid[2] =	{-1, -1};
+int selectorid[2] =	{-1, -1};
+int curalt[2] =		{-1, -1};
+int buttonendpt =	-1;
+
+int id;
+Device *ad;
+
+Audiocontrol controls[2][Ncontrol] = {
+	{
+	[Speed_control] = {		"speed",		0, {0}, 0,	44100,	Undef},
+	[Mute_control] = {		"mute",		0, {0}, 0,	0,		Undef},
+	[Volume_control] = {	"volume",		0, {0}, 0,	0,		Undef},
+	[Bass_control] = {		"bass",		0, {0}, 0,	0,		Undef},
+	[Mid_control] = {		"mid",		0, {0}, 0,	0,		Undef},
+	[Treble_control] = {		"treble",		0, {0}, 0,	0,		Undef},
+	[Equalizer_control] = {	"equalizer",	0, {0}, 0,	0,		Undef},
+	[Agc_control] = {		"agc",		0, {0}, 0,	0,		Undef},
+	[Delay_control] = {		"delay",		0, {0}, 0,	0,		Undef},
+	[Bassboost_control] = {	"bassboost",	0, {0}, 0,	0,		Undef},
+	[Loudness_control] = {	"loudness",	0, {0}, 0,	0,		Undef},
+	[Channel_control] = {	"channels",	0, {0}, 0,	2,		Undef},
+	[Resolution_control] = {	"resolution",	0, {0}, 0,	16,		Undef},
+	}, {
+	[Speed_control] = {		"speed",		0, {0}, 0,	44100,	Undef},
+	[Mute_control] = {		"mute",		0, {0}, 0,	0,		Undef},
+	[Volume_control] = {	"volume",		0, {0}, 0,	0,		Undef},
+	[Bass_control] = {		"bass",		0, {0}, 0,	0,		Undef},
+	[Mid_control] = {		"mid",		0, {0}, 0,	0,		Undef},
+	[Treble_control] = {		"treble",		0, {0}, 0,	0,		Undef},
+	[Equalizer_control] = {	"equalizer",	0, {0}, 0,	0,		Undef},
+	[Agc_control] = {		"agc",		0, {0}, 0,	0,		Undef},
+	[Delay_control] = {		"delay",		0, {0}, 0,	0,		Undef},
+	[Bassboost_control] = {	"bassboost",	0, {0}, 0,	0,		Undef},
+	[Loudness_control] = {	"loudness",	0, {0}, 0,	0,		Undef},
+	[Channel_control] = {	"channels",	0, {0}, 0,	2,		Undef},
+	[Resolution_control] = {	"resolution",	0, {0}, 0,	16,		Undef},
+	}
+};
+
+int
+setaudioalt(int rec, Audiocontrol *c, int control)
+{
+	if (debug & Dbgcontrol)
+		fprint(2, "setcontrol %s: Set alt %d\n", c->name, control);
+	curalt[rec] = control;
+	if (setupcmd(ad->ep[0], RH2D|Rstandard|Rinterface, SET_INTERFACE, control, interface[rec], nil, 0) < 0){
+		if (debug & Dbgcontrol) fprint(2, "setcontrol: setupcmd %s failed\n", c->name);
+			return -1;
+	}
+	return control;
+}
+
+int
+findalt(int rec, int nchan, int res, int speed)
+{
+	Endpt *ep;
+	Audioalt *a;
+	Dalt *da;
+	int i, j, k, retval;
+
+	retval = -1;
+	controls[rec][Channel_control].min = 1000000;
+	controls[rec][Channel_control].max = 0;
+	controls[rec][Channel_control].step = Undef;
+	controls[rec][Resolution_control].min = 1000000;
+	controls[rec][Resolution_control].max = 0;
+	controls[rec][Resolution_control].step = Undef;
+	for (i = 0; i < Nendpt; i++) {
+		if ((ep = ad->ep[i]) == nil)
+			continue;
+		if(ep->csp != CSP(CL_AUDIO, 2, 0))
+			continue;
+		if (ep->iface == nil) {
+			fprint(2, "\tno interface\n");
+			return 0;
+		}
+		if ((rec == Play && (ep->iface->addr &  0x80))
+		|| (rec == Record && (ep->iface->addr &  0x80) == 0))
+			continue;
+		for (j = 0; j < 16; j++) {
+			if ((da = ep->iface->dalt[j]) == nil || (a = da->devspec) == nil)
+				continue;
+			if (a->nchan < controls[rec][Channel_control].min)
+				controls[rec][Channel_control].min = a->nchan;
+			if (a->nchan > controls[rec][Channel_control].max)
+				controls[rec][Channel_control].max = a->nchan;
+			if (a->res < controls[rec][Resolution_control].min)
+				controls[rec][Resolution_control].min = a->res;
+			if (a->res > controls[rec][Resolution_control].max)
+				controls[rec][Resolution_control].max = a->res;
+			controls[rec][Channel_control].settable = 1;
+			controls[rec][Channel_control].readable = 1;
+			controls[rec][Resolution_control].settable = 1;
+			controls[rec][Resolution_control].readable = 1;
+			controls[rec][Speed_control].settable = 1;
+			controls[rec][Speed_control].readable = 1;
+			if (a->nchan == nchan && a->res == res){
+				if(speed == Undef)
+					retval = j;
+				else if(a->caps & (has_discfreq|onefreq)){
+					for(k = 0; k < nelem(a->freqs); k++){
+						if(a->freqs[k] == speed){
+							retval = j;
+							break;
+						}
+					}
+				} else {
+					if(speed >= a->minfreq && speed <= a->maxfreq)
+						retval = j;
+				}
+			}
+		}
+	}
+	if ((debug & Dbgcontrol) && retval < 0){
+		fprint(2, "findalt(%d, %d, %d, %d) failed\n", rec, nchan, res, speed);
+	}
+	return retval;
+}
+
+int
+setspeed(int rec, int speed)
+{
+	int ps, n, no;
+	Audioalt *a;
+	Dalt *da;
+	Endpt *ep;
+	char cmdbuf[32];
+	uchar buf[3];
+
+	if (curalt[rec] < 0){
+		fprint(2, "Must set channels and resolution before speed\n");
+		return Undef;
+	}
+	if (endpt[rec] < 0)
+		sysfatal("endpt[%s] not set\n", rec?"Record":"Playback");
+	ep = ad->ep[endpt[rec]];
+	if (ep->iface == nil)
+		sysfatal("no interface");
+	if (curalt[rec] < 0)
+		sysfatal("curalt[%s] not set\n", rec?"Record":"Playback");
+	da = ep->iface->dalt[curalt[rec]];
+	a = da->devspec;
+	no = -1;
+	if (a->caps & onefreq){
+		speed = a->freqs[0];		/* speed not settable, but packet size must still be set */
+	}else if (a->caps & has_contfreq){
+		if (speed < a->minfreq)
+			speed = a->minfreq;
+		else if (speed > a->maxfreq)
+			speed = a->maxfreq;
+		if (debug & Dbgcontrol)
+			fprint(2, "Setting continuously variable %s speed to %d\n",
+				rec?"record":"playback", speed);
+	}else if (a->caps & has_discfreq){
+		int dist, i;
+		dist = 1000000;
+		no = -1;
+		for (i = 0; a->freqs[i] > 0; i++)
+			if (abs(a->freqs[i] - speed) < dist){
+				dist = abs(a->freqs[i] - speed);
+				no = i;
+			}
+		if (no == -1){
+			if (debug & Dbgcontrol)
+				fprint(2, "no = -1\n");
+			return Undef;
+		}
+		speed = a->freqs[no];
+		if (debug & Dbgcontrol)
+			fprint(2, "Setting discreetly variable %s speed to %d\n",
+				rec?"record":"playback", speed);
+	}else{
+		if (debug & Dbgcontrol)
+			fprint(2, "can't happen\n?");
+		return Undef;
+	}
+	if (a->caps & has_setspeed){
+		if (debug & Dbgcontrol)
+			fprint(2, "Setting %s speed to %d Hz;",
+				rec?"record":"playback", speed);
+		if (a->caps & has_discfreq){
+			buf[0] = no;
+			buf[1] = 0;
+			buf[2] = 0;
+		}else{
+			buf[0] = speed;
+			buf[1] = speed >> 8;
+			buf[2] = speed >> 16;
+		}
+		if (setupcmd(ad->ep[0], RH2D|Rclass|Rendpt, SET_CUR, sampling_freq_control<<8, endpt[rec], buf, 3) < 0)
+			return Undef;
+		if (setupreq(ad->ep[0], RD2H|Rclass|Rendpt, GET_CUR, sampling_freq_control<<8, endpt[rec], 3) < 0)
+			return Undef;
+		n = setupreply(ad->ep[0], buf, 3);
+		if (n != 3)
+			return Undef;
+		if (buf[2]){
+			if (debug & Dbgcontrol)
+				fprint(2, "Speed out of bounds %d (0x%x)\n",
+					buf[0] | buf[1] << 8 | buf[2] << 16,
+					buf[0] | buf[1] << 8 | buf[2] << 16);
+		}else
+			speed = buf[0] | buf[1] << 8 | buf[2] << 16;
+		if (debug & Dbgcontrol)
+			fprint(2, " speed now %d Hz;", speed);
+	}
+	ps = ((speed * da->interval + 999) / 1000)
+		* controls[rec][Channel_control].value[0]
+		* controls[rec][Resolution_control].value[0]/8;
+	if(ps > da->maxpkt){
+		fprint(2, "packet size %d > maximum packet size %d",
+			ps, da->maxpkt);
+		return Undef;
+	}
+	if (debug & Dbgcontrol)
+		fprint(2, "Configuring %s endpoint for %d Hz\n",
+				rec?"record":"playback", speed);
+	sprint(cmdbuf, "ep %d %d %c %ld %d", endpt[rec], da->interval, rec?'r':'w', 
+		controls[rec][Channel_control].value[0]*controls[rec][Resolution_control].value[0]/8,
+		speed);
+	if (write(ad->ctl, cmdbuf, strlen(cmdbuf)) != strlen(cmdbuf)){
+		fprint(2, "writing %s to #U/usb/%d/ctl: %r\n", cmdbuf, id);
+		return Undef;
+	}
+	if (debug & Dbgcontrol) fprint(2, "sent `%s' to /dev/usb/%d/ctl\n", cmdbuf, id);
+	return speed;
+}
+
+long
+getspeed(int rec, int which)
+{
+	int i, n;
+	Audioalt *a;
+	Dalt *da;
+	Endpt *ep;
+	uchar buf[3];
+
+	if (curalt[rec] < 0){
+		fprint(2, "Must set channels and resolution before getspeed\n");
+		return Undef;
+	}
+	if (endpt[rec] < 0)
+		sysfatal("endpt[%s] not set\n", rec?"Record":"Playback");
+	ep = ad->ep[endpt[rec]];
+	if (ep->iface == nil)
+		sysfatal("no interface");
+	if (curalt[rec] < 0)
+		sysfatal("curalt[%s] not set\n", rec?"Record":"Playback");
+	da = ep->iface->dalt[curalt[rec]];
+	a = da->devspec;
+	if (a->caps & onefreq){
+		if (which == GET_RES)
+			return Undef;
+		return a->freqs[0];		/* speed not settable */
+	}else if (a->caps & has_setspeed){
+		if (setupreq(ad->ep[0], RD2H|Rclass|Rendpt, which, sampling_freq_control<<8, endpt[rec], 3) < 0)
+			return Undef;
+		n = setupreply(ad->ep[0], buf, 3);
+		if (n != 3)
+			return Undef;
+		if (buf[2]){
+			if (debug & Dbgcontrol)
+				fprint(2, "Speed out of bounds\n");
+			if ((a->caps & has_discfreq) && (buf[0] | buf[1] << 8) < 8)
+				return a->freqs[buf[0] | buf[1] << 8];
+		}
+		return buf[0] | buf[1] << 8 | buf[2] << 16;
+	}else if (a->caps & has_contfreq){
+		if (which == GET_CUR)
+			return controls[rec][Speed_control].value[0];
+		if (which == GET_MIN)
+			return a->minfreq;
+		if (which == GET_MAX)
+			return a->maxfreq;
+		if (which == GET_RES)
+			return 1;
+	}else if (a->caps & has_discfreq){
+		if (which == GET_CUR)
+			return controls[rec][Speed_control].value[0];
+		if (which == GET_MIN)
+			return a->freqs[0];
+		for (i = 0; i < 8 && a->freqs[i] > 0; i++)
+			;
+		if (which == GET_MAX)
+			return a->freqs[i-1];
+		if (which == GET_RES)
+			return Undef;
+	}
+	if (debug & Dbgcontrol)
+		fprint(2, "can't happen\n?");
+	return Undef;
+}
+
+int
+setcontrol(int rec, char *name, long *value)
+{
+	int i, ctl, m;
+	byte buf[3];
+	int type, req, control, index, count;
+	Audiocontrol *c;
+
+	c = nil;
+	for (ctl = 0; ctl < Ncontrol; ctl++){
+		c = &controls[rec][ctl];
+		if (strcmp(name, c->name) == 0)
+			break;
+	}
+	if (ctl == Ncontrol){
+		if (debug & Dbgcontrol) fprint(2, "setcontrol: control not found\n");
+		return -1;
+	}
+	if (c->settable == 0) {
+		if (debug & Dbgcontrol) fprint(2, "setcontrol: control %d.%d not settable\n", rec, ctl);
+		if (c->chans){
+			for (i = 0; i < 8; i++)
+				if ((c->chans & 1 << i) && c->value[i] != value[i])
+					return -1;
+			return 0;
+		}
+		if (c->value[0] != value[0])
+			return -1;
+		return 0;
+	}
+	if (c->chans){
+		value[0] = 0;	// set to average
+		m = 0;
+		for (i = 1; i < 8; i++)
+			if (c->chans & 1 << i){
+				if (c->min != Undef && value[i] < c->min)
+					value[i] = c->min;
+				if (c->max != Undef && value[i] > c->max)
+					value[i] = c->max;
+				value[0] += value[i];
+				m++;
+			} else
+				value[i] = Undef;
+		if (m) value[0] /= m;
+	}else{
+		if (c->min != Undef && value[0] < c->min)
+			value[0] = c->min;
+		if (c->max != Undef && value[0] > c->max)
+			value[0] = c->max;
+	}
+	req = SET_CUR;
+	count = 1;
+	switch(ctl){
+	default:
+		if (debug & Dbgcontrol) fprint(2, "setcontrol: can't happen\n");
+		return -1;
+	case Speed_control:
+		if ((value[0] = setspeed(rec, value[0])) < 0)
+			return -1;
+		c->value[0] = value[0];
+		return 0;
+	case Equalizer_control:
+		/* not implemented */
+		return -1;
+	case Resolution_control:
+		control = findalt(rec, controls[rec][Channel_control].value[0], value[0], defaultspeed[rec]);
+		if(control < 0 || setaudioalt(rec, c, control) < 0){
+			if (debug & Dbgcontrol) fprint(2, "setcontrol: can't find setting for %s\n",
+				c->name);
+			return -1;
+		}
+		c->value[0] = value[0];
+		controls[rec][Speed_control].value[0] = defaultspeed[rec];
+		return 0;
+	case Volume_control:
+	case Delay_control:
+		count = 2;
+		/* fall through */
+	case Mute_control:
+	case Bass_control:
+	case Mid_control:
+	case Treble_control:
+	case Agc_control:
+	case Bassboost_control:
+	case Loudness_control:
+		type = RH2D|Rclass|Rinterface;
+		control = ctl<<8;
+		index = featureid[rec]<<8;
+		break;
+	case Channel_control:
+		control = findalt(rec, value[0], controls[rec][Resolution_control].value[0], defaultspeed[rec]);
+		if(control < 0 || setaudioalt(rec, c, control) < 0){
+			if (debug & Dbgcontrol) fprint(2, "setcontrol: can't find setting for %s\n",
+				c->name);
+			return -1;
+		}
+		c->value[0] = value[0];
+		controls[rec][Speed_control].value[0] = defaultspeed[rec];
+		return 0;
+	}
+	if (c->chans){
+		for (i = 1; i < 8; i++)
+			if (c->chans & 1 << i){
+				switch(count){
+				case 2:
+					buf[1] = value[i] >> 8;
+				case 1:
+					buf[0] = value[i];
+				}
+				if (setupcmd(ad->ep[0], type, req, control | i, index, buf, count) < 0){
+					if (debug & Dbgcontrol) fprint(2, "setcontrol: setupcmd %s failed\n",
+						controls[rec][ctl].name);
+					return -1;
+				}
+				c->value[i] = value[i];
+			}
+	}else{
+		switch(count){
+		case 2:
+			buf[1] = value[0] >> 8;
+		case 1:
+			buf[0] = value[0];
+		}
+		if (setupcmd(ad->ep[0], type, req, control, index, buf, count) < 0){
+			if (debug & Dbgcontrol) fprint(2, "setcontrol: setupcmd %s failed\n",
+				c->name);
+			return -1;
+		}
+	}
+	c->value[0] = value[0];
+	return 0;
+}
+
+int
+getspecialcontrol(int rec, int ctl, int req, long *value)
+{
+	byte buf[3];
+	int m, n, i;
+	int type, control, index, count;
+	short svalue;
+
+	count = 1;
+	switch(ctl){
+	default:
+		return Undef;
+	case Speed_control:
+		value[0] =  getspeed(rec, req);
+		return 0;
+	case Channel_control:
+	case Resolution_control:
+		if (req == GET_MIN)
+			value[0] = controls[rec][ctl].min;
+		if (req == GET_MAX)
+			value[0] = controls[rec][ctl].max;
+		if (req == GET_RES)
+			value[0] = controls[rec][ctl].step;
+		if (req == GET_CUR)
+			value[0] = controls[rec][ctl].value[0];
+		return 0;
+	case Volume_control:
+	case Delay_control:
+		count = 2;
+		/* fall through */
+	case Mute_control:
+	case Bass_control:
+	case Mid_control:
+	case Treble_control:
+	case Equalizer_control:
+	case Agc_control:
+	case Bassboost_control:
+	case Loudness_control:
+		type = RD2H|Rclass|Rinterface;
+		control = ctl<<8;
+		index = featureid[rec]<<8;
+		break;
+	}
+	if (controls[rec][ctl].chans){
+		m = 0;
+		value[0] = 0; // set to average
+		for (i = 1; i < 8; i++){
+			value[i] = Undef;
+			if (controls[rec][ctl].chans & 1 << i){
+				if (setupreq(ad->ep[0], type, req, control | i, index, count) < 0)
+					return Undef;
+				n = setupreply(ad->ep[0], buf, count);
+				if (n != count)
+					return -1;
+				switch (count) {
+				case 2:
+					svalue = buf[1] << 8 | buf[0];
+					if (req == GET_CUR){
+						value[i] = svalue;
+						value[0] += svalue;
+						m++;
+					}else
+						value[0] = svalue;
+					break;
+				case 1:
+					if (req == GET_CUR){
+						value[i] = buf[0];
+						value[0] += buf[0];
+						m++;
+					}else
+						value[0] = buf[0];
+				}
+			}
+		}
+		if (m) value[0] /= m;
+		return 0;
+	}
+	value[0] = Undef;
+	if (setupreq(ad->ep[0], type, req, control, index, count) < 0)
+		return -1;
+	n = setupreply(ad->ep[0], buf, count);
+	if (n != count)
+		return -1;
+	switch (count) {
+	case 2:
+		svalue = buf[1] << 8 | buf[0];
+		value[0] = svalue;
+		break;
+	case 1:
+		value[0] = buf[0];
+	}
+	return 0;
+}
+
+int
+getcontrol(int rec, char *name, long *value)
+{
+	int i;
+
+	for (i = 0; i < Ncontrol; i++){
+		if (strcmp(name, controls[rec][i].name) == 0)
+			break;
+	}
+	if (i == Ncontrol)
+		return -1;
+	if (controls[rec][i].readable == 0)
+		return -1;
+	if(getspecialcontrol(rec, i, GET_CUR, value) < 0)
+		return -1;
+	memmove(controls[rec][i].value, value, sizeof controls[rec][i].value);
+	return 0;
+}
+
+void
+getcontrols(void)
+{
+	int rec, ctl, i;
+	Audiocontrol *c;
+	long v[8];
+
+	for (rec = 0; rec < 2; rec++)
+		for (ctl = 0; ctl < Ncontrol; ctl++){
+			c = &controls[rec][ctl];
+			if (c->readable){
+				if (verbose)
+					fprint(2, "%s %s control",
+						rec?"Record":"Playback", controls[rec][ctl].name);
+				c->min = (getspecialcontrol(rec, ctl, GET_MIN, v) < 0) ? Undef : v[0];
+				if (verbose && c->min != Undef)
+					fprint(2, ", min %ld", c->min);
+				c->max = (getspecialcontrol(rec, ctl, GET_MAX, v) < 0) ? Undef : v[0];
+				if (verbose && c->max != Undef)
+					fprint(2, ", max %ld", c->max);
+				c->step = (getspecialcontrol(rec, ctl, GET_RES, v) < 0) ? Undef : v[0];
+				if (verbose && c->step != Undef)
+					fprint(2, ", step %ld", c->step);
+				if (getspecialcontrol(rec, ctl, GET_CUR, c->value) == 0){
+					if (verbose) {
+						if (c->chans){
+							fprint(2, ", values");
+							for (i = 1; i < 8; i++)
+								if (c->chans & 1 << i)
+									fprint(2, "[%d] %ld  ", i, c->value[i]);
+						}else
+							fprint(2, ", value %ld", c->value[0]);
+					}
+				}
+				if (verbose)
+					fprint(2, "\n");
+			} else {
+				c->min = Undef;
+				c->max = Undef;
+				c->step = Undef;
+				c->value[0] = Undef;
+				if (debug & Dbgcontrol)
+					fprint(2, "%s %s control not settable\n",
+						rec?"Playback":"Record", controls[rec][ctl].name);
+			}
+		}
+}
+
+int
+ctlparse(char *s, Audiocontrol *c, long *v)
+{
+	int i, j, nf, m;
+	char *vals[9];
+	char *p;
+	long val;
+
+	nf = tokenize(s, vals, nelem(vals));
+	if (nf <= 0)
+		return -1;
+	if (c->chans){
+		j = 0;
+		m = 0;
+		SET(val);
+		v[0] = 0;	// will compute average of v[i]
+		for (i = 1; i < 8; i++)
+			if (c->chans & 1 << i) {
+				if (j < nf){
+					val = strtol(vals[j], &p, 0);
+					if (val == 0 && *p != '\0' && *p != '%')
+						return -1;
+					if (*p == '%' && c->min != Undef)
+						val = (val*c->max + (100-val)*c->min)/100;
+					j++;
+				}
+				v[i] = val;
+				v[0] += val;
+				m++;
+			} else
+				v[i] = Undef;
+		if (m) v[0] /= m;
+	} else {
+		val = strtol(vals[0], &p, 0);
+		if (*p == '%' && c->min != Undef)
+			val = (val*c->max + (100-val)*c->min)/100;
+		v[0] = val;
+	}
+	return 0;
+}
+
+int
+Aconv(Fmt *fp)
+{
+	char str[256];
+	Audiocontrol *c;
+	int fst, i;
+	char *p;
+
+	c = va_arg(fp->args, Audiocontrol*);
+	p = str;
+	if (c->chans) {
+		fst = 1;
+		for (i = 1; i < 8; i++)
+			if (c->chans & 1 << i){
+				p = seprint(p, str+sizeof str, "%s%ld", fst?"'":" ", c->value[i]);
+				fst = 0;
+			}
+		seprint(p, str+sizeof str, "'");
+	} else
+		seprint(p, str+sizeof str, "%ld", c->value[0]);
+	return fmtstrcpy(fp, str);
+}

+ 29 - 0
sys/src/cmd/usb/audio/usbaudioctl.h

@@ -0,0 +1,29 @@
+enum{
+	Undef = 0x80000000,
+	Play = 0,
+	Record = 1,
+};
+
+typedef struct Audiocontrol Audiocontrol;
+
+struct Audiocontrol {
+	char		*name;
+	uchar	readable;
+	uchar	settable;
+	uchar	chans;		/* 0 is master, non-zero is bitmap */
+	long		value[8];		/* 0 is master; value[0] == Undef -> all values Undef */
+	long		min, max, step;
+};
+
+
+extern Audiocontrol controls[2][Ncontrol];
+extern int endpt[2];
+extern int interface[2];
+extern int featureid[2];
+extern int selectorid[2];
+extern int buttonendpt;
+
+int	ctlparse(char *s, Audiocontrol *c, long *v);
+void	ctlevent(void);
+
+#pragma	varargck	type	"A"	Audiocontrol*

+ 0 - 288
sys/src/cmd/usb/lib/config.c

@@ -1,288 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include "usb.h"
-#include "usbproto.h"
-
-static int	loadconfig(Device *d, int n);
-static int	checkep(Dalt*, Endpt*);
-static void	adddesc(Ddesc*, uchar*);
-static void	dumplangids(Device*);
-
-int
-describedevice(Device *d)
-{
-	int i, nr;
-	DDevice *dd;
-	uchar buf[1023];
-
-	nr = setupreq(d, RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (DEVICE<<8)|0, 0, buf, sizeof(buf));
-	if(nr < 0) {
-		werrstr("describedevice: %r");
-		return -1;
-	}
-	if(nr < DDEVLEN) {
-		werrstr("describedevice: short device descriptor (%d < %d)", nr, DDEVLEN);
-		return -1;
-	}
-	dd = (DDevice*)buf;
-	if(dd->bDescriptorType != DEVICE || dd->bLength < DDEVLEN) {
-		werrstr("describedevice: bogus device descriptor");
-		return -1;
-	}
-	d->vers = GET2(dd->bcdUSB);
-	d->csp = CSP(dd->bDeviceClass, dd->bDeviceSubClass, dd->bDeviceProtocol);
-	d->max0 = dd->bMaxPacketSize0;
-	d->vid = GET2(dd->idVendor);
-	d->did = GET2(dd->idProduct);
-	d->release = GET2(dd->bcdDevice);
-	d->manufacturer = dd->iManufacturer;
-	d->product = dd->iProduct;
-	d->serial = dd->iSerialNumber;
-	d->nconf = dd->bNumConfigurations;
-
-	/* read all configurations */
-	if(d->config != nil)
-		free(d->config);
-	d->config = emallocz(d->nconf*sizeof(Dconf), 1);
-	for(i = 0; i < d->nconf; i++)
-		if(loadconfig(d, i) < 0)
-			return -1;
-	return 0;
-}
-
-static uchar type[] =
-{
-	[0]	Econtrol,
-	[1]	Eiso,
-	[2]	Ebulk,
-	[3]	Eintr,
-};
-
-static uchar isotype[] =
-{
-	[0]	Eunknown,
-	[1]	Easync,
-	[2]	Eadapt,
-	[3]	Esync,
-};
-
-static int
-loadconfig(Device *d, int n)
-{
-	int i, nr;
-	Dconf *c;
-	Dinf *intf;
-	Endpt *ep;
-	DConfig *dc;
-	Ddesc *desc;
-	DInterface *di;
-	Dalt *alt, **alttail;
-	DEndpoint *dep;
-	uchar buf[1023], *p, *ebuf;
-
-	nr = setupreq(d, RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (CONFIGURATION<<8)|n, 0, buf, sizeof(buf));
-	if(nr < 0) {
-		werrstr("loadconfig: %r");
-		return -1;
-	}
-	if(nr < DCONFLEN) {
-		werrstr("loadconfig: short configuration descriptor (%d < %d)", nr, 2);
-		return -1;
-	}
-	dc = (DConfig*)buf;
-	if(dc->bDescriptorType != CONFIGURATION || dc->bLength < DCONFLEN) {
-		werrstr("describedevice: bogus configuration descriptor");
-		return -1;
-	}
-	if(GET2(dc->wTotalLength) != nr) {
-		werrstr("describedevice: configuration descriptor length mismatch");
-		return -1;
-	}
-	c = &d->config[n];
-	c->d = d;
-	c->x = n;
-	c->nif = dc->bNumInterfaces;
-	c->cval = dc->bConfigurationValue;
-	c->config = dc->iConfiguration;
-	c->attrib = dc->bmAttributes;
-	c->milliamps = dc->MaxPower*2;		/* 2mA units */
-
-	c->iface = emallocz(c->nif*sizeof(Dinf), 1);
-	for(i = 0; i < c->nif; i++) {
-		intf = &c->iface[i];
-		intf->d = d;
-		intf->conf = c;
-		intf->x = i;
-	}
-	alttail = emallocz(c->nif*sizeof(Dalt*), 1);
-	alt = nil;
-	ep = nil;
-
-	p = buf+dc->bLength;
-	ebuf = buf+nr;
-	while(p < ebuf) {
-		if(p+p[0] > ebuf) {
-			werrstr("truncated descriptor in loadconfig");
-			goto error;
-		}
-		switch(p[1]) {
-		case DEVICE:
-		case CONFIGURATION:
-			werrstr("illegal descriptor in loadconfig: %x", p[1]);
-			goto error;
-		case INTERFACE:
-			if(checkep(alt, ep) < 0)
-				goto error;
-			di = (DInterface*)p;
-			i = di->bInterfaceNumber;
-			if(i >= c->nif) {
-				werrstr("interface number out of bounds");
-				goto error;
-			}
-			intf = &c->iface[i];
-			alt = mallocz(sizeof(Dalt), 1);
-			alt->intf = intf;
-			alt->alt = di->bAlternateSetting;
-			alt->npt = di->bNumEndpoints;
-			alt->ep = emallocz(alt->npt*sizeof(Endpt), 1);
-			alt->next = nil;
-			if(alttail[i] == nil) {
-				intf->alt = alt;
-				intf->csp = CSP(di->bInterfaceClass, di->bInterfaceSubClass, di->bInterfaceProtocol);
-				intf->interface = di->iInterface;
-			}
-			else
-				alttail[i]->next = alt;
-			alttail[i] = alt;
-			ep = nil;
-			break;
-		case ENDPOINT:
-			if(alt == nil) {
-				werrstr("endpoint descriptor without interface");
-				goto error;
-			}
-			if(ep == nil)
-				ep = &alt->ep[0];
-			else {
-				ep++;
-				if(ep - alt->ep > alt->npt) {
-					werrstr("too many endpoints for interface");
-					goto error;
-				}
-			}
-			dep = (DEndpoint*)p;
-			ep->addr = dep->bEndpointAddress & 0x0f;
-			ep->dir = (dep->bEndpointAddress & 0x80) ? Ein : Eout;
-			ep->type = type[dep->bmAttributes & 0x03];
-			ep->isotype = isotype[(dep->bmAttributes>>2) & 0x03];
-			ep->maxpkt = GET2(dep->wMaxPacketSize);
-			ep->pollms = dep->bInterval;
-			break;
-		default:
-			if(alt == nil)
-				desc = &c->desc;
-			else if(ep == nil)
-				desc = &alt->desc;
-			else
-				desc = &ep->desc;
-			adddesc(desc, p);
-		}
-		p += p[0];
-	}
-	free(alttail);
-	return checkep(alt, ep);
-
-error:
-	free(alttail);
-	return -1;
-}
-
-static int
-checkep(Dalt *alt, Endpt *ep)
-{
-	int nep;
-
-	if(alt == nil)
-		return 0;
-	if(ep == nil)
-		nep = 0;
-	else
-		nep = ep-alt->ep+1;
-	if(nep != alt->npt) {
-		werrstr("incorrect number of endpoint descriptors %d != %d", nep, alt->npt);
-		return -1;
-	}
-	return 0;
-}
-
-static void
-adddesc(Ddesc *desc, uchar *p)
-{
-	int len;
-
-	len = p[0];
-	desc->data = realloc(desc->data, desc->bytes+len);
-	memmove(desc->data+desc->bytes, p, len);
-	desc->bytes += len;
-	desc->ndesc++;
-}
-
-static void
-dumplangids(Device *d)
-{
-	int nr, i;
-	uchar buf[1023];
-
-	nr = setupreq(d, RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (STRING<<8)|0, 0, buf, sizeof(buf)-2);
-	if(nr < 0) {
-		fprint(2, "dumplangids: %r\n");
-		return;
-	}
-	if(nr < 2 || buf[0] != nr || buf[1] != STRING) {
-		fprint(2, "dumplangids: bogus descriptor\n");
-		return;
-	}
-	for(i = 1; i < nr/2; i++)
-		fprint(2, "%d\n", GET2(&buf[i*2]));
-}
-
-void
-loadstr(Device *d, int i, int langid)
-{
-	int nr;
-	uchar buf[256+2];
-
-	if(i == 0 || d->strings[i] != nil)
-		return;
-	nr = setupreq(d, RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (STRING<<8)|i, langid, buf, sizeof(buf)-2);
-	if(nr < 0) {
-		d->strings[i] = smprint("loadstr(%d): %r", i);
-		return;
-	}
-	if(nr < 2 || buf[0] != nr || buf[1] != STRING) {
-		d->strings[i] = smprint("loadstr(%d): bogus string", i);
-		return;
-	}
-	buf[nr] = 0;
-	buf[nr+1] = 0;
-	d->strings[i] = smprint("%S", (ushort*)(buf+2));
-}
-
-void
-loadstrings(Device *d, int langid)
-{
-	int i, j;
-	Dconf *c;
-
-	loadstr(d, d->manufacturer, langid);
-	loadstr(d, d->product, langid);
-	loadstr(d, d->serial, langid);
-
-	for(i = 0; i < d->nconf; i++) {
-		c = &d->config[i];
-		loadstr(d, c->config, langid);
-		for(j = 0; j < c->nif; j++)
-			loadstr(d, c->iface[j].interface, langid);
-	}
-}

+ 84 - 17
sys/src/cmd/usb/lib/device.c

@@ -6,10 +6,18 @@
 static int
 readnum(int fd)
 {
-	int n;
 	char buf[20];
+	int n;
 
-	n = read(fd, buf, sizeof buf);
+	for(;;){
+		n = read(fd, buf, sizeof buf);
+		if (n < 0){
+			rerrstr(buf, sizeof buf);
+			if (strcmp(buf, "interrupted") != 0)
+				break;
+		} else
+			break;
+	}
 	buf[sizeof(buf)-1] = 0;
 	return n <= 0? -1: strtol(buf, nil, 0);
 }
@@ -60,15 +68,14 @@ opendev(int ctlrno, int id)
 
 	d->ctlrno = ctlrno;
 	d->id = id;
+	d->ep[0] = newendpt(d, 0, 0);
 	return d;
 }
 
 void
 closedev(Device *d)
 {
-	int i, j;
-	Dconf *conf;
-	Dalt *alt, *nextalt;
+	int i;
 
 	if(d==nil)
 		return;
@@ -78,17 +85,77 @@ closedev(Device *d)
 	close(d->setup);
 	close(d->status);
 
-	for(i = 0; i < d->nconf; i++) {
-		conf = &d->config[i];
-		for(j = 0; j < conf->nif; j++) {
-			for(alt = conf->iface[j].alt; alt != nil; alt = nextalt) {
-				nextalt = alt->next;
-				free(alt->ep);
-				free(alt);
-			}
-		}
-		free(conf->iface);
-	}
-	free(d->config);
+	for(i=0; i<nelem(d->ep); i++)
+		free(d->ep[i]);
 	free(d);
 }
+
+void
+setdevclass(Device *d, int n)
+{
+	Endpt *e;
+
+	if (e = d->ep[n]) {
+		if (verbose) fprint(2, "class %d %d %#6.6lux\n",
+			d->nif, n, e->csp);
+		fprint(d->ctl, "class %d %d %#6.6lux",
+			d->nif, n, e->csp);
+	}
+}
+
+int
+describedevice(Device *d)
+{
+	DDevice *dd;
+	byte buf[1023];
+	int nr = -1;
+
+	if (setupreq(d->ep[0], RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (DEVICE<<8)|0, 0, sizeof(buf)) < 0 ||
+	   (nr = setupreply(d->ep[0], buf, sizeof(buf))) < DDEVLEN) {
+		fprint(2, "usb: error reading device descriptor, got %d of %d\n",
+			nr, DDEVLEN);
+		return -1;
+	}
+	/* extract gubbins */
+	pdesc(d, -1, -1, buf, nr);
+	dd = (DDevice*)buf;
+	d->csp = CSP(dd->bDeviceClass, dd->bDeviceSubClass, dd->bDeviceProtocol);
+	d->ep[0]->maxpkt = dd->bMaxPacketSize0;
+	if (dd->bDeviceClass == 9)
+		d->class = Hubclass;
+	else
+		d->class = Otherclass;
+	d->nconf = dd->bNumConfigurations;
+	d->vid = GET2(dd->idVendor);
+	d->did = GET2(dd->idProduct);
+	return 0;
+}
+
+int
+loadconfig(Device *d, int n)
+{
+	byte buf[1023];
+	int nr;
+
+	if (setupreq(d->ep[0], RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (CONFIGURATION<<8)|n, 0, sizeof(buf)) < 0 ||
+	   (nr = setupreply(d->ep[0], buf, sizeof(buf))) < 1) {
+		fprint(2, "usb: error reading configuration descriptor\n");
+		return -1;
+	}
+	/* extract gubbins */
+	pdesc(d, n, -1, buf, nr);
+	return 0;
+}
+
+Endpt *
+newendpt(Device *d, int id, ulong csp)
+{
+	Endpt *e;
+
+	e = mallocz(sizeof(*e), 1);
+	e->id = id;
+	e->dev = d;
+	e->csp = csp;
+	e->maxpkt = 32;
+	return e;
+}

+ 497 - 73
sys/src/cmd/usb/lib/dump.c

@@ -4,101 +4,525 @@
 #include <bio.h>
 #include "usb.h"
 
-static char *type[] =
-{
-	[Econtrol]		"Control",
-	[Eiso]		"Isochronous",
-	[Ebulk]		"Bulk",
-	[Eintr]		"Interrupt",
+int verbose;
+
+typedef struct Flags Flags;
+typedef struct Classes Classes;
+
+struct Flags {
+	int	bit;
+	char*	name0;
+	char*	name1;
 };
 
-static char *isotype[] =
+struct Classes {
+	char*	name;
+	struct {
+		char*	name;
+		char*	proto[4];
+	} subclass[4];
+};
+
+static Classes	classname[] = {
+	[CL_AUDIO]		{"audio", {[1] {"control"}, [2] {"stream"}, [3]{"midi"}}},
+	[CL_COMMS]		{"comms", {[1] {"abstract", {[1]"AT"}}}},
+	[CL_HID]		{"hid", {[1]{"boot", {[1]"kbd", [2]"mouse"}}}},
+	[CL_PRINTER]	{"printer", {[1]"printer", {[1] "uni", [2]"bi"}}},
+	[CL_HUB]		{"hub", {[1]{"hub"}}},
+	[CL_DATA]		{"data"},
+};
+
+static	void	pflag(Flags*, uint);
+
+char *
+sclass(ulong csp)
+{
+	Classes *cs;
+	int n;
+	static char buf[64];
+	int c, s, p;
+
+	c = Class(csp);
+	s = Subclass(csp);
+	p = Proto(csp);
+	if(c < 0 || c >= nelem(classname) || (cs = &classname[c])->name == nil){
+		sprint(buf, "%d.%d.%d", c, s, p);
+		return buf;
+	}
+	n = sprint(buf, "%s.", cs->name);
+	if(s < 0 || s >= nelem(cs->subclass) || cs->subclass[s].name == nil)
+		sprint(buf+n, "%d.%d", s, p);
+	else{
+		n += sprint(buf+n, "%s.", cs->subclass[s].name);
+		if(p < 0 || p >= nelem(cs->subclass[s].proto) || cs->subclass[s].proto[p] == nil)
+			sprint(buf+n, "%d", p);
+		else
+			sprint(buf+n, "%s", cs->subclass[s].proto[p]);
+	}
+	return buf;
+}
+
+void
+pdevice(Device *, int, ulong, void *b, int n)
+{
+	DDevice *d;
+
+	if(n < DDEVLEN)
+		return;
+	d = b;
+	if (debug & Dbginfo) {
+		fprint(2, "usb (bcd)%c%c%c%c",
+				'0'+((d->bcdUSB[1]>>4)&0xf), '0'+(d->bcdUSB[1]&0xf),
+				'0'+((d->bcdUSB[0]>>4)&0xf), '0'+(d->bcdUSB[0]&0xf));
+		fprint(2, " class %d subclass %d proto %d [%s] max0 %d",
+			d->bDeviceClass, d->bDeviceSubClass, d->bDeviceProtocol,
+			sclass(CSP(d->bDeviceClass, d->bDeviceSubClass, d->bDeviceProtocol)),
+			d->bMaxPacketSize0);
+		fprint(2, " vendor %#x product %#x device (bcd)%c%c%c%c",
+			GET2(d->idVendor), GET2(d->idProduct),
+			'0'+((d->bcdDevice[1]>>4)&0xf), '0'+(d->bcdDevice[1]&0xf),
+			'0'+((d->bcdDevice[0]>>4)&0xf), '0'+(d->bcdDevice[0]&0xf));
+		fprint(2, " man %d prod %d serial %d nconfig %d",
+			d->iManufacturer, d->iProduct, d->iSerialNumber,
+			d->bNumConfigurations);
+	}
+}
+
+void
+phid(Device *, int, ulong, void *b, int n)
 {
-	[Eunknown]	"",
-	[Easync]		" (Asynchronous)",
-	[Eadapt]		" (Adaptive)",
-	[Esync]		" (Synchronous)",
+	DHid *d;
+
+	if(n < DHIDLEN){
+		fprint(2, "hid too short\n");
+		return;
+	}
+	d = b;
+	if (debug & Dbginfo)
+		fprint(2, "HID (bcd)%c%c%c%c country %d nhidclass %d classdtype %#x dlen %d\n",
+			'0'+((d->bcdHID[1]>>4)&0xf), '0'+(d->bcdHID[1]&0xf),
+			'0'+((d->bcdHID[0]>>4)&0xf), '0'+(d->bcdHID[0]&0xf),
+			d->bCountryCode, d->bNumDescriptors,
+			d->bClassDescriptorType, GET2(d->wItemLength));
+}
+
+static	Flags	ioflags[] = {
+	{0, "Data", "Constant"},
+	{1, "Array", "Variable"},
+	{2, "Absolute", "Relative"},
+	{3, "NoWrap", "Wrap"},
+	{4, "Linear", "NonLinear"},
+	{5, "PreferredState", "No Preferred State"},
+	{6, "No Null position", "Null state"},
+	{7, "Non Volatile", "Volatile"},
+	{8, "Bit Field", "Buffered Bytes"},
+	{-1, nil, nil},
 };
 
+static void
+pflag(Flags *tab, uint v)
+{
+	char buf[200], *s;
+	int n;
+
+	n = 0;
+	buf[0] = 0;
+	for(; tab->name0 != nil; tab++){
+		if(v & (1<<tab->bit))
+			s = tab->name1;
+		else
+			s = tab->name0;
+		if(s != nil && *s)
+			n += snprint(buf+n, sizeof(buf)-n, ", %s", s);
+	}
+	if((debug & Dbginfo) && buf[0])
+		fprint(2, "[%s]", buf+2);
+}
+
 void
-dumpstring(int fd, char *prefix, Device *d, int index)
+preport(Device *, int, ulong, byte *b, int n)
 {
-	char *s;
+	byte *s, *es;
+	int tag, nb, i, indent;
+	int v;
+	Flags *tab;
+
+	s = b+2;
+	es = b+n;
+	indent = 0;
+	while(s < es){
+		for(i=0; i<indent; i++)
+			fprint(2, " ");
+		tag = *s++;
+		if(tag == Tlong){
+			fprint(2, "long report tag");
+			return;
+		}
+		if((nb = tag&3)==3)
+			nb = 4;
+		v = 0;
+		for(i=0; i<nb; i++)
+			v |= s[i]<<(i*8);
+		switch(tag & Tmtype){
+		case Treserved:
+			if(tag == Tlong){
+				fprint(2, "long report tag");
+				return;
+			}
+			fprint(2, "illegal tag");
+			return;
+		case Tmain:
+			tab = nil;
+			if (debug & Dbginfo) {
+				switch(tag & Tmitem){
+				case Tinput:	fprint(2, "Input"); tab = ioflags; break;
+				case Toutput:	fprint(2, "Output"); tab = ioflags; break;
+				case Tfeature:	fprint(2, "Feature"); tab = ioflags; break;
+				case Tcoll:	fprint(2, "Collection"); indent++; break;
+				case Tecoll:	fprint(2, "End Collection"); indent--; break;
+				default:		fprint(2, "unexpected item %.2x", tag);
+				}
+				fprint(2, "=%#ux", v);
+				if(tab != nil)
+					pflag(tab, v);
+			}
+			break;
+		case Tglobal:
+			if (debug & Dbginfo) {
+				fprint(2, "Global %#ux: ", v);
+				switch(tag & Tmitem){
+				case Tusagepage:
+					fprint(2, "Usage Page %#ux", v);
+					break;
+				case Tlmin:
+					fprint(2, "Logical Min %d", v);
+					break;
+				case Tlmax:
+					fprint(2, "Logical Max %d", v);
+					break;
+				case Tpmin:
+					fprint(2, "Physical Min %d", v);
+					break;
+				case Tpmax:
+					fprint(2, "Physical Max %d", v);
+					break;
+				case Tunitexp:
+					fprint(2, "Unit Exponent %d", v);
+					break;
+				case Tunit:
+					fprint(2, "Unit %d", v);
+					break;
+				case Trepsize:
+					fprint(2, "Report size %d", v);
+					break;
+				case TrepID:
+					fprint(2, "Report ID %#x", v);
+					break;
+				case Trepcount:
+					fprint(2, "Report Count %d", v);
+					break;
+				case Tpush:
+					fprint(2, "Push %d", v);
+					break;
+				case Tpop:
+					fprint(2, "Pop %d", v);
+					break;
+				default:
+					fprint(2, "Unknown %#ux", v);
+					break;
+				}
+			}
+			break;
+		case Tlocal:
+			if (debug & Dbginfo) {
+				fprint(2, "Local %#ux: ", v);
+				switch(tag & Tmitem){
+				case Tusage:
+					fprint(2, "Usage %d", v);
+					break;
+				case Tumin:
+					fprint(2, "Usage min %d", v);
+					break;
+				case Tumax:
+					fprint(2, "Usage max %d", v);
+					break;
+				case Tdindex:
+					fprint(2, "Designator index %d", v);
+					break;
+				case Tdmin:
+					fprint(2, "Designator min %d", v);
+					break;
+				case Tdmax:
+					fprint(2, "Designator max %d", v);
+					break;
+				case Tsindex:
+					fprint(2, "String index %d", v);
+					break;
+				case Tsmin:
+					fprint(2, "String min %d", v);
+					break;
+				case Tsmax:
+					fprint(2, "String max %d", v);
+					break;
+				case Tsetdelim:
+					fprint(2, "Set delim %#ux", v);
+					break;
+				default:
+					fprint(2, "Unknown %#ux", v);
+					break;
+				}
+			}
+			break;
+		}
+		fprint(2, "\n");
+		s += nb;
+	}
+}
+
+void
+phub(Device *, int, ulong, void *b, int n)
+{
+	DHub *d;
 
-	if(index == 0)
+	if(n < DHUBLEN)
 		return;
-	s = d->strings[index];
-	if(s == nil)
-		fprint(fd, "%s<string %d>\n", prefix, index);
-	else
-		fprint(fd, "%s%s\n", prefix, s);
+	d = b;
+	if (debug & Dbginfo)
+		fprint(2, "nport %d charac %#.4x pwr %dms current %dmA remov %#.2x",
+			d->bNbrPorts, GET2(d->wHubCharacteristics), d->bPwrOn2PwrGood*2,
+			d->bHubContrCurrent, d->DeviceRemovable[0]);
 }
 
 void
-dumpdesc(int fd, char *prefix, Ddesc *desc)
+pstring(Device *, int, ulong, void *b, int n)
 {
-	uchar *p;
-	int i, j, len;
+	byte *rb;
+	char *s;
+	Rune r;
+	int l;
 
-	if(desc->ndesc == 0)
+	if(n <= 2){
+		fprint(2, "\"\"");
 		return;
-	fprint(fd, "%s%d descriptors\n", prefix, desc->ndesc);
-	p = desc->data;
-	for(i = 0; i < desc->ndesc; i++) {
-		fprint(fd, "%s\t", prefix);
-		len = *p++;
-		for(j = 1; j < len; j++)
-			fprint(fd, "%.2ux ", *p++);
-		fprint(fd, "\n");
 	}
+	if(n & 1){
+		fprint(2, "illegal count\n");
+		return;
+	}
+	n /= 2;
+	rb = (byte*)b + 2;
+	s = malloc(n*UTFmax+1);
+	for(l=0; --n >= 0; rb += 2){
+		r = GET2(rb);
+		l += runetochar(s+l, &r);
+	}
+	s[l] = 0;
+	fprint(2, "\"%s\"", s);
+	free(s);
 }
 
 void
-dumpdevice(int fd, Device *d)
+pcs_raw(char *tag, byte *b, int n)
+{
+	int i;
+
+	if (debug & Dbginfo) {
+		fprint(2, "%s", tag);
+		for(i=2; i<n; i++)
+			fprint(2, " %.2x", b[i]);
+	}
+}
+
+static void
+pcs_config(Device *, int, ulong, void *b, int n)
+{
+	pcs_raw("CS_CONFIG", b, n);
+}
+
+static void
+pcs_string(Device *, ulong, void *b, int n)
 {
-	int i, j, k;
-	Dconf *c;
-	Dinf *intf;
-	Dalt *alt;
-	Endpt *ep;
-
-	fprint(fd, "device %D: %lud.%lud.%lud %.4x/%.4x\n",
-		d, Class(d->csp), Subclass(d->csp), Proto(d->csp), d->vid, d->did);
-	fprint(fd, "\tUSB version: %x.%.2x\n", d->vers>>8, d->vers&0xff);
-	fprint(fd, "\tmaximum control packet size: %d\n", d->max0);
-	fprint(fd, "\tdevice release: %x.%.2x\n", d->release>>8, d->release&0xff);
-	dumpstring(fd, "\tmanufacturer: ", d, d->manufacturer);
-	dumpstring(fd, "\tproduct: ", d, d->product);
-	dumpstring(fd, "\tserial: ", d, d->serial);
-	fprint(fd, "\tconfigurations: %d\n", d->nconf);
-	for(i = 0; i < d->nconf; i++) {
-		c = &d->config[i];
-		fprint(fd, "\t\tconfiguration %d: %d interfaces, %dmA required\n", c->cval, c->nif, c->milliamps);
-		dumpstring(fd, "\t\tname: ", d, c->config);
-		fprint(fd, "\t\tattributes:");
-		if(c->attrib & Cbuspowered)
-			fprint(fd, " buspowered");
-		if(c->attrib & Cselfpowered)
-			fprint(fd, " selfpowered");
-		if(c->attrib & Cremotewakeup)
-			fprint(fd, " remotewakeup");
-		fprint(fd, "\n");
-		dumpdesc(fd, "\t\t\t", &c->desc);
-		for(j = 0; j < c->nif; j++) {
-			intf = &c->iface[j];
-			fprint(fd, "\t\tinterface %d: %lud.%lud.%lud\n", j, Class(intf->csp), Subclass(intf->csp), Proto(intf->csp));
-			dumpstring(fd, "\t\tname: ", d, intf->interface);
-			for(alt = intf->alt; alt != nil; alt = alt->next) {
-				fprint(fd, "\t\t\talternate %d: %d endpoints\n", alt->alt, alt->npt);
-				dumpdesc(fd, "\t\t\t\t", &alt->desc);
-				for(k = 0; k < alt->npt; k++) {
-					ep = &alt->ep[k];
-					fprint(2, "\t\t\t\tendpoint %d-%s: type %s%s maxpkt %d poll %dms\n",
-						ep->addr, ep->dir == Ein ? "in" : "out", type[ep->type], isotype[ep->isotype],
-						ep->maxpkt, ep->pollms);
-					dumpdesc(fd, "\t\t\t\t\t", &ep->desc);
+	pcs_raw("CS_STRING", b, n);
+}
+
+static void
+pcs_endpoint(Device *, int, ulong, void *bb, int n)
+{
+	byte *b = bb;
+
+	if (debug & Dbginfo) {
+		switch(b[2]) {
+		case 0x01:
+			fprint(2, "CS_ENDPOINT for TerminalID %d, delay %d, format_tag %#ux\n",
+				b[3], b[4], b[5] | (b[6]<<8));
+			break;
+		case 0x02:
+			fprint(2, "CS_INTERFACE FORMAT_TYPE %d, channels %d, subframesize %d, resolution %d, freqtype %d, ",
+				b[3], b[4], b[5], b[6], b[7]);
+			fprint(2, "freq0 %d, freq1 %d\n",
+				b[8] | (b[9]<<8) | (b[10]<<16), b[11] | (b[12]<<8) | (b[13]<<16));
+			break;
+		default:
+			pcs_raw("CS_INTERFACE", bb, n);
+		}
+	}
+}
+
+static void
+pcs_interface(Device *, int n, ulong, void *bb, int nb) {
+
+	if ((debug & Dbginfo) && n >= 0) {
+		pcs_raw("CS_INTERFACE", bb, nb);
+	}
+}
+
+void
+pdesc(Device *d, int c, ulong csp, byte *b, int n)
+{
+	void (*f)(Device *, int, ulong, void*, int);
+	int ifc = -1;
+	int dalt = -1;
+	int ep;
+	int class, subclass, proto;
+	DConfig *dc;
+	DInterface *di;
+	DEndpoint *de;
+
+	class = Class(csp);
+
+	if (c >= nelem(d->config)) {
+		fprint(2, "Too many interfaces (%d of %d)\n",
+			c, nelem(d->config));
+		return;
+	}
+	if (debug & Dbginfo)
+		fprint(2, "pdesc %d.%d [%d]\n", d->id, c, n);
+	for(; n > 2 && b[0] && b[0] <= n; b += b[0]){
+		if (debug & Dbginfo)
+			fprint(2, "desc %d.%d [%d] %#2.2x: ", d->id, c, b[0], b[1]);
+		switch (b[1]) {
+		case CONFIGURATION:
+			if(b[0] < DCONFLEN)
+				return;
+			dc = (DConfig*)b;
+			d->config[c]->nif = dc->bNumInterfaces;
+			d->config[c]->cval = dc->bConfigurationValue;
+			d->config[c]->attrib = dc->bmAttributes;
+			d->config[c]->milliamps = dc->MaxPower*2;
+			d->nif += d->config[c]->nif;
+			if (debug & Dbginfo)
+				fprint(2, "config %d: tdlen %d ninterface %d iconfig %d attr %#.2x power %dmA\n",
+					dc->bConfigurationValue, GET2(dc->wTotalLength),
+					dc->bNumInterfaces, dc->iConfiguration, dc->bmAttributes,
+					dc->MaxPower*2);
+			break;
+		case INTERFACE:
+			if(n < DINTERLEN)
+				return;
+			di = (DInterface *)b;
+			class = di->bInterfaceClass;
+			subclass = di->bInterfaceSubClass;
+			proto = di->bInterfaceProtocol;
+			csp = CSP(class, subclass, proto);
+			if (debug & Dbginfo)
+				fprint(2, "interface %d: alt %d nept %d class %#x subclass %#x proto %d [%s] iinterface %d\n",
+					di->bInterfaceNumber, di->bAlternateSetting,
+					di->bNumEndpoints, class, subclass, proto,
+					sclass(csp),
+					di->iInterface);
+			if (c < 0) {
+				fprint(2, "Unexpected INTERFACE message\n");
+				return;
+			}
+			ifc = di->bInterfaceNumber;
+			dalt = di->bAlternateSetting;
+			if (ifc < 0 || ifc >= nelem(d->config[c]->iface))
+				sysfatal("Bad interface number %d", ifc);
+			if (dalt < 0 || dalt >= nelem(d->config[c]->iface[ifc]->dalt))
+				sysfatal("Bad alternate number %d", dalt);
+			if (d->config[c] == nil)
+				sysfatal("No config");
+			if (ifc == 0) {
+				if (c == 0)
+					d->ep[0]->csp = csp;
+				d->config[c]->csp = csp;
+			}
+			if (d->config[c]->iface[ifc] == nil) {
+				d->config[c]->iface[ifc] = mallocz(sizeof(Dinf), 1);
+				d->config[c]->iface[ifc]->csp = csp;
+			}
+			d->config[c]->iface[ifc]->interface = di->bInterfaceNumber;
+			break;
+		case ENDPOINT:
+			if(n < DENDPLEN)
+				return;
+			de = (DEndpoint *)b;
+			if (debug & Dbginfo) {
+				fprint(2, "addr %#2.2x attrib %#2.2x maxpkt %d interval %dms",
+					de->bEndpointAddress, de->bmAttributes,
+					GET2(de->wMaxPacketSize), de->bInterval);
+				if(de->bEndpointAddress & 0x80)
+					fprint(2, " [IN]");
+				else
+					fprint(2, " [OUT]");
+				switch(de->bmAttributes&0x33){
+				case 0:	fprint(2, " [Control]"); break;
+				case 1:	fprint(2, " [Iso]");
+						switch(de->bmAttributes&0xc){
+						case 0x4:	fprint(2, " [Asynchronous]"); break;
+						case 0x8:	fprint(2, " [Adaptive]"); break;
+						case 0xc:	fprint(2, " [Synchronous]"); break;
+						}
+						break;
+				case 2:	fprint(2, " [Bulk]"); break;
+				case 3:	fprint(2, " [Interrupt]"); break;
+				}
+				if(b[0] == 9)
+					fprint(2, "refresh %d synchaddress %d", b[7], b[8]);
+				fprint(2, "\n");
+			}
+			if (c < 0 || ifc < 0 || dalt < 0) {
+				fprint(2, "Unexpected ENDPOINT message\n");
+				return;
+			}
+			if (d->config[c]->iface[ifc] == nil)
+				sysfatal("d->config[c]->iface[ifc] == nil");
+			if (d->config[c]->iface[ifc]->dalt[dalt] == nil)
+				d->config[c]->iface[ifc]->dalt[dalt] = mallocz(sizeof(Dalt),1);
+			d->config[c]->iface[ifc]->addr = de->bEndpointAddress;
+			d->config[c]->iface[ifc]->dalt[dalt]->maxpkt = GET2(de->wMaxPacketSize);
+			d->config[c]->iface[ifc]->dalt[dalt]->attrib = de->bmAttributes;
+			d->config[c]->iface[ifc]->dalt[dalt]->interval = de->bInterval;
+			ep = de->bEndpointAddress & 0xf;
+			if (d->ep[ep] == nil)
+				d->ep[ep] = newendpt(d, ep, class);
+			d->ep[ep]->csp = csp;
+			d->ep[ep]->conf = d->config[c];
+			d->ep[ep]->iface = d->config[c]->iface[ifc];
+			if (d->nif <= ep) d->nif = ep+1;
+			break;
+		default:
+			f = nil;
+			if(b[1] < nelem(dprinter))
+				f = dprinter[b[1]];
+			if(f != nil) {
+				(*f)(d, c, (dalt<<24) | (ifc<<16) | (csp&0xffff), b, b[0]);
+				if (debug & Dbginfo)
+					fprint(2, "\n");
+			}
+			else {
+				if (verbose) {
+					int i;
+
+					fprint(2, "(unknown type)");
+					for(i=1; i<b[0]; i++)
+						fprint(2, " %.2x", b[i]);
+					fprint(2, "\n");
 				}
+				else if (debug & Dbginfo)
+					fprint(2, "\n");
 			}
 		}
+		n -= b[0];
 	}
 }

+ 6 - 3
sys/src/cmd/usb/lib/mkfile

@@ -2,7 +2,6 @@
 
 LIB=usb.a$O
 OFILES=\
-	config.$O\
 	device.$O\
 	dump.$O\
 	fmt.$O\
@@ -11,9 +10,13 @@ OFILES=\
 
 HFILES=\
 	usb.h\
-	usbproto.h\
+
+UPDATE=\
+	$HFILES\
+	${OFILES:%.$O=%.c}\
+	mkfile\
 
 </sys/src/cmd/mklib
 
-install safeinstall:V:	$LIB
+install:V:	$LIB
 	date

+ 81 - 50
sys/src/cmd/usb/lib/setup.c

@@ -2,72 +2,103 @@
 #include <libc.h>
 #include <thread.h>
 #include "usb.h"
-#include "usbproto.h"
 
-static int
-setupcmd(int fd, uchar *data, int count)
+int
+setupcmd(Endpt *e, int type, int req, int value, int index, byte *data, int count)
 {
-	int n;
+	byte *wp;
+	int n, i, fd;
 
-	n = write(fd, data, count);
-	if(n < 0) {
-		werrstr("setupcmd: write err: %r");
+	if (e == nil)
+		abort();
+	fd = e->dev->setup;
+	if(fd < 0)
+		sysfatal("RSC: this used to use the global usbsetup0\n");
+	wp = malloc(8+count);
+	if (wp == nil) sysfatal("setupcmd: malloc");
+	wp[0] = type;
+	wp[1] = req;
+	PUT2(wp+2, value);
+	PUT2(wp+4, index);
+	PUT2(wp+6, count);
+	memmove(wp+8, data, count);
+	if (debugdebug) {
+		fprint(2, "out\t%d\t[%d]", fd, 8+count);
+		for(i=0; i<8+count; i++)
+			fprint(2, " %.2ux", wp[i]);
+		fprint(2, "\n");
+	}
+	n = write(fd, wp, 8+count);
+	if (n < 0) {
+		fprint(2, "setupreq: write err: %r\n");
 		return -1;
 	}
-	if(n != count) {
-		werrstr("setupcmd: short write: %d of %d", n, count);
+	if (n != 8+count) {
+		fprint(2, "setupcmd: short write: %d\n", n);
 		return -1;
 	}
 	return n;
 }
 
-static int
-setupout(int fd, uchar *req, uchar *data, int count)
-{
-	int n;
-	uchar *wp;
-
-	if(count == 0)
-		return setupcmd(fd, req, 8);
-
-	wp = emalloc(8+count);
-	memmove(wp, req, 8);
-	memmove(wp+8, data, count);
-	n = setupcmd(fd, wp, 8+count);
-	free(wp);
-	return n;
-}
-
-static int
-setupin(int fd, uchar *req, uchar *data, int count)
+int
+setupreq(Endpt *e, int type, int req, int value, int index, int count)
 {
-	int n;
+	byte *wp, buf[8];
+	int n, i, fd;
 
-	n = setupcmd(fd, req, 8);
-	if(n < 0)
-		return n;
-	n = read(fd, data, count);
-	if(n < 0)
-		werrstr("setupin: read err: %r");
-	else if(n != count)
-		werrstr("setupin: short read (%d < %d)", n, count);
+	if (e == nil)
+		abort();
+	fd = e->dev->setup;
+	if(fd < 0)
+		sysfatal("RSC: this used to use the global usbsetup0\n");
+	wp = buf;
+	wp[0] = type;
+	wp[1] = req;
+	PUT2(wp+2, value);
+	PUT2(wp+4, index);
+	PUT2(wp+6, count);
+	if (debugdebug) {
+		fprint(2, "out\t%d\t[8]", fd);
+		for(i=0; i<8; i++)
+			fprint(2, " %.2ux", buf[i]);
+		fprint(2, "\n");
+	}
+	n = write(fd, buf, 8);
+	if (n < 0) {
+		fprint(2, "setupreq: write err: %r\n");
+		return -1;
+	}
+	if (n != 8) {
+		fprint(2, "setupreq: short write: %d\n", n);
+		return -1;
+	}
 	return n;
 }
 
 int
-setupreq(Device *d, int type, int request, int value, int index, uchar *data, int count)
+setupreply(Endpt *e, void *buf, int nb)
 {
-	int fd;
-	uchar req[8];
+	uchar *p;
+	int i, fd;
+	char err[32];
 
-	fd = d->setup;
-	req[0] = type;
-	req[1] = request;
-	PUT2(req+2, value);
-	PUT2(req+4, index);
-	PUT2(req+6, count);
-	if((type&RD2H) != 0)
-		return setupin(fd, req, data, count);
-	else
-		return setupout(fd, req, data, count);
+	fd = e->dev->setup;
+	if(fd < 0)
+		sysfatal("RSC: this used to use the global usbsetup0\n");
+	for(;;){
+		nb = read(fd, buf, nb);
+		if (nb >= 0)
+			break;
+		rerrstr(err, sizeof err);
+		if (strcmp(err, "interrupted") != 0)
+			break;
+	}
+	p = buf;
+	if (debugdebug) {
+		fprint(2, "in\t%d\t[%d]", fd, nb);
+		for(i=0; i<nb; i++)
+			fprint(2, " %.2ux", p[i]);
+		fprint(2, "\n");
+	}
+	return nb;
 }

+ 327 - 102
sys/src/cmd/usb/lib/usb.h

@@ -1,138 +1,361 @@
-typedef struct Device Device;
+/*
+ * USB implementation for Plan 9
+ *	(c) 1998, 1999 C H Forsyth
+ */
+
+enum {
+	Dbginfo = 0x01,
+	Dbgfs = 0x02,
+	Dbgproc = 0x04,
+	Dbgcontrol = 0x08,
+};
+
+extern int debug, debugdebug, verbose;
+
+typedef uchar byte;
+
+#ifndef CHANNOP
+typedef struct Ref Ref;
+
+#define threadprint fprint
+#endif
+
+/*
+ * USB definitions
+ */
+
+typedef struct DConfig DConfig;
+typedef struct DDevice DDevice;
+typedef struct DEndpoint DEndpoint;
+typedef struct DHid DHid;
+typedef struct DHub DHub;
+typedef struct DInterface DInterface;
 typedef struct Dconf Dconf;
-typedef struct Ddesc Ddesc;
-typedef struct Dinf Dinf;
 typedef struct Dalt Dalt;
+typedef struct Device Device;
+typedef struct Dinf Dinf;
 typedef struct Endpt Endpt;
 
-struct Device
+typedef struct Namelist Namelist;
+
+#ifndef nelem
+#define	nelem(x)	(sizeof((x))/sizeof((x)[0]))
+#endif
+
+#define	GET2(p)	((((p)[1]&0xFF)<<8)|((p)[0]&0xFF))
+#define	PUT2(p,v)	{((p)[0] = (v)); ((p)[1] = (v)>>8);}
+
+enum
 {
-	Ref;
-	int		ctlrno;
-	int		id;
-	int		state;
-	int		ctl;
-	int		setup;
-	int		status;
-	int		ls;			/* low speed */
+	TokIN = 0x69,
+	TokOUT = 0xE1,
+	TokSETUP = 0x2D,
 
-	int		vers;			/* USB version supported, in BCD */
-	ulong	csp;			/* USB class/subclass/proto */
-	int		max0;		/* max packet size for endpoint 0 */
-	int		vid;			/* vendor id */
-	int		did;			/* product (device) id */
-	int		release;		/* device release number, in BCD */
-	int		manufacturer;	/* string index */
-	int		product;		/* string index */
-	int		serial;		/* string index */
-	int		nconf;
-	Dconf*	config;
-	char		*strings[256];
+	/* request type */
+	RH2D = 0<<7,
+	RD2H = 1<<7,
+	Rstandard = 0<<5,
+	Rclass = 1<<5,
+	Rvendor = 2<<5,
+	Rdevice = 0,
+	Rinterface = 1,
+	Rendpt = 2,
+	Rother = 3,
+
+	/* standard requests */
+	GET_STATUS = 0,
+	CLEAR_FEATURE = 1,
+	SET_FEATURE = 3,
+	SET_ADDRESS = 5,
+	GET_DESCRIPTOR = 6,
+	SET_DESCRIPTOR = 7,
+	GET_CONFIGURATION = 8,
+	SET_CONFIGURATION = 9,
+	GET_INTERFACE = 10,
+	SET_INTERFACE = 11,
+	SYNCH_FRAME = 12,
+
+	GET_CUR = 0x81,
+	GET_MIN = 0x82,
+	GET_MAX = 0x83,
+	GET_RES = 0x84,
+	SET_CUR = 0x01,
+	SET_MIN = 0x02,
+	SET_MAX = 0x03,
+	SET_RES = 0x04,
+
+	/* hub class feature selectors */
+	C_HUB_LOCAL_POWER = 0,
+	C_HUB_OVER_CURRENT,
+	PORT_CONNECTION = 0,
+	PORT_ENABLE = 1,
+	PORT_SUSPEND = 2,
+	PORT_OVER_CURRENT = 3,
+	PORT_RESET = 4,
+	PORT_POWER = 8,
+	PORT_LOW_SPEED = 9,
+	C_PORT_CONNECTION = 16,
+	C_PORT_ENABLE,
+	C_PORT_SUSPEND,
+	C_PORT_OVER_CURRENT,
+	C_PORT_RESET,
+
+	/* descriptor types */
+	DEVICE = 1,
+	CONFIGURATION = 2,
+	STRING = 3,
+	INTERFACE = 4,
+	ENDPOINT = 5,
+	HID = 0x21,
+	REPORT = 0x22,
+	PHYSICAL = 0x23,
+
+	/* feature selectors */
+	DEVICE_REMOTE_WAKEUP = 1,
+	ENDPOINT_STALL = 0,
+
+	/* report types */
+	Tmtype = 3<<2,
+	Tmitem = 0xF0,
+	Tmain = 0<<2,
+		Tinput = 0x80,
+		Toutput = 0x90,
+		Tfeature = 0xB0,
+		Tcoll = 0xA0,
+		Tecoll = 0xC0,
+	 Tglobal = 1<<2,
+		Tusagepage = 0x00,
+		Tlmin = 0x10,
+		Tlmax = 0x20,
+		Tpmin = 0x30,
+		Tpmax = 0x40,
+		Tunitexp = 0x50,
+		Tunit = 0x60,
+		Trepsize = 0x70,
+		TrepID = 0x80,
+		Trepcount = 0x90,
+		Tpush = 0xA0,
+		Tpop = 0xB0,
+	 Tlocal = 2<<2,
+		Tusage = 0x00,
+		Tumin = 0x10,
+		Tumax = 0x20,
+		Tdindex = 0x30,
+		Tdmin = 0x40,
+		Tdmax = 0x50,
+		Tsindex = 0x70,
+		Tsmin = 0x80,
+		Tsmax = 0x90,
+		Tsetdelim = 0xA0,
+	 Treserved = 3<<2,
+	 Tlong = 0xFE,
+
+	/* parameters */
+	Nendpt =	16,
+
+	/* device state */
+	Detached = 0,
+	Attached,
+	Enabled,
+	Assigned,
+	Configured,
+
+	/* classes */
+	Noclass = 0,
+	Hubclass,
+	Otherclass,
 };
 
-struct Ddesc
+enum
 {
-	int		ndesc;		/* number of descriptors */
-	int		bytes;		/* total size of descriptors */
-	uchar	*data;		/* descriptor data */
+	CL_AUDIO = 1,
+	CL_COMMS = 2,
+	CL_HID = 3,
+	CL_PRINTER = 7,
+	CL_HUB = 9,
+	CL_DATA = 10,
 };
 
-struct Dconf
+struct Endpt
 {
-	Device	*d;			/* owning device */
-	int		x;			/* index into Device.config array */
-	int		nif;			/* number of interfaces */
-	int		cval;			/* value for set configuration request */
-	int		config;		/* string index */
-	int		attrib;
-	int		milliamps;	/* maximum power in this configuration */
-	Ddesc	desc;		/* additional descriptors for this configuration */
+	int		id;
+	int		class;
+	ulong	csp;
+	int		maxpkt;
+	Device*	dev;
+	Dconf*	conf;
 	Dinf*	iface;
 };
 
-struct Dinf
+struct Dalt
 {
-	Device	*d;			/* owning device */
-	Dconf	*conf;		/* owning configuration */
-	int		x;			/* index into Dconf.iface array */
-	ulong	csp;			/* USB class/subclass/proto */
-	int		interface;		/* string index */
-	Dalt		*alt;			/* linked list of alternatives */
-	Dinf		*next;		/* caller-maintained list of interfaces */
+	int		maxpkt;	/* max packet size */
+	int		attrib;
+	int		interval;
+	void*	devspec;	/* device specific settings */
 };
 
-struct Dalt
+struct Dinf
 {
-	Dinf		*intf;			/* owning interface */
-	int		alt;			/* alternate number, used to select this alternate */
-	int		npt;			/* number of endpoints */
-	Endpt*	ep;			/* endpoints for this interface alternate */
-	Ddesc	desc;		/* additional descriptors for this alternate */
-	Dalt*		next;			/* next in linked list of alternatives */
+	int 		interface;	/* interface number */
+	int		addr;	/* endpoint number */
+	ulong	csp;		/* USB class/subclass/proto */
+	Dalt*		dalt[16];
 };
 
-struct Endpt
+struct Dconf
 {
-	uchar	addr;		/* endpoint address, 0-15 */
-	uchar	dir;			/* direction, Ein/Eout */
-	uchar	type;			/* Econtrol, Eiso, Ebulk, Eintr */
-	uchar	isotype;		/* Eunknown, Easync, Eadapt, Esync */
-	int		maxpkt;		/* maximum packet size for endpoint */
-	int		pollms;		/* polling interval for interrupts */
-	Ddesc	desc;		/* additional descriptors for this endpoint */
+	ulong	csp;			/* USB class/subclass/proto */
+	int		nif;			/* number of interfaces */
+	int		cval;			/* value for set configuration */
+	int		attrib;
+	int		milliamps;		/* maximum power in this configuration */
+	Dinf*	iface[16];		/* up to 16 interfaces */
 };
 
+/* Dconf.attrib */
 enum
 {
-	/* Device.state */
-	Detached = 0,
-	Attached,
-	Enabled,
-	Assigned,
-	Configured,
-
-	/* Dconf.attrib */
 	Cbuspowered = 1<<7,
 	Cselfpowered = 1<<6,
 	Cremotewakeup = 1<<5,
+};
+	
+struct Device
+{
+	Ref;
+	int		ctlrno;
+	int		ctl;
+	int		setup;
+	int		status;
+	int		state;
+	int		id;
+	int		class;
+	int		npt;
+	int		ls;			/* low speed */
+	ulong	csp;		/* USB class/subclass/proto */
+	int		nconf;
+	int		nif;		/* number of interfaces (sum of per-conf `nif's) */
+	int		vid;		/* vendor id */
+	int		did;		/* product (device) id */
+	Dconf*	config[16];
+	Endpt*	ep[Nendpt];
+};
 
-	/* Endpt.dir */
-	Ein = 0,
-	Eout,
+/*
+ * layout of standard descriptor types
+ */
+struct DDevice
+{
+	byte	bLength;
+	byte	bDescriptorType;
+	byte	bcdUSB[2];
+	byte	bDeviceClass;
+	byte	bDeviceSubClass;
+	byte	bDeviceProtocol;
+	byte	bMaxPacketSize0;
+	byte	idVendor[2];
+	byte	idProduct[2];
+	byte	bcdDevice[2];
+	byte	iManufacturer;
+	byte	iProduct;
+	byte	iSerialNumber;
+	byte	bNumConfigurations;
+};
+#define	DDEVLEN	18
 
-	/* Endpt.type */
-	Econtrol = 0,
-	Eiso,
-	Ebulk,
-	Eintr,
+struct DConfig
+{
+	byte	bLength;
+	byte	bDescriptorType;
+	byte	wTotalLength[2];
+	byte	bNumInterfaces;
+	byte	bConfigurationValue;
+	byte	iConfiguration;
+	byte	bmAttributes;
+	byte	MaxPower;
+};
+#define	DCONFLEN	9
 
-	/* Endpt.isotype */
-	Eunknown = 0,
-	Easync,
-	Eadapt,
-	Esync,
+struct DInterface
+{
+	byte	bLength;
+	byte	bDescriptorType;
+	byte	bInterfaceNumber;
+	byte	bAlternateSetting;
+	byte	bNumEndpoints;
+	byte	bInterfaceClass;
+	byte	bInterfaceSubClass;
+	byte	bInterfaceProtocol;
+	byte	iInterface;
+};
+#define	DINTERLEN	9
+
+struct DEndpoint
+{
+	byte	bLength;
+	byte	bDescriptorType;
+	byte	bEndpointAddress;
+	byte	bmAttributes;
+	byte	wMaxPacketSize[2];
+	byte	bInterval;
 };
+#define	DENDPLEN	7
+
+struct DHid
+{
+	byte	bLength;
+	byte	bDescriptorType;
+	byte	bcdHID[2];
+	byte	bCountryCode;
+	byte	bNumDescriptors;
+	byte	bClassDescriptorType;
+	byte	wItemLength[2];
+};
+#define	DHIDLEN	9
+
+struct DHub
+{
+	byte	bLength;
+	byte	bDescriptorType;
+	byte	bNbrPorts;
+	byte	wHubCharacteristics[2];
+	byte	bPwrOn2PwrGood;
+	byte	bHubContrCurrent;
+	byte	DeviceRemovable[1];	/* variable length */
+/*	byte	PortPwrCtrlMask;		/* variable length, deprecated in USB v1.1 */
+};
+#define	DHUBLEN	9
+
+struct Namelist
+{
+	short	index;
+	char		*name;
+};
+
+typedef struct Drivetab
+{
+	ulong	csp;
+	void	(*driver)(Device *d);
+} Drivetab;
 
 #define Class(csp)		((csp)&0xff)
 #define Subclass(csp)	(((csp)>>8)&0xff)
 #define Proto(csp)		(((csp)>>16)&0xff)
 #define CSP(c, s, p)	((c) | ((s)<<8) | ((p)<<16))
 
-enum
-{
-	/* known classes */
-	CL_AUDIO = 1,
-	CL_COMMS = 2,
-	CL_HID = 3,
-	CL_PHYSICAL = 5,
-	CL_IMAGE = 6,
-	CL_PRINTER = 7,
-	CL_STORAGE = 8,
-	CL_HUB = 9,
-	CL_DATA = 10,
-	CL_CHIP = 11,
-	CL_SECURITY = 13,
-};
+extern void (*dprinter[0x100])(Device *, int, ulong, void *b, int n);
+
+/*
+ * format routines
+ */
+void	pdesc	(Device *, int, ulong, byte *, int);
+void	preport	(Device *, int, ulong, byte *, int);
+void	pstring	(Device *, int, ulong, void *, int);
+void	phub	(Device *, int, ulong, void *, int);
+void	pdevice	(Device *, int, ulong, void *, int);
+void	phid	(Device *, int, ulong, void *, int);
+void	pcs_raw(char *tag, byte *b, int n);
 
 /*
  * interface
@@ -141,13 +364,15 @@ void		usbfmtinit(void);
 Device*	opendev(int, int);
 void		closedev(Device*);
 int		describedevice(Device*);
-void		dumpdevice(int, Device*);
-void		loadstr(Device*, int, int);
-void		loadstrings(Device*, int);
-
-int		setupreq(Device*, int, int, int, int, uchar*, int);
-
+int		loadconfig(Device *d, int n);
+Endpt *	newendpt(Device *d, int id, ulong csp);
+int		setupcmd(Endpt*, int, int, int, int, byte*, int);
+int		setupreq(Endpt*, int, int, int, int, int);
+int		setupreply(Endpt*, void*, int);
+void		setdevclass(Device *d, int n);
 void	*	emalloc(ulong);
 void	*	emallocz(ulong, int);
 
+char	*	namefor(Namelist *, int);
+
 #pragma	varargck	type  "D"	Device*

+ 0 - 153
sys/src/cmd/usb/lib/usbproto.h

@@ -1,153 +0,0 @@
-/*
- *	USB protocol requests on Endpoint 0
- */
-
-typedef uchar byte;
-
-#define	GET2(p)	((((p)[1]&0xFF)<<8)|((p)[0]&0xFF))
-#define	PUT2(p,v)	{((p)[0] = (v)); ((p)[1] = (v)>>8);}
-#define	GET4(p)	((((p)[3]&0xFF)<<24)|(((p)[2]&0xFF)<<16)|(((p)[1]&0xFF)<<8)|((p)[0]&0xFF))
-#define	PUT4(p,v)	{((p)[0] = (v)); ((p)[1] = (v)>>8); ((p)[2] = (v)>>16); ((p)[3] = (v)>>24);}
-#define	BIT(i)	(1<<(i))
-
-/*
- *	All device classes
- */
-enum
-{
-	/* request type */
-	RH2D = 0<<7,
-	RD2H = 1<<7,
-	Rstandard = 0<<5,
-	Rclass = 1<<5,
-	Rvendor = 2<<5,
-	Rdevice = 0,
-	Rinterface = 1,
-	Rendpt = 2,
-	Rother = 3,
-
-	/* standard requests (type Rstandard) */
-	GET_STATUS = 0,
-	CLEAR_FEATURE = 1,
-	SET_FEATURE = 3,
-	SET_ADDRESS = 5,
-	GET_DESCRIPTOR = 6,
-	SET_DESCRIPTOR = 7,
-	GET_CONFIGURATION = 8,
-	SET_CONFIGURATION = 9,
-	GET_INTERFACE = 10,
-	SET_INTERFACE = 11,
-	SYNCH_FRAME = 12,
-
-	/* descriptor types */
-	DEVICE = 1,
-	CONFIGURATION = 2,
-	STRING = 3,
-	INTERFACE = 4,
-	ENDPOINT = 5,
-	HID = 0x21,
-	REPORT = 0x22,
-	PHYSICAL = 0x23,
-};
-
-typedef struct DDevice DDevice;
-struct DDevice
-{
-	byte	bLength;
-	byte	bDescriptorType;
-	byte	bcdUSB[2];
-	byte	bDeviceClass;
-	byte	bDeviceSubClass;
-	byte	bDeviceProtocol;
-	byte	bMaxPacketSize0;
-	byte	idVendor[2];
-	byte	idProduct[2];
-	byte	bcdDevice[2];
-	byte	iManufacturer;
-	byte	iProduct;
-	byte	iSerialNumber;
-	byte	bNumConfigurations;
-};
-#define	DDEVLEN	18
-
-typedef struct DConfig DConfig;
-struct DConfig
-{
-	byte	bLength;
-	byte	bDescriptorType;
-	byte	wTotalLength[2];
-	byte	bNumInterfaces;
-	byte	bConfigurationValue;
-	byte	iConfiguration;
-	byte	bmAttributes;
-	byte	MaxPower;
-};
-#define	DCONFLEN	9
-
-typedef struct DInterface DInterface;
-struct DInterface
-{
-	byte	bLength;
-	byte	bDescriptorType;
-	byte	bInterfaceNumber;
-	byte	bAlternateSetting;
-	byte	bNumEndpoints;
-	byte	bInterfaceClass;
-	byte	bInterfaceSubClass;
-	byte	bInterfaceProtocol;
-	byte	iInterface;
-};
-#define	DINTERLEN	9
-
-typedef struct DEndpoint DEndpoint;
-struct DEndpoint
-{
-	byte	bLength;
-	byte	bDescriptorType;
-	byte	bEndpointAddress;
-	byte	bmAttributes;
-	byte	wMaxPacketSize[2];
-	byte	bInterval;
-};
-#define	DENDPLEN	7
-
-/*
- *	Hub Class
- */
-enum
-{
-	/* hub class feature selectors */
-	C_HUB_LOCAL_POWER = 0,
-	C_HUB_OVER_CURRENT,
-
-	PORT_CONNECTION = 0,
-	PORT_ENABLE = 1,
-	PORT_SUSPEND = 2,
-	PORT_OVER_CURRENT = 3,
-	PORT_RESET = 4,
-	PORT_POWER = 8,
-	PORT_LOW_SPEED = 9,
-	C_PORT_CONNECTION = 16,
-	C_PORT_ENABLE,
-	C_PORT_SUSPEND,
-	C_PORT_OVER_CURRENT,
-	C_PORT_RESET,
-
-	/* feature selectors */
-	DEVICE_REMOTE_WAKEUP = 1,
-	ENDPOINT_STALL = 0,
-};
-
-typedef struct DHub DHub;
-struct DHub
-{
-	byte	bLength;
-	byte	bDescriptorType;
-	byte	bNbrPorts;
-	byte	wHubCharacteristics[2];
-	byte	bPwrOn2PwrGood;
-	byte	bHubContrCurrent;
-	byte	DeviceRemovable[1];	/* variable length */
-/*	byte	PortPwrCtrlMask;		/* variable length, deprecated in USB v1.1 */
-};
-#define	DHUBLEN	9

+ 18 - 5
sys/src/cmd/usb/lib/util.c

@@ -3,14 +3,27 @@
 #include <thread.h>
 #include "usb.h"
 
+int debug, debugdebug, verbose;
+
+char *
+namefor(Namelist *list, int item)
+{
+	while (list->name){
+		if (list->index == item)
+			return list->name;
+		list++;
+	}
+	return "<unnamed>";
+}
+
 void *
 emalloc(ulong size)
 {
 	void *x;
 
 	x = malloc(size);
-	if(x == nil)
-		sysfatal("malloc: %r");
+	if (x == nil)
+		sysfatal("maloc: %r");
 	return x;
 }
 
@@ -20,9 +33,9 @@ emallocz(ulong size, int zero)
 	void *x;
 
 	x = malloc(size);
-	if(x == nil)
-		sysfatal("malloc: %r");
-	if(zero)
+	if (x == nil)
+		sysfatal("maloc: %r");
+	if (zero)
 		memset(x, 0, size);
 	return x;
 }

+ 8 - 1
sys/src/cmd/usb/mouse/mkfile → sys/src/cmd/usb/misc/mkfile

@@ -1,14 +1,21 @@
 </$objtype/mkfile
 
 TARG=\
+#	readir\
 	usbmouse\
+#	usbprobe\
 
 HFILES=\
 	../lib/usb.h\
-	../lib/usbproto.h\
 
 LIB=../lib/usb.a$O
 
+UPDATE=\
+	$HFILES\
+	${OFILES:%.$O=%.c}\
+	mkfile\
+	usbprint\
+
 BIN=/$objtype/bin/usb
 </sys/src/cmd/mkmany
 

+ 12 - 0
sys/src/cmd/usb/misc/usbprint

@@ -0,0 +1,12 @@
+#!/bin/rc
+
+for(c in `{seq 16}){
+	for(i in `{seq 20}){
+		if (grep -s 'Enabled 0x020107' '#U'/usb$c/$i/status){
+			echo -n 'ep 2 bulk w 64 32' >'#U'/usb$c/$i/ctl
+			bind '#U'/usb$c/$i/ep2data /n/lp
+			exit ''
+		}
+	}
+}
+exit 'no printer'

+ 14 - 4
sys/src/cmd/usb/mkfile

@@ -4,14 +4,24 @@ DIRS=\
 	lib\
 	usbd\
 	audio\
-	mouse\
-	printer\
+	misc\
+
+UPDATE=\
+	mkfile\
 
 none:VQ:
-	echo mk all, install, installall, clean, or nuke
+	echo mk all, install, clean, or nuke
 
-all install installall safeinstall clean nuke:VQ:
+all install clean nuke:VQ:
 	for (i in $DIRS) @{
 		cd $i
 		mk $target
 	}
+
+update:V:
+	update $UPDATEFLAGS $UPDATE
+	for (i in $DIRS) @{
+		echo update $i
+		cd $i
+		mk 'UPDATEFLAGS='$"UPDATEFLAGS update
+	}

+ 0 - 179
sys/src/cmd/usb/mouse/usbmouse.c

@@ -1,179 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include <stdio.h>
-
-int mousefd, ctlfd, mousein;
-
-char hbm[]			= "Enabled 0x020103\n";
-char *mouseinfile	= "#m/mousein";
-char *statfmt		= "#U/usb%d/%d/status";
-char *ctlfmt		= "#U/usb%d/%d/ctl";
-char *msefmt		= "#U/usb%d/%d/ep1data";
-char *ctlstr		= "ep 1 bulk r 3 32";
-char ctlfile[32];
-char msefile[32];
-
-int verbose;
-int nofork;
-int accel;
-int maxacc = 3;
-int debug;
-
-void work(void *);
-
-int
-robusthandler(void*, char *s)
-{
-	if (debug) fprint(2, "inthandler: %s\n", s);
-	return (s && (strstr(s, "interrupted")|| strstr(s, "hangup")));
-}
-
-long
-robustread(int fd, void *buf, long sz)
-{
-	long r;
-	char err[ERRMAX];
-
-	do {
-		r = read(fd , buf, sz);
-		if (r < 0)
-			rerrstr(err, sizeof(err));
-	} while (r < 0 && robusthandler(nil, err));
-	return r;
-}
-
-static int
-scale(int x)
-{
-	int sign = 1;
-
-	if(x < 0){
-		sign = -1;
-		x = -x;
-	}
-	switch(x){
-	case 0:
-	case 1:
-	case 2:
-	case 3:
-		break;
-	case 4:
-		x = 6 + (accel>>2);
-		break;
-	case 5:
-		x = 9 + (accel>>1);
-		break;
-	default:
-		x *= maxacc;
-		break;
-	}
-	return sign*x;
-}
-
-char maptab[] = {
-	0x0, 0x1, 0x4, 0x5, 0x2, 0x3, 0x6, 0x7
-};
-
-void
-usage(void)
-{
-	fprint(2, "usage: %s [-vf] [-a accel] [ctlrno usbport]\n", argv0);
-	threadexitsall("usage");
-}
-
-void
-threadmain(int argc, char *argv[])
-{
-	FILE *f;
-	int ctlrno, i;
-	char line[256];
-
-	rfork(RFNOTEG);
-
-	ARGBEGIN{
-	case 'v':
-		verbose=1;
-		break;
-	case 'f':
-		nofork=1;
-		break;
-	case 'a':
-		accel=strtol(ARGF(), nil, 0);
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	switch (argc) {
-	case 0:
-		for (ctlrno = 0; ctlrno < 16; ctlrno++) {
-			for (i = 0; i < 128; i++) {
-				sprint(line, statfmt, ctlrno, i);
-				f = fopen(line, "r");
-				if (f == nil)
-					break;
-				if (fgets(line, sizeof line, f) && strcmp(hbm, line) == 0) {
-					snprint(ctlfile, sizeof ctlfile, ctlfmt, ctlrno, i);
-					snprint(msefile, sizeof msefile, msefmt, ctlrno, i);
-					fclose(f);
-					goto found;
-				}
-				fclose(f);
-			}
-		}
-		threadexitsall("no mouse");
-	found:
-		break;
-	case 2:
-		ctlrno = atoi(argv[0]);
-		i = atoi(argv[1]);
-		snprint(ctlfile, sizeof ctlfile, ctlfmt, ctlrno, i);
-		snprint(msefile, sizeof msefile, msefmt, ctlrno, i);
-		break;
-	default:
-		usage();
-	}
-
-	if ((ctlfd = open(ctlfile, OWRITE)) < 0)
-		sysfatal("%s: %r", ctlfile);
-	if (verbose)
-		fprint(2, "Send %s to %s\n", ctlstr, ctlfile);
-	write(ctlfd, ctlstr, strlen(ctlstr));
-	close(ctlfd);
-	if ((mousefd = open(msefile, OREAD)) < 0)
-		sysfatal("%s: %r", msefile);
-	if (verbose)
-		fprint(2, "Start reading from %s\n", msefile);
-	if ((mousein = open(mouseinfile, OWRITE)) < 0)
-		sysfatal("%s: %r", mouseinfile);
-	atnotify(robusthandler, 1);
-	if (nofork)
-		work(nil);
-	else
-		proccreate(work, nil, 4*1024);
-	threadexits(nil);
-}
-
-void
-work(void *){
-	char buf[4];
-	int x, y;
-
-	for (;;) {
-		switch (robustread(mousefd, buf, 3)) {
-		case 3:
-			if (accel) {
-				x = scale(buf[1]);
-				y = scale(buf[2]);
-			} else {
-				x = buf[1];
-				y = buf[2];
-			}
-			fprint(mousein, "m%11d %11d %11d", x, y, maptab[buf[0]&0x7]);
-			break;
-		case -1:
-			sysfatal("read error: %r");
-		}
-	}
-}

+ 0 - 12
sys/src/cmd/usb/printer/mkfile

@@ -1,12 +0,0 @@
-</386/mkfile
-
-BIN=/$objtype/bin/usb
-
-none:VQ:
-	echo mk all, install, installall, clean, or nuke
-
-install installall safeinstall:V:
-	cp usbprinter $BIN
-
-all safeinstall clean nuke:V:
-	echo usbprinter

+ 0 - 13
sys/src/cmd/usb/printer/usbprinter

@@ -1,13 +0,0 @@
-#!/bin/rc
-
-if (! test -e /dev/usb)
-	bind -b '#U' /dev
-
-for(i in /dev/usb?/[0-9]*){
-	if (grep -s 'Enabled 0x020107' $i/status){
-		echo -n 'ep 2 bulk w 64 32' >$i/ctl
-		bind $i/ep2data /n/lp
-		exit ''
-	}
-}
-exit 'no printer'

+ 1 - 1
sys/src/cmd/usb/usbd/dat.h

@@ -27,4 +27,4 @@ struct Port
 
 #pragma	varargck	type  "H"	Hub*
 
-extern int verbose, debug;
+extern int verbose;

+ 0 - 131
sys/src/cmd/usb/usbd/device.c

@@ -1,131 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include "usb.h"
-#include "usbproto.h"
-
-#include "dat.h"
-#include "fns.h"
-
-void
-devspeed(Device *d, int ls)
-{
-	if(fprint(d->ctl, "speed %d", !ls) < 0)
-		sysfatal("devspeed: write error: %r");
-	if(debug)
-		fprint(2, "usbd: %D: set speed %s\n", d, ls?"low":"high");
-}
-
-int
-getmaxpkt(Device *d)
-{
-	int nr;
-	byte buf[8];
-	DDevice *dd;
-
-	nr = setupreq(d, RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (DEVICE<<8)|0, 0, buf, sizeof(buf));
-	if(nr < sizeof(buf)) {
-		fprint(2, "usbd: getmaxpkt: error reading device descriptor for %D, got %d of %d\n", d, nr, sizeof(buf));
-		return -1;
-	}
-	dd = (DDevice*)buf;
-	return dd->bMaxPacketSize0;
-}
-
-int
-setaddress(Device *d, int id)
-{
-	if(setupreq(d, RH2D, SET_ADDRESS, id, 0, nil, 0) < 0) {
-		fprint(2, "usbd: set address %D <- %d failed\n", d, id);
-		return -1;
-	}
-	return 0;
-}
-
-int
-setconfig(Device *d, int cval)
-{
-	int i, j, ret;
-	Dconf *c;
-	Dalt *alt;
-	Dinf *intf;
-	Endpt *ep;
-
-	c = nil;
-	for(i = 0; i < d->nconf; i++) {
-		if(d->config[i].cval == cval) {
-			c = &d->config[i];
-			break;
-		}
-	}
-	if(c == nil) {
-		werrstr("setconfig: cval %d not found", cval);
-		return -1;
-	}
-	if(setupreq(d, RH2D, SET_CONFIGURATION, cval, 0, nil, 0) < 0)
-		return -1;
-
-	/* BUG: temporary hack; the "class" stuff does NOT belong in the driver! */
-	if(d->csp != 0)
-		fprint(d->ctl, "class 15 0 0x%lux", d->csp);
-	/* ... */
-
-	for(i = 0; i < c->nif; i++) {
-		intf = &c->iface[i];
-
-		/* BUG: temporary hack; the "class" stuff does NOT belong in the driver! */
-		if((Class(intf->csp) == 1 || Class(intf->csp) == 3) && Subclass(intf->csp) == 1)
-			fprint(d->ctl, "class 15 0 0x%lux", intf->csp);
-		/* ... */
-
-		alt = intf->alt;
-		if(alt == nil)
-			continue;
-
-		/* BUG: temporary hack -- first alternate is often a `disabled' state */
-		if(alt->next != nil && alt->next->npt > alt->npt)
-			alt = alt->next;
-		/* ... */
-
-		for(j = 0; j < alt->npt; j++) {
-			ep = &alt->ep[j];
-
-			/* BUG: temporary hack; the "class" stuff does NOT belong in the driver! */
-			if(fprint(d->ctl, "class 15 %d 0x%lux", ep->addr, intf->csp) < 0)
-				fprint(2, "set class addr %d failed: %r\n", ep->addr);
-			/* ... */
-
-			if(ep->maxpkt == 0)
-				continue;
-			ret = -1;
-			switch(ep->type) {
-			case Econtrol:
-				ret = fprint(d->ctl, "ep %d bulk rw %d 1", ep->addr, ep->maxpkt);
-				break;
-			case Eiso:
-				ret = fprint(d->ctl, "ep %d 1 %s 1 %d000", ep->addr, ep->dir == Ein ? "r" : "w", ep->maxpkt);
-				break;
-			case Ebulk:
-				ret = fprint(d->ctl, "ep %d bulk %s %d 1", ep->addr, ep->dir == Ein ? "r" : "w", ep->maxpkt);
-				break;
-			case Eintr:
-				ret = fprint(d->ctl, "ep %d bulk %s %d 1", ep->addr, ep->dir == Ein ? "r" : "w", ep->maxpkt);
-				break;
-			}
-			if(ret < 0)
-				fprint(2, "ep %d message failed\n", ep->addr);
-		}
-	}
-	d->state = Configured;
-	return 0;
-}
-
-/*
-int
-setalternate(Device *d, int i, int alt)
-{
-	if(setupreq(d, RH2D, SET_CONFIGURATION, n, 0, nil, 0) < 0)
-		return -1;
-	return 0;
-}
-*/

+ 5 - 6
sys/src/cmd/usb/usbd/fns.h

@@ -3,20 +3,19 @@ Hub* roothub(int);
 Hub* newhub(Hub*, Device*);
 void	freehub(Hub*);
 int	Hfmt(Fmt*);
-int	portenable(Hub*, int, int);
-int	portreset(Hub*, int);
-int	portpower(Hub*, int, int);
+void	portenable(Hub*, int, int);
+void	portreset(Hub*, int);
+void	portpower(Hub*, int, int);
 int	portstatus(Hub*, int);
 
 /* setup.c */
 void	devspeed(Device*, int);
+void	setup0(Device*, int, int, int, int, int);
+void	setconfig(Device*, int);
 int	getmaxpkt(Device*);
 int	setaddress(Device*, int);
-int	setconfig(Device*, int);
-int	setalternate(Device*, int, int);
 
 /* usbd.c */
-void	roothubproc(void *);
 void	enumerate(void *);
 Device* configure(Hub *h, int port);
 void detach(Hub *h, int port);

+ 39 - 33
sys/src/cmd/usb/usbd/hub.c

@@ -2,7 +2,6 @@
 #include <libc.h>
 #include <thread.h>
 #include "usb.h"
-#include "usbproto.h"
 
 #include "dat.h"
 #include "fns.h"
@@ -46,23 +45,20 @@ newhub(Hub *parent, Device *d)
 	h->ctlrno = parent->ctlrno;
 	h->dev0 = parent->dev0;
 
-	nr = setupreq(d, RD2H|Rclass|Rdevice, GET_DESCRIPTOR, (0<<8)|0, 0, buf, sizeof(buf));
-	if(nr < 0) {
-		werrstr("newhub: %r");
-Error:
+	if (setupreq(d->ep[0], RD2H|Rclass|Rdevice, GET_DESCRIPTOR, (0<<8)|0, 0, sizeof(buf)) < 0 ||
+	   (nr = setupreply(d->ep[0], buf, sizeof(buf))) < DHUBLEN) {
+		fprint(2, "usbd: error reading hub descriptor\n");
 		free(h);
 		return nil;
 	}
-	if(nr < DHUBLEN) {
-		werrstr("newhub: short device descriptor (%d < %d)", nr, DHUBLEN);
-		goto Error;
-	}
+	pdesc(d, -1, -1, buf, nr);
 	dd = (DHub*)buf;
 	nport = dd->bNbrPorts;
 	nmap = 1 + nport/8;
 	if(nr < 7 + 2*nmap) {
-		werrstr("newhub: hub descriptor too small");
-		goto Error;
+		fprint(2, "usbd: hub descriptor too small\n");
+		free(h);
+		return nil;
 	}
 
 	h->nport = nport;
@@ -116,7 +112,7 @@ Hfmt(Fmt *f)
 	return fmtprint(f, "usb%d/%d", h->ctlrno, h->d->id);
 }
 
-static int
+static void
 hubfeature(Hub *h, int port, int feature, int on)
 {
 	int cmd;
@@ -125,37 +121,46 @@ hubfeature(Hub *h, int port, int feature, int on)
 		cmd = SET_FEATURE;
 	else
 		cmd = CLEAR_FEATURE;
-	return setupreq(h->d, Rclass|Rother, cmd, feature, port, nil, 0);
+	setup0(h->d, Rclass|Rother, cmd, feature, port, 0);
 }
 
-int
+void
 portenable(Hub *h, int port, int on)
 {
-	if(h->isroot)
-		return fprint(h->portfd, "%s %d", on? "enable": "disable", port);
-	return hubfeature(h, port, PORT_ENABLE, on);
+	if(h->isroot) {
+		if(fprint(h->portfd, "%s %d", on? "enable": "disable", port) < 0)
+			sysfatal("usbd: portenable: write error: %r");
+		return;
+	}
+	if(port == 0)
+		return;
+	hubfeature(h, port, PORT_ENABLE, on);
 }
 
-int
+void
 portreset(Hub *h, int port)
 {
 	if(h->isroot) {
 		if(fprint(h->portfd, "reset %d", port) < 0)
-			return -1;
+			sysfatal("usbd: portreset: write error: %r");
 		sleep(100);
-		return 0;
+		return;
 	}
-	return hubfeature(h, port, PORT_RESET, 1);
+	if(port == 0)
+		return;
+	hubfeature(h, port, PORT_RESET, 1);
 }
 
-int
+void
 portpower(Hub *h, int port, int on)
 {
 	if(h->isroot) {
 		/* no power control */
-		return 0;
+		return;
 	}
-	return hubfeature(h, port, PORT_POWER, on);
+	if(port == 0)
+		return;
+	hubfeature(h, port, PORT_POWER, on);
 }
 
 static struct
@@ -176,6 +181,7 @@ int
 portstatus(Hub *h, int port)
 {
 	int x;
+	Endpt *e;
 	byte buf[4];
 	int n, nf, i, j;
 	char *status, *q, *qe, *field[20];
@@ -184,11 +190,8 @@ portstatus(Hub *h, int port)
 		seek(h->portfd, 0, 0);
 		status = malloc(8192);
 		n = read(h->portfd, status, 8192);
-		if(n <= 0) {
-			werrstr("portstatus read: %r");
-			free(status);
-			return -1;
-		}
+		if (n <= 0)
+			sysfatal("usbd: can't read usb port status: %r");
 		status[n] = '\0';
 		q = status;
 		for(;;) {
@@ -215,9 +218,12 @@ portstatus(Hub *h, int port)
 		free(status);
 		return x;
 	}
-	if(setupreq(h->d, RD2H|Rclass|Rother, GET_STATUS, 0, port, buf, sizeof(buf)) < sizeof(buf)) {
-		werrstr("portstatus: setupreq: %r");
-		return -1;
+	e = h->d->ep[0];
+	if (setupreq(e, RD2H|Rclass|Rother, GET_STATUS, 0, port, sizeof(buf)) < 0
+	  || setupreply(e, buf, sizeof(buf)) < sizeof(buf)) {
+		if (debug)
+			sysfatal("usbd: error reading hub status %H.%d", h, port);
+		return 0;
 	}
-	return GET4(buf);
+	return GET2(buf);
 }

+ 7 - 2
sys/src/cmd/usb/usbd/mkfile

@@ -2,18 +2,23 @@
 
 TARG=usbd
 OFILES=\
-	device.$O\
 	hub.$O\
+	setup.$O\
 	usbd.$O\
 
 HFILES=\
 	dat.h\
 	fns.h\
 	../lib/usb.h\
-	../lib/usbproto.h\
 
 LIB=../lib/usb.a$O
 
+UPDATE=\
+	$HFILES\
+	${OFILES:%.$O=%.c}\
+	mkfile\
+	/sys/man/3/usb\
+
 BIN=/$objtype/bin/usb
 </sys/src/cmd/mkone
 

+ 56 - 0
sys/src/cmd/usb/usbd/setup.c

@@ -0,0 +1,56 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "usb.h"
+
+#include "dat.h"
+#include "fns.h"
+
+void
+devspeed(Device *d, int ls)
+{
+	if(fprint(d->ctl, "speed %d", !ls) < 0)
+		sysfatal("devspeed: write error: %r");
+	if(debug)
+		fprint(2, "usbd: %D: set speed %s\n", d, ls?"low":"high");
+}
+
+void
+setup0(Device *d, int type, int req, int value, int index, int count)
+{
+	if(setupreq(d->ep[0], type, req, value, index, count) < 0)
+		sysfatal("usbd: %D: transaction error", d);
+}
+
+void
+setconfig(Device *d, int n)
+{
+	setup0(d, RH2D, SET_CONFIGURATION, n, 0, 0);
+	d->state = Configured;
+}
+
+int
+getmaxpkt(Device *d)
+{
+	DDevice *dd;
+	byte buf[8];
+	int nr = -1;
+
+	if (setupreq(d->ep[0], RD2H|Rstandard|Rdevice, GET_DESCRIPTOR, (DEVICE<<8)|0, 0, sizeof(buf)) < 0 ||
+	   (nr = setupreply(d->ep[0], buf, sizeof(buf))) < sizeof(buf)) {
+		fprint(2, "usbd: getmaxpkt: error reading device descriptor for %D, got %d of %d\n", d, nr, sizeof(buf));
+		return -1;
+	}
+	dd = (DDevice*)buf;
+	return dd->bMaxPacketSize0;
+}
+
+int
+setaddress(Device *d, int id)
+{
+	if (setupreq(d->ep[0], RH2D, SET_ADDRESS, id, 0, 0) < 0) {
+		fprint(2, "usbd: set address %D <- %d failed\n", d, id);
+		return -1;
+	}
+	return 0;
+}

+ 105 - 125
sys/src/cmd/usb/usbd/usbd.c

@@ -1,7 +1,6 @@
 #include <u.h>
 #include <libc.h>
 #include <thread.h>
-#include "usbproto.h"
 #include "usb.h"
 
 #include "dat.h"
@@ -9,8 +8,11 @@
 
 #define STACKSIZE 128*1024
 
+static int dontfork;
+
 Ref	busy;
-int	debug, verbose;
+
+int debug;
 
 typedef struct Enum Enum;
 struct Enum
@@ -19,57 +21,21 @@ struct Enum
 	int port;
 };
 
+void (*dprinter[])(Device *, int, ulong, void *b, int n) = {
+	[STRING] pstring,
+	[DEVICE] pdevice,
+	[0x29] phub,
+};
+
 static void
 usage(void)
 {
-	fprint(2, "usage: usbd [-v] [-d]\n");
+	fprint(2, "usage: usbd\n");
 	threadexitsall("usage");
 }
 
 void
-threadmain(int argc, char **argv)
-{
-	int i;
-	Hub *h;
-
-	ARGBEGIN {
-	case 'd':
-		debug++;
-		break;
-	case 'v':
-		verbose = 1;
-		break;
-	} ARGEND
-
-	if(argc)
-		usage();
-
-	rfork(RFNOTEG);
-	if(access("/dev/usb0", 0) < 0 && bind("#U", "/dev", MAFTER) < 0)
-		sysfatal("%s: can't bind #U after /dev: %r\n", argv0);
-
-	usbfmtinit();
-	fmtinstall('H', Hfmt);
-
-	/* don't hold window open */
-	close(0);
-	close(1);
-	if(!debug && !verbose)
-		close(2);
-
-	for(i = 0; (h = roothub(i)) != nil; i++) {
-		incref(&busy);
-		proccreate(roothubproc, h, STACKSIZE);
-	}
-	while(busy.ref)
-		sleep(100);
-	if(verbose)
-		fprint(2, "usbd: enumeration complete\n");
-	threadexits(nil);
-}
-
-void
-roothubproc(void *a)
+work(void *a)
 {
 	int port;
 	Hub *hub;
@@ -91,59 +57,98 @@ roothubproc(void *a)
 		yield();
 		if (busy.ref == 0)
 			sleep(2000);
-		else if(debug > 1)
-			fprint(2, "usbd: busy.ref %ld\n", busy.ref);
 	}
 }
 
+void
+threadmain(int argc, char **argv)
+{
+	int i;
+	Hub *h;
+
+	ARGBEGIN{
+	case 'f':
+		dontfork=1;
+		break;
+	case 'd':
+		debug++;
+		break;
+	case 'v':
+		verbose = 1;
+		break;
+	}ARGEND
+	if (argc)
+		usage();
+	if (access("/dev/usb0", 0) < 0 && bind("#U", "/dev", MAFTER) < 0)
+		sysfatal("%s: can't bind #U after /dev: %r\n", argv0);
+
+	usbfmtinit();
+	fmtinstall('H', Hfmt);
+
+	/* always fork off usb[1-n] */
+	for(i=1; (h = roothub(i)) != nil; i++) {
+		incref(&busy);
+		proccreate(work, h, STACKSIZE);
+	}
+
+	/* usb0 might be handled in this proc */
+	if((h = roothub(0)) != nil){
+		incref(&busy);
+		if (dontfork) {
+			work(h);
+		} else {
+			rfork(RFNOTEG);
+			proccreate(work, h, STACKSIZE);
+			/* don't hold window open */
+			close(0);
+			close(1);
+			if(!debug && !verbose)
+				close(2);
+		}
+	}
+	if (debug)
+		fprint(2, "done\n");
+	while (busy.ref)
+		sleep(100);
+	threadexits(nil);
+}
+
 void
 enumerate(void *v)
 {
+	int i, port;
 	Device *d;
 	Enum *arg;
 	Hub *h, *nh;
-	int i, port, status;
 
 	arg = v;
 	h = arg->hub;
 	port = arg->port;
 	free(arg);
 
-	for(;;) {
-		status = portstatus(h, port);
-		if(status < 0) {
-badstatus:
-			if(debug)
-				fprint(2, "usbd: %H.%d: %r\n", h, port);
-			threadexits(nil);
-		}
-		if((status & (1<<PORT_CONNECTION)) == 0) {
+	for (;;) {
+		if((portstatus(h, port) & (1<<PORT_CONNECTION)) == 0) {
 			decref(&busy);
-			if(verbose)
+			if (verbose)
 				fprint(2, "usbd: %H: port %d empty\n", h, port);
-			for(;;) {
+			do {
 				yield();
-				if(debug > 1)
+				if (debugdebug)
 					fprint(2, "usbd: probing %H.%d\n", h, port);
 				sleep(500);
-				status = portstatus(h, port);
-				if(status < 0)
-					goto badstatus;
-				if((status & (1<<PORT_CONNECTION)) != 0)
-					break;
-			}
+			} while((portstatus(h, port) & (1<<PORT_CONNECTION)) == 0);
 			incref(&busy);
 		}
 		if(verbose)
 			fprint(2, "usbd: %H: port %d attached\n", h, port);
 		d = configure(h, port);
 		if(d == nil) {
-			if(verbose || debug)
-				fprint(2, "usbd: can't configure port %H.%d: %r\n", h, port);
+			if(verbose)
+				fprint(2, "usbd: can't configure port %H.%d\n", h, port);
 			decref(&busy);
 			threadexits("configure");
 		}
-		if(Class(d->csp) == CL_HUB) {
+		if(d->class == Hubclass) {
 			if(debug)
 				fprint(2, "usbd: %H.%d: hub %d attached\n", h, port, d->id);
 			setconfig(d, 1);
@@ -158,7 +163,7 @@ badstatus:
 			/* TO DO: initialise status endpoint */
 			for(i=1; i<=nh->nport; i++)
 				portpower(nh, i, 1);
-			sleep(100+nh->pwrms);
+			sleep(nh->pwrms);
 			for(i=1; i<=nh->nport; i++) {
 				arg = emallocz(sizeof(Enum), 1);
 				arg->hub = nh;
@@ -166,34 +171,27 @@ badstatus:
 				incref(&busy);
 				threadcreate(enumerate, arg, STACKSIZE);
 			}
-			h->port[port-1].hub = nh;
 		}else{
 			if(debug)
 				fprint(2, "usbd: %H.%d: %d: not hub, %s speed\n", h, port, d->id, d->ls?"low":"high");
 			setconfig(d, 1);	/* TO DO */
+//unconscionable kludge (testing camera)
+if(d->class == 10) setup0(d, RH2D|Rinterface, SET_INTERFACE, 10, 0, 0);
 		}
 		decref(&busy);
-		for(;;) {
-			status = portstatus(h, port);
-			if(status < 0) {
-				detach(h, port);
-				goto badstatus;
-			}
-			if((status & (1<<PORT_CONNECTION)) == 0)
-				break;
-			if(debug > 1)
-				fprint(2, "usbd: checking %H.%d\n", h, port);
+		while(portstatus(h, port) & (1<<PORT_CONNECTION)) {
+			if (debugdebug)
+				fprint(2, "checking %H.%d\n", h, port);
 			yield();
-			if(d->state == Detached) {
-				if(verbose)
-					fprint(2, "usbd: %H: port %d detached by parent hub\n", h, port);
+			if (d->state == Detached) {
+				if (verbose)
+					fprint(2, "%H: port %d detached by parent hub\n", h, port);
 				/* parent hub died */
 				threadexits(nil);
 			}
 		}
-		incref(&busy);
 		if(verbose)
-			fprint(2, "usbd: %H: port %d detached\n", h, port);
+			fprint(2, "%H: port %d detached\n", h, port);
 		detach(h, port);
 	}
 	threadexits(nil);
@@ -204,39 +202,28 @@ configure(Hub *h, int port)
 {
 	Port *p;
 	Device *d;
-	int s, maxpkt, ls;
+	int i, s, maxpkt, ls;
 
-	if(portenable(h, port, 1) < 0)
-		return nil;
-	sleep(100);
-	if(portreset(h, port) < 0)
-		return nil;
-	sleep(100);
+	portenable(h, port, 1);
+	sleep(20);
+	portreset(h, port);
+	sleep(20);
 	s = portstatus(h, port);
-	if(s == -1)
-		return nil;
-	if(debug)
+	if (debug)
 		fprint(2, "%H.%d status %#ux\n", h, port, s);
-	if((s & (1<<PORT_CONNECTION)) == 0)
+	if ((s & (1<<PORT_CONNECTION)) == 0)
 		return nil;
-	sleep(100);
-	if((s & (1<<PORT_SUSPEND)) == 0) {
+	if ((s & (1<<PORT_SUSPEND)) == 0) {
 		if (debug)
 			fprint(2, "enabling port %H.%d\n", h, port);
-		if(portenable(h, port, 1) < 0)
-			return nil;
-		sleep(100);
+		portenable(h, port, 1);
 		s = portstatus(h, port);
-		if(s == -1)
-			return nil;
-		sleep(100);
 		if (debug)
 			fprint(2, "%H.%d status now %#ux\n", h, port, s);
 	}
 
 	ls = (s & (1<<PORT_LOW_SPEED)) != 0;
 	devspeed(h->dev0, ls);
-	sleep(100);
 	maxpkt = getmaxpkt(h->dev0);
 	if(maxpkt < 0) {
 Error0:
@@ -246,6 +233,7 @@ Error0:
 	d = opendev(h->ctlrno, -1);
 	d->ls = ls;
 	d->state = Enabled;
+	d->ep[0]->maxpkt = maxpkt;
 	if(fprint(d->ctl, "maxpkt 0 %d", maxpkt) < 0) {
 Error1:
 		closedev(d);
@@ -254,16 +242,18 @@ Error1:
 	if(setaddress(h->dev0, d->id) < 0)
 		goto Error1;
 	d->state = Assigned;
-	sleep(100);
 	devspeed(d, ls);
-	sleep(100);
 	if(describedevice(d) < 0)
 		goto Error1;
-	if(verbose || debug) {
-		loadstrings(d, 1033);
-		dumpdevice(2, d);
-	}
 
+	/* read configurations 0 to n */
+	for(i=0; i<d->nconf; i++) {
+		if(d->config[i] == nil)
+			d->config[i] = mallocz(sizeof(*d->config[i]),1);
+		loadconfig(d, i);
+	}
+	for(i=0; i<16; i++)
+		setdevclass(d, i);
 	p = &h->port[port-1];
 	p->d = d;
 	return d;
@@ -272,25 +262,15 @@ Error1:
 void
 detach(Hub *h, int port)
 {
-	int i;
 	Port *p;
-	Hub *hh;
 	Device *d;
 
 	p = &h->port[port-1];
-	hh = p->hub;
-	if(hh != nil) {
-		for(i = 1; i <= hh->nport; i++)
-			detach(hh, i);
-		freehub(hh);
+	if(p->hub != nil) {
+		freehub(p->hub);
 		p->hub = nil;
 	}
 	d = p->d;
-	if(d == nil || d->state == Detached)
-		return;
-	if(debug || verbose)
-		fprint(2, "usbd: detaching %D from %H.%d\n", d, h, port);
 	d->state = Detached;	/* return i/o error on access */
 	closedev(d);
-	p->d = nil;
 }