Browse Source

Plan 9 from Bell Labs 2008-02-06

David du Colombier 13 years ago
parent
commit
495c8fca17

+ 25 - 18
dist/replica/_plan9.db

@@ -1413,7 +1413,7 @@ lib/face/48x48x4/x/xigh.1 - 664 sys sys 1142019024 1204
 lib/face/48x48x4/y - 20000000775 sys sys 1020895714 0
 lib/face/48x48x4/z - 20000000775 sys sys 1020895714 0
 lib/face/48x48x8 - 20000000775 sys sys 1123100641 0
-lib/face/48x48x8/.dict - 664 sys sys 1196685315 4324
+lib/face/48x48x8/.dict - 664 sys sys 1202248817 4382
 lib/face/48x48x8/Z - 20000000775 sys sys 1020895714 0
 lib/face/48x48x8/a - 20000000775 sys sys 1056983599 0
 lib/face/48x48x8/a/alcortes.1 - 664 sys sys 1176753392 976
@@ -1433,6 +1433,7 @@ lib/face/48x48x8/c/cespedes.1 - 664 sys sys 1176753392 957
 lib/face/48x48x8/c/chesky.1 - 664 sys sys 1161120611 1929
 lib/face/48x48x8/c/chrislocke.1 - 664 sys sys 1057005038 1613
 lib/face/48x48x8/c/comcast.1 - 664 sys sys 1057025679 6972
+lib/face/48x48x8/c/coraid.1 - 444 sys sys 1202248824 6972
 lib/face/48x48x8/d - 20000000775 sys sys 1118196820 0
 lib/face/48x48x8/d/daiello.1 - 664 sys sys 1176753392 902
 lib/face/48x48x8/d/dancross.1 - 664 sys sys 1057029244 1580
@@ -1448,6 +1449,7 @@ lib/face/48x48x8/f/forsyth.1 - 664 sys sys 1056982111 1864
 lib/face/48x48x8/f/fst.1 - 664 sys sys 1157149515 1099
 lib/face/48x48x8/g - 20000000775 sys sys 1140276024 0
 lib/face/48x48x8/g/gabidiaz.1 - 664 sys sys 1176753392 931
+lib/face/48x48x8/g/georgia.1 - 664 sys sys 1202248860 1683
 lib/face/48x48x8/g/gmail.1 - 664 sys sys 1097900774 1779
 lib/face/48x48x8/g/google.1 - 664 sys sys 1038967265 712
 lib/face/48x48x8/h - 20000000775 sys sys 1039727284 0
@@ -5808,7 +5810,7 @@ sys/doc/sam/refs - 464 sys sys 944959644 2652
 sys/doc/sam/sam.ms - 464 sys sys 1138396552 94640
 sys/doc/sam/sam.pdf - 664 sys sys 1020384352 156123
 sys/doc/sam/sam.ps - 664 sys sys 960837910 707546
-sys/doc/sam/sam.tut - 464 sys sys 944959644 40481
+sys/doc/sam/sam.tut - 464 sys sys 1202248612 40481
 sys/doc/sleep.ms - 664 sys sys 1138396447 15272
 sys/doc/sleep.ps - 664 sys sys 960837920 263882
 sys/doc/spin.ms - 664 sys sys 1138396447 67493
@@ -7707,7 +7709,7 @@ sys/man/3/srv - 664 sys sys 1196638942 1470
 sys/man/3/ssl - 664 sys sys 1196638942 3413
 sys/man/3/tls - 664 sys sys 1196638942 7018
 sys/man/3/uart - 664 sys sys 1196638942 2003
-sys/man/3/usb - 664 sys sys 1196638942 7179
+sys/man/3/usb - 664 sys sys 1202258356 7527
 sys/man/3/vga - 664 sys sys 1196638942 4987
 sys/man/4 - 20000000775 sys sys 1128556957 0
 sys/man/4/0intro - 664 sys sys 1196638942 472
@@ -7752,7 +7754,7 @@ sys/man/4/u9fs - 664 sys sys 1196638944 4748
 sys/man/4/upasfs - 664 sys sys 1196638944 6212
 sys/man/4/usb - 664 sys sys 1196638944 4682
 sys/man/4/usbd - 664 sys sys 1196638944 712
-sys/man/4/usbdisk - 664 sys sys 1200688323 2785
+sys/man/4/usbdisk - 664 sys sys 1202256707 3025
 sys/man/4/vacfs - 664 sys sys 1196638944 1545
 sys/man/4/webcookies - 664 sys sys 1196638944 3525
 sys/man/4/webfs - 664 sys sys 1196638944 6518
@@ -7862,7 +7864,7 @@ sys/man/8/partfs - 664 sys sys 1196638947 869
 sys/man/8/pcmcia - 664 sys sys 1196638947 408
 sys/man/8/pem - 664 sys sys 1196638947 1189
 sys/man/8/ping - 664 sys sys 1196638947 3650
-sys/man/8/plan9.ini - 664 sys sys 1196638947 23835
+sys/man/8/plan9.ini - 664 sys sys 1202255136 23868
 sys/man/8/pop3 - 664 sys sys 1197574309 3122
 sys/man/8/ppp - 664 sys sys 1196638948 4430
 sys/man/8/prep - 664 sys sys 1196638948 14201
@@ -8090,7 +8092,7 @@ sys/src/9/pc/devlpt.c - 664 sys sys 1184469951 4423
 sys/src/9/pc/devpccard.c - 664 sys sys 1184469910 39336
 sys/src/9/pc/devrtc.c - 664 sys sys 1015014515 7167
 sys/src/9/pc/devtv.c - 664 sys sys 1184469620 45423
-sys/src/9/pc/devusb.c - 664 sys sys 1168305372 18752
+sys/src/9/pc/devusb.c - 664 sys sys 1202251756 20662
 sys/src/9/pc/devvga.c - 664 sys sys 1181083003 9334
 sys/src/9/pc/dma.c - 664 sys sys 1142966373 5332
 sys/src/9/pc/ether2000.c - 664 sys sys 1173287379 4901
@@ -8166,7 +8168,7 @@ sys/src/9/pc/screen.h - 664 sys sys 1147023549 4256
 sys/src/9/pc/sd53c8xx.c - 664 sys sys 1170456695 55276
 sys/src/9/pc/sd53c8xx.i - 664 sys sys 1128547230 28453
 sys/src/9/pc/sd53c8xx.n - 664 sys sys 1131290556 12657
-sys/src/9/pc/sdata.c - 664 sys sys 1186361525 52991
+sys/src/9/pc/sdata.c - 664 sys sys 1202251523 53036
 sys/src/9/pc/sdiahci.c - 664 sys sys 1200348596 38496
 sys/src/9/pc/sdmv50xx.c - 664 sys sys 1199910989 33838
 sys/src/9/pc/sdmylex.c - 664 sys sys 1189229947 28395
@@ -8177,8 +8179,9 @@ sys/src/9/pc/uartaxp.i - 664 sys sys 1155243528 111326
 sys/src/9/pc/uarti8250.c - 664 sys sys 1177676872 13957
 sys/src/9/pc/uartisa.c - 664 sys sys 1127126907 1777
 sys/src/9/pc/uartpci.c - 664 sys sys 1190235592 4685
-sys/src/9/pc/usb.h - 664 sys sys 1165555430 4257
-sys/src/9/pc/usbuhci.c - 664 sys sys 1184466791 31205
+sys/src/9/pc/usb.h - 664 sys sys 1202251665 4590
+sys/src/9/pc/usbohci.c - 664 sys sys 1202254075 47560
+sys/src/9/pc/usbuhci.c - 664 sys sys 1202252076 31839
 sys/src/9/pc/vga.c - 664 sys sys 1131290595 5148
 sys/src/9/pc/vga3dfx.c - 664 sys sys 1133218367 3833
 sys/src/9/pc/vgaark2000pv.c - 664 sys sys 1131290600 3422
@@ -14257,34 +14260,34 @@ sys/src/cmd/usb/audio - 20000000775 sys sys 1091204980 0
 sys/src/cmd/usb/audio/audiofs.c - 664 sys sys 1172903208 18518
 sys/src/cmd/usb/audio/audiosub.c - 664 sys sys 1172764044 8275
 sys/src/cmd/usb/audio/mkfile - 664 sys sys 1091204980 349
-sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1172764045 10358
+sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1202255398 10343
 sys/src/cmd/usb/audio/usbaudio.h - 664 sys sys 1140695062 1889
 sys/src/cmd/usb/audio/usbaudioctl.c - 664 sys sys 1172764044 18825
 sys/src/cmd/usb/audio/usbaudioctl.h - 664 sys sys 1140695062 618
 sys/src/cmd/usb/disk - 20000000775 sys sys 1193181450 0
-sys/src/cmd/usb/disk/disk.c - 664 sys sys 1200688320 20111
+sys/src/cmd/usb/disk/disk.c - 664 sys sys 1202256113 20245
 sys/src/cmd/usb/disk/mkfile - 664 sys sys 1193181450 359
 sys/src/cmd/usb/lib - 20000000775 sys sys 1091204979 0
-sys/src/cmd/usb/lib/device.c - 664 sys sys 1168308464 3284
-sys/src/cmd/usb/lib/dump.c - 664 sys sys 1168308417 13122
+sys/src/cmd/usb/lib/device.c - 664 sys sys 1202255312 3552
+sys/src/cmd/usb/lib/dump.c - 664 sys sys 1202255256 13075
 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 1165044747 1936
+sys/src/cmd/usb/lib/setup.c - 664 sys sys 1202255323 1933
 sys/src/cmd/usb/lib/usb.h - 664 sys sys 1165044715 7066
 sys/src/cmd/usb/lib/util.c - 664 sys sys 1091204978 523
 sys/src/cmd/usb/misc - 20000000775 sys sys 1091282306 0
 sys/src/cmd/usb/misc/mkfile - 664 sys sys 1167255850 374
-sys/src/cmd/usb/misc/usbmouse.c - 664 sys sys 1178824856 3755
+sys/src/cmd/usb/misc/usbmouse.c - 664 sys sys 1202255573 3768
 sys/src/cmd/usb/misc/usbprint - 775 sys sys 1167253831 314
 sys/src/cmd/usb/misc/usbprobe - 775 sys sys 1167253836 173
 sys/src/cmd/usb/mkfile - 664 sys sys 1193181446 361
 sys/src/cmd/usb/usbd - 20000000775 sys sys 1091204979 0
 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 1168308558 4294
+sys/src/cmd/usb/usbd/hub.c - 664 sys sys 1202255474 4292
 sys/src/cmd/usb/usbd/mkfile - 664 sys sys 1091204979 304
-sys/src/cmd/usb/usbd/setup.c - 664 sys sys 1168308573 1351
-sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1168308592 5204
+sys/src/cmd/usb/usbd/setup.c - 664 sys sys 1202255463 1351
+sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1202255449 5327
 sys/src/cmd/va - 20000000775 sys sys 1039727598 0
 sys/src/cmd/va/a.h - 664 sys sys 1089299166 2915
 sys/src/cmd/va/a.y - 664 sys sys 944961340 7211
@@ -15856,3 +15859,7 @@ usr/glenda/lib/profile - 664 glenda glenda 1105128663 890
 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/bin/usb/disk - 775 sys sys 1202272000 187347
+386/bin/usb/usbaudio - 775 sys sys 1202272003 188183
+386/bin/usb/usbd - 775 sys sys 1202272005 131144
+386/bin/usb/usbmouse - 775 sys sys 1202272007 109417

+ 25 - 22
dist/replica/plan9.db

@@ -483,10 +483,10 @@
 386/bin/upas/unspam - 775 sys sys 1064598367 38
 386/bin/upas/vf - 775 sys sys 1181704900 97444
 386/bin/usb - 20000000775 sys sys 1019538890 0
-386/bin/usb/disk - 775 sys sys 1200717250 187004
-386/bin/usb/usbaudio - 775 sys sys 1184731243 188000
-386/bin/usb/usbd - 775 sys sys 1184731243 130757
-386/bin/usb/usbmouse - 775 sys sys 1184731244 109661
+386/bin/usb/disk - 775 sys sys 1202272000 187347
+386/bin/usb/usbaudio - 775 sys sys 1202272003 188183
+386/bin/usb/usbd - 775 sys sys 1202272005 131144
+386/bin/usb/usbmouse - 775 sys sys 1202272007 109417
 386/bin/usb/usbprint - 775 sys sys 1196537245 314
 386/bin/usb/usbprobe - 775 sys sys 1196537245 173
 386/bin/vac - 775 sys sys 1196742539 171330
@@ -1413,7 +1413,7 @@ lib/face/48x48x4/x/xigh.1 - 664 sys sys 1142019024 1204
 lib/face/48x48x4/y - 20000000775 sys sys 1020895714 0
 lib/face/48x48x4/z - 20000000775 sys sys 1020895714 0
 lib/face/48x48x8 - 20000000775 sys sys 1123100641 0
-lib/face/48x48x8/.dict - 664 sys sys 1196685315 4324
+lib/face/48x48x8/.dict - 664 sys sys 1202248817 4382
 lib/face/48x48x8/Z - 20000000775 sys sys 1020895714 0
 lib/face/48x48x8/a - 20000000775 sys sys 1056983599 0
 lib/face/48x48x8/a/alcortes.1 - 664 sys sys 1176753392 976
@@ -1433,6 +1433,7 @@ lib/face/48x48x8/c/cespedes.1 - 664 sys sys 1176753392 957
 lib/face/48x48x8/c/chesky.1 - 664 sys sys 1161120611 1929
 lib/face/48x48x8/c/chrislocke.1 - 664 sys sys 1057005038 1613
 lib/face/48x48x8/c/comcast.1 - 664 sys sys 1057025679 6972
+lib/face/48x48x8/c/coraid.1 - 444 sys sys 1202248824 6972
 lib/face/48x48x8/d - 20000000775 sys sys 1118196820 0
 lib/face/48x48x8/d/daiello.1 - 664 sys sys 1176753392 902
 lib/face/48x48x8/d/dancross.1 - 664 sys sys 1057029244 1580
@@ -1448,6 +1449,7 @@ lib/face/48x48x8/f/forsyth.1 - 664 sys sys 1056982111 1864
 lib/face/48x48x8/f/fst.1 - 664 sys sys 1157149515 1099
 lib/face/48x48x8/g - 20000000775 sys sys 1140276024 0
 lib/face/48x48x8/g/gabidiaz.1 - 664 sys sys 1176753392 931
+lib/face/48x48x8/g/georgia.1 - 664 sys sys 1202248860 1683
 lib/face/48x48x8/g/gmail.1 - 664 sys sys 1097900774 1779
 lib/face/48x48x8/g/google.1 - 664 sys sys 1038967265 712
 lib/face/48x48x8/h - 20000000775 sys sys 1039727284 0
@@ -5808,7 +5810,7 @@ sys/doc/sam/refs - 464 sys sys 944959644 2652
 sys/doc/sam/sam.ms - 464 sys sys 1138396552 94640
 sys/doc/sam/sam.pdf - 664 sys sys 1020384352 156123
 sys/doc/sam/sam.ps - 664 sys sys 960837910 707546
-sys/doc/sam/sam.tut - 464 sys sys 944959644 40481
+sys/doc/sam/sam.tut - 464 sys sys 1202248612 40481
 sys/doc/sleep.ms - 664 sys sys 1138396447 15272
 sys/doc/sleep.ps - 664 sys sys 960837920 263882
 sys/doc/spin.ms - 664 sys sys 1138396447 67493
@@ -7707,7 +7709,7 @@ sys/man/3/srv - 664 sys sys 1196638942 1470
 sys/man/3/ssl - 664 sys sys 1196638942 3413
 sys/man/3/tls - 664 sys sys 1196638942 7018
 sys/man/3/uart - 664 sys sys 1196638942 2003
-sys/man/3/usb - 664 sys sys 1196638942 7179
+sys/man/3/usb - 664 sys sys 1202258356 7527
 sys/man/3/vga - 664 sys sys 1196638942 4987
 sys/man/4 - 20000000775 sys sys 1128556957 0
 sys/man/4/0intro - 664 sys sys 1196638942 472
@@ -7752,7 +7754,7 @@ sys/man/4/u9fs - 664 sys sys 1196638944 4748
 sys/man/4/upasfs - 664 sys sys 1196638944 6212
 sys/man/4/usb - 664 sys sys 1196638944 4682
 sys/man/4/usbd - 664 sys sys 1196638944 712
-sys/man/4/usbdisk - 664 sys sys 1200688323 2785
+sys/man/4/usbdisk - 664 sys sys 1202256707 3025
 sys/man/4/vacfs - 664 sys sys 1196638944 1545
 sys/man/4/webcookies - 664 sys sys 1196638944 3525
 sys/man/4/webfs - 664 sys sys 1196638944 6518
@@ -7862,7 +7864,7 @@ sys/man/8/partfs - 664 sys sys 1196638947 869
 sys/man/8/pcmcia - 664 sys sys 1196638947 408
 sys/man/8/pem - 664 sys sys 1196638947 1189
 sys/man/8/ping - 664 sys sys 1196638947 3650
-sys/man/8/plan9.ini - 664 sys sys 1196638947 23835
+sys/man/8/plan9.ini - 664 sys sys 1202255136 23868
 sys/man/8/pop3 - 664 sys sys 1197574309 3122
 sys/man/8/ppp - 664 sys sys 1196638948 4430
 sys/man/8/prep - 664 sys sys 1196638948 14201
@@ -8090,7 +8092,7 @@ sys/src/9/pc/devlpt.c - 664 sys sys 1184469951 4423
 sys/src/9/pc/devpccard.c - 664 sys sys 1184469910 39336
 sys/src/9/pc/devrtc.c - 664 sys sys 1015014515 7167
 sys/src/9/pc/devtv.c - 664 sys sys 1184469620 45423
-sys/src/9/pc/devusb.c - 664 sys sys 1168305372 18752
+sys/src/9/pc/devusb.c - 664 sys sys 1202251756 20662
 sys/src/9/pc/devvga.c - 664 sys sys 1181083003 9334
 sys/src/9/pc/dma.c - 664 sys sys 1142966373 5332
 sys/src/9/pc/ether2000.c - 664 sys sys 1173287379 4901
@@ -8166,7 +8168,7 @@ sys/src/9/pc/screen.h - 664 sys sys 1147023549 4256
 sys/src/9/pc/sd53c8xx.c - 664 sys sys 1170456695 55276
 sys/src/9/pc/sd53c8xx.i - 664 sys sys 1128547230 28453
 sys/src/9/pc/sd53c8xx.n - 664 sys sys 1131290556 12657
-sys/src/9/pc/sdata.c - 664 sys sys 1186361525 52991
+sys/src/9/pc/sdata.c - 664 sys sys 1202251523 53036
 sys/src/9/pc/sdiahci.c - 664 sys sys 1200348596 38496
 sys/src/9/pc/sdmv50xx.c - 664 sys sys 1199910989 33838
 sys/src/9/pc/sdmylex.c - 664 sys sys 1189229947 28395
@@ -8177,8 +8179,9 @@ sys/src/9/pc/uartaxp.i - 664 sys sys 1155243528 111326
 sys/src/9/pc/uarti8250.c - 664 sys sys 1177676872 13957
 sys/src/9/pc/uartisa.c - 664 sys sys 1127126907 1777
 sys/src/9/pc/uartpci.c - 664 sys sys 1190235592 4685
-sys/src/9/pc/usb.h - 664 sys sys 1165555430 4257
-sys/src/9/pc/usbuhci.c - 664 sys sys 1184466791 31205
+sys/src/9/pc/usb.h - 664 sys sys 1202251665 4590
+sys/src/9/pc/usbohci.c - 664 sys sys 1202254075 47560
+sys/src/9/pc/usbuhci.c - 664 sys sys 1202252076 31839
 sys/src/9/pc/vga.c - 664 sys sys 1131290595 5148
 sys/src/9/pc/vga3dfx.c - 664 sys sys 1133218367 3833
 sys/src/9/pc/vgaark2000pv.c - 664 sys sys 1131290600 3422
@@ -14257,34 +14260,34 @@ sys/src/cmd/usb/audio - 20000000775 sys sys 1091204980 0
 sys/src/cmd/usb/audio/audiofs.c - 664 sys sys 1172903208 18518
 sys/src/cmd/usb/audio/audiosub.c - 664 sys sys 1172764044 8275
 sys/src/cmd/usb/audio/mkfile - 664 sys sys 1091204980 349
-sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1172764045 10358
+sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1202255398 10343
 sys/src/cmd/usb/audio/usbaudio.h - 664 sys sys 1140695062 1889
 sys/src/cmd/usb/audio/usbaudioctl.c - 664 sys sys 1172764044 18825
 sys/src/cmd/usb/audio/usbaudioctl.h - 664 sys sys 1140695062 618
 sys/src/cmd/usb/disk - 20000000775 sys sys 1193181450 0
-sys/src/cmd/usb/disk/disk.c - 664 sys sys 1200688320 20111
+sys/src/cmd/usb/disk/disk.c - 664 sys sys 1202256113 20245
 sys/src/cmd/usb/disk/mkfile - 664 sys sys 1193181450 359
 sys/src/cmd/usb/lib - 20000000775 sys sys 1091204979 0
-sys/src/cmd/usb/lib/device.c - 664 sys sys 1168308464 3284
-sys/src/cmd/usb/lib/dump.c - 664 sys sys 1168308417 13122
+sys/src/cmd/usb/lib/device.c - 664 sys sys 1202255312 3552
+sys/src/cmd/usb/lib/dump.c - 664 sys sys 1202255256 13075
 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 1165044747 1936
+sys/src/cmd/usb/lib/setup.c - 664 sys sys 1202255323 1933
 sys/src/cmd/usb/lib/usb.h - 664 sys sys 1165044715 7066
 sys/src/cmd/usb/lib/util.c - 664 sys sys 1091204978 523
 sys/src/cmd/usb/misc - 20000000775 sys sys 1091282306 0
 sys/src/cmd/usb/misc/mkfile - 664 sys sys 1167255850 374
-sys/src/cmd/usb/misc/usbmouse.c - 664 sys sys 1178824856 3755
+sys/src/cmd/usb/misc/usbmouse.c - 664 sys sys 1202255573 3768
 sys/src/cmd/usb/misc/usbprint - 775 sys sys 1167253831 314
 sys/src/cmd/usb/misc/usbprobe - 775 sys sys 1167253836 173
 sys/src/cmd/usb/mkfile - 664 sys sys 1193181446 361
 sys/src/cmd/usb/usbd - 20000000775 sys sys 1091204979 0
 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 1168308558 4294
+sys/src/cmd/usb/usbd/hub.c - 664 sys sys 1202255474 4292
 sys/src/cmd/usb/usbd/mkfile - 664 sys sys 1091204979 304
-sys/src/cmd/usb/usbd/setup.c - 664 sys sys 1168308573 1351
-sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1168308592 5204
+sys/src/cmd/usb/usbd/setup.c - 664 sys sys 1202255463 1351
+sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1202255449 5327
 sys/src/cmd/va - 20000000775 sys sys 1039727598 0
 sys/src/cmd/va/a.h - 664 sys sys 1089299166 2915
 sys/src/cmd/va/a.y - 664 sys sys 944961340 7211

+ 26 - 0
dist/replica/plan9.log

@@ -18414,3 +18414,29 @@
 1202131804 0 c sys/src/9/pc/etherm10g2k.i - 664 sys sys 1202131465 1094881
 1202131804 1 c sys/src/9/pc/etherm10g4k.i - 664 sys sys 1202131484 1065187
 1202162404 0 c sys/man/8/ipserv - 664 sys sys 1202161489 3268
+1202248804 0 c lib/face/48x48x8/.dict - 664 sys sys 1202248817 4382
+1202248804 1 a lib/face/48x48x8/c/coraid.1 - 444 sys sys 1202248824 6972
+1202248804 2 c sys/doc/sam/sam.tut - 464 sys sys 1202248612 40481
+1202250604 0 a lib/face/48x48x8/g/georgia.1 - 664 sys sys 1202248860 1683
+1202252404 0 c sys/src/9/pc/devusb.c - 664 sys sys 1202251756 20662
+1202252404 1 c sys/src/9/pc/sdata.c - 664 sys sys 1202251523 53036
+1202252404 2 c sys/src/9/pc/usb.h - 664 sys sys 1202251665 4590
+1202252404 3 c sys/src/9/pc/usbuhci.c - 664 sys sys 1202252076 31839
+1202254203 0 a sys/src/9/pc/usbohci.c - 664 sys sys 1202254075 47560
+1202256004 0 c sys/man/3/usb - 664 sys sys 1202255168 7541
+1202256004 1 c sys/man/8/plan9.ini - 664 sys sys 1202255136 23868
+1202256004 2 c sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1202255398 10343
+1202256004 3 c sys/src/cmd/usb/disk/disk.c - 664 sys sys 1202256113 20245
+1202256004 4 c sys/src/cmd/usb/lib/device.c - 664 sys sys 1202255312 3552
+1202256004 5 c sys/src/cmd/usb/lib/dump.c - 664 sys sys 1202255256 13075
+1202256004 6 c sys/src/cmd/usb/lib/setup.c - 664 sys sys 1202255323 1933
+1202256004 7 c sys/src/cmd/usb/misc/usbmouse.c - 664 sys sys 1202255573 3768
+1202256004 8 c sys/src/cmd/usb/usbd/hub.c - 664 sys sys 1202255474 4292
+1202256004 9 c sys/src/cmd/usb/usbd/setup.c - 664 sys sys 1202255463 1351
+1202256004 10 c sys/src/cmd/usb/usbd/usbd.c - 664 sys sys 1202255449 5327
+1202257803 0 c sys/man/4/usbdisk - 664 sys sys 1202256707 3025
+1202259604 0 c sys/man/3/usb - 664 sys sys 1202258356 7527
+1202272204 0 c 386/bin/usb/disk - 775 sys sys 1202272000 187347
+1202272204 1 c 386/bin/usb/usbaudio - 775 sys sys 1202272003 188183
+1202272204 2 c 386/bin/usb/usbd - 775 sys sys 1202272005 131144
+1202272204 3 c 386/bin/usb/usbmouse - 775 sys sys 1202272007 109417

+ 2 - 0
lib/face/48x48x8/.dict

@@ -37,6 +37,7 @@ cn/unknown u/unknown.cn
 comcast.net/unknown c/comcast.1
 coraid.com/mennis m/mennis.1
 coraid.com/quanstro q/quanstro.1
+coraid.com/unknown c/coraid.1
 cr/unknown u/unknown.cr
 cwru.edu/noah.evans n/noah.1
 cz/unknown u/unknown.cz
@@ -136,6 +137,7 @@ th/unknown u/unknown.th
 tj/unknown u/unknown.tj
 ua/unknown u/unknown.ua
 uc3m.es/alcortes a/alcortes.1
+uga.edu/unknown g/georgia.1
 unipg.it/mirko.mariotti m/mirko.1
 us/unknown u/unknown.us
 utwente.nl/Axel.Belinfante a/axel.2

File diff suppressed because it is too large
+ 0 - 0
lib/face/48x48x8/c/coraid.1


BIN
lib/face/48x48x8/g/georgia.1


+ 10 - 10
sys/doc/sam/sam.tut

@@ -16,7 +16,7 @@
 ..
 .de WC
 .lg 0
-\%\&\\$3\f(CS\\$1\fP\&\\$2
+\%\&\\$3\f(CI\\$1\fP\&\\$2
 .lg
 ..
 .TL
@@ -170,7 +170,7 @@ To get started, we need some text to play with.
 Any text will do; try something from
 James Gosling's Emacs manual:
 .P1
-$ \f(CSsam -d
+$ \f(CIsam -d
 a
 This manual is organized in a rather haphazard manner.  The first
 several sections were written hastily in an attempt to provide a
@@ -221,7 +221,7 @@ but adds the text
 .I before
 dot.
 .P1
-.ft CS
+.ft CI
 i
 Introduction
 \&.
@@ -524,7 +524,7 @@ means
 after the end
 .R
 of dot.
-For example, if the file contains \f(CWA\f(CSAA\f(CWA\f1,
+For example, if the file contains \f(CWA\f(CIAA\f(CWA\f1,
 with dot set to the middle two
 .CW A 's
 (the slanting characters),
@@ -1130,7 +1130,7 @@ This manual is organized in a rather haphazard manner.  The first
 several sections were written hastily in an attempt to provide a
 general introduction to the commands in Emacs and to try to show
 the method in the madness that is the Emacs command structure.
-.ft CS
+.ft CI
 ,x/Emacs/{
 	=
 	+-p
@@ -1151,7 +1151,7 @@ to
 .CW vi
 and vice versa.  We can type
 .P1
-.ft CS
+.ft CI
 ,x/Emacs|vi/{
 	g/Emacs/ c/vi/
 	g/vi/ c/Emacs/
@@ -1160,7 +1160,7 @@ and vice versa.  We can type
 .P2
 or even
 .P1
-.ft CS
+.ft CI
 ,x/[a-zA-Z]+/{
 	g/Emacs/ v/....../ c/vi/
 	g/vi/ v/.../ c/Emacs/
@@ -1434,9 +1434,9 @@ with a few files;
 the easiest way to do this is to start it
 with a list of Unix file names to edit.
 .P1
-$ \f(CSecho *.ms\f(CW
+$ \f(CIecho *.ms\f(CW
 conquest.ms death.ms emacs.ms famine.ms slaughter.ms
-$ \f(CSsam -d *.ms\f(CW
+$ \f(CIsam -d *.ms\f(CW
  -. conquest.ms
 .P2
 (I'm sorry the Horsemen don't appear in liturgical order.)
@@ -1716,7 +1716,7 @@ We can use an
 .CW f
 command to identify which file the variable appears in:
 .P1
-.ft CS
+.ft CI
 X/\e.c$/ ,g/variable/ {
 	f
 	,x/variable/+-{

+ 27 - 14
sys/man/3/usb

@@ -95,18 +95,29 @@ is
 .IP
 .B ep
 .I n
+.B ctl
+.I "mode maxpkt nbuf
+.PP
+or
+.IP
+.B ep
+.I n
 .B bulk
 .I "mode maxpkt nbuf
 .PP
 or
 .IP
 .B ep
+.I "n period mode maxpkt
+.PP
+or
+.IP
+.B ep
 .I "n period mode samplesize hz
 .PP
-The first form configures a non-real-time stream, the second an
-.I isochronous
-(real-time) stream.
-In both forms,
+There are four forms for, respectively, Control, Bulk, Interrupt and
+Isochronous traffic (see USB specs for what that means).
+In all forms,
 .I n
 is the endpoint to be configured, and
 .I mode
@@ -117,33 +128,35 @@ for read only,
 for write only, or
 .B rw
 for reading and writing.
-In the first form,
-.I maxpkt
+.I Maxpkt
 is the maximum packet size to be used (between 8 and 1023),
 and
 .I nbuf
 is the number of buffers to be allocated by the driver.
 .PP
-In the second form,
-.I period
-is the number of milliseconds between packets.  This number is usually
-dictated by the device.  It must be between 1 and 1000.
+.I Period
+is the number of milliseconds between packets (iso) or polls (interrupt).
+This number is usually dictated by the device.  It must be between 1 and 1000.
 The
 .I samplesize
 is the size in bytes of the data units making up packets, and
 .I hz
 is the number of data units transmitted or received per second.
 .PP
-The data rate is thus
+The data rate for an isochronous channel is
 .IR hz × samplesize
 bytes per second, and the number of samples in a packet
 will be 
 .RI ( period × hz )/1000,
 rounded up or down.
 Packets do not contain fractional samples.
+A 16-bit stereo 44.1 KHz audio stream will thus have 44100 4-byte samples
+per second, typically in a 1ms period.  Ove a 10 ms period, this yields 9
+packets of 176 bytes followed by a 180-byte packet (the driver figures it
+out for you).
 .PP
 The mouse, which produces 3-byte samples, is configured with
-.BR "ep 1 bulk r 3 32" :
+.BR "ep 1 ctl r 3 32" :
 endpoint 1 is configured for non-real-time read-only 3-byte messages
 and allows 32 of them to be outstanding.
 .PP
@@ -232,13 +245,13 @@ configuration.
 .br
 .B /sys/src/9/pc/devusb.c
 .br
-.B /sys/src/9/pc/usbuhci.c
+.B /sys/src/9/pc/usb[ou]hci.c
 .SH "SEE ALSO"
 .IR usb (4),
 .IR usbd (4),
 .IR plan9.ini (8)
 .SH BUGS
-OpenHCI (OHCI) and EHCI USB controllers are not yet supported.
+EHCI USB 2 controllers are not yet supported.
 .PP
 The interface for configuring endpoints is at variance with the standard.
 .PP

+ 13 - 5
sys/man/4/usbdisk

@@ -4,7 +4,7 @@ usbdisk, usbfat: - serve USB mass storage devices
 .SH SYNOPSIS
 .B usb/disk
 [
-.B -dDf
+.B -dDfl
 ] [
 .B -m
 .I mountpoint
@@ -18,7 +18,7 @@ usbdisk, usbfat: - serve USB mass storage devices
 .LP
 .B usbfat:
 [
-.B -f
+.B -fl
 ] [
 .I disk
 [
@@ -37,7 +37,7 @@ and
 where
 .I n
 is the number of a LUN to access,
-for all LUNs of the named or found USB device.
+for all detected LUNs of the named or found USB device.
 .I Disk
 searches for a USB device with class 8 (storage),
 subclass 2 (ATAPI CD/DVD),
@@ -74,6 +74,14 @@ The
 option avoids freaking out some cheap USB flash disks by not issuing
 UMS reset commands to them.
 The
+.B -l
+option asks the device for its maximum LUN.
+By default,
+.I disk
+assumes a maximum LUN of zero, since some devices
+get upset if you ask them for their maximum LUN.
+Flash memory devices are likely to have multiple LUNs.
+The
 .B -m
 option mounts the served hierarchy on
 .I mountpoint
@@ -91,7 +99,7 @@ Access the usual preformatted FAT partition:
 .IP
 .EX
 % usb/usbd
-% usb/disk
+% usb/disk -l
 % disk/fdisk -p /n/disk/0/data
 part dos 7 31559
 % dossrv -f /n/disk/0/data:7 usbstorage
@@ -153,6 +161,6 @@ so one can invoke
 .IR dossrv (4)
 directly.
 .PP
-USB 1.0 flash disks' I/O rates are slow and variable.
+USB 1 flash disks' I/O rates are slow and variable.
 Reading and writing in large units (e.g., 4KB) seems to be faster
 by an order of magnitude when transferring large volumes of data.

+ 2 - 1
sys/man/8/plan9.ini

@@ -386,7 +386,8 @@ Intersil Prism 2.5 chipset.
 .SS DISKS, TAPES
 (S)ATA controllers are autodetected.
 .SS \fLusbX=type=uhci\fP
-This specifies the settings for a USB UHCI controller.
+.SS \fLusbX=type=ohci\fP
+This specifies the settings for a USB UHCI or OHCI controller.
 Like the Ethernet controllers, USB controllers are autodetected
 after scanning for the ones listed in
 .IR plan9.ini .

+ 105 - 37
sys/src/9/pc/devusb.c

@@ -13,10 +13,9 @@
 #include	"usb.h"
 
 static int debug = 0;
+static int debugtoggle = 0;
 
-#define Chatty	1
-#define DPRINT if(Chatty)print
-#define XPRINT if(debug)iprint
+#define XPRINT if(debug)print
 
 Usbhost*	usbhost[MaxUsb];
 
@@ -110,7 +109,7 @@ static Cmdtab usbctlmsg[] =
 	CMclass,	"class",	0,
 	CMdata,		"data",		3,
 	CMdebug,	"debug",	3,
-	CMep,		"ep",		6,
+	CMep,		"ep",		0,
 	CMmaxpkt,	"maxpkt",	3,
 	CMadjust,	"adjust",	3,
 	CMspeed,	"speed",	2,
@@ -235,7 +234,7 @@ usbnewdevice(Usbhost *uh)
 	d = nil;
 	qlock(uh);
 	if(waserror()){
-		if (d) {
+		if(d){
 			uh->dev[d->x] = nil;
 			freept(d->ep[0]);
 			free(d);
@@ -251,13 +250,13 @@ usbnewdevice(Usbhost *uh)
 			d->ref = 1;
 			d->x = i;
 			d->id = (uh->idgen << 8) | i;
+			d->speed = Fullspeed;
 			d->state = Enabled;
 			XPRINT("calling devendpt in usbnewdevice\n");
 			e = devendpt(d, 0, 1);	/* always provide ctl endpt 0 */
 			e->mode = ORDWR;
-			e->in.epmode = e->out.epmode = Ctlmode;	/* OHCI */
-			// epsetMPS(e, 64, 64);		/* OHCI; see epalloc*/
-			e->iso = 0;
+			e->epmode = Ctlmode;	/* OHCI */
+			e->epnewmode = Ctlmode;	/* OHCI */
 			e->sched = -1;
 			uh->dev[i] = d;
 			break;
@@ -381,7 +380,7 @@ usbgen(Chan *c, char *, Dirtab*, int, int s, Dir *dp)
 		return 0;
 	snprint(up->genbuf, sizeof up->genbuf, "ep%ddata", s);
 	mkqid(&q, PATH(Qep0+s, slot, bus), c->qid.vers, QTFILE);
-	switch(e->mode) {
+	switch(e->mode){
 	case OREAD:
 		perm = 0444;
 		break;
@@ -631,11 +630,11 @@ epstatus(char *s, char *se, Endpt *e, int i)
 
 	p = seprint(s, se, "%2d %#6.6lux %10lud bytes %10lud blocks\n",
 		i, e->csp, e->nbytes, e->nblocks);
-	if(e->iso){
+	if(e->epmode == Isomode){
 		p = seprint(p, se, "bufsize %6d buffered %6d",
 			e->maxpkt, e->buffered);
 		if(e->toffset)
-			p = seprint(p, se, " offset  %10lud time %19lld\n",
+			p = seprint(p, se, " offset  %10llud time %19lld\n",
 				e->toffset, e->time);
 		p = seprint(p, se, "\n");
 	}
@@ -666,9 +665,12 @@ usbread(Chan *c, void *a, long n, vlong offset)
 		if(e == nil || e->mode == OWRITE)
 			error(Egreg);
 		if(t == 0) {
-			if(e->iso)
+			if(e->epmode == Isomode)
 				error(Egreg);
- 			e->rdata01 = 1;
+			if(e->override)
+				e->override = 0;
+			else
+				e->rdata01 = 1;
 			n = uh->read(uh, e, a, n, 0LL);
 			if(e->setin){
 				e->setin = 0;
@@ -767,10 +769,23 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
 		ct = lookupcmd(cb, usbctlmsg, nelem(usbctlmsg));
 		switch(ct->index){
 		case CMspeed:
-			d->ls = strtoul(cb->f[1], nil, 0) == 0;
+			XPRINT("speed %s\n", cb->f[1]);
+			if(strcmp(cb->f[1], "low") == 0)
+				d->speed = Lowspeed;
+			else if(strcmp(cb->f[1], "full") == 0)
+				d->speed = Fullspeed;
+			else if(strcmp(cb->f[1], "high") == 0)
+				d->speed = Highspeed;
+			else if(strtoul(cb->f[1], nil, 0) == 0)
+				d->speed = Lowspeed;
+			else
+				d->speed = Fullspeed;
+			for(i = 0; i < nelem(d->ep); i++)
+				if(d->ep[i])
+					uh->epmode(uh, d->ep[i]);
 			break;
 		case CMclass:
-			if (cb->nf != 4 && cb->nf != 6)
+			if (cb->nf != 5 && cb->nf != 7)
 				cmderror(cb, Ebadusbmsg);
 			/*
 			 * class #ifc ept csp
@@ -781,9 +796,9 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
 			if (i < 0 || i >= nelem(d->ep) ||
 			    d->npt > nelem(d->ep) || i >= d->npt)
 				cmderror(cb, Ebadusbmsg);
-			if (cb->nf == 6) {
-				d->vid = strtoul(cb->f[4], nil, 0);
-				d->did = strtoul(cb->f[5], nil, 0);
+			if(cb->nf == 7){
+				d->vid = strtoul(cb->f[5], nil, 0);
+				d->did = strtoul(cb->f[6], nil, 0);
 			}
 			if (i == 0)
 				d->csp = strtoul(cb->f[3], nil, 0);
@@ -792,6 +807,9 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
 				d->ep[i] = devendpt(d, i, 1);
 			}
 			d->ep[i]->csp = strtoul(cb->f[3], nil, 0);
+			d->ep[i]->maxpkt = strtoul(cb->f[4], nil, 0);
+			if(uh->epmaxpkt)
+				uh->epmaxpkt(uh, d->ep[i]);
 			break;
 		case CMdata:
 			i = strtoul(cb->f[1], nil, 0);
@@ -799,6 +817,7 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
 				error(Ebadusbmsg);
 			e = d->ep[i];
 			e->wdata01 = e->rdata01 = strtoul(cb->f[2], nil, 0) != 0;
+			e->override = 1;
 			break;
 		case CMmaxpkt:
 			i = strtoul(cb->f[1], nil, 0);
@@ -808,13 +827,15 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
 			e->maxpkt = strtoul(cb->f[2], nil, 0);
 			if(e->maxpkt > 1500)
 				e->maxpkt = 1500;
+			if(uh->epmaxpkt)
+				uh->epmaxpkt(uh, e);
 			break;
 		case CMadjust:
 			i = strtoul(cb->f[1], nil, 0);
 			if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil)
 				error(Ebadusbmsg);
 			e = d->ep[i];
-			if (e->iso == 0)
+			if(e->epmode != Isomode)
 				error(Eperm);
 			i = strtoul(cb->f[2], nil, 0);
 			/* speed may not result in change of maxpkt */
@@ -845,11 +866,13 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
 			if(i < 0 || i >= nelem(d->ep) || d->ep[i] == nil)
 				error(Ebadusbmsg);
 			e = d->ep[i];
-			e->err = nil;
+			e->dir[Dirout].err = e->dir[Dirin].err = nil;
 			break;
 		case CMep:
-			/* ep n `bulk' mode maxpkt nbuf     OR
-			 * ep n period mode samplesize Hz
+			/* Ctlmode:	ep n `ctl'  mode maxpkt nbuf	OR
+			 * Bulkmode:	ep n `bulk' mode maxpkt nbuf	OR
+			 * Isomode:	ep n period mode samplesize Hz	OR
+			 * Intrmode:	ep n period mode maxpkt
 			 */
 			i = strtoul(cb->f[1], nil, 0);
 			if(i < 0 || i >= nelem(d->ep)) {
@@ -871,28 +894,70 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
 				error(Eperm);
 			if(strcmp(cb->f[2], "bulk") == 0){
 				/* ep n `bulk' mode maxpkt nbuf */
-				e->iso = 0;
+				if(cb->nf != 6)
+					error("arg count");
 				i = strtoul(cb->f[4], nil, 0);
-				if(i < 8 || i > 1023)
-					i = 8;
+				if(i < 1 || i > 1023){
+					XPRINT("maxpkt: 1 <= %d < 1024\n", i);
+					error(Ebadarg);
+				}
+				e->maxpkt = i;
+				i = strtoul(cb->f[5], nil, 0);
+				if(i < 1 || i > 32){
+					XPRINT("nbuf: 1 <= %d <= 32\n", i);
+					error(Ebadarg);
+				}
+				e->nbuf = i;
+				e->epnewmode = Bulkmode;
+			}else if(strcmp(cb->f[2], "ctl") == 0){
+				/* ep n `ctl' mode maxpkt nbuf */
+				if(cb->nf != 6)
+					error("arg count");
+				i = strtoul(cb->f[4], nil, 0);
+				if(i < 8 || i > 1023){
+					XPRINT("maxpkt: 8 <= %d < 1024\n", i);
+					error(Ebadarg);
+				}
 				e->maxpkt = i;
 				i = strtoul(cb->f[5], nil, 0);
-				if(i >= 1 && i <= 32)
-					e->nbuf = i;
-			} else {
+				if(i < 1 || i > 32){
+					XPRINT("nbuf: 1 <= %d <= 32\n", i);
+					error(Ebadarg);
+				}
+				e->nbuf = i;
+				e->epnewmode = Ctlmode;
+			}else if(cb->nf == 5){
+				/* ep n period mode maxpkt */
+				i = strtoul(cb->f[2], nil, 0);
+				if(i > 0 && i <= 1000){
+					e->pollms = i;
+				}else {
+					XPRINT("pollms: 0 <= %d <= 1000\n", i);
+					error(Ebadarg);
+				}
+				i = strtoul(cb->f[4], nil, 0);
+				if(i >= 1 && i < 256){
+					e->maxpkt = i;
+				}else {
+					XPRINT("maxpkt: 0 < %d <= 8\n", i);
+					error(Ebadarg);
+				}
+				e->nbuf = 1;	/* just in case */
+				e->epnewmode = Intrmode;
+			}else if(cb->nf == 6){
 				/* ep n period mode samplesize Hz */
 				i = strtoul(cb->f[2], nil, 0);
 				if(i > 0 && i <= 1000){
 					e->pollms = i;
 				}else {
-					XPRINT("field 4: 0 <= %d <= 1000\n", i);
+					XPRINT("Hz: 0 <= %d <= 1000\n", i);
 					error(Ebadarg);
 				}
 				i = strtoul(cb->f[4], nil, 0);
 				if(i >= 1 && i <= 8){
 					e->samplesz = i;
 				}else {
-					XPRINT("field 4: 0 < %d <= 8\n", i);
+					XPRINT("samplesize: 0 < %d <= 8\n", i);
 					error(Ebadarg);
 				}
 				i = strtoul(cb->f[5], nil, 0);
@@ -901,14 +966,14 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
 					e->hz = i;
 					e->remain = 0;
 				}else {
-					XPRINT("field 5: 1 < %d <= 100000 Hz\n",
-						i);
+					XPRINT("field 6: 1 < %d <= 100000 Hz\n", i);
 					error(Ebadarg);
 				}
 				e->maxpkt = (e->hz*e->pollms + 999)/1000 *
 					e->samplesz;
-				e->iso = 1;
-			}
+				e->epnewmode = Isomode;
+			}else
+				error("arg count");
 			e->mode = strcmp(cb->f[3],"r") == 0? OREAD:
 				  strcmp(cb->f[3],"w") == 0? OWRITE: ORDWR;
 			uh->epmode(uh, e);
@@ -923,14 +988,17 @@ usbwrite(Chan *c, void *a, long n, vlong offset)
 	case Qep0:	/* SETUP endpoint 0 */
 		/* should canqlock etc */
 		e = d->ep[0];
-		if(e == nil || e->iso)
+		if(e == nil || e->epmode == Isomode)
 			error(Egreg);
 		if(n < 8)
 			error(Eio);
 		nw = *(uchar*)a & RD2H;
-		e->wdata01 = 0;
+		if(e->override)
+			e->override = 0;
+		else
+			e->wdata01 = 0;
 		n = uh->write(uh, e, a, n, 0LL, uh->toksetup);
-		if(nw == 0) {	/* host to device: use IN[DATA1] to ack */
+		if(nw == 0){	/* host to device: use IN[DATA1] to ack */
 			e->rdata01 = 1;
 			nw = uh->read(uh, e, cmd, 0LL, 8);
 			if(nw != 0)

+ 2 - 1
sys/src/9/pc/sdata.c

@@ -40,7 +40,7 @@ enum {					/* I/O ports */
 	Cylhi		= 5,		/* cylinder high */
 	Bytehi		= 5,		/* byte count hi (PACKET) */
 	Lbahi		= 5,		/* LBA<23-16>, LBA<47-40> */
-	Dh		= 6,		/* Device/Head, LBA<32-14> */
+	Dh		= 6,		/* Device/Head, LBA<27-24> */
 	Status		= 7,		/* (read) */
 	Command		= 7,		/* (write) */
 
@@ -1960,6 +1960,7 @@ atapnp(void)
 			 * This can probably be lumped in with the 768 above.
 			 */
 			/*FALLTHROUGH*/
+		case (0x209A<<16)|0x1022:	/* AMD CS5536 */
 		case (0x01BC<<16)|0x10DE:	/* nVidia nForce1 */
 		case (0x0065<<16)|0x10DE:	/* nVidia nForce2 */
 		case (0x0085<<16)|0x10DE:	/* nVidia nForce2 MCP */

+ 44 - 34
sys/src/9/pc/usb.h

@@ -12,10 +12,10 @@ enum
 	MaxUsbDev = 32,	/* max # of attached USB devs, including root hub (Udev*) */
 
 	/* request type */
-	RH2D = 0<<7,
-	RD2H = 1<<7,
+	RH2D = 0<<7,		/* output */
+	RD2H = 1<<7,		/* input */
 	Rstandard = 0<<5,
-	Rclass = 1<<5,
+	Rclass	= 1<<5,
 	Rvendor = 2<<5,
 
 	Rdevice = 0,
@@ -32,10 +32,15 @@ enum
 /* for OHCI */
 typedef struct ED ED;
 struct ED {
-	ulong ctrl;
-	ulong tail;		/* transfer descriptor */
-	ulong head;
-	ulong next;
+	ulong	ctrl;
+	ulong	tail;		/* transfer descriptor */
+	ulong	head;
+	ulong	next;
+};
+
+enum{
+	Dirout,
+	Dirin,
 };
 
 /*
@@ -43,55 +48,53 @@ struct ED {
  */
 struct Endpt
 {
-	ED *ined;		/* for OHCI */
-	ED *outed;		/* for OHCI */
 	Ref;
 	Lock;
 	int	x;		/* index in Udev.ep */
-	struct {		/* OHCI */
-		int epmode;
-		int	nbuf;	/* number of buffers allowed */
-		int	ntd;
-		int	mps;
-	} out;
-	struct {		/* OHCI */
-		int epmode;
-		int	nbuf;	/* number of buffers allowed */
-		int	sched;	/* schedule index; -1 if undefined or aperiodic */
-		int	pollms;	/* polling interval in msec */
-		int	ntd;
-		int	mps;
-	} in;
+	struct{		/* OHCI */
+		char*	err;	/* needs to be global for unstall; fix? */
+		int	xdone;
+		int	xstarted;
+		int	queued;	/* # of TDs queued on ED */
+		Rendez	rend;
+	}	dir[2];
+	int	epmode;
+	int	epnewmode;
 	int	id;		/* hardware endpoint address */
 	int	maxpkt;		/* maximum packet size (from endpoint descriptor) */
  	uchar	wdata01;	/* 0=DATA0, 1=DATA1 for output direction */
  	uchar	rdata01;	/* 0=DATA0, 1=DATA1 for input direction */
+ 	int	override;	/* a data command sets this and prevents
+ 				 * auto setting of rdata01 or wdata01
+ 				 */
 	uchar	eof;
 	ulong	csp;
 	uchar	mode;		/* OREAD, OWRITE, ORDWR */
 	uchar	nbuf;		/* number of buffers allowed */
-	uchar	iso;
 	uchar	debug;
 	uchar	active;		/* listed for examination by interrupts */
 	int	setin;
-	/* ISO related: */
+	/* ISO is all half duplex, so need only one copy of these: */
+	ulong	bw;		/* bandwidth requirement (OHCI) */
 	int	hz;
 	int	remain;		/* for packet size calculations */
+	int	partial;	/* last iso packet may have been half full */
+	Block	*bpartial;
 	int	samplesz;
 	int	sched;		/* schedule index; -1 if undefined or aperiodic */
 	int	pollms;		/* polling interval in msec */
 	int	psize;		/* (remaining) size of this packet */
 	int	off;		/* offset into packet */
 	/* Real-time iso stuff */
-	ulong	foffset;	/* file offset (to detect seeks) */
+	vlong	foffset;	/* file offset (to detect seeks) */
 	ulong	poffset;	/* offset of next packet to be queued */
-	ulong	toffset;	/* offset associated with time */
+	short	frnum;		/* frame number associated with poffset */
+	int	rem;		/* remainder after rounding Hz to samples/ms */
+	vlong	toffset;	/* offset associated with time */
 	vlong	time;		/* time associated with offset */
 	int	buffered;	/* bytes captured but unread, or written but unsent */
 	/* end ISO stuff */
 
-	ulong	bw;		/* bandwidth requirement (OHCI) */
-
 	Udev*	dev;		/* owning device */
 
 	ulong	nbytes;
@@ -104,15 +107,12 @@ struct Endpt
 	 * except perhaps err.
 	 */
 	QLock	rlock;
-	Rendez	rr;
 	Queue*	rq;
 
 	QLock	wlock;
-	Rendez	wr;
 	Queue*	wq;
 
 	int	ntd;
-	char*	err;		/* needs to be global for unstall; fix? */
 
 	Endpt*	activef;	/* active endpoint list */
 };
@@ -122,7 +122,9 @@ enum {
 	Nomode,
 	Ctlmode,
 	Bulkmode,
-	Intrmode
+	Intrmode,
+	Isomode,
+	Nmodes,
 };
 
 /* device parameters */
@@ -140,6 +142,13 @@ enum
 	Hubclass = 9,
 };
 
+typedef enum {
+	Fullspeed,	/* Don't change order, used in ehci h/w interface */
+	Lowspeed,
+	Highspeed,
+	Nospeed,
+} Speed;	/* Device speed */
+
 /*
  * active USB device
  */
@@ -156,7 +165,7 @@ struct Udev
 	ulong	csp;
 	ushort	vid;		/* vendor id */
 	ushort	did;		/* product id */
-	int	ls;
+	Speed	speed;	
 	int	npt;
 	Endpt*	ep[16];		/* active end points */
 
@@ -188,6 +197,7 @@ struct Usbhost
 	void	(*epopen)(Usbhost*, Endpt*);
 	void	(*epclose)(Usbhost*, Endpt*);
 	void	(*epmode)(Usbhost*, Endpt*);
+	void	(*epmaxpkt)(Usbhost*, Endpt*);
 
 	long	(*read)(Usbhost*, Endpt*, void*, long, vlong);
 	long	(*write)(Usbhost*, Endpt*, void*, long, vlong, int);

+ 2304 - 0
sys/src/9/pc/usbohci.c

@@ -0,0 +1,2304 @@
+/*
+ * USB Open Host Controller Interface (OHCI) driver
+ * from Charles Forsyth's devohci.c, 5 Aug 2006.
+ */
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"io.h"
+#include	"../port/error.h"
+
+#include	"usb.h"
+
+#define XPRINT	if(usbhdebug) print
+#define XIPRINT	if(usbhdebug) iprint
+#define XEPRINT	if(usbhdebug || ep->debug) print
+#define XEIPRINT if(usbhdebug || ep->debug) iprint
+
+#define	IPRINT(x) iprint x
+
+static int usbhdebug = 0;
+static int dcls;
+
+enum {
+	Ned = 63 + 32,
+	Ntd = 256,
+};
+
+/*
+ * USB packet definitions
+ */
+enum {
+	Otoksetup = 0,
+	Otokout = 1,
+	Otokin = 2,
+
+	/* port status - UHCI style */
+	Suspend =	1<<12,
+	PortReset =	1<<9,
+	SlowDevice =	1<<8,
+	ResumeDetect =	1<<6,
+	PortEnableChange = 1<<3,	/* write 1 to clear */
+	PortEnable = 	1<<2,
+	ConnectStatusChange = 1<<1,	/* write 1 to clear */
+	DevicePresent =	1<<0,
+};
+
+typedef struct Ctlr Ctlr;
+typedef struct QTree QTree;
+
+enum {
+	ED_MPS_MASK = 0x7ff,
+	ED_MPS_SHIFT = 16,
+	ED_C_MASK  = 1,
+	ED_C_SHIFT = 1,
+	ED_F_BIT = 1 << 15,
+	ED_S_MASK  = 1,
+	ED_S_SHIFT = 13,
+	ED_D_MASK  = 3,
+	ED_D_SHIFT = 11,
+	ED_H_MASK  = 1,
+	ED_H_SHIFT = 0,
+};
+
+typedef struct Endptx Endptx;
+typedef struct TD TD;
+
+struct Endptx
+{
+	Lock;		/* for manipulating ed */
+	ED	*ed;	/* Single endpoint descriptor */
+	int	ntd;	/* Number of TDs in use */
+	int	overruns;
+};
+
+struct TD {
+	ulong	ctrl;
+	ulong	cbp;
+	ulong	nexttd;
+	ulong	be;
+	ushort	offsets[8];	/* Iso TDs only */
+	/* driver specific; pad to multiple of 32 */
+	TD*	next;
+	Endpt	*ep;
+	Block	*bp;
+	ulong	flags;
+	ulong	offset;		/* offset associated with end of data */
+	ulong	bytes;		/* bytes in this TD */
+	ulong	pad[2];
+};
+
+enum {
+	TD_R_SHIFT = 18,
+	TD_DP_MASK = 3,
+	TD_DP_SHIFT = 19,
+	TD_CC_MASK = 0xf,
+	TD_CC_SHIFT = 28,
+	TD_EC_MASK = 3,
+	TD_EC_SHIFT = 26,
+
+	TD_FLAGS_LAST = 1 << 0,
+};
+
+typedef struct HCCA HCCA;
+struct HCCA {
+	ulong	intrtable[32];
+	ushort	framenumber;
+	ushort	pad1;
+	ulong	donehead;
+	uchar	reserved[116];
+};
+
+/* OHCI registers */
+typedef struct OHCI OHCI;
+struct OHCI {
+	/* control and status group */
+/*00*/	ulong	revision;
+	ulong	control;
+	ulong	cmdsts;
+	ulong	intrsts;
+
+/*10*/	ulong	intrenable;
+	ulong	intrdisable;
+	/* memory pointer group */
+	ulong	hcca;
+	ulong	periodcurred;
+
+/*20*/	ulong	ctlheaded;
+	ulong	ctlcurred;
+	ulong	bulkheaded;
+	ulong	bulkcurred;
+
+/*30*/	ulong	donehead;
+	/* frame counter group */
+	ulong	fminterval;
+	ulong	fmremaining;
+	ulong	fmnumber;
+
+/*40*/	ulong	periodicstart;
+	ulong	lsthreshold;
+	/* root hub group */
+	ulong	rhdesca;
+	ulong	rhdescb;
+
+/*50*/	ulong	rhsts;
+	ulong	rhportsts[15];
+
+/*90*/	ulong	pad25[20];
+
+	/* unknown */
+/*e0*/	ulong	hostueaddr;
+	ulong	hostuests;
+	ulong	hosttimeoutctrl;
+	ulong	pad59;
+
+/*f0*/	ulong	pad60;
+	ulong	hostrevision;
+	ulong	pad62[2];
+/*100*/
+};
+
+/*
+ * software structures
+ */
+
+static struct {
+	int	bit;
+	char	*name;
+} portstatus[] = {
+	{ Suspend,		"suspend", },
+	{ PortReset,		"reset", },
+	{ SlowDevice,		"lowspeed", },
+	{ ResumeDetect,		"resume", },
+	{ PortEnableChange,	"portchange", },
+	{ PortEnable,		"enable", },
+	{ ConnectStatusChange,	"statuschange", },
+	{ DevicePresent,	"present", },
+};
+
+struct QTree {
+	QLock;
+	int	nel;
+	int	depth;
+	ulong*	bw;
+	ED	**root;
+};
+
+/* device parameters */
+static char *devstates[] = {
+	[Disabled]		"Disabled",
+	[Attached]		"Attached",
+	[Enabled]		"Enabled",
+};
+
+struct Ctlr {
+	Lock;	/* protects state shared with interrupt (eg, free list) */
+	int	active;
+	Pcidev*	pcidev;
+	int	irq;
+	ulong	tbdf;
+	Ctlr*	next;
+	int	nports;
+
+	OHCI	*base;		/* equiv to io in uhci */
+	HCCA	*uchcca;
+	int	idgen;		/* version # to distinguish new connections */
+	QLock	resetl;		/* lock controller during USB reset */
+
+	struct {
+		Lock;
+		TD*	pool;
+		TD*	free;
+		int	alloced;
+	} td;
+
+	struct {
+		QLock;
+		ED*	pool;
+		ED*	free;
+		int	alloced;
+	} ed;
+
+	/* TODO: what happened to ctlq, etc. from uhci? */
+
+	QTree*	tree;		/* tree for t Endpt i/o */
+
+	struct {
+		QLock;
+		Endpt*	f;
+	} activends;
+};
+
+enum {
+	HcRevision =	0x00,
+	HcControl =	0x01,
+		HcfsMask =	3 << 6,
+		HcfsReset =	0 << 6,
+		HcfsResume =	1 << 6,
+		HcfsOperational=2 << 6,
+		HcfsSuspend =	3 << 6,
+		Ble =	1 << 5,
+		Cle =	1 << 4,
+		Ie =	1 << 3,
+		Ple =	1 << 2,
+		Cbsr_MASK = 3,
+	HcCommandStatus = 0x02,
+		Ocr =	1 << 3,
+		Blf =	1 << 2,
+		Clf =	1 << 1,
+		Hcr =	1 << 0,
+	HcIntrStatus =	0x03,
+	HcIntrEnable =	0x04,
+		Mie =	1 << 31,
+		Oc =	1 << 30,
+		Rhsc =	1 << 6,
+		Fno =	1 << 5,
+		Ue =	1 << 4,
+		Rd =	1 << 3,
+		Sf =	1 << 2,
+		Wdh =	1 << 1,
+		So =	1 << 0,
+	HcIntrDisable =	0x05,
+	HcFmIntvl =	0x0d,
+		HcFmIntvl_FSMaxpack_MASK = 0x7fff,
+		HcFmIntvl_FSMaxpack_SHIFT = 16,
+	HcFmRemaining =	0x0e,
+	HcFmNumber =	0x0f,
+	HcLSThreshold =	0x11,
+	HcRhDescA =	0x12,
+		HcRhDescA_POTPGT_MASK =	0xff << 24,
+		HcRhDescA_POTPGT_SHIFT =	24,
+	HcRhDescB =	0x13,
+	HcRhStatus =	0x14,
+		Lps =	1 << 0,
+		Cgp =	1 << 0,
+		Oci =	1 << 1,
+		Drwe =	1 << 15,
+		Srwe =	1 << 15,
+		LpsC =	1 << 16,
+		Sgp =	1 << 16,
+		Ccic =	1 << 17,
+		Crwe =	1 << 31,
+	HcRhPortStatus1 = 0x15,
+		Ccs =	1 << 0,
+		Cpe =	1 << 0,
+		Pes =	1 << 1,
+		Spe =	1 << 1,
+		Pss =	1 << 2,
+		Poci =	1 << 3,
+		Prs =	1 << 4,
+		Spr =	1 << 4,
+		Pps =	1 << 8,
+		Spp=	1 << 8,
+		Lsda =	1 << 9,
+		Cpp =	1 << 9,
+		Csc =	1 << 16,
+		Pesc =	1 << 17,
+		Pssc =	1 << 18,
+		Ocic =	1 << 19,
+		Prsc =	1 << 20,
+	HcRhPortStatus2 =	0x16,
+
+	L2NFRAME =	5,
+	NFRAME =	1 << L2NFRAME,
+	/* TODO: from UHCI; correct for OHCI? */
+	FRAMESIZE = NFRAME*sizeof(ulong), /* fixed by hardware; aligned to same */
+};
+
+static char *modename[] = {
+[Ctlmode]=	"Ctl",
+[Bulkmode] =	"Bulk",
+[Intrmode] =	"Intr",
+[Isomode] =	"Iso",
+};
+
+static char *omodename[] = {
+[OREAD] = "r",
+[OWRITE] = "w",
+[ORDWR] = "rw",
+};
+
+int ohciinterrupts[Nmodes];
+
+static Ctlr* ctlrhead;
+static Ctlr* ctlrtail;
+
+static	char	Estalled[] = "usb endpoint stalled";
+static	char	EnotWritten[] = "usb write unfinished";
+static	char	EnotRead[] = "usb read unfinished";
+static	char	Eunderrun[] = "usb endpoint underrun";
+
+static	QLock	usbhstate;	/* protects name space state */
+
+static void	eptactivate(Ctlr *ub, Endpt *ep);
+static void	eptdeactivate(Ctlr *ub, Endpt *e);
+static long	read (Usbhost *, Endpt*, void*, long, vlong);
+static void	scanpci(void);
+static int	schedendpt(Ctlr *ub, Endpt *ep, int direction);
+static void	unschedendpt(Ctlr *ub, Endpt *ep, int);
+static long	write(Usbhost *, Endpt*, void*, long, vlong, int);
+static long	qtd(Ctlr*, Endpt*, int, Block*, uchar*, uchar*, int, ulong);
+
+static short
+refcnt(Block *b, int i)
+{
+	short v;
+	static Lock l;
+
+	ilock(&l);
+	v = (b->flag += i);
+	iunlock(&l);
+	if(v < 0)
+		iprint("refcnt 0x%lux %d\n", b, v);
+	return v;
+}
+
+static void
+freewb(Block *b)
+{
+	if(b == nil || refcnt(b, -1) > 0)
+		return;
+
+	if(b->base > b->rp || b->rp > b->wp || b->wp > b->lim)
+		iprint("freebw: %lux %lux %lux %lux\n",
+			b->base, b->rp, b->wp, b->lim);
+	/* poison the block in case someone is still holding onto it */
+	b->next = (Block*)0xdeadcafe;
+	b->rp = (uchar*)0xdeadcafe;
+	b->wp = (uchar*)0xdeadcafe;
+	b->lim = (uchar*)0xdeadcafe;
+	b->base = (uchar*)0xdeadcafe;
+
+	free(b);
+}
+
+Block *
+allocwb(long size)
+{
+	Block *b;
+
+	b = allocb(size);
+	b->flag = 1;
+	b->free = freewb;
+	return b;
+}
+
+void
+printdata(void *pdata, int itemsize, int nitems)
+{
+	int i;
+	uchar *p1;
+	ushort *p2;
+	ulong *p4;
+
+	if(!usbhdebug)
+		return;
+	p1 = pdata;
+	p2 = pdata;
+	p4 = pdata;
+	i = 0;
+	for(;;){
+		switch(itemsize){
+		default:
+			assert(0);
+		case 1:
+			print("%2.2ux ", *p1++);
+			break;
+		case 2:
+			print("%4.4ux ", *p2++);
+			break;
+		case 4:
+			print("%8.8lux ", *p4++);
+			break;
+		}
+		if(++i >= nitems || (i & ((0x40 >> itemsize) - 1)) == 0){
+			print("\n");
+			if(i >= nitems)
+				break;
+		}
+	}
+}
+
+/*
+ * i left these in so that we could use the same
+ * driver on several other platforms (in principle).
+ * the processor on which it was originally developed
+ * had an IO MMU and thus another address space.
+ * it's nothing to do with USB as such.
+ */
+ulong
+va2hcva(void *va)
+{
+	if(va == nil)
+		return 0;
+	return PADDR(va);
+}
+
+void *
+hcva2va(ulong hcva)
+{
+	if(hcva == 0)
+		return nil;
+	return KADDR(hcva);
+}
+
+void *
+va2ucva(void *va)
+{
+	return va;
+}
+
+void *
+hcva2ucva(ulong hcva)
+{
+	if(hcva == 0)
+		return nil;
+	if(hcva & 0xf0000000){
+		iprint("hcva2ucva: bad 0x%lux, called from 0x%lux\n",
+			hcva, getcallerpc(&hcva));
+		return nil;
+	}
+	return KADDR(hcva);
+}
+
+#define	IOCACHED	0
+#define	invalidatedcacheva(va)
+#define	dcclean(p, n)
+
+static void
+EDinit(ED *ed, int mps, int f, int k, int s, int d, int en, int fa,
+	TD *tail, TD *head, int c, int h, ED *next)
+{
+	/* check nothing is running? */
+	ed->ctrl = (mps & ED_MPS_MASK) << ED_MPS_SHIFT
+		| (f & 1) << 15
+		| (k & 1) << 14
+		| (s & ED_S_MASK) << ED_S_SHIFT
+		| (d & 3) << 11		/* 00 is obtained from TD (used here) */
+		| (en & 0xf) << 7
+		| (fa & 0x7f);
+	ed->tail =  va2hcva(tail) & ~0xF;
+	ed->head = (va2hcva(head) & ~0xF)
+		| (c & ED_C_MASK) << ED_C_SHIFT
+		| (h & ED_H_MASK) << ED_H_SHIFT;
+	ed->next = va2hcva(next) & ~0xF;
+}
+
+static void
+EDsetS(ED *ed, int s)
+{
+	XIPRINT("EDsetS: %s speed\n", s == Lowspeed ? "low" : "high");
+	if(s == Lowspeed)
+		ed->ctrl |= 1 << ED_S_SHIFT;
+	else
+		ed->ctrl &= ~(1 << ED_S_SHIFT);
+}
+
+static void
+EDsetMPS(ED *ed, int mps)
+{
+	ed->ctrl = (ed->ctrl & ~(ED_MPS_MASK << ED_MPS_SHIFT)) |
+		(mps & ED_MPS_MASK) << ED_MPS_SHIFT;
+}
+
+static void
+EDsetC(ED *ed, int c)
+{
+	ed->head = (ed->head & ~(ED_C_MASK << ED_C_SHIFT)) |
+		(c & ED_C_MASK) << ED_C_SHIFT;
+}
+
+static void
+EDsetH(ED *ed, int h)
+{
+	ed->head = (ed->head & ~(ED_H_MASK << ED_H_SHIFT)) |
+		(h & ED_H_MASK) << ED_H_SHIFT;
+}
+
+static int
+EDgetH(ED *ed)
+{
+	return (ed->head >> ED_H_SHIFT) & ED_H_MASK;
+}
+
+static int
+EDgetC(ED *ed)
+{
+	return (ed->head >> ED_C_SHIFT) & ED_C_MASK;
+}
+
+static void
+EDsetnext(ED *ed, void *va)
+{
+	ed->next = va2hcva(va) & ~0xF;
+}
+
+static ED *
+EDgetnext(ED *ed)
+{
+	return hcva2ucva(ed->next & ~0xF);
+}
+
+static void
+EDsettail(ED *ed, void *va)
+{
+	ed->tail = va2hcva(va) & ~0xF;
+}
+
+static TD *
+EDgettail(ED *ed)
+{
+	return hcva2ucva(ed->tail & ~0xF);
+}
+
+static void
+EDsethead(ED *ed, void *va)
+{
+	ed->head = (ed->head & 0xf) | (va2hcva(va) & ~0xF);
+}
+
+static TD *
+EDgethead(ED *ed)
+{
+	return hcva2ucva(ed->head & ~0xF);
+}
+
+static ED *
+EDalloc(Ctlr *ub)
+{
+	ED *t;
+
+	qlock(&ub->ed);
+	t = ub->ed.free;
+	if(t == nil){
+		qunlock(&ub->ed);
+		return nil;
+	}
+	ub->ed.free = (ED *)t->next;
+	ub->ed.alloced++;
+	if (0)
+		print("%d endpoints allocated\n", ub->ed.alloced);
+	qunlock(&ub->ed);
+	t->next = 0;
+	return t;
+}
+
+void
+TDsetnexttd(TD *td, TD *va)
+{
+	td->nexttd = va2hcva(va) & ~0xF;
+}
+
+TD *
+TDgetnexttd(TD *td)
+{
+	return hcva2ucva(td->nexttd & ~0xF);
+}
+
+void
+OHCIsetControlHeadED(OHCI *ohci, ED *va)
+{
+	ohci->ctlheaded = va2hcva(va) & ~0xF;
+}
+
+ED *
+OHCIgetControlHeadED(OHCI *ohci)
+{
+	return hcva2ucva(ohci->ctlheaded);
+}
+
+void
+OHCIsetBulkHeadED(OHCI *ohci, ED *va)
+{
+	ohci->bulkheaded = va2hcva(va) & ~0xF;
+}
+
+ED *
+OHCIgetBulkHeadED(OHCI *ohci)
+{
+	return hcva2ucva(ohci->bulkheaded);
+}
+
+static TD *
+TDalloc(Ctlr *ub, Endpt *ep, int musthave)		/* alloctd */
+{
+	TD *t;
+	Endptx *epx;
+
+	for(;;){
+		ilock(ub);
+		t = ub->td.free;
+		if(t)
+			break;
+		iunlock(ub);
+		if(up == nil){
+			if(musthave)
+				panic("TDalloc: out of descs");
+			return nil;
+		}
+		tsleep(&up->sleep, return0, 0, 100);
+	}
+
+	ub->td.free = t->next;
+	epx = ep->private;
+	epx->ntd++;
+	ub->td.alloced++;
+	iunlock(ub);
+	memset(t, 0, sizeof(TD));
+	t->ep = ep;
+	return t;
+}
+
+/* call under ilock */
+static void
+TDfree(Ctlr *ub, TD *t)					/* freetd */
+{
+	Endptx *epx;
+
+	if(t == 0)
+		return;
+
+	if(t->ep){
+		epx = t->ep->private;
+		epx->ntd--;
+	} else
+		t->ep = nil;			/* redundant? */
+	t->bp = nil;
+	t->next = ub->td.free;
+	ub->td.free = t;
+	ub->td.alloced--;
+}
+
+static void
+EDfree(Ctlr *ub, ED *t)
+{
+	TD *td, *next;
+
+	if(t == 0)
+		return;
+	qlock(&ub->ed);
+	t->next = (ulong)ub->ed.free;
+	ub->ed.free = t;
+	ub->ed.alloced--;
+	if (0)
+		print("%d endpoints allocated\n", ub->ed.alloced);
+	ilock(ub);
+	for(td = EDgethead(t); td; td = next){
+		next = TDgetnexttd(td);
+		TDfree(ub, td);
+	}
+	iunlock(ub);
+	EDsethead(t, 0);
+	EDsettail(t, 0);
+	qunlock(&ub->ed);
+}
+
+static void
+waitSOF(Ctlr *ub)
+{
+	/*
+	 * wait for SOF - interlock with interrupt handler so
+	 * done queue processed first.
+	 */
+	int frame = ub->uchcca->framenumber & 0x3f;
+
+	do {
+		delay(2);
+	} while(frame == (ub->uchcca->framenumber & 0x3f));
+}
+
+static void
+dumptd(TD *td, char *s)
+{
+	int i;
+	Endpt *ep;
+
+	ep = td->ep;
+	print("\t%s: 0x%.8lux ctrl 0x%.8lux cbp 0x%.8lux "
+		"nexttd 0x%.8lux be 0x%.8lux, flags %lux\n",
+		s, td, td->ctrl, td->cbp, td->nexttd, td->be, td->flags);
+	if(ep->epmode != Isomode){
+		print("\t\tbytes: %ld\n", td->be + 1 - td->cbp);
+		return;
+	}
+	print("\t\t0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux 0x%ux\n",
+		td->offsets[0], td->offsets[1], td->offsets[2], td->offsets[3],
+		td->offsets[4], td->offsets[5], td->offsets[6], td->offsets[7]);
+	print("\t\tbytes:");
+	for(i = 0; i < td->ctrl >> 24 & 0x7; i++)
+		print(" %d", (td->offsets[i+1]-td->offsets[i])&0xfff);
+	print(" %ld\n", (td->be + 1 - td->offsets[i]) & 0xfff);
+}
+
+static void
+dumped(ED *ed)
+{
+	TD *tailp, *td;
+
+	tailp = EDgettail(ed);
+	td = EDgethead(ed);
+	print("dumpED 0x%lux: ctrl 0x%lux tail 0x%lux head 0x%lux next 0x%lux\n",
+		ed, ed->ctrl, ed->tail, ed->head, ed->next);
+	if(tailp == td)
+		return;
+	do {
+		dumptd(td, "td");
+	} while((td = TDgetnexttd(td)) != tailp);
+}
+
+static void
+dumpstatus(Ctlr *ub)
+{
+	ED *ed;
+
+	print("dumpstatus 0x%lux, frame 0x%ux:\n", ub, ub->uchcca->framenumber);
+	print("control 0x%lux, cmdstat 0x%lux, intrsts 0x%lux\n",
+		ub->base->control, ub->base->cmdsts, ub->base->intrsts);
+	print("Control:\n");
+	for(ed = OHCIgetControlHeadED(ub->base); ed; ed = EDgetnext(ed))
+		dumped(ed);
+	print("Bulk:\n");
+	for(ed = OHCIgetBulkHeadED(ub->base); ed; ed = EDgetnext(ed))
+		dumped(ed);
+	print("Iso:\n");
+	for(ed = ub->tree->root[0]; ed; ed = EDgetnext(ed))
+		dumped(ed);
+	print("frame 0x%ux:\n", ub->uchcca->framenumber);
+}
+
+/*
+ * halt the ED and free input or output transfer descs
+ * called when the relevant lock in the enclosing Endpt is held
+ */
+
+static void
+EDcancel(Ctlr *ub, ED *ed, int dirin)
+{
+	int tddir, iso, n;
+	TD *tailp, *headp, *td, *prev, *next;
+	Endpt *ep;
+
+	if(ed == nil)
+		return;
+
+	/* halt ED if not already halted */
+	if(EDgetH(ed) != 1){
+		EDsetH(ed, 1);
+		waitSOF(ub);
+	}
+
+	SET(tddir);
+	if((iso = ed->ctrl & ED_F_BIT) != 0)
+		switch((ed->ctrl >> 11) & 0x3){
+		default:
+			panic("ED iso direction unset");
+		case Otokin:	tddir = Dirin;	break;
+		case Otokout:	tddir = Dirout;	break;
+		}
+
+	/* can now clean up TD list of ED */
+	tailp = EDgettail(ed);
+	headp = EDgethead(ed);
+	n = 0;
+	prev = nil;
+	td = headp;
+	while(td != tailp){
+		ep = td->ep;
+		if(iso == 0)
+			switch((td->ctrl >> TD_DP_SHIFT) & TD_DP_MASK){
+			default:
+				panic("TD direction unset");
+			case Otoksetup:	tddir = Dirout;	break;
+			case Otokin:	tddir = Dirin;	break;
+			case Otokout:	tddir = Dirout;	break;
+			}
+		else if(usbhdebug || ep->debug)
+			print("EDcancel: buffered: %d, bytes %ld\n",
+				ep->buffered, td->bytes);
+		next = TDgetnexttd(td);
+		if(dirin == 2 || dirin == tddir){
+			XEPRINT("%d/%d: EDcancel %d\n", ep->dev->x, ep->x, tddir);
+			/* Remove this sucker */
+			ep->buffered -= td->bytes;
+			if(ep->buffered < 0)
+				ep->buffered = 0;
+			ilock(ub);
+			ep->dir[tddir].queued--;
+			if(tddir == Dirout){
+				freeb(td->bp);
+				td->bp = nil;
+			}
+			if(prev)
+				TDsetnexttd(prev, next);
+			else
+				EDsethead(ed, next);
+			TDfree(ub, td);
+			n++;
+			iunlock(ub);
+		}else{
+			XEPRINT("%d/%d: EDcancel skip %d\n", ep->dev->x, ep->x,
+				tddir);
+			prev = td;
+		}
+		td = next;
+	}
+	XPRINT("EDcancel: %d\n", n);
+}
+
+static void
+eptactivate(Ctlr *ub, Endpt *ep)
+{
+	Endptx *epx;
+
+	qlock(&ub->activends);
+	if(ep->active == 0){
+		epx = ep->private;
+		XEPRINT("%d/%d: activate\n", ep->dev->x, ep->x);
+		ep->active = 1;
+		/*
+		 * set the right speed
+		 */
+		EDsetS(epx->ed, ep->dev->speed);
+		switch(ep->epmode){
+		case Ctlmode:
+			/*
+			 * chain the two descs together, and
+			 * bind to beginning of control queue
+			 */
+			EDsetnext(epx->ed, OHCIgetControlHeadED(ub->base));
+			OHCIsetControlHeadED(ub->base, epx->ed);
+			/*
+			 * prompt controller to absorb new queue on next pass
+			 */
+			ub->base->cmdsts |= Clf;
+			XEPRINT("%d/%d: activated in control queue\n",
+				ep->dev->x, ep->x);
+			break;
+		case Bulkmode:
+			EDsetnext(epx->ed, OHCIgetBulkHeadED(ub->base));
+			OHCIsetBulkHeadED(ub->base, epx->ed);
+			ub->base->cmdsts |= Blf;
+			XEPRINT("%d/%d: activated %s in bulk input queue\n",
+				ep->dev->x, ep->x, omodename[ep->mode]);
+			break;
+		case Isomode:
+			if(ep->mode != OWRITE)
+				schedendpt(ub, ep, Dirin);
+			if(ep->mode != OREAD)
+				schedendpt(ub, ep, Dirout);
+			ep->buffered = 0;
+			ep->partial = 0;
+			break;
+		case Intrmode:
+			if(ep->mode != OWRITE)
+				schedendpt(ub, ep, Dirin);
+			if(ep->mode != OREAD)
+				schedendpt(ub, ep, Dirout);
+			break;
+		case Nomode:
+			break;
+		default:
+			panic("eptactivate: wierd epmode %d\n", ep->epmode);
+		}
+		ep->dir[Dirin].xdone  = ep->dir[Dirin].xstarted =  0;
+		ep->dir[Dirout].xdone = ep->dir[Dirout].xstarted = 0;
+		ep->activef = ub->activends.f;
+		ub->activends.f = ep;
+	}
+	qunlock(&ub->activends);
+}
+
+static void
+EDpullfrombulk(Ctlr *ub, ED *ed)
+{
+	ED *this, *prev, *next;
+
+	this = OHCIgetBulkHeadED(ub->base);
+	ub->base->bulkcurred = 0;
+	prev = nil;
+	while(this != nil && this != ed){
+		prev = this;
+		this = EDgetnext(this);
+	}
+	if(this == nil){
+		print("EDpullfrombulk: not found\n");
+		return;
+	}
+	next = EDgetnext(this);
+	if(prev == nil)
+		OHCIsetBulkHeadED(ub->base, next);
+	else
+		EDsetnext(prev, next);
+	EDsetnext(ed, nil);		/* wipe out next field */
+}
+
+static void
+EDpullfromctl(Ctlr *ub, ED *ed)
+{
+	ED *this, *prev, *next;
+
+	this = OHCIgetControlHeadED(ub->base);
+	ub->base->ctlcurred = 0;
+	prev = nil;
+	while(this != nil && this != ed){
+		prev = this;
+		this = EDgetnext(this);
+	}
+	if(this == nil)
+		panic("EDpullfromctl: not found\n");
+	next = EDgetnext(this);
+	if(prev == nil)
+		OHCIsetControlHeadED(ub->base, next);
+	else
+		EDsetnext(prev, next);
+	EDsetnext(ed, nil);		/* wipe out next field */
+}
+
+static void
+eptdeactivate(Ctlr *ub, Endpt *ep)
+{
+	ulong ctrl;
+	Endpt **l;
+	Endptx *epx;
+
+	/* could be O(1) but not worth it yet */
+	qlock(&ub->activends);
+	if(ep->active){
+		epx = ep->private;
+		XEPRINT("ohci: eptdeactivate %d/%d\n", ep->dev->x, ep->x);
+		ep->active = 0;
+		for(l = &ub->activends.f; *l != ep; l = &(*l)->activef)
+			if(*l == nil){
+				qunlock(&ub->activends);
+				panic("usb eptdeactivate");
+			}
+		*l = ep->activef;
+		/* pull it from the appropriate queue */
+		ctrl = ub->base->control;
+		switch(ep->epmode){
+		case Ctlmode:
+			if(ctrl & Cle){
+				ub->base->control &= ~Cle;
+				waitSOF(ub);
+			}
+			EDpullfromctl(ub, epx->ed);
+			if(ctrl & Cle){
+				ub->base->control |= Cle;
+				/*
+				 * don't fill it if there is nothing in it -
+				 * shouldn't be necessary according to the
+				 * spec., but practice is different
+				 */
+				if(OHCIgetControlHeadED(ub->base))
+					ub->base->cmdsts |= Clf;
+			}
+			break;
+		case Bulkmode:
+			if(ctrl & Ble){
+				ub->base->control &= ~Ble;
+				waitSOF(ub);
+			}
+			EDpullfrombulk(ub, epx->ed);
+			if(ctrl & Ble){
+				ub->base->control |= Ble;
+				/*
+				 * don't fill it if there is nothing in it -
+				 * shouldn't be necessary according to the
+				 * spec., but practice is different
+				 */
+				if(OHCIgetBulkHeadED(ub->base))
+					ub->base->cmdsts |= Blf;
+			}
+			break;
+		case Intrmode:
+		case Isomode:
+			if(ep->mode != OWRITE)
+				unschedendpt(ub, ep, Dirin);
+			if(ep->mode != OREAD)
+				unschedendpt(ub, ep, Dirout);
+			waitSOF(ub);
+			break;
+		case Nomode:
+			break;
+		default:
+			panic("eptdeactivate: wierd in.epmode %d\n",
+				ep->epmode);
+		}
+	}
+	qunlock(&ub->activends);
+}
+
+static void
+kickappropriatequeue(Ctlr *ub, Endpt *ep, int)
+{
+	switch(ep->epmode){
+	case Nomode:
+		break;
+	case Ctlmode:
+		ub->base->cmdsts |= Clf;
+		break;
+	case Bulkmode:
+		ub->base->cmdsts |= Blf;
+		break;
+	case Intrmode:
+	case Isomode:
+		/* no kicking required */
+		break;
+	default:
+		panic("wierd epmode %d\n", ep->epmode);
+	}
+}
+
+static void
+eptenable(Ctlr *ub, Endpt *ep, int dirin)
+{
+	ED *ed;
+	Endptx *epx;
+
+	epx = ep->private;
+	ed = epx->ed;
+	if(EDgetH(ed) == 1){
+		EDsetH(ed, 0);
+		kickappropriatequeue(ub, ep, dirin);
+		if(ep->epmode == Isomode || ep->epmode == Intrmode)
+			waitSOF(ub);
+	}
+}
+
+/*
+ * return smallest power of 2 >= n
+ */
+static int
+flog2(int n)
+{
+	int i;
+
+	for(i = 0; (1 << i) < n; i++)
+		;
+	return i;
+}
+
+/*
+ * return smallest power of 2 <= n
+ */
+static int
+flog2lower(int n)
+{
+	int i;
+
+	for(i = 0; (1 << (i + 1)) <= n; i++)
+		;
+	return i;
+}
+
+static int
+pickschedq(QTree *qt, int pollms, ulong bw, ulong limit)
+{
+	int i, j, d, upperb, q;
+	ulong best, worst, total;
+
+	d = flog2lower(pollms);
+	if(d > qt->depth)
+		d = qt->depth;
+	q = -1;
+	worst = 0;
+	best = ~0;
+	upperb = (1 << (d+1)) - 1;
+	for(i = (1 << d) - 1; i < upperb; i++){
+		total = qt->bw[0];
+		for(j = i; j > 0; j = (j - 1) / 2)
+			total += qt->bw[j];
+		if(total < best){
+			best = total;
+			q = i;
+		}
+		if(total > worst)
+			worst = total;
+	}
+	if(worst + bw >= limit)
+		return -1;
+	return q;
+}
+
+static int
+schedendpt(Ctlr *ub, Endpt *ep, int dirin)
+{
+	int q;
+	ED *ed;
+	Endptx *epx;
+
+	epx = ep->private;
+	qlock(ub->tree);
+	/* TO DO: bus bandwidth limit */
+	q = pickschedq(ub->tree, ep->pollms, ep->bw, ~0);
+	XEPRINT("schedendpt, dir %d Q index %d, ms %d, bw %ld\n",
+		dirin, q, ep->pollms, ep->bw);
+	if(q < 0){
+		qunlock(ub->tree);
+		return -1;
+	}
+	ub->tree->bw[q] += ep->bw;
+	ed = ub->tree->root[q];
+	ep->sched = q;
+	EDsetnext(epx->ed, EDgetnext(ed));
+	EDsetnext(ed, epx->ed);
+	XEPRINT("%d/%d: sched on q %d pollms %d\n",
+		ep->dev->x, ep->x, q, ep->pollms);
+	qunlock(ub->tree);
+	return 0;
+}
+
+static void
+unschedendpt(Ctlr *ub, Endpt *ep, int dirin)
+{
+	int q;
+	ED *prev, *this, *next;
+	Endptx *epx;
+
+	epx = ep->private;
+	if((q = ep->sched) < 0)
+		return;
+	qlock(ub->tree);
+	ub->tree->bw[q] -= ep->bw;
+
+	prev = ub->tree->root[q];
+	this = EDgetnext(prev);
+	while(this != nil && this != epx->ed){
+		prev = this;
+		this = EDgetnext(this);
+	}
+	if(this == nil)
+		print("unschedendpt %d %d: not found\n", dirin, q);
+	else{
+		next = EDgetnext(this);
+		EDsetnext(prev, next);
+	}
+	qunlock(ub->tree);
+}
+
+/* at entry, *e is partly populated */
+static void
+epalloc(Usbhost *uh, Endpt *ep)
+{
+	int id;
+	Endptx *epx;
+	Ctlr *ctlr;
+	Udev *d;
+	TD *dtd;
+
+	XEPRINT("ohci: epalloc from devusb\n");
+	ctlr = uh->ctlr;
+	id = ep->id;
+	d = ep->dev;
+
+	epx = malloc(sizeof(Endptx));
+	memset(epx, 0, sizeof(Endptx));
+	ep->private = epx;
+
+	dtd = nil;
+	if(waserror()){
+		XEPRINT("ohci: epalloc error\n");
+		EDfree(ctlr, epx->ed);
+		epx->ed = nil;
+		TDfree(ctlr, dtd);
+		nexterror();
+	}
+	if(epx->ed)
+		error("usb: already allocated");
+	if((epx->ed = EDalloc(ctlr)) == nil)
+		error(Enomem);
+	ep->bw = 1;			/* all looks the same currently */
+	if((dtd = TDalloc(ctlr, ep, 0)) == nil)
+		error(Enomem);
+	EDinit(epx->ed, ep->maxpkt, 0, 0, 0, 0, id, d->id, dtd, dtd, 0, 0, 0);
+	XEPRINT("ohci: epalloc done\n");
+	poperror();
+}
+
+static void
+epfree(Usbhost *uh, Endpt *ep)
+{
+	Endptx *epx;
+	Ctlr *ctlr;
+
+	epx = ep->private;
+	ctlr = uh->ctlr;
+	XEPRINT("ohci: epfree %d/%d from devusb\n", ep->dev->x, ep->x);
+
+	if(ep->active)
+		panic("epfree: active");
+	EDfree(ctlr, epx->ed);
+	epx->ed = nil;
+	free(epx);
+	ep->private = nil;
+}
+
+static void
+epopen(Usbhost *uh, Endpt *ep)
+{
+	Ctlr *ctlr;
+
+	XEPRINT("ohci: epopen %d/%d from devusb\n", ep->dev->x, ep->x);
+	ctlr = uh->ctlr;
+	if((ep->epmode == Isomode || ep->epmode == Intrmode) && ep->active)
+		error("already open");
+	eptactivate(ctlr, ep);
+}
+
+static int
+setfrnum(Ctlr *ub, Endpt *ep)
+{
+	short frnum, d;
+	static int adj;
+
+	/* adjust frnum as necessary... */
+	frnum = ub->base->fmnumber + (ep->buffered*1000)/ep->bw;
+	d = frnum - ep->frnum;
+	if(d < -100 || d > 100){
+		/* We'd play in the past */
+		if(0 && d > 1000)
+			/* We're more than a second off: */
+			print("d %d, done %d, started %d, buffered %d\n", d,
+				ep->dir[Dirout].xdone, ep->dir[Dirout].xstarted,
+				ep->buffered);
+		if(ep->dir[Dirout].xdone == ep->dir[Dirout].xstarted)
+			ep->buffered = adj = 0;
+		if(0 && (adj++ & 0xff) == 0)
+			print("adj %d %d\n", d, ep->buffered);
+		ep->frnum = ub->base->fmnumber + 10 + (ep->buffered*1000)/ep->bw;
+		ep->partial = 0;
+		return 1;
+	}
+	return 0;
+}
+
+static int
+ceptdone(void *arg)
+{
+	Endpt *ep;
+
+	ep = arg;
+	return ep->dir[Dirout].xdone - ep->dir[Dirout].xstarted >= 0
+		|| ep->dir[Dirout].err;
+}
+
+static void
+epclose(Usbhost *uh, Endpt *ep)
+{
+	Ctlr *ctlr;
+	int xdone, part;
+	Endptx *epx;
+
+	XEPRINT("ohci: epclose %d/%d from devusb, %d buffered\n",
+		ep->dev->x, ep->x, ep->buffered);
+	ctlr = uh->ctlr;
+	epx = ep->private;
+	if(ep->epmode == Isomode && ep->active){
+		qlock(&ep->wlock);
+		if(ep->partial && setfrnum(ctlr, ep) == 0){
+			part = ep->partial;
+			memset(ep->bpartial->wp, 0, ep->maxpkt - ep->partial);
+			ep->bpartial->wp = ep->bpartial->rp + ep->maxpkt;
+			qtd(uh->ctlr, ep, Dirout, nil, ep->bpartial->rp,
+				ep->bpartial->wp, Otokout, TD_FLAGS_LAST);
+			XEPRINT("epclose: wrote partial block %d\n", part);
+			ep->partial = 0;
+		}
+		qunlock(&ep->wlock);
+		XEPRINT("epclose: wait for outstanding TDs, xdone %d"
+			", xstarted %d, buffered %d, queued %d\n",
+			ep->dir[Dirout].xdone, ep->dir[Dirout].xstarted,
+			ep->buffered, ep->dir[Dirout].queued);
+		while(ep->dir[Dirout].err == nil
+		&& (xdone = ep->dir[Dirout].xdone) - ep->dir[Dirout].xstarted < 0){
+			tsleep(&ep->dir[Dirout].rend, ceptdone, ep, 500);
+			if(xdone == ep->dir[Dirout].xdone){
+				print("no progress\n");
+				break;
+			}
+		}
+		if(ep->dir[Dirout].err)
+			XEPRINT("error: %s\n", ep->dir[Dirout].err);
+		if(ep->buffered)
+			XEPRINT("epclose: done waiting, xdone %d, xstarted %d, "
+				"buffered %d, queued %d\n",
+				ep->dir[Dirout].xdone, ep->dir[Dirout].xstarted,
+				ep->buffered, ep->dir[Dirout].queued);
+	}
+	lock(epx);
+	EDcancel(ctlr, epx->ed, 2);
+	unlock(epx);
+	if(ep->epmode == Isomode && ep->buffered)
+		XEPRINT("epclose: after cancelling, xdone %d, xstarted %d"
+			", buffered %d, queued %d\n",
+			ep->dir[Dirout].xdone, ep->dir[Dirout].xstarted,
+			ep->buffered, ep->dir[Dirout].queued);
+	eptdeactivate(ctlr, ep);
+}
+
+static void
+epmaxpkt(Usbhost *, Endpt *ep)
+{
+	Endptx *epx;
+
+	epx = ep->private;
+	XEPRINT("ohci: epmaxpkt %d/%d: %d\n",
+		ep->dev->x, ep->x, ep->maxpkt);
+	EDsetMPS(epx->ed, ep->maxpkt);
+}
+
+static void
+epmode(Usbhost *uh, Endpt *ep)
+{
+	int tok, reactivate;
+	Ctlr *ctlr;
+	Endptx *epx;
+
+	epx = ep->private;
+	ctlr = uh->ctlr;
+	XEPRINT("ohci: epmode %d/%d %s → %s\n",
+		ep->dev->x, ep->x, modename[ep->epmode], modename[ep->epnewmode]);
+	reactivate = 0;
+	if(ep->epnewmode != ep->epmode)
+		if(reactivate = ep->active){
+			XEPRINT("ohci: epmode %d/%d: already open\n",
+				ep->dev->x, ep->x);
+			eptdeactivate(ctlr, ep);
+		}
+	EDsetS(epx->ed, ep->dev->speed);
+	switch(ep->epnewmode){
+	default:
+		panic("devusb is sick");
+	case Intrmode:
+//		ep->debug++;
+		ep->bw = ep->maxpkt*1000/ep->pollms;	/* bytes/sec */
+		XEPRINT("ohci: epmode %d/%d %s, intr: maxpkt %d, pollms %d, bw %ld\n",
+			ep->dev->x, ep->x, omodename[ep->mode],
+			ep->maxpkt, ep->pollms, ep->bw);
+		break;
+	case Isomode:
+//		ep->debug++;
+		ep->rem = 999;
+		switch(ep->mode){
+		default:
+			panic("ep mode");
+		case ORDWR:
+			error("iso unidirectional only");
+		case OREAD:
+			tok = Otokin;
+			error("iso read not implemented");
+			break;
+		case OWRITE:
+			tok = Otokout;
+			break;
+		}
+		XEPRINT("ohci: epmode %d/%d %s, iso: maxpkt %d, pollms %d, hz %d, samp %d\n",
+			ep->dev->x, ep->x, omodename[ep->mode],
+			ep->maxpkt, ep->pollms, ep->hz, ep->samplesz);
+		ep->bw = ep->hz * ep->samplesz;		/* bytes/sec */
+		/* Use Iso TDs: */
+		epx->ed->ctrl |= ED_F_BIT;
+		/* Set direction in ED, no room in an Iso TD for this */
+		epx->ed->ctrl &= ~(ED_D_MASK << ED_D_SHIFT);
+		epx->ed->ctrl |= tok << ED_D_SHIFT;
+		break;
+	case Bulkmode:
+//		ep->debug++;
+		/*
+		 * Each Bulk device gets a queue head hanging off the
+		 * bulk queue head
+		 */
+		break;
+	case Ctlmode:
+		break;
+	}
+	ep->epmode = ep->epnewmode;
+	epmaxpkt(uh, ep);
+	if(reactivate){
+		XEPRINT("ohci: epmode %d/%d: reactivate\n", ep->dev->x, ep->x);
+		eptactivate(ctlr, ep);
+	}
+}
+
+static long
+qtd(Ctlr *ub, Endpt *ep, int dirin , Block *bp, uchar *base, uchar *limit,
+	int pid, ulong flags)
+{
+	int fc, mps;
+	ulong x;
+	uchar *p;
+	ED *ed;
+	Endptx *epx;
+	TD *dummytd, *td;
+
+	epx = ep->private;
+	ed = epx->ed;
+	td = hcva2ucva(ed->tail);
+	td->flags = flags;
+	if(ep->epmode == Isomode){
+		x = va2hcva(base);
+		td->cbp = x & ~0xfff;
+		x &= 0xfff;
+		p = base;
+		setfrnum(ub, ep);
+		td->ctrl = ep->frnum & 0xffff;
+		fc = 0;
+		for(;;){
+			/* Calculate number of samples in next packet */
+			mps = (ep->hz + ep->rem)/1000;
+			/* rem is the partial sample left over */
+			ep->rem += ep->hz - 1000*mps;
+			mps *= ep->samplesz;
+			if(mps > ep->maxpkt)
+				panic("Packet size");
+			if(ep->partial == 0 && mps > limit - p){
+				/* Save this data for later ... */
+				ep->partial = limit - p;
+				if(fc-- == 0)
+					return p - base;	/* No TD */
+				/* We do have a TD, send this one off normally */
+				td->flags |= TD_FLAGS_LAST;
+				break;
+			}else if(mps >= limit - p){
+				td->flags |= TD_FLAGS_LAST;
+				mps = limit - p;
+				ep->partial = 0;
+			}
+			td->offsets[fc] = 0xe000 | x;
+			x += mps;
+			p += mps;
+			ep->frnum++;
+			if(fc == 7 || limit - p == 0)
+				break;
+			fc++;
+		}
+		td->ctrl |= fc << 24;
+	}else{
+		td->cbp = va2hcva(base);
+		td->ctrl = (pid & TD_DP_MASK) << TD_DP_SHIFT;
+		p = base;
+		mps = 0x2000 - ((ulong)p & 0xfff);
+		if(mps > ep->maxpkt)
+			mps = ep->maxpkt;
+		if(mps >= limit - p){
+			mps = limit - base;
+			td->flags |= TD_FLAGS_LAST;
+		}
+		p += mps;
+	}
+	td->be = va2hcva(p == nil? nil: p - 1);
+	td->ep = ep;
+	td->bytes = p - base;
+	ep->buffered += td->bytes;
+	td->bp = bp;
+	if(td->flags & TD_FLAGS_LAST)
+		ep->dir[dirin].xstarted++;
+	if(dirin == Dirout && bp)
+		refcnt(bp, 1);
+	dummytd = TDalloc(ub, ep, 1);
+	TDsetnexttd(td, dummytd);
+	ep->dir[dirin].queued++;
+	EDsettail(ed, dummytd);
+	if(usbhdebug || ep->debug)
+		dumptd(td, "qtd: before");
+	kickappropriatequeue(ub, ep, dirin);
+	return p - base;
+}
+
+Block*
+allocrcvb(long size)
+{
+	Block *b;
+	int asize;
+
+	asize = ROUND(size, dcls) + dcls - 1;
+	/*
+	 * allocate enough to align rp to dcls, and have an integral number
+	 * of cache lines in the buffer
+	 */
+	while(waserror())
+		tsleep(&up->sleep, return0, 0, 100);
+	b = allocb(asize);
+	poperror();
+	/*
+	 * align the rp and wp
+	 */
+	b->rp = b->wp = (uchar *)ROUND((ulong)b->rp, dcls);
+	/*
+	 * invalidate the cache lines which enclose the buffer
+	 */
+	if(IOCACHED){
+		uchar *p;
+
+		p = b->rp;
+		while(size > 0){
+			invalidatedcacheva((ulong)p);
+			p += dcls;
+			size -= dcls;
+		}
+	}
+	return b;
+}
+
+/*
+ * build the periodic scheduling tree:
+ * framesize must be a multiple of the tree size
+ */
+static QTree *
+mkqhtree(Ctlr *ub)
+{
+	int i, n, d, o, leaf0, depth;
+	ED **tree;
+	QTree *qt;
+
+	depth = flog2(32);
+	n = (1 << (depth+1)) - 1;
+	qt = mallocz(sizeof(*qt), 1);
+	if(qt == nil)
+		return nil;
+	qt->nel = n;
+	qt->depth = depth;
+	qt->bw = mallocz(n * sizeof(qt->bw), 1);
+	if(qt->bw == nil){
+		free(qt);
+		return nil;
+	}
+	tree = mallocz(n * sizeof(ED *), 1);
+	if(tree == nil){
+		free(qt->bw);
+		free(qt);
+		return nil;
+	}
+	for(i = 0; i < n; i++)
+		if((tree[i] = EDalloc(ub)) == nil)
+			break;
+
+	if(i < n){
+		int j;
+
+		for(j = 0; j < i; j++)
+			EDfree(ub, tree[j]);
+		free(tree);
+		free(qt->bw);
+		free(qt);
+		return nil;
+	}
+
+	qt->root = tree;
+	EDinit(qt->root[0], 8, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+	for(i = 1; i < n; i++)
+		EDinit(tree[i], 8, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, tree[(i-1)/2]);
+
+	/* distribute leaves evenly round the frame list */
+	leaf0 = n / 2;
+	for(i = 0; i < 32; i++){
+		o = 0;
+		for(d = 0; d < depth; d++){
+			o <<= 1;
+			if(i & (1 << d))
+				o |= 1;
+		}
+		if(leaf0 + o >= n){
+			print("leaf0=%d o=%d i=%d n=%d\n", leaf0, o, i, n);
+			break;
+		}
+		ub->uchcca->intrtable[i] = va2hcva(tree[leaf0 + o]);
+	}
+	return qt;
+}
+
+static void
+portreset(Usbhost *uh, int port)
+{
+	Ctlr *ctlr;
+
+	XIPRINT("ohci: portreset(port %d) from devusb\n", port);
+	ctlr = uh->ctlr;
+	/* should check that device not being configured on other port? */
+	qlock(&ctlr->resetl);
+	if(waserror()){
+		qunlock(&ctlr->resetl);
+		nexterror();
+	}
+	ilock(ctlr);
+	ctlr->base->rhportsts[port - 1] = Spp | Spr;
+	while((ctlr->base->rhportsts[port - 1] & Prsc) == 0){
+		iunlock(ctlr);
+		XIPRINT("ohci: portreset, wait for reset complete\n");
+		ilock(ctlr);
+	}
+	ctlr->base->rhportsts[port - 1] = Prsc;
+	iunlock(ctlr);
+	poperror();
+	qunlock(&ctlr->resetl);
+}
+
+static void
+portenable(Usbhost *uh, int port, int on)
+{
+	Ctlr *ctlr;
+
+	XIPRINT("ohci: portenable(port %d, on %d) from devusb\n", port, on);
+	ctlr = uh->ctlr;
+	/* should check that device not being configured on other port? */
+	qlock(&ctlr->resetl);
+	if(waserror()){
+		qunlock(&ctlr->resetl);
+		nexterror();
+	}
+	ilock(ctlr);
+	if(on)
+		ctlr->base->rhportsts[port - 1] = Spe | Spp;
+	else
+		ctlr->base->rhportsts[port - 1] = Cpe;
+	iunlock(ctlr);
+	poperror();
+	qunlock(&ctlr->resetl);
+}
+
+static int
+getportstatus(Ctlr *ub, int port)
+{
+	int v;
+	ulong ohcistatus;
+
+	ohcistatus = ub->base->rhportsts[port - 1];
+	v = 0;
+	if(ohcistatus & Ccs)
+		v |= DevicePresent;
+	if(ohcistatus & Pes)
+		v |= PortEnable;
+	if(ohcistatus & Pss)
+		v |= Suspend;
+	if(ohcistatus & Prs)
+		v |= PortReset;
+	else {
+		/* port is not in reset; these potential writes are ok */
+		if(ohcistatus & Csc){
+			/* TODO: could notify usbd equivalent here */
+			v |= ConnectStatusChange;
+			ub->base->rhportsts[port - 1] = Csc;
+		}
+		if(ohcistatus & Pesc){
+			/* TODO: could notify usbd equivalent here */
+			v |= PortEnableChange;
+			ub->base->rhportsts[port - 1] = Pesc;
+		}
+	}
+	if(ohcistatus & Lsda)
+		v |= SlowDevice;
+	if(ohcistatus & Ccs)
+		XIPRINT("portstatus(%d) = OHCI 0x%.8lux UHCI 0x%.8ux\n",
+			port, ohcistatus, v);
+	return v;
+}
+
+/* this is called several times every few seconds, possibly due to usbd */
+static void
+portinfo(Usbhost *uh, char *s, char *se)
+{
+	int x, i, j;
+	Ctlr *ctlr;
+
+	XIPRINT("ohci: portinfo from devusb\n");
+	ctlr = uh->ctlr;
+	for(i = 1; i <= 4; i++) {
+		ilock(ctlr);
+		x = getportstatus(ctlr, i);
+		iunlock(ctlr);
+		s = seprint(s, se, "%d %ux", i, x);
+		for(j = 0; j < nelem(portstatus); j++)
+			if((x & portstatus[j].bit) != 0)
+				s = seprint(s, se, " %s", portstatus[j].name);
+		s = seprint(s, se, "\n");
+	}
+}
+
+void
+interrupt(Ureg *, void *arg)
+{
+	int dirin, cc;
+	ulong ctrl, status;
+	uchar *p;
+	Block *bp;
+	Ctlr *ub;
+	Endpt *ep;
+	Endptx *epx;
+	TD *donetd, *nexttd;
+	Usbhost *eh;
+
+	XIPRINT("ohci: interrupt\n");
+	eh = arg;
+	ub = eh->ctlr;
+	status = ub->base->intrsts;
+	status &= ub->base->intrenable;
+	status &= Oc | Rhsc | Fno
+		| Ue
+		| Rd | Sf | Wdh
+		| So;
+	if(status & Wdh){
+		/* LSb of donehead has bit that says there are other interrupts */
+		donetd = hcva2ucva(ub->uchcca->donehead & ~0xf);
+		XIPRINT("donetd 0x%.8lux\n", donetd);
+	}else
+		donetd = 0;
+	ub->base->intrsts = status;
+	status &= ~Wdh;
+	while(donetd){
+		ctrl = donetd->ctrl;
+		ep = donetd->ep;
+		bp = donetd->bp;
+		donetd->bp = nil;
+		epx = ep->private;
+
+		ohciinterrupts[ep->epmode]++;
+		dirin = ((ctrl >> TD_DP_SHIFT) & TD_DP_MASK) == Otokin;
+		ep->buffered -= donetd->bytes;
+		if(ep->epmode == Isomode){
+			dirin = Dirout;
+			if(ep->buffered < 0){
+				print("intr: buffered %d bytes %ld\n",
+					ep->buffered, donetd->bytes);
+				ep->buffered = 0;
+			}
+		}
+		cc = (ctrl >> TD_CC_SHIFT) & TD_CC_MASK;
+		if((usbhdebug || ep->debug) && (cc != 0 && cc != 9)){
+			print("%d/%d: cc %d frnum 0x%lux\n",
+				ep->dev->x, ep->x, cc, ub->base->fmnumber);
+			dumptd(donetd, "after");
+		}
+		switch(cc){
+		case 8:			/* Overrun, Not an error */
+			epx->overruns++;
+			/* fall through to no error code */
+		case 0:			/* noerror */
+			if((donetd->flags & TD_FLAGS_LAST) == 0)
+				break;
+			if(dirin){
+				if(bp){
+					p = hcva2va(donetd->be + 1);
+					if(p < bp->wp)
+						print("interrupt: bp: rp 0x%lux"
+							", wp 0x%lux→0x%lux\n",
+							bp->rp, bp->wp, p);
+					bp->wp = p;
+				}
+			}
+			ep->dir[dirin].xdone++;
+			wakeup(&ep->dir[dirin].rend);
+			break;