diff options
Diffstat (limited to 'slof/fs/usb')
-rw-r--r-- | slof/fs/usb/usb-enumerate.fs | 257 | ||||
-rw-r--r-- | slof/fs/usb/usb-hub.fs | 468 | ||||
-rw-r--r-- | slof/fs/usb/usb-kbd-device-support.fs | 105 | ||||
-rw-r--r-- | slof/fs/usb/usb-keyboard.fs | 345 | ||||
-rw-r--r-- | slof/fs/usb/usb-mouse.fs | 26 | ||||
-rw-r--r-- | slof/fs/usb/usb-ohci.fs | 1109 | ||||
-rw-r--r-- | slof/fs/usb/usb-static.fs | 85 | ||||
-rw-r--r-- | slof/fs/usb/usb-storage-support.fs | 222 | ||||
-rw-r--r-- | slof/fs/usb/usb-storage-wrapper.fs | 181 | ||||
-rw-r--r-- | slof/fs/usb/usb-storage.fs | 464 | ||||
-rw-r--r-- | slof/fs/usb/usb-support.fs | 628 |
11 files changed, 3890 insertions, 0 deletions
diff --git a/slof/fs/usb/usb-enumerate.fs b/slof/fs/usb/usb-enumerate.fs new file mode 100644 index 0000000..a027ec5 --- /dev/null +++ b/slof/fs/usb/usb-enumerate.fs @@ -0,0 +1,257 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ create the device tree for hub + +: (hub-create) ( -- ) + mps port-number new-device-address port-number + ( mps port-number usb-address port-number ) + new-device set-space ( mps port-number usb-address ) + encode-int s" USB-ADDRESS" property ( mps port-number ) + s" Address Set" usb-debug-print + encode-int s" reg" property ( mps ) + s" Port Number Set" usb-debug-print + encode-int s" MPS-DCP" property + s" MPS Set" usb-debug-print + s" usb-hub.fs" INCLUDED + s" Driver Included" usb-debug-print + finish-device +; + + +\ encode properties for scsi or atapi device + +: (atapi-scsi-property-set) ( -- ) + dd-buffer @ e + c@ ( Manuf ) + dd-buffer @ f + c@ ( Manuf Prod ) + dd-buffer @ 10 + c@ ( Manuf Prod Serial-Num ) + cd-buffer @ 16 + w@-le ( Manuf Prod Serial-Num ep-mps ) + cd-buffer @ 14 + c@ ( Manuf Prod Serial-Num ep-mps ep-addr ) + cd-buffer @ 1d + w@-le ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ) + cd-buffer @ 1b + c@ ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr ) + mps port-number new-device-address port-number + ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr + mps port-num usb-addr port-num ) + new-device set-space + ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr + mps port-num usb-addr ) + encode-int s" USB-ADDRESS" property + ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr + mps port-num ) + encode-int s" reg" property + ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr + mps ) + encode-int s" MPS-DCP" property + ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr ) + 2 0 DO + dup 80 and IF + 7f and encode-int + s" BULK-IN-EP-ADDR" property + encode-int s" MPS-BULKIN" property + ELSE + encode-int s" BULK-OUT-EP-ADDR" property + encode-int s" MPS-BULKOUT" property + THEN + LOOP ( Manuf Prod Serial-Num ) + encode-int s" iSerialNumber" property ( Manuf Prod ) + encode-int s" iProduct" property ( Manuf ) + encode-int s" iManufacturer" property +; + + +\ To classify device as hub/atapi/scsi/HID device + +: (device-classify) + ( -- Interface-protocol Interface-subclass Interface-class TRUE|FALSE ) + cd-buffer @ BULK-CONFIG-DESCRIPTOR-LEN erase + cd-buffer @ BULK-CONFIG-DESCRIPTOR-LEN mps new-device-address + ( buffer descp-len mps usb-address ) + control-std-get-configuration-descriptor + IF + cd-buffer @ 1+ c@ ( Descriptor-type ) + 2 = IF + cd-buffer @ 10 + c@ ( protocol ) + cd-buffer @ f + c@ ( protocol subclass ) + cd-buffer @ e + c@ ( protocol subclass class ) + TRUE + ELSE + s" Not a valid configuration descriptor!!" usb-debug-print + FALSE + THEN + ELSE + s" Unable to read configuration descriptor!!" usb-debug-print + FALSE + THEN +; + + +\ create device tree for Atapi SFF-8020 device + +: (atapi-8020-create) ( -- ) + (atapi-scsi-property-set) + s" usb-storage.fs" INCLUDED + finish-device +; + +\ create device tree for Atapi SFF-8070 device + +: (atapi-8070-create) ( -- ) + (atapi-scsi-property-set) + s" usb-storage.fs" INCLUDED + \ s" storage" device-name + finish-device +; + + +\ create device tree for SCSI device + +: (scsi-create) ( -- ) + mps new-device-address 0 ch-buffer 1 control-std-get-maxlun ( TRUE|FALSE ) + IF + s" GET-MAX-LUN IS WORKING :" usb-debug-print + ELSE + s" ERROR in GET-MAX-LUN " usb-debug-print + cd-buffer @ 5 + c@ to temp1 + temp1 new-device-address control-std-set-configuration drop + THEN + \ FIXME: an IBM external HDD reported a number of 127 LUNs which could + \ not be set up. We need to understand how to set up the device + \ to report the correct number of LUNs. + \ The USB Massbulk Standard 1.0 defines a maximum of 15 mult. LUNs. + \ Workaround: Devices that might report a higher number are treated + \ as having exactly one LUN. Without this workaround the + \ USB scan hangs during the setup of non-available LUNs. + ch-buffer c@ dup 0= swap f > or IF + s" + LUN: " ch-buffer c@ usb-debug-print-val + (atapi-scsi-property-set) + s" usb-storage.fs" INCLUDED + finish-device + + ELSE + s" - LUN: " ch-buffer c@ usb-debug-print-val + (atapi-scsi-property-set) + s" usb-storage-wrapper.fs" INCLUDED + finish-device + + THEN +; + + +\ Classify USB storage device by sub-class code + +: (classify-storage) ( interface-protocol interface-subclass -- ) + s" USB: Mass Storage Device Found!" usb-debug-print + swap 50 <> IF + s" USB storage: Protocol is not 50." usb-debug-print + drop EXIT + THEN + ( interface-subclass ) + CASE + 02 OF (atapi-8020-create) s" 2 ATAPI " usb-debug-print ENDOF + 05 OF (atapi-8070-create) s" 5 ATAPI " usb-debug-print ENDOF + 06 OF (scsi-create) s" 6 SCSI " usb-debug-print ENDOF + dup OF s" USB storage: Unsupported sub-class code." usb-debug-print ENDOF + ENDCASE +; + + +\ create keyboard device tree + +: (keyboard-create) ( -- ) + cd-buffer @ 1f + c@ ( ep-mps ) + cd-buffer @ 1d + c@ ( ep-mps ep-addr ) + mps port-number new-device-address port-number + ( ep-mps ep-addr mps port-num usb-addr port-num ) + new-device set-space ( ep-mps ep-addr mps port-num usb-addr ) + encode-int s" USB-ADDRESS" property ( ep-mps ep-addr mps port-num ) + encode-int s" reg" property ( ep-mps ep-addr mps ) + encode-int s" MPS-DCP" property ( ep-mps ep-addr ) + 7f and encode-int s" INT-IN-EP-ADDR" property + encode-int s" MPS-INTIN" property + new-device-address \ device-speed + s" usb-keyboard.fs" INCLUDED + finish-device +; + +: (mouse-create) ( -- ) + mps port-number new-device-address port-number + ( mps port-num usb-addr port-num ) + new-device set-space ( mps port-num usb-addr ) + encode-int s" USB-ADDRESS" property ( mps port-num ) + encode-int s" reg" property ( mps ) + encode-int s" MPS-DCP" property + s" usb-mouse.fs" INCLUDED + finish-device +; + + +\ Classify by interface class code + +: (classify-by-interface) ( -- ) + (device-classify) IF + ( Interface-protocol Interface-subclass Interface-class ) + CASE + 08 OF + ( Interface-protocol Interface-subclass ) + (classify-storage) + ENDOF + 03 OF + ( Interface-protocol Interface-subclass ) + s" USB: HID Found!" usb-debug-print + 01 = IF + case + 01 of + s" USB keyboard!" usb-debug-print + (keyboard-create) + endof + 02 of + s" USB mouse!" usb-debug-print + (mouse-create) + endof + dup of + s" USB: unsupported HID!" usb-debug-print + endof + endcase + ELSE + s" USB: unsupported HID!" usb-debug-print + THEN + ENDOF + dup OF + ( Interface-protocol Interface-subclass ) + s" USB: unsupported interface type." usb-debug-print + 2drop + ENDOF + ENDCASE + THEN +; + + +\ create usb device tree depending upon classification of the device +\ after encoding apt properties + +: create-usb-device-tree ( -- ) + dd-buffer @ DEVICE-DESCRIPTOR-DEVCLASS-OFFSET + c@ ( Device-class ) + CASE + HUB-DEVICE-CLASS OF s" USB: HUB found" usb-debug-print + (hub-create) + ENDOF + NO-CLASS OF + \ In this case, the INTERFACE descriptor + \ tells you whats what -- Refer USB spec. + (classify-by-interface) + ENDOF + DUP OF + s" USB: Unknown device found." usb-debug-print + ENDOF + ENDCASE +; diff --git a/slof/fs/usb/usb-hub.fs b/slof/fs/usb/usb-hub.fs new file mode 100644 index 0000000..ac0ae66 --- /dev/null +++ b/slof/fs/usb/usb-hub.fs @@ -0,0 +1,468 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ ---------------------------------------------------------------------------- +\ On detection of a hub after reading the device descriptor this package has to +\ be called so that the hub enumeration is done to idenitify the down stream +\ device +\ -------------------------------------------------------------------------- +\ OF properties +\ -------------------------------------------------------------------------- + + +s" hub" device-name +s" usb" device-type +1 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + +\ converts physical address to text unit string + + +: encode-unit ( port-addr -- unit-str unit-len ) 1 hex-encode-unit ; + + +\ Converts text unit string to phyical address + + +: decode-unit ( addr len -- port-addr ) 1 hex-decode-unit ; + +0 VALUE new-device-address +0 VALUE port-number +0 VALUE MPS-DCP +0 VALUE mps +0 VALUE my-usb-address + +00 value device-speed + + +\ Get parameters passed from the parent. + +: mps-property-set ( -- ) + s" HUB Compiling mps-property-set " usb-debug-print + s" USB-ADDRESS" get-my-property ( TRUE | prop-addr prop-len FALSE ) + IF + s" notpossible" usb-debug-print + ELSE + decode-int nip nip to my-usb-address + THEN + s" MPS-DCP" get-my-property ( TRUE | prop-addr prop-len FALSE ) + IF + s" MPS-DCP property not found Assuming 8 as MAX PACKET SIZE" ( str len ) + usb-debug-print + s" for the default control pipe" usb-debug-print + 8 to MPS-DCP + ELSE + s" MPS-DCP property found!!" usb-debug-print ( prop-addr prop-len FALSE ) + decode-int nip nip to MPS-DCP + THEN +; + + +\ -------------------------------------------------------------------------- +\ Constant declarations +\ -------------------------------------------------------------------------- + + +2303080000000000 CONSTANT hppwr-set +2301080000000000 CONSTANT hppwr-clear +2303040000000000 CONSTANT hprst-set +A300000000000400 CONSTANT hpsta-get +2303010000000000 CONSTANT hpena-set +A006002900000000 CONSTANT hubds-get +8 CONSTANT DEFAULT-CONTROL-MPS +12 CONSTANT DEVICE-DESCRIPTOR-LEN +9 CONSTANT CONFIG-DESCRIPTOR-LEN +20 CONSTANT BULK-CONFIG-DESCRIPTOR-LEN + + +\ TODO: +\ CONFIG-DESCRIPTOR-LEN should be only 9. The interface +\ and endpoint descriptors returned along with config +\ descriptor are variable and 0x19 is a very wrong VALUE +\ to specify for this #define. + + +1 CONSTANT DEVICE-DESCRIPTOR-TYPE +1 CONSTANT DEVICE-DESCRIPTOR-TYPE-OFFSET +4 CONSTANT DEVICE-DESCRIPTOR-DEVCLASS-OFFSET +7 CONSTANT DEVICE-DESCRIPTOR-MPS-OFFSET +9 CONSTANT HUB-DEVICE-CLASS +0 CONSTANT NO-CLASS + + +\ -------------------------------------------------------------------------- +\ Temporary Variable declarations +\ -------------------------------------------------------------------------- + +00 VALUE temp1 +00 VALUE temp2 +00 VALUE temp3 +00 VALUE po2pg \ Power On to Power Good + + +\ -------------------------------------------------------------------------- +\ Buffer allocations +\ -------------------------------------------------------------------------- + + +VARIABLE setup-packet \ 8 bytes for setup packet +VARIABLE ch-buffer \ 1 byte character buffer + +INSTANCE VARIABLE dd-buffer +INSTANCE VARIABLE cd-buffer + +\ TODO: +\ Should arrive a proper value for the size of the "cd-buffer" + +8 chars alloc-mem VALUE status-buffer +9 chars alloc-mem VALUE hd-buffer + + +: (allocate-mem) ( -- ) + DEVICE-DESCRIPTOR-LEN chars alloc-mem dd-buffer ! + BULK-CONFIG-DESCRIPTOR-LEN chars alloc-mem cd-buffer ! +; + + +: (de-allocate-mem) ( -- ) + dd-buffer @ ?dup IF + DEVICE-DESCRIPTOR-LEN free-mem + 0 dd-buffer ! + THEN + cd-buffer @ ?dup IF + BULK-CONFIG-DESCRIPTOR-LEN free-mem + 0 cd-buffer ! + THEN +; + + +\ standard open firmware methods + +: open ( -- TRUE ) + (allocate-mem) + TRUE +; + +: close ( -- ) + (de-allocate-mem) +; + + +\ -------------------------------------------------------------------------- +\ Parent's method +\ -------------------------------------------------------------------------- + + +: controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE|FALSE ) + s" controlxfer" $call-parent +; + +: control-std-set-address ( speedbit -- usb-address TRUE|FALSE ) + s" control-std-set-address" $call-parent +; + +: control-std-get-device-descriptor + ( data-buffer data-len MPS funcAddr -- TRUE|FALSE ) + s" control-std-get-device-descriptor" $call-parent +; + +: control-std-get-configuration-descriptor + ( data-buffer data-len MPS funcAddr -- TRUE|FALSE ) + s" control-std-get-configuration-descriptor" $call-parent +; + +: control-std-get-maxlun + ( MPS fun-addr dir data-buff data-len -- TRUE|FALSE) + s" control-std-get-maxlun" $call-parent +; + +: control-std-set-configuration + ( configvalue FuncAddr -- TRUE|FALSE ) + s" control-std-set-configuration" $call-parent +; + +: control-std-get-string-descriptor + ( StringIndex data-buffer data-len MPS FuncAddr -- TRUE|FALSE ) + s" control-std-get-string-descriptor" $call-parent +; + +: rw-endpoint + ( pt ed-type toggle buffer length mps address -- toggle TRUE|toggle FALSE ) + s" rw-endpoint" $call-parent +; + +: debug-td ( -- ) + s" debug-td" $call-parent +; + + +\ -------------------------------------------------------------------------- +\ HUB specific methods +\ -------------------------------------------------------------------------- +\ To bring on the power on a valid port of a hub with a valid USB address +\ -------------------------------------------------------------------------- + + +: control-hub-port-power-set ( port# -- TRUE|FALSE ) + hppwr-set setup-packet ! ( port#) + setup-packet 4 + c! + 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE | FALSE ) +; + + +\ -------------------------------------------------------------------------- +\ To put power off on ports where device detection or enumeration has failed +\ -------------------------------------------------------------------------- + + +: control-hub-port-power-clear ( port#-- TRUE|FALSE ) + hppwr-clear setup-packet ! ( port#) + setup-packet 4 + c! + 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) +; + + +\ ------------------------------------------------------------------------- +\ To reset a valid port of a hub with a valid USB +\ address +\ -------------------------------------------------------------------------- + + +: control-hub-port-reset-set ( port# -- TRUE|FALSE ) + hprst-set setup-packet ! ( port# ) + setup-packet 4 + c! + 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) +; + + +\ ------------------------------------------------------------------------- +\ To enable a particular valid port of a hub with a valid USB address +\ ------------------------------------------------------------------------- + + +: control-hub-port-enable ( port# -- TRUE|FALSE ) + hpena-set setup-packet ! ( port# ) + setup-packet 4 + c! + 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) +; + + +\ ------------------------------------------------------------------------- +\ To get the status of a valid port of a hub with +\ a valid USB address +\ ------------------------------------------------------------------------- + + +: control-hub-port-status-get ( buffer port# -- TRUE|FALSE ) + hpsta-get setup-packet ! ( buffer port# ) + setup-packet 4 + c! ( buffer ) + 0 swap 4 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) +; + + +\ -------------------------------------------------------------------------- +\ To get the hub descriptor to understand how many ports are vailable and the +\ specs of those ports +\ --------------------------------------------------------------------------- + + +: control-get-hub-descriptor ( buffer buffer-length -- TRUE|FALSE ) + hubds-get setup-packet ! + dup setup-packet 6 + w!-le ( buffer buffer-length ) + 0 -rot setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE ) +; + + +s" usb-enumerate.fs" INCLUDED + + +: hub-configure-port ( port# -- ) + + \ Step 1: set the Port Power + usb-test-flag + IF + ." Port: " dup . cr + 150 ms \ wait for bad devices + THEN + + dup control-hub-port-power-set drop ( port# ) + BEGIN ( port# ) + status-buffer 4 erase ( port# ) + status-buffer over control-hub-port-status-get drop ( port# ) + status-buffer w@-le 102 and 0= ( port# TRUE|FALSE ) + WHILE ( port# ) + REPEAT ( port# ) + po2pg 3 * ms \ wait for bPwrOn2PwrGood*3 ms + + usb-test-flag + IF + 150 ms + THEN + \ STEP 2: Reset the port. + + dup control-hub-port-reset-set drop ( port# ) + BEGIN ( port# ) + status-buffer 4 erase ( port# ) + status-buffer over control-hub-port-status-get drop ( port# ) + status-buffer w@-le 10 and ( port# TRUE|FALSE ) + usb-test-flag + IF + s" Port Satus: " status-buffer w@-le usb-debug-print-val + THEN + WHILE ( port# ) + REPEAT ( port# ) + + \ after reset set port enable -important- + dup control-hub-port-enable drop ( port# ) + + usb-test-flag + IF + 10 ms + THEN + + \ STEP 3: Check if a device is connected to the + \ port. + + status-buffer 4 erase ( port# ) + status-buffer over control-hub-port-status-get drop ( port# ) + status-buffer w@-le 103 and 103 <> ( port# TRUE|FALSE ) + s" Port status bits: " status-buffer w@-le usb-debug-print-val + IF ( port# ) + drop + s" Connect status: No device connected " usb-debug-print + EXIT + THEN + + \ New addition: Sometimes the port status returns connected + \ but Set address was failing. Analysis showed that such + \ ports do not set this bit to 1. + + status-buffer 2 + w@-le 1 and 1 <> ( port# ) + IF ( port# ) + drop + s" No device connected to port- set addresss failed" usb-debug-print + EXIT + THEN + s" HUB: New device found!!!" usb-debug-print +\ s" HUB: Status buffer first word -> " usb-debug-print +\ s" HUB: Status buffer second word -> " usb-debug-print + + \ STEP 4: Assign an address to this device. + + status-buffer w@-le 200 and 4 lshift \ get speed bit + dup to device-speed \ store speed bit + ( port# speedbit ) + control-std-set-address ( port# usb-addr TRUE|FALSE ) + 50 ms ( port# usb-addr TRUE|FALSE ) + debug-td ( port# usb-addr TRUE|FALSE ) + IF ( port# usb-addr ) + device-speed or ( port# usb-addr+speedbit ) + to new-device-address ( port# ) + to port-number + dd-buffer @ DEVICE-DESCRIPTOR-LEN erase + dd-buffer @ DEFAULT-CONTROL-MPS DEFAULT-CONTROL-MPS new-device-address + ( buffer mps mps usb-addr ) + control-std-get-device-descriptor ( TRUE|FALSE ) + IF + dd-buffer @ DEVICE-DESCRIPTOR-TYPE-OFFSET + c@ ( descriptor-type ) + DEVICE-DESCRIPTOR-TYPE <> ( TRUE|FALSE ) + IF + s" HUB: ERROR!! Invalid Device Descriptor for the new device" + usb-debug-print + ELSE + dd-buffer @ DEVICE-DESCRIPTOR-MPS-OFFSET + c@ to mps + + \ Re-read the device descriptor again with the known MPS. + + dd-buffer @ DEVICE-DESCRIPTOR-LEN erase + dd-buffer @ DEVICE-DESCRIPTOR-LEN mps new-device-address + ( buffer descp-len mps usb-addr ) + \ s" DEVICE DESCRIPTOR: " usb-debug-print + control-std-get-device-descriptor drop + \ dd-buffer usb-debug-print-val + create-usb-device-tree + THEN + ELSE + s" ERROR!! Failed to get device descriptor" usb-debug-print + THEN + ELSE ( port# ) + s" USB Set Adddress failed!!" usb-debug-print ( port# ) + s" Clearing Port Power..." usb-debug-print ( port# ) + control-hub-port-power-clear ( TRUE|FALSE ) + IF + s" Port power down " usb-debug-print + ELSE + s" Unable to clear port power!!!" usb-debug-print + THEN + THEN +; + + +\ --------------------------------------------------------------------------- +\ To enumerate all the valid ports of hub +\ TODO: +\ 1. Remove hardcoded constants. +\ 2. Remove Endian Dependencies. +\ 3. Return values of controlxfer should be checked. +\ --------------------------------------------------------------------------- + +: hub-enumerate ( -- ) + cd-buffer @ CONFIG-DESCRIPTOR-LEN erase + + \ Get HUB configuration and SET the configuration + \ note: remove hard-coded constants. + + cd-buffer @ CONFIG-DESCRIPTOR-LEN MPS-DCP my-usb-address + ( buffer descp-len mps usb-address ) + control-std-get-configuration-descriptor drop + cd-buffer @ 1+ c@ 2 <> IF + s" Unable to read configuration descriptor" usb-debug-print + EXIT + THEN + cd-buffer @ 4 + c@ 1 <> IF + s" Not a valid HUB config descriptor" usb-debug-print + EXIT + THEN + + \ TODO: Do further checkings on the returned Configuration descriptor + \ before proceeding to accept it. + + cd-buffer @ 5 + c@ to temp1 \ Store the configuration in temp1 + temp1 my-usb-address control-std-set-configuration drop + my-usb-address to temp1 + hd-buffer 9 erase + hd-buffer 9 control-get-hub-descriptor drop + + \ PENDING: 1. Check Return value. + \ 2. HUB descriptor size is variable. Currently we r hardcoding + \ a value of 9. + + hd-buffer 2 + c@ to temp2 + s" HUB: Found " usb-debug-print \ temp2 . + s" number of downstream hub ports! : " temp2 usb-debug-print-val + hd-buffer 5 + c@ to po2pg \ get bPwrOn2PwrGood + temp2 1+ 1 DO + I hub-configure-port + LOOP +; + + +\ -------------------------------------------------------------------------- +\ To initialize hub +\ -------------------------------------------------------------------------- + +(allocate-mem) +mps-property-set +hub-enumerate +(de-allocate-mem) + diff --git a/slof/fs/usb/usb-kbd-device-support.fs b/slof/fs/usb/usb-kbd-device-support.fs new file mode 100644 index 0000000..ccf1b42 --- /dev/null +++ b/slof/fs/usb/usb-kbd-device-support.fs @@ -0,0 +1,105 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +00 value kbd-addr +to kbd-addr +8 alloc-mem to kbd-report +4 chars alloc-mem value kbd-data + +: rw-endpoint + s" rw-endpoint" $call-parent ; + +: controlxfer + s" controlxfer" $call-parent ; + +: control-std-get-device-descriptor + s" control-std-get-device-descriptor" $call-parent ; + +: control-std-get-configuration-descriptor + s" control-std-get-configuration-descriptor" $call-parent ; + +: control-std-set-configuration + s" control-std-set-configuration" $call-parent ; + +: control-cls-set-protocol ( reportvalue FuncAddr -- TRUE|FALSE ) + to temp1 + to temp2 + 210b000000000100 setup-packet ! + temp2 kbd-data l!-le + 1 kbd-data 1 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer +; + +: control-cls-set-idle ( reportvalue FuncAddr -- TRUE|FALSE ) + to temp1 + to temp2 + 210a000000000000 setup-packet ! + temp2 kbd-data l!-le + 0 kbd-data 0 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer +; + +: control-std-get-report-descriptor ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE ) + to temp1 + to temp2 + to temp3 + 8106002200000000 setup-packet ! + temp3 setup-packet 6 + w!-le + 0 swap temp3 setup-packet temp2 temp1 controlxfer +; + +: kbd-init + s" Starting to initialize keyboard" usb-debug-print + s" MPS-INTIN" get-my-property + if + s" not possible" usb-debug-print + else + decode-int nip nip to mps-int-in + then + s" INT-IN-EP-ADDR" get-my-property + if + s" not possible" usb-debug-print + else + decode-int nip nip to int-in-ep + then + + 7f alloc-mem to cfg-buffer + s" Allocated buffers!!" usb-debug-print + + cfg-buffer 12 8 kbd-addr \ get device descriptor + control-std-get-device-descriptor + drop + \ s" dev_desc=" type cfg-buffer 12 dump cr + + cfg-buffer 9 8 kbd-addr \ get config descriptor + control-std-get-configuration-descriptor + drop + \ s" cfg_desc=" type cfg-buffer 9 dump cr + + cfg-buffer 5 + c@ kbd-addr \ set configuration + control-std-set-configuration + drop + s" KBDS: Set config returned" usb-debug-print + + 0 kbd-addr control-cls-set-protocol drop \ set protocol=boot mode + s" KBDS: Set protocol returned" usb-debug-print + + 0 kbd-addr control-cls-set-idle drop \ set idle + s" KBDS: Set idle returned" usb-debug-print + + cfg-buffer 40 8 kbd-addr \ get report descriptor + control-std-get-report-descriptor + drop + \ s" report_desc=" type cfg-buffer 40 dump cr + + s" Finished initializing keyboard" usb-debug-print +; + diff --git a/slof/fs/usb/usb-keyboard.fs b/slof/fs/usb/usb-keyboard.fs new file mode 100644 index 0000000..b0c4be9 --- /dev/null +++ b/slof/fs/usb/usb-keyboard.fs @@ -0,0 +1,345 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +s" keyboard" device-name +s" keyboard" device-type + +3 encode-int s" assigned-addresses" property +1 encode-int s" reg" property +1 encode-int s" configuration#" property +s" EN" encode-string s" language" property + +1 constant NumLk +2 constant CapsLk +4 constant ScrLk + +00 value kbd-addr +to kbd-addr \ save speed bit +8 value mps-dcp +8 constant DEFAULT-CONTROL-MPS +8 chars alloc-mem value setup-packet +8 chars alloc-mem value kbd-report +4 chars alloc-mem value multi-key +0 value cfg-buffer +0 value led-state +0 value temp1 +0 value temp2 +0 value temp3 +0 value ret +0 value scancode +0 value kbd-shift +0 value kbd-scan +0 value key-old +0 value expire-ms +0 value mps-int-in +0 value int-in-ep +0 value int-in-toggle + +kbd-addr \ give speed bit to include file +s" usb-kbd-device-support.fs" included + +: control-cls-set-report ( reportvalue FuncAddr -- TRUE|FALSE ) + to temp1 + to temp2 + 2109000200000100 setup-packet ! + temp2 kbd-data l!-le + 1 kbd-data 1 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer +; + +: control-cls-get-report ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE ) + to temp1 + to temp2 + to temp3 + a101000100000000 setup-packet ! + temp3 setup-packet 6 + w!-le + 0 swap temp3 setup-packet temp2 temp1 controlxfer +; + +: int-get-report ( -- ) \ get report for interrupt transfer + 0 2 int-in-toggle kbd-report 8 mps-int-in + kbd-addr int-in-ep 7 lshift or rw-endpoint \ get report + swap to int-in-toggle if + kbd-report @ ff00000000000000 and 38 rshift to kbd-shift \ store shift status + kbd-report @ 0000ffffffffffff and to kbd-scan \ store scan codes + else + 0 to kbd-shift \ clear shift status + 0 to kbd-scan \ clear scan code buffer + then +; + +: ctl-get-report ( -- ) \ get report for control transfer + kbd-report 8 8 kbd-addr control-cls-get-report if \ get report + kbd-report @ ff00000000000000 and 38 rshift to kbd-shift \ store shift status + kbd-report @ 0000ffffffffffff and to kbd-scan \ store scan codes + else + 0 to kbd-shift \ clear shift status + 0 to kbd-scan \ clear scan code buffer + then +; + +: open ( -- true ) + true +; + +: close ; + +: set-led ( led -- ) + dup to led-state + kbd-addr control-cls-set-report drop +; + +: is-shift ( -- true|false ) + kbd-shift 22 and if + true + else + false + then +; + +: is-alt ( -- true|false ) + kbd-shift 44 and if + true + else + false + then +; + +: is-ctrl ( -- true|false ) + kbd-shift 11 and if + true + else + false + then +; + +: ctrl_alt_del_key ( char -- ) + is-ctrl if \ ctrl is pressed? + is-alt if \ alt is pressed? + 4c = if \ del is pressed? + s" reboot.... " usb-debug-print + \ reset-all \ reboot + drop false \ invalidate del key on top of stack + then + false \ dummy for last drop + then + then + drop \ clear stack +; + +: get-ukbd-char ( ScanCode -- char|false ) + dup ctrl_alt_del_key \ check ctrl+alt+del + dup to scancode \ store scan code + case \ translate scan code --> char + 04 of [char] a endof + 05 of [char] b endof + 06 of [char] c endof + 07 of [char] d endof + 08 of [char] e endof + 09 of [char] f endof + 0a of [char] g endof + 0b of [char] h endof + 0c of [char] i endof + 0d of [char] j endof + 0e of [char] k endof + 0f of [char] l endof + 10 of [char] m endof + 11 of [char] n endof + 12 of [char] o endof + 13 of [char] p endof + 14 of [char] q endof + 15 of [char] r endof + 16 of [char] s endof + 17 of [char] t endof + 18 of [char] u endof + 19 of [char] v endof + 1a of [char] w endof + 1b of [char] x endof + 1c of [char] y endof + 1d of [char] z endof + 1e of [char] 1 endof + 1f of [char] 2 endof + 20 of [char] 3 endof + 21 of [char] 4 endof + 22 of [char] 5 endof + 23 of [char] 6 endof + 24 of [char] 7 endof + 25 of [char] 8 endof + 26 of [char] 9 endof + 27 of [char] 0 endof + 28 of 0d endof \ Enter + 29 of 1b endof \ ESC + 2a of 08 endof \ Backsace + 2b of 09 endof \ Tab + 2c of 20 endof \ Space + 2d of [char] - endof + 2e of [char] = endof + 2f of [char] [ endof + 30 of [char] ] endof + 31 of [char] \ endof + 33 of [char] ; endof + 34 of [char] ' endof + 35 of [char] ` endof + 36 of [char] , endof + 37 of [char] . endof + 38 of [char] / endof + 39 of led-state CapsLk xor set-led false endof \ CapsLk + 3a of 1b 7e31315b to multi-key endof \ F1 + 3b of 1b 7e32315b to multi-key endof \ F2 + 3c of 1b 7e33315b to multi-key endof \ F3 + 3d of 1b 7e34315b to multi-key endof \ F4 + 3e of 1b 7e35315b to multi-key endof \ F5 + 3f of 1b 7e37315b to multi-key endof \ F6 + 40 of 1b 7e38315b to multi-key endof \ F7 + 41 of 1b 7e39315b to multi-key endof \ F8 + 42 of 1b 7e30315b to multi-key endof \ F9 + 43 of 1b 7e31315b to multi-key endof \ F10 + 44 of 1b 7e33315b to multi-key endof \ F11 + 45 of 1b 7e34315b to multi-key endof \ F12 + 47 of led-state ScrLk xor set-led false endof \ ScrLk + 49 of 1b 7e315b to multi-key endof \ Ins + 4a of 1b 7e325b to multi-key endof \ Home + 4b of 1b 7e335b to multi-key endof \ PgUp + 4c of 1b 7e345b to multi-key endof \ Del + 4d of 1b 7e355b to multi-key endof \ End + 4e of 1b 7e365b to multi-key endof \ PgDn + 4f of 1b 435b to multi-key endof \ R-arrow + 50 of 1b 445b to multi-key endof \ L-arrow + 51 of 1b 425b to multi-key endof \ D-arrow + 52 of 1b 415b to multi-key endof \ U-arrow + 53 of led-state NumLk xor set-led false endof \ NumLk + 54 of [char] / endof \ keypad / + 55 of [char] * endof \ keypad * + 56 of [char] - endof \ keypad - + 57 of [char] + endof \ keypad + + 58 of 0d endof \ keypad Enter + 89 of [char] \ endof \ japanese yen + dup of false endof \ other keys are false + endcase + to ret \ store char + led-state CapsLk and 0 <> if \ if CapsLk is on + scancode 03 > if \ from a to z ? + scancode 1e < if + ret 20 - to ret \ to Upper case + then + then + then + is-shift if \ if shift is on + scancode 03 > if \ from a to z ? + scancode 1e < if + ret 20 - to ret \ to Upper case + else + scancode + case \ translate scan code --> char + 1e of [char] ! endof + 1f of [char] @ endof + 20 of [char] # endof + 21 of [char] $ endof + 22 of [char] % endof + 23 of [char] ^ endof + 24 of [char] & endof + 25 of [char] * endof + 26 of [char] ( endof + 27 of [char] ) endof + 2d of [char] _ endof + 2e of [char] + endof + 2f of [char] { endof + 30 of [char] } endof + 31 of [char] | endof + 33 of [char] : endof + 34 of [char] " endof + 35 of [char] ~ endof + 36 of [char] < endof + 37 of [char] > endof + 38 of [char] ? endof + dup of ret endof \ other keys are no change + endcase + to ret \ overwrite new char + then + then + then + led-state NumLk and 0 <> if \ if NumLk is on + scancode + case \ translate scan code --> char + 59 of [char] 1 endof + 5a of [char] 2 endof + 5b of [char] 3 endof + 5c of [char] 4 endof + 5d of [char] 5 endof + 5e of [char] 6 endof + 5f of [char] 7 endof + 60 of [char] 8 endof + 61 of [char] 9 endof + 62 of [char] 0 endof + 63 of [char] . endof \ keypad . + dup of ret endof \ other keys are no change + endcase + to ret \ overwirte new char + then + ret \ return char +; + +: usb-kread ( -- char|false ) \ usb key read for control transfer + multi-key 0 <> if \ if multi scan code key is pressed + multi-key ff and \ read one byte from buffer + multi-key 8 rshift to multi-key \ move to next byte + else \ normal key check + \ if interrupt transfer + int-get-report \ read report (interrupt transfer) + \ else control transfer + \ ctl-get-report \ read report (control transfer) + \ end of interrupt/control switch + kbd-scan 0 <> if \ scan code exist? + begin kbd-scan ff and dup 00 = while \ get a last scancode in report buffer + kbd-scan 8 rshift to kbd-scan \ This algorithm is wrong --> must be fixed! + drop \ KBD doesn't set scancode in pressed order!!! + repeat + dup key-old <> if \ if the scancode is new + dup to key-old \ save current scan code + get-ukbd-char \ translate scan code --> char + milliseconds fa + to expire-ms \ set typematic delay 250ms + else \ scan code is not changed + milliseconds expire-ms > if \ if timer is expired ... should be considered timer carry over + get-ukbd-char \ translate scan code --> char + milliseconds 21 + to expire-ms \ set typematic rate 30cps + else \ timer is not expired + drop false \ do nothing + then + then + else + 0 to key-old \ clear privious key + false \ no scan code --> return false + then + then +; + + +: key-read ( -- char ) + 0 begin drop usb-kread dup 0 <> until \ read key input (Interrupt transfer) +; + + +: read ( addr len -- actual ) + 0= IF drop 0 EXIT THEN + usb-kread ?dup IF swap c! 1 ELSE 0 swap c! -2 THEN +; + + +kbd-init \ keyboard initialize +milliseconds to expire-ms \ Timer initialize +0 to multi-key \ multi key buffer clear +7 set-led \ flash leds +250 ms +0 set-led + +s" keyboard" get-node node>path set-alias + diff --git a/slof/fs/usb/usb-mouse.fs b/slof/fs/usb/usb-mouse.fs new file mode 100644 index 0000000..1703196 --- /dev/null +++ b/slof/fs/usb/usb-mouse.fs @@ -0,0 +1,26 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +s" mouse" device-name +s" mouse" device-type + +1 encode-int s" configuration#" property +2 encode-int s" #buttons" property +4 encode-int s" assigned-addresses" property +2 encode-int s" reg" property + +: open true ; +: close ; +: get-event ( msec -- pos.x pos.y buttons true|false ) +; + diff --git a/slof/fs/usb/usb-ohci.fs b/slof/fs/usb/usb-ohci.fs new file mode 100644 index 0000000..5b71d56 --- /dev/null +++ b/slof/fs/usb/usb-ohci.fs @@ -0,0 +1,1109 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ We expect to base address of the OHCI controller on the stack: + +CONSTANT baseaddrs + +s" OHCI base address = " baseaddrs usb-debug-print-val + + +\ Open Firmware Properties + + +s" usb" 2dup device-name device-type +1 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + + +\ converts physical address to text unit string + + +: encode-unit ( port -- unit-str unit-len ) 1 hex-encode-unit ; + + +\ Converts text unit string to phyical address + + +: decode-unit ( addr len -- port ) 1 hex-decode-unit ; + + +\ Data Structure Definitions +\ OHCI Task Descriptor Structure. + + +STRUCT + /l field td>tattr + /l field td>cbptr + /l field td>ntd + /l field td>bfrend +CONSTANT /tdlen + + +\ OHCI Endpoint Descriptor Structure. + + +STRUCT + /l field ed>eattr + /l field ed>tdqtp + /l field ed>tdqhp + /l field ed>ned +CONSTANT /edlen + + +\ HCCA Done queue location packaged as a structure for ease OF use. + + +STRUCT + /l field hc>hcattr + /l field hc>hcdone +CONSTANT /hclen + + +\ OHCI Memory Mapped Registers + + +\ : get-base-address ( -- baseaddr ) +\ s" assigned-addresses" get-my-property IF +\ s" not possible" usb-debug-print +\ -1 +\ ELSE ( addr len ) +\ decode-int drop ( addr len ) +\ decode-int drop ( addr len ) +\ decode-int nip nip ( n ) +\ THEN +\ \ TODO: Use translate-address here +\ ; + +\ get-base-address CONSTANT baseaddrs + +baseaddrs 4 + CONSTANT hccontrol +baseaddrs 8 + CONSTANT hccomstat +baseaddrs 0c + CONSTANT hcintstat +baseaddrs 14 + CONSTANT hcintdsbl +baseaddrs 18 + CONSTANT hchccareg +baseaddrs 20 + CONSTANT hcctrhead +baseaddrs 24 + CONSTANT hccurcont +baseaddrs 28 + CONSTANT hcbulkhead +baseaddrs 2c + CONSTANT hccurbulk +baseaddrs 30 + CONSTANT hcdnehead +baseaddrs 34 + CONSTANT hcintrval +baseaddrs 48 + CONSTANT hcrhdescA +baseaddrs 54 + CONSTANT hcrhpstat + + +\ Constants for COMSTAT register + + +2 CONSTANT CLF + +\ Constants for INTSTAT register + +2 CONSTANT WDH + +\ Constants for RH Port Status Register + +1 CONSTANT RHP-CCS +2 CONSTANT RHP-PES +10 CONSTANT RHP-PRS +100 CONSTANT RHP-PPS +100000 CONSTANT RHP-PRSC + +\ Constants for OHCI + +0 CONSTANT OHCI-DP-SETUP +1 CONSTANT OHCI-DP-OUT +2 CONSTANT OHCI-DP-IN +3 CONSTANT OHCI-DP-INVALID + +\ 8-byte Standard Device Requests + Hub class specific requests. + +8006000100001200 CONSTANT get-ddescp +8006000200000900 CONSTANT get-cdescp +8006000400000900 CONSTANT get-idescp +8006000500000700 CONSTANT get-edescp +A006000000001000 CONSTANT get-hdescp +0009010000000000 CONSTANT set-cdescp +2303010004000000 CONSTANT hpenable-set +2303040001000000 CONSTANT hp1rst-set +2303040002000000 CONSTANT hp2rst-set +2303040003000000 CONSTANT hp3rst-set +2303040004000000 CONSTANT hp4rst-set +2303080001000000 CONSTANT hp1pwr-set +2303080002000000 CONSTANT hp2pwr-set +2303080003000000 CONSTANT hp3pwr-set +2303080004000000 CONSTANT hp4pwr-set +A003000000000400 CONSTANT hstatus-get +A300000001000400 CONSTANT hp1sta-get +A300000002000400 CONSTANT hp2sta-get +A300000003000400 CONSTANT hp3sta-get +A300000004000400 CONSTANT hp4sta-get +8008000000000100 CONSTANT get-config + +A1FE000000000100 CONSTANT GET-MAX-LUN + +2 18 lshift CONSTANT DATA0-TOGGLE +3 18 lshift CONSTANT DATA1-TOGGLE +0f 1c lshift CONSTANT CC-FRESH-TD +8 CONSTANT STD-REQUEST-SETUP-SIZE +0 13 lshift CONSTANT TD-DP-SETUP +1 13 lshift CONSTANT TD-DP-OUT +2 13 lshift CONSTANT TD-DP-IN + +400001 CONSTANT ed-cntatr +400002 CONSTANT ed-cntatr1 +80081 CONSTANT ed-hubatr +80000 CONSTANT ed-defatr +0f0e40000 CONSTANT td-attr +00 VALUE ptr + + +\ TD Management constants and Data structures. + + +200 CONSTANT MAX-TDS +0 VALUE td-freelist-head +0 VALUE td-freelist-tail +0 VALUE num-free-tds + +INSTANCE VARIABLE td-list-region + +\ ED Management constants + + +14 CONSTANT MAX-EDS +0 VALUE ed-freelist-head +0 VALUE num-free-eds +INSTANCE VARIABLE ed-list-region +0 VALUE usb-address +0 VALUE initial-hub-address +0 VALUE new-device-address +0 VALUE mps +0 VALUE DEBUG-TDS +0 VALUE case-failed \ available for general use to see IF a CASE statement + \ failed or not. +0 VALUE WHILE-failed \ available for general use to see IF a WHILE LOOP + \ failed in the middle. Used to break from the + \ WHILE LOOP + +8 CONSTANT DEFAULT-CONTROL-MPS +12 CONSTANT DEVICE-DESCRIPTOR-LEN +1 CONSTANT DEVICE-DESCRIPTOR-TYPE +1 CONSTANT DEVICE-DESCRIPTOR-TYPE-OFFSET +4 CONSTANT DEVICE-DESCRIPTOR-DEVCLASS-OFFSET +7 CONSTANT DEVICE-DESCRIPTOR-MPS-OFFSET + +20 CONSTANT BULK-CONFIG-DESCRIPTOR-LEN + +9 CONSTANT HUB-DEVICE-CLASS +0 CONSTANT NO-CLASS + +VARIABLE setup-packet \ 8 bytes for setup packet +VARIABLE ch-buffer \ 1 byte character buffer + +INSTANCE VARIABLE dd-buffer +INSTANCE VARIABLE cd-buffer + + +\ Temporary variables for functions. These variables have to be initialized +\ before usage in functions and their values assume significance only during +\ the function's execution time. Should be used like local variables. +\ CAUTION: +\ If you are calling functions that destroy contents OF these variables, be +\ smart enuf to save the values before calling them. +\ It is recommended that these temporary variables are used only amidst normal +\ FORTH words -- not among the vicinity OF any OF the functions OF this node. + + +0 VALUE temp1 +0 VALUE temp2 +0 VALUE temp3 +0 VALUE extra-bytes +0 VALUE num-td +0 VALUE current + +0 VALUE device-speed + + +\ Debug functions for displaying ED, TD and their combo list. + +: display-ed ( ED-ADDRESS -- ) + TO temp1 + usb-debug-flag IF + s" Dump OF ED " type temp1 u. cr + s" eattr : " type temp1 ed>eattr l@-le u. cr + s" tdqhp : " type temp1 ed>tdqhp l@-le u. cr + s" tdqtp : " type temp1 ed>tdqtp l@-le u. cr + s" ned : " type temp1 ed>ned l@-le u. cr + THEN +; + + +\ Displays the transfer descriptors + +: display-td ( TD-ADDRESS -- ) + TO temp1 + usb-debug-flag IF + s" TD " type temp1 u. s" dump: " type cr + s" td>tattr : " type temp1 td>tattr l@-le u. cr + s" td>cbptr : " type temp1 td>cbptr l@-le u. cr + s" td>ntd : " type temp1 td>ntd l@-le u. cr + s" td>bfrend : " type temp1 td>bfrend l@-le u. cr + THEN +; + + +\ display's the descriptors + + +: display-descriptors ( ED-ADDRESS -- ) + 10 1- not and ( ED-ADDRESS~ ) + dup display-ed ed>tdqhp l@-le BEGIN ( ED-ADDRESS~ ) + 10 1- not and ( ED-ADDRESS~ ) + dup 0<> ( ED-ADDRESS~ TRUE | FALSE ) + WHILE + dup display-td td>ntd l@-le ( ED-ADDRESS~ ) + REPEAT + drop +; + + +\ --------------------------------------------------------------------------- +\ TD LIST MANAGEMENT WORDS +\ ------------------------ +\ The following are WORDS internal to this node. They are supposed to +\ be used by other WORDS inside this device node. +\ The first three WORDS below form the interface. The fourth and fifth +\ word is a helper function and is not exposed to other portions OF this +\ device node. +\ a) initialize-td-free-list +\ b) allocate-td-list +\ c) (free-td-list) +\ d) find-td-list-tail-and-size +\ e) zero-out-a-td-except-link +\ ---------------------------------------------------------------------------- + + +: zero-out-a-td-except-link ( td -- ) + + + \ There r definitely smarter ways to DO it especially + \ on a 64-bit machine. + + \ Optimization, Portability: + \ -------------------------- + \ Replace the following code by two "!" OF zeroes. Since + \ we know that an "td" is actually 16 bytes and that we + \ will be executing on a 64-bit machine, we can finish OFf + \ with 2 stores. But that WONT be portable. + + + dup 0 swap td>tattr l!-le ( td ) + dup 0 swap td>cbptr l!-le ( td ) + dup 0 swap td>bfrend l!-le ( td ) + drop +; + + +\ COLON DEFINITION: initialize-td-free-list - Internal Function + +\ Initialize the TD Free List Region and create a linked list OF successive +\ TDs. Note that the NEXT pointers are all in little-endian and they +\ can be directly used for HC purposes. + + +: initialize-td-free-list ( -- ) + MAX-TDS 0= IF EXIT THEN + td-list-region @ 0= IF EXIT THEN + td-list-region @ TO temp1 + 0 TO temp2 BEGIN + temp1 zero-out-a-td-except-link + temp1 /tdlen + dup temp1 td>ntd l!-le TO temp1 + temp2 1+ TO temp2 + temp2 MAX-TDS = ( TRUE | FALSE ) + UNTIL + temp1 /tdlen - dup 0 swap td>ntd l!-le TO td-freelist-tail + td-list-region @ TO td-freelist-head + MAX-TDS TO num-free-tds +; + + +\ COLON DEFINITION: allocate-td-list -- Internal function +\ Argument: +\ The function accepts a non-negative number and allocates +\ a TD-LIST containing that many TDs. A TD-LIST is a list +\ OF TDs that are linked by the next-td field. The next-td +\ field is in little-endian mode so that the TD list can +\ be directly re-used by the HC. +\ Return value: +\ The function returns "head" and "tail" OF the allocated +\ TD-LIST. If for any reason, the function cannot allocate +\ the TD-LIST, the function returns 2 NULL pointers in the +\ stack indicating that the allocation failed. + +\ Note that the TD list returned is NULL terminated. i.e +\ the nextTd field OF the tail is NULL. + + + +: allocate-td-list ( n -- head tail ) + dup 0= IF drop 0 0 EXIT THEN ( 0 0 ) + dup num-free-tds > IF drop 0 0 EXIT THEN ( 0 0 ) + dup num-free-tds = IF ( n ) + drop td-freelist-head td-freelist-tail ( td-freelist-head td-freelist-tail ) + 0 TO td-freelist-head ( td-freelist-head td-freelist-tail ) + 0 TO td-freelist-tail ( td-freelist-head td-freelist-tail ) + 0 TO num-free-tds ( td-freelist-head td-freelist-tail ) + EXIT + THEN + + \ If we are here THEN we know that the requested number OF TDs is less + \ than what we actually have. We need TO traverse the list and find the + \ new Head pointer position and THEN update the head pointer accordingly. + \ Update num-free-tds + + dup num-free-tds swap - TO num-free-tds ( n ) + + \ Traverse through the Free list to identify the element that exists after + \ "n" TDs. Use the info to return the head and tail pointer and update + \ the new td-list-head + + td-freelist-head ( n td-list-head ) + dup TO temp1 ( n td-list-head ) + swap ( td-list-head n ) + 0 DO ( td-list-head ) + temp1 TO temp2 ( td-list-head ) + temp1 td>ntd l@-le TO temp1 ( td-list-head ) + LOOP ( td-list-head ) + temp2 ( td-list-head td-list-tail ) + dup td>ntd 0 swap l!-le ( td-list-head td-list-tail ) + temp1 TO td-freelist-head ( td-list-head td-list-tail ) +; + + +\ COLON DEFINITION: find-td-list-tail-and-size +\ This function counts the number OF TD elements +\ in the given list. It also returns the last tail +\ TD OF the TD list. + +\ ASSUMPTION: +\ A NULL terminated TD list is assumed. A not-well formed +\ list can result in in-determinate behaviour. + +\ ROOM FOR ENHANCEMENT: +\ We could arrive at a generic function for counting +\ list elements to which the next-ptr OFfset can also +\ be passed as an argument (in this case it is >ntd) +\ This function can THEN be changed to call the +\ function with "0 >ntd" as an additional argument +\ (apart from head and tail) + + +: find-td-list-tail-and-size ( head -- tail n ) + TO temp1 + 0 TO temp2 + 0 TO temp3 + DEBUG-TDS IF + s" BEGIN find-td-list-tail-and-size: " usb-debug-print + THEN + BEGIN + temp1 0<> ( TRUE|FALSE ) + WHILE + DEBUG-TDS IF + temp1 u. cr + THEN + temp1 TO temp3 + temp1 td>ntd l@-le TO temp1 + temp2 1+ TO temp2 + REPEAT + temp3 temp2 ( tail n ) + DEBUG-TDS IF + s" END find-td-list-tail-and-size" usb-debug-print + THEN +; + + +\ COLON DEFINITION: (free-td-list) + +\ Arguments: (head --) +\ The "head" pointer OF the TD-LIST to be freed is passed as +\ an argument to this function. The function merely adds the list to the +\ already existing TD-LIST + +\ Assumptions: +\ The function assumes that the TD-LIST passed as argument is a well-formed +\ list. The function does not DO any check on it. +\ But since, the "TD-LIST" is generally freed from the DONE-QUEUE which is +\ a well-formed list, the interface makes much sense. + +\ Return values: +\ Nothing is returned. The arguments passed are popped OFf. + + +: (free-td-list) ( head -- ) + + \ Enhancement: + \ We could zero-out-a-td-except-link for the TD list that is being freed. + \ This way, we could prevent some nasty repercussions OF bugs (that r yet + \ to be discovered). but we can include this enhancement during the testing + \ phase. + + dup find-td-list-tail-and-size num-free-tds + TO num-free-tds ( head tail ) + td-freelist-tail 0= IF ( head tail ) + dup TO td-freelist-tail ( head tail ) + THEN ( head tail ) + td>ntd td-freelist-head swap l!-le ( head ) + TO td-freelist-head +; + + +\ END OF TD LIST MANAGEMENT WORDS +\ ED Management section BEGINs +\ ---------------------------- + + +: zero-out-an-ed-except-link ( ed -- ) + + \ There are definitely smarter ways to do it especially + \ on a 64-bit machine. + + \ Optimization, Portability: + \ -------------------------- + \ Replace by a "!" and "l!". we know that an "ed" is + \ actually 16 bytes and that we will be executing on + \ a 64-bit machine, we can finish OFf with 2 stores. + \ But that WONT be portable. + + dup 0 swap ed>eattr l!-le ( ed ) + dup 0 swap ed>tdqtp l!-le ( ed ) + dup 0 swap ed>tdqhp l!-le ( ed ) + drop +; + +\ Intialises ed-list afresh + +: initialize-ed-free-list ( -- ) + MAX-EDS 0= IF EXIT THEN + ed-list-region @ 0= IF + s" init-ed-list: ed-list-region is not allocated!" usb-debug-print + EXIT + THEN + ed-list-region @ TO temp1 + 0 TO temp2 BEGIN + temp1 zero-out-an-ed-except-link + temp1 /edlen + dup temp1 ed>ned l!-le TO temp1 + temp2 1+ TO temp2 + temp2 MAX-EDS = + UNTIL + temp1 /edlen - ed>ned 0 swap l!-le + ed-list-region @ TO ed-freelist-head + MAX-EDS TO num-free-eds +; + + +\ allocate an ed and return ed address + + +: allocate-ed ( -- ed-ptr ) + num-free-eds 0= IF 0 EXIT THEN + ed-freelist-head ( ed-freelist-head ) + ed-freelist-head ed>ned l@-le TO ed-freelist-head ( ed-freelist-head ) + num-free-eds 1- TO num-free-eds ( ed-freelist-head ) + dup ed>ned 0 swap l!-le \ Terminate the Link. ( ed-freelist-head ) +; + + +\ free the given ed pointer + +: free-ed ( ed-ptr -- ) + dup zero-out-an-ed-except-link ( ed-ptr ) + dup ed>ned ed-freelist-head swap l!-le ( ed-ptr ) + TO ed-freelist-head + num-free-eds 1+ TO num-free-eds +; + + +\ Buffer allocations +\ ------------------ +\ Note: +\ ----- +\ 1. What should we DO IF alloc-mem fails ? +\ 2. alloc-mem must return aligned memory addresses. +\ 3. alloc-mem must return DMAable memory! + +\ Memory for the HCCA - must stay allocated as long as the HC is operational! +100 alloc-mem VALUE hchcca +hchcca ff and IF + \ This should never happen - alloc-mem always aligns + s" Warning: hchcca not aligned!" usb-debug-print +THEN + +84 hchcca + CONSTANT hchccadneq + + +: (allocate-mem) ( -- ) + /tdlen MAX-TDS * 10 + alloc-mem dup td-list-region ! ( td-list-region-ptr ) + f and IF + s" Warning: td-list-region not aligned!" usb-debug-print + THEN + initialize-td-free-list + + /edlen MAX-EDS * 10 + alloc-mem dup ed-list-region ! ( ed-list-region-ptr ) + f and IF + s" Warning: ed-list-region not aligned!" usb-debug-print + THEN + initialize-ed-free-list + + DEVICE-DESCRIPTOR-LEN chars alloc-mem dd-buffer ! + BULK-CONFIG-DESCRIPTOR-LEN chars alloc-mem cd-buffer ! +; + + +\ The method makes sure that when the host node is closed all +\ associated buffer allocations made for data-structures as +\ well as data-buffers are freed + +: (de-allocate-mem) ( -- ) + td-list-region @ ?dup IF + /tdlen MAX-TDS * 10 + free-mem + 0 td-list-region ! + THEN + ed-list-region @ ?dup IF + /edlen MAX-EDS * 10 + free-mem + 0 ed-list-region ! + THEN + dd-buffer @ ?dup IF + DEVICE-DESCRIPTOR-LEN free-mem + 0 dd-buffer ! + THEN + cd-buffer @ ?dup IF + BULK-CONFIG-DESCRIPTOR-LEN free-mem + 0 cd-buffer ! + THEN +; + + +\ Suspend hostcontroller (and the bus). +\ This method must be called before the operating system starts. +\ It prevents the HC from doing DMA in the background during boot +\ (e.g. updating its frame number counter in the HCCA) + +: hc-suspend ( -- ) + \ s" USB HC suspend with hccontrol=" type hccontrol . cr + 00C3 hccontrol rl!-le \ Suspend USB host controller +; + + +\ OF methods + +: open ( -- TRUE|FALSE ) + (allocate-mem) + TRUE +; + +: close ( -- ) + (de-allocate-mem) +; + + +\ COLON DEFINITION: HC-enable-control-list-processing +\ Enables USB HC transactions on control list. + +: HC-enable-control-list-processing ( -- ) + hccomstat dup rl@-le 02 or swap rl!-le + hccontrol dup rl@-le 10 or swap rl!-le +; + + +\ COLON DEFINTION: HC-enable-bulk-list-processing +\ PENDING: Remove Hard coded constants. + +: HC-enable-bulk-list-processing ( -- ) + hccomstat dup rl@-le 04 or swap rl!-le + hccontrol dup rl@-le 20 or swap rl!-le +; + + +: HC-enable-interrupt-list-processing ( -- ) + hccontrol dup rl@-le 04 or swap rl!-le +; + + +\ Clearing WDH to allow HC to write into DOne queue again + +: (HC-ACK-WDH) ( -- ) WDH hcintstat rl!-le ; + +\ Checking whether anything has been written into DOne queue + +: (HC-CHECK-WDH) ( -- ) hcintstat rl@-le WDH and 0<> ; + + +\ Disable USB transaction and keep it ready + +: disable-control-list-processing ( -- ) + hccontrol dup rl@-le ffffffef and swap rl!-le + hccomstat dup rl@-le fffffffd and swap rl!-le +; + +: disable-bulk-list-processing ( -- ) + hccontrol dup rl@-le ffffffdf and swap rl!-le + hccomstat dup rl@-le fffffffb and swap rl!-le +; + + +: disable-interrupt-list-processing ( -- ) + hccontrol dup rl@-le fffffffb and swap rl!-le +; + + +\ COLON DEFINITION: fill-TD-list + +\ This function accepts a TD list and a data-buffer and +\ distributes this data buffer over the TD list depending +\ on the Max Packet Size. + +\ Arguments: +\ ---------- +\ (from bottom OF stack) +\ 1. addr -- Address OF the data buffer +\ 2. dlen -- Length OF the data buffer above. +\ 3. dir -- Tells whether the TDs r for an IN or +\ OUT transaction. +\ 4. MPS -- Maximum Packet Size associated with the endpoint +\ that will use this TD list. +\ 5. TD-List-Head - Head pointer OF the List OF TDs. +\ This list is NOT expected to be NULL terminated. + +\ Assumptions: +\ ----------- +\ 1. TD-List for data is well-formed and has sufficient entries +\ to hold "dlen". +\ 2. The TDs toggle field is assumed to be taken from the endpoint +\ descriptor's "toggle carry" field. +\ 3. Assumes that the caller specifies the correct start-toggle. +\ If the caller specifies a wrong data toggle OF 1 for a SETUP +\ PACKET, this method will not find it out. + +\ COLON DEFINTION: (toggle-current-toggle) +\ Scope: Internal to fill-TD-list +\ Functionality: +\ Toggles the "T" field that is passed as argument. +\ "T" as in the "T" field OF the TD. + +0 VALUE current-toggle +: fill-TD-list ( start-toggle addr dlen dp MPS TD-List-Head -- ) + TO temp1 ( start-toggle addr dlen dp MPS ) + TO temp2 ( start-toggle addr dlen dp ) + CASE ( start-toggle addr dlen ) + OHCI-DP-SETUP OF TD-DP-SETUP TO temp3 ENDOF ( start-toggle addr dlen ) + OHCI-DP-IN OF TD-DP-IN TO temp3 ENDOF ( start-toggle addr dlen ) + OHCI-DP-OUT OF TD-DP-OUT TO temp3 ENDOF ( start-toggle addr dlen ) + dup OF -1 TO temp3 ( start-toggle addr dlen ) + s" fill-TD-list: Invalid DP specified" usb-debug-print + ENDOF + ENDCASE + temp3 -1 = IF EXIT THEN ( start-toggle addr dlen ) + + +\ temp1 -- TD-List-Head +\ temp2 -- Max Packet Size +\ temp3 -- TD-DP-IN or TD-DP-OUT or TD-DP-SETUP + + rot ( addr dlen start-toggle ) + TO current-toggle swap ( dlen addr ) + BEGIN + over temp2 >= ( dlen addr TRUE|FALSE ) + WHILE ( dlen addr ) + dup temp1 td>cbptr l!-le ( dlen addr ) + current-toggle 18 lshift ( dlen addr current-toggle~ ) + DATA0-TOGGLE ( dlen addr current-toggle~ toggle ) + CC-FRESH-TD temp3 or or or ( dlen addr or-result ) + temp1 td>tattr l!-le ( dlen addr~ ) + dup temp2 1- + temp1 td>bfrend l!-le ( dlen addr~ ) + temp2 + ( dlen next-addr ) + swap temp2 - swap + temp1 td>ntd l@-le TO temp1 ( dlen next-addr) + current-toggle ( dlen next-addr current-toggle ) + CASE + 0 OF 1 TO current-toggle ENDOF + 1 OF 0 TO current-toggle ENDOF + ENDCASE + REPEAT ( dlen addr ) + over 0<> IF + dup temp1 td>cbptr l!-le ( dlen addr ) + current-toggle 18 lshift ( dlen addr curent-toggle~ ) + DATA0-TOGGLE ( dlen addr curent-toggle~ toggle ) + CC-FRESH-TD temp3 or or or ( dlen addr or-result ) + temp1 td>tattr l!-le ( dlen addr ) + + 1- temp1 td>bfrend l!-le + ELSE + 2drop + THEN +; + + +\ COLON DEFINITION: (td-list-status ) +\ FUNCTIONALITY: +\ To traverse the TD list to check for a TD carrying non-zero CC return the +\ respective TD address and CC ELSE 0 +\ SCOPE: +\ Internal method + +: (td-list-status) ( PointerToTDlist -- failingTD CCode TRUE | 0 ) + BEGIN ( PointerToTDlist ) + dup 0<> ( PointerToTDlist TRUE|FALSE ) + IF ( PointerToTDlist ) + dup td>tattr l@-le f0000000 and 1c rshift dup 0= TRUE swap + ( PointerToTDlist CCode TRUE TRUE|FALSE ) + ELSE + drop FALSE dup ( FALSE ) + THEN + WHILE + drop drop td>ntd l@-le + REPEAT +; + + +\ ================================================================== +\ COLON DEFINITION: (wait-for-done-q) +\ FUNCTIONALITY: +\ To DO a timed polling OF the DOne queue and acknowledge and return +\ the address OF the last retired Td list +\ SCOPE: +\ Internal method +\ ================================================================== + + +: (wait-for-done-q) ( timeout -- TD-list TRUE | FALSE ) + BEGIN ( timeout ) + dup 0<> ( timeout TRUE|FALSE ) + WHILE ( timeout ) + (HC-CHECK-WDH) ( timeout TRUE|FALSE ) + IF ( timeout ) + drop 0 ( 0 ) + ELSE ( timeout ) + 1- ( timeout ) + 1 ms ( timeout ) + THEN ( timeout ) + + \ Wait for 1 milli-second. + \ PENDING: There should be a better way. + + REPEAT ( timeout ) + drop + hchccadneq rl@-le dup 0<> IF ( td-list ) + TRUE ( td-list TRUE ) + 0 hchccadneq rl!-le ( td-list TRUE ) + (HC-ACK-WDH) ( td-list TRUE ) + ELSE FALSE ( td-list FALSE ) + THEN ( td-list TRUE|FALSE ) +; + + +\ displays free tds + + +: debug-td ( -- ) + s" Num Free TDs = " num-free-tds usb-debug-print-val +; + + +\ display content of frame counter + +\ : debug-frame-counter ( -- ) +\ 40 1 DO +\ ." Frame ct at HCCA at end OF enumeration = " +\ hchcca 80 + rl@-le . +\ LOOP +\ ; + +\ ============================================================================ +\ COLON DEFINITION: HC-reset +\ This routine should be the first to be executed. +\ This routine will reset the HC and will bring it to Operational +\ state. +\ PENDING: +\ Arrive at the right value OF FrameInterval. Currently we are hardcoding +\ it. +\ ========================================================================== + + +: HC-reset ( -- ) + 00 hccontrol rl!-le + hccomstat dup rl@-le 01 or swap rl!-le + BEGIN + hccomstat rl@-le 01 and 0<> + WHILE + REPEAT + hchcca hchccareg rl!-le + 0000 hcctrhead rl!-le + 0ffff hcintdsbl rl!-le + 0000 hcbulkhead rl!-le + 0083 hccontrol rl!-le + 23f02edf hcintrval rl!-le +; + + +: error-recovery ( -- ) + initialize-td-free-list + initialize-ed-free-list + HC-reset +; + +\ ================================================================ +: store-initial-usb-hub-address ( -- ) + usb-address TO initial-hub-address +; + +: reset-to-initial-usb-hub-address ( -- ) + initial-hub-address TO usb-address +; + +\ allocate-usb-address: +\ Function allocates an USB address. +\ See RISK below. + + +: allocate-usb-address ( -- usb-address ) + usb-address 7f <> ( TRUE|FALSE ) + IF + usb-address 1+ TO usb-address \ RISK: Check to see IF it overflows 127 + usb-address ( usb-address ) + THEN ( usb-address ) +; + +s" usb-support.fs" INCLUDED + + + +\ ===================================================================== +\ COLON DEFINTION: control-std-set-address +\ INTERFACE FUNCTION +\ Function allocates an USB addrss and uses it to send SET-ADDRESS packet +\ to the default USB address. +\ This is an interface function available to child nodes. + +: control-std-set-address ( speedbit -- usb-address TRUE | FALSE ) + >r ( R: speedbit ) + 0005000000000000 setup-packet ! + allocate-usb-address dup setup-packet 2 + c! ( usb-addr R: speedbit ) + s" USB set-address: " 2 pick usb-debug-print-val ( usb-addr R: speedbit ) + 0 0 0 setup-packet 8 r> controlxfer ( usb-addr TRUE | FALSE ) + IF ( TRUE | FALSE ) + TRUE ( TRUE ) + ELSE + drop FALSE \ PENDING: Return the allocated address back. ( FALSE ) + THEN ( TRUE | FALSE ) +; + + +\ Fetches the device decriptor of the usb-device + + +: control-std-get-device-descriptor + ( data-buffer data-len MPS fa -- TRUE|FALSE ) + 8006000100000000 setup-packet ! + 2 pick setup-packet 6 + w!-le + ( data-buffer data-len MPS fa ) + setup-packet -rot ( data-buffer data-len setup-packet MPS fa ) + >r >r >r >r >r 0 r> r> r> r> r> + ( 0 data-buffer data-len setup-packet MPS fa ) + controlxfer ( TRUE | FALSE ) +; + + +\ ================================================================== +\ To retrieve the configuration descriptor OF a device +\ with a valid USB address + + +: control-std-get-configuration-descriptor + ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE ) + TO temp1 ( data-buffer data-len MPS ) + TO temp2 ( data-buffer data-len ) + TO temp3 ( data-buffer ) + 8006000200000000 setup-packet ! + temp3 setup-packet 6 + w!-le + 0 swap temp3 setup-packet temp2 temp1 controlxfer +; + +\ Fectes num of logical units available for a device +: control-std-get-maxlun ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE ) + GET-MAX-LUN setup-packet ! ( MPS fun-addr dir data-buff data-len ) + setup-packet 5 pick 5 pick + ( MPS fun-addr dir data-buff data-len setup-packet MPS fun-addr ) + controlxfer ( MPS fun-addr TRUE | FALSE ) + nip nip ( TRUE | FALSE ) +; + +\ get the string descriptor of the usb device + + +: control-std-get-string-descriptor + ( StringIndex data-buffer data-len MPS FuncAddr -- TRUE | FALSE ) + TO temp1 ( StringIndex data-buffer data-len MPS ) + TO temp2 ( StringIndex data-buffer data-len ) + TO temp3 ( StringIndex ) + 8006000300000000 setup-packet ! + temp3 setup-packet 6 + w!-le + 409 setup-packet 4 + w!-le \ US English Language code. + swap ( data buffer StringIndex ) + setup-packet 2 + c! ( data-buffer ) + 0 swap temp3 setup-packet temp2 temp1 controlxfer ( TRUE | FALSE ) +; + +\ sets a valid usb configaration for a device + +: control-std-set-configuration ( configvalue FuncAddr -- TRUE|FALSE ) + TO temp1 ( configvalue ) + TO temp2 + 0009000000000000 setup-packet ! \ RISK: Endian and 64-bit assumptions + temp2 setup-packet 2 + w!-le + 0 0 0 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer + + \ NOTE: We could use DEFAULT-CONTROL-MPS because there is no data phase + \ associated with this control xfer. Its a dont care. +; + + +\ To set the device address retrive the device descriptor and build the +\ usb device tree by passing device class + + +0 VALUE port-number + +s" usb-enumerate.fs" INCLUDED + +: rhport-enumerate ( port-num -- ) + TO port-number + device-speed control-std-set-address ( usb-addr TRUE | FALSE ) + IF + device-speed or ( usb-addr+speedbit ) + TO new-device-address + dd-buffer @ 8 erase + + \ Read Device Descriptor - First 8 bytes. + + dd-buffer @ DEFAULT-CONTROL-MPS DEFAULT-CONTROL-MPS ( buffer mps mps ) + new-device-address control-std-get-device-descriptor ( TRUE | FALSE ) + IF + ELSE + s" USB: Read Dev Descriptor failed" usb-debug-print EXIT + + \ NOTE: Tomorrow, IF there is a LOOP here,we may need to UNLOOP before + \ "EXIT"ing. Beware. Much depends on what LOOPing construct is used. + + THEN + + \ Read the Descriptor Type and check IF we have read correctly. + + dd-buffer @ DEVICE-DESCRIPTOR-TYPE-OFFSET + c@ ( Descriptor-type ) + DEVICE-DESCRIPTOR-TYPE <> IF + s" USB: Error Reading Device Descriptor" usb-debug-print + s" Read descriptor is not OF the right type" usb-debug-print + s" Aborting enumeration" usb-debug-print + EXIT + \ NOTE: Tomorrow, IF u have a LOOP here THEN we may need to + \ UNLOOP before EXITing. Depends on what type OF LOOPing construct + \ is used. Beware. + + THEN + + \ Read the MPS and store it. + + dd-buffer @ DEVICE-DESCRIPTOR-MPS-OFFSET + c@ TO mps + + \ NOTE: Probably, we could check MPS for only 8/16/32/64 + \ hmm.. not now... + + \ Read the device class to see what type OF device it is and create an + \ appropriate child node here. + create-usb-device-tree + ELSE + s" Set address failed on port " port-number usb-debug-print-val + s" Aborting Enumeration." usb-debug-print + EXIT + + \ NOTE: Tomorrow , IF u have a LOOP here THEN we may need to + \ UNLOOP before EXITing. Depends on what type OF LOOPing construct + \ is used. Beware. + + THEN +; + + +\ ========================================================================= +\ PROTOTYPE FUNCTION: "rhport-initialize" +\ Detect Device, reset and enable the respective port. +\ COLON Definition rhport-initialize accepts the total number OF root hub +\ ports as an argument and probes every available root hub port and initiates +\ the build OF the USB devie sub-tree so is effectively the mother OF all +\ USB device nodes that are to be detected and instantiated. +\ ========================================================================== + + +VARIABLE total-rh-ports +0 VALUE current-stat + +: rhport-initialize ( total-rh-ports -- ) + total-rh-ports ! + hcrhpstat TO current-stat + total-rh-ports @ 1+ 1 DO + hcrhdescA rl@-le 0300 and 0100 = ( TRUE|FALSE ) + IF + 100 current-stat rl!-le + hcrhdescA 3 + rb@ 2 * ms + THEN + current-stat rl@-le RHP-CCS and 0<> ( TRUE|FALSE ) + IF + s" Device at this port!" usb-debug-print + RHP-PPS current-stat rl!-le \ port power on + hcrhdescA 3 + rb@ 2 * ms \ wait for POTPGT*2 ms + RHP-PES current-stat rl!-le \ port enable + 50 ms + RHP-PRS current-stat rl!-le \ port reset + 50 ms + \ RHP-PRSC current-stat rl!-le + + current-stat rl@-le 200 and 4 lshift + to device-speed \ store speed bit + + I ['] rhport-enumerate CATCH IF \ Scan port + s" USB scan failed on root hub port: " rot usb-debug-print-val + reset-to-initial-usb-hub-address + THEN + ELSE + s" No device detected at this port." usb-debug-print + THEN + current-stat 4 + TO current-stat + LOOP +; + + +\ =================================================== +\ Enumeration at Host level +\ =================================================== + +: enumerate ( -- ) + HC-reset + ['] hc-suspend add-quiesce-xt \ Assert that HC will be supsended + hcrhdescA rl@-le 000000ff and ( total-rh-ports ) + store-initial-usb-hub-address + rhport-initialize \ Probe all available RH ports + reset-to-initial-usb-hub-address +; + + +\ Create an alias for this controller: +set-ohci-alias + diff --git a/slof/fs/usb/usb-static.fs b/slof/fs/usb/usb-static.fs new file mode 100644 index 0000000..0067549 --- /dev/null +++ b/slof/fs/usb/usb-static.fs @@ -0,0 +1,85 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ Set usb-debug flag to TRUE for debugging output: +0 VALUE usb-debug-flag +0 VALUE usb-test-flag + +\ Print a debug message when usb-debug-flag is set +: usb-debug-print ( str len -- ) + usb-debug-flag IF type cr ELSE 2drop THEN +; + +\ Print a debug message with corresponding value when usb-debug-flag is set +: usb-debug-print-val ( str len val -- ) + usb-debug-flag IF -ROT type . cr ELSE drop 2drop THEN +; + + +0 VALUE ohci-alias-num + +\ create a new ohci device alias for the current node: +: set-ohci-alias ( -- ) + ohci-alias-num dup 1+ TO ohci-alias-num ( num ) + s" ohci" rot $cathex strdup \ create alias name + get-node node>path \ get path string + set-alias \ and set the alias +; + +0 VALUE cdrom-alias-num + +\ create a new ohci device alias for the current node: +: set-cdrom-alias ( -- ) + cdrom-alias-num dup 1+ TO cdrom-alias-num ( num ) + s" cdrom" rot $cathex strdup \ create alias name + get-node node>path \ get path string + set-alias \ and set the alias +; + +: usb-create-alias-name ( num -- str len ) + >r s" ohciX" 2dup + 1- ( str len last-char-ptr R: num ) + r> [char] 0 + swap c! ( str len R: ) +; + +\ Scan all USB host controllers for attached devices: +: usb-scan + \ Scan all OHCI chips: + ." Scan USB... " cr + 0 >r \ Counter for alias + BEGIN + r@ usb-create-alias-name + find-alias ?dup ( false | str len len R: num ) + WHILE + usb-debug-flag IF + ." * Scanning hub " 2dup type ." ..." cr + THEN + open-dev ?dup IF ( ihandle R: num ) + dup to my-self + dup ihandle>phandle dup set-node + child ?dup IF + delete-node s" Deleting node" usb-debug-print + THEN + >r s" enumerate" r@ $call-method \ Scan host controller + r> close-dev 0 set-node 0 to my-self + THEN ( R: num ) + r> 1+ >r ( R: num+1 ) + REPEAT r> drop + 0 TO ohci-alias-num + 0 TO cdrom-alias-num + s" cdrom0" find-alias ( false | dev-path len ) + dup IF + s" cdrom" 2swap ( alias-name len' dev-path len ) + set-alias ( -- ) + ELSE + drop ( -- ) + THEN +; diff --git a/slof/fs/usb/usb-storage-support.fs b/slof/fs/usb/usb-storage-support.fs new file mode 100644 index 0000000..5013c2c --- /dev/null +++ b/slof/fs/usb/usb-storage-support.fs @@ -0,0 +1,222 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ --------------------------------------------------------------------------- +\ Parent methods +\ --------------------------------------------------------------------------- + +: rw-endpoint + ( pt ed-type toggle buffer length mps addres -- toggle TRUE | toggle FALSE ) + s" rw-endpoint" $call-parent + ( toggle TRUE | toggle FALSE ) +; + +: controlxfer ( dir addr dlen setup-packet MPS ep-fun --- TRUE|FALSE ) + s" controlxfer" $call-parent + ( TRUE | FALSE ) +; + +: control-std-get-configuration-descriptor + ( data-buffer data-len MPS FuncAddr -- TRUE | FALSE ) + s" control-std-get-configuration-descriptor" $call-parent + ( TRUE | FALSE ) +; + +: control-std-set-configuration ( configvalue FuncAddr -- TRUE | FALSE ) + s" control-std-set-configuration" $call-parent ( TRUE | FALSE ) +; + +: bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- ) + s" bulk-reset-recovery-procedure" $call-parent +; + + +\ --------------------------------------------------------------------------- +\ Bulk support package methods +\ --------------------------------------------------------------------------- + +: build-cbw ( address tag transfer-len direction lun command-len -- ) + s" build-cbw" ihandle-bulk @ $call-method +; + +: analyze-csw ( address -- residue tag TRUE | reason FALSE ) + s" analyze-csw" ihandle-bulk @ $call-method + ( residue tag TRUE | reason FALSE ) +; + + +\ --------------------------------------------------------------------------- +\ SCSI support package methods +\ --------------------------------------------------------------------------- + +: build-read ( address lba #blocks -- ) + s" build-read" ihandle-scsi @ $call-method +; + +: build-inquiry ( address alloc-len -- ) + s" build-inquiry" ihandle-scsi @ $call-method +; + +: return-inquiry ( address -- version# peripheral-device-type ) + s" return-inquiry" ihandle-scsi @ $call-method + ( version# peripheral-device-type ) +; + +: build-mode-sense ( address alloc-len page-code page-control -- ) + s" build-mode-sense" ihandle-scsi @ $call-method +; + +: build-read-capacity ( address -- ) + s" build-read-capacity" ihandle-scsi @ $call-method +; + +: build-seek ( address lba -- ) + s" build-seek" ihandle-scsi @ $call-method +; + +: build-start ( address -- ) + s" build-start" ihandle-scsi @ $call-method +; + +: build-stop ( address -- ) + s" build-stop" ihandle-scsi @ $call-method +; + +\ : build-load ( address -- ) +\ s" build-load" ihandle-scsi @ $call-method +\ ; + +\ : build-unload ( address -- ) +\ s" build-unload" ihandle-scsi @ $call-method +\ ; + +: build-test-unit-ready ( address -- ) + s" build-test-unit-ready" ihandle-scsi @ $call-method +; + +: return-test-unit-ready ( address -- status ) + s" return-unit-ready" ihandle-scsi @ $call-method ( status ) +; + +: build-read-toc ( address session# alloc-len -- ) + s" build-read-toc" ihandle-scsi @ $call-method +; + +: build-request-sense ( address alloc-len -- ) + s" build-request-sense" ihandle-scsi @ $call-method +; + +: return-request-sense ( address -- FALSE | ASCQ ASC sense-key TRUE ) + s" return-request-sense" ihandle-scsi @ $call-method + ( FALSE | ASCQ ASC sense-key TRUE ) +; + + +\ ======================================================= +\ NATIVE METHODS USED EITHER AT PROBE TIME OR TIME +\ WHEN INSTANCE IS CREATED +\ ======================================================= + + +\ -------------------------------------------------------- +\ COLON DEFINITION: the method is a probe-time method +\ used to: +\ 1. decode the properties and store in variables +\ 2. allocat buffers required for the device and +\ 3. set the right configuration after extracting the +\ configuration descriptor +\ -------------------------------------------------------- + +: device-init ( -- ) + s" Starting to initialize usb-storage device" usb-debug-print + s" USB-ADDRESS" get-my-property ( TRUE | propaddr proplen FALSE ) + IF + s" not possible" usb-debug-print + ELSE + decode-int nip nip to my-usb-address + THEN + s" MPS-BULKOUT" get-my-property ( TRUE | propaddr proplen FALSE ) + IF + s" not possible" usb-debug-print + ELSE + decode-int nip nip to mps-bulk-out + THEN + s" MPS-BULKIN" get-my-property ( TRUE | propaddr proplen FALSE ) + IF + s" not possible" usb-debug-print + ELSE + decode-int nip nip to mps-bulk-in + THEN + s" BULK-IN-EP-ADDR" get-my-property ( TRUE | propaddr proplen FALSE ) + IF + s" not possible" usb-debug-print + ELSE + decode-int nip nip to bulk-in-ep + THEN + s" BULK-OUT-EP-ADDR" get-my-property ( TRUE | propaddr proplen FALSE ) + IF + s" not possible" usb-debug-print + ELSE + decode-int nip nip to bulk-out-ep + THEN + s" MPS-DCP" get-my-property ( TRUE | propaddr proplen FALSE ) + IF + s" Not possible" usb-debug-print + ELSE + decode-int nip nip to mps-dcp + THEN + s" LUN" get-my-property ( TRUE | propaddr proplen FALSE ) + IF + s" NOT Possible to extract LUN" usb-debug-print + ELSE + decode-int nip nip to lun + THEN + s" Extracted properties inherited from parent." usb-debug-print + + \ PENDING: + \ Do some return value check here... + + 40 alloc-mem to command-buffer + 80 alloc-mem to response-buffer + 10 alloc-mem to csw-buffer + 8 alloc-mem to cfg-buffer + s" Allocated buffers." usb-debug-print + cfg-buffer 8 mps-dcp my-usb-address ( buffer len mps fun-addr ) + control-std-get-configuration-descriptor ( TRUE | FALSE ) + drop + s" Configuration descriptor extracted." usb-debug-print + cfg-buffer 5 + c@ my-usb-address ( configvalue fun-addr ) + control-std-set-configuration ( TRUE | FALSE ) + s" usb-storage: Set config returned: " rot usb-debug-print-val +; + + +\ ---------------------------------------------------- +\ Internal methods +\ ---------------------------------------------------- + + +: (open-package) ( ihandle-var name-str name-len -- ) + find-package IF ( ihandle-var phandle ) + 0 0 rot open-package ( ihandle-var ihandle ) + swap ! + ELSE + s" Support package not found" usb-debug-print + THEN +; + +: (close-package) ( ihandle-var -- ) + dup @ close-package + 0 swap ! +; + diff --git a/slof/fs/usb/usb-storage-wrapper.fs b/slof/fs/usb/usb-storage-wrapper.fs new file mode 100644 index 0000000..eb3d547 --- /dev/null +++ b/slof/fs/usb/usb-storage-wrapper.fs @@ -0,0 +1,181 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +\ ----------------------------------------------------------- +\ OF properties +\ ----------------------------------------------------------- + +s" scsi" device-name +s" block-type" device-type +1 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + + +: encode-unit 1 hex-encode-unit ; + +: decode-unit 1 hex-decode-unit ; + + +\ ----------------------------------------------------------- +\ Specific properties +\ ----------------------------------------------------------- + +1 chars alloc-mem VALUE ch-buffer +8 VALUE mps-dcp +0 VALUE port-number +0 VALUE my-usb-address + + +: control-std-get-maxlun + ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE ) + s" control-std-get-maxlun" $call-parent +; + + +: control-std-get-configuration-descriptor + ( data-buffer data-len MPS funcAddr -- TRUE|FALSE ) + s" control-std-get-configuration-descriptor" $call-parent +; + +: rw-endpoint + ( pt ed-type toggle buffer length mps address -- toggle TRUE|toggle FALSE ) + s" rw-endpoint" $call-parent +; + +: controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE|FALSE ) + s" controlxfer" $call-parent +; + +: control-std-set-configuration + ( configvalue FuncAddr -- TRUE|FALSE ) + s" control-std-set-configuration" $call-parent +; + +\ This method is used for extracting the properties from it's parent and +\ storing these value to temporary variable so that they can used later. + +: extract-properties ( -- ) + s" USB-ADDRESS" get-inherited-property ( prop-addr prop-len FALSE | TRUE ) + IF + s" notpossible" usb-debug-print + ELSE + decode-int nip nip to my-usb-address + THEN + s" MPS-DCP" get-inherited-property ( prop-addr prop-len FALSE | TRUE ) + IF + s" MPS-DCP property not found.Assume 8 as MAX PACKET SIZE" usb-debug-print + s" for the default control pipe" usb-debug-print + 8 to mps-dcp + ELSE + s" MPS-DCP property found!!" usb-debug-print + decode-int nip nip to mps-dcp + THEN + s" reg" get-inherited-property ( prop-addr prop-len FLASE | TRUE ) + IF + s" notpossible" usb-debug-print + ELSE + decode-int nip nip to port-number + THEN +; + + +\ This method is used for creating the child nodes for every Logical unit +\ available in the device, this method will call control-std-get-maxlun for +\ for finding the maximum Logical units supported by the device and along with +\ the creation of nodes this method encodes the properties of the node also. + +: create-tree ( -- ) + mps-dcp my-usb-address 0 ch-buffer 1 ( MPS fun-addr dir data-buff data-len ) + control-std-get-maxlun ( TRUE | FALSE ) + + \ This method extracts the maximum number of Logical Units Supported by + \ the Device . if no Logical Units are present then 0 will be taken as the + \ max logical units. if the device doesn't support the GET-MAX-LUN command + \ then the device may can be stalled as a temporary fix to come out from + \ the stalling situations we can issue the control-std-set-configuration with + \ appropriate arguments + + + IF + s" GET-MAX-LUN IS WORKING :" usb-debug-print + ELSE + s" ERROR in GET-MAX-LUN " usb-debug-print + THEN + ch-buffer c@ 1 + 0 ( max-lun+1 0 ) + DO + s" iManufacturer" get-inherited-property drop ( prop-addr prop-len TRUE ) + decode-int nip nip ( iManu ) + s" iProduct" get-inherited-property drop + ( iManu prop-addr prop-len TRUE | FALSE ) + decode-int nip nip ( iManu iProd ) + s" iSerialNumber" get-inherited-property drop + ( iManu iProd prop-addr prop-len TRUE | FALSE ) + decode-int nip nip ( iManu iProd iSerNum ) + s" MPS-BULKOUT" get-inherited-property drop + ( iManu iProd iSerNum prop-len prop-addr TRUE | FALSE ) + decode-int nip nip ( iManu iProd iSerNum MPS-BULKOUT ) + s" BULK-OUT-EP-ADDR" get-inherited-property drop + ( iManu iProd iSerNum MPS-BULKOUT prop-addr prop-len TRUE|FALSE ) + decode-int nip nip ( iManu iProd iSerNum MPS-BULKOUT BULK-OUT-EP-ADDR ) + s" MPS-BULKIN" get-inherited-property drop + ( iManu iProd iSerNum MPS-BULKOUT BULK-OUT-EP-ADDR prop-addr prop-len + TRUE | FALSE ) + decode-int nip nip + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN ) + s" BULK-IN-EP-ADDR" get-inherited-property drop + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN prop-addr + prop-len TRUE | FALSE ) + decode-int nip nip + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN + BULKIN-EP-ADDR ) + mps-dcp port-number my-usb-address I + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN + BULKIN-EP-ADDR mps-dcp port-address my-usb-address lun-number ) + new-device + + \ creates new device child node, doesn't consume any argument from stack + + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN + BULKIN-EP-ADDR mps-dcp port-address my-usb-address lun-number ) + + set-space + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN + BULKIN-EP-ADDR mps-dcp port-number my-usb-address ) + encode-int s" USB-ADDRESS" property + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN + BULKIN-EP-ADDR mps-dcp port-number ) + encode-int s" reg" property + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN ) + ( BULKIN-EP-ADDR mps-dcp port-number ) + encode-int s" MPS-DCP" property + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN + BULKIN-EP-ADDR ) + I encode-int s" LUN" property + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN + BULKIN-EP-ADDR ) + encode-int s" BULK-IN-EP-ADDR" property + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN ) + encode-int s" MPS-BULKIN" property + ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR ) + encode-int s" BULK-OUT-EP-ADDR" property + ( iManu iProd iSernum MPS-BULKOUT ) + encode-int s" MPS-BULKOUT" property ( iManu iProd iSerNum ) + encode-int s" iSerialNumber" property ( iManu iProd ) + encode-int s" iProduct" property ( iManu ) + encode-int s" iManufacturer" property ( -- ) + s" usb-storage.fs" INCLUDED + finish-device + LOOP +; + +extract-properties \ Extract the properties from parent +create-tree \ this method creates the node for every lun with properties diff --git a/slof/fs/usb/usb-storage.fs b/slof/fs/usb/usb-storage.fs new file mode 100644 index 0000000..642e46a --- /dev/null +++ b/slof/fs/usb/usb-storage.fs @@ -0,0 +1,464 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + + +\ ----------------------------------------------------------- +\ OF properties +\ ----------------------------------------------------------- + +s" storage" device-name +s" block" device-type + +2 encode-int s" #address-cells" property +0 encode-int s" #size-cells" property + + +\ ----------------------------------------------------------- +\ Specific properties +\ ----------------------------------------------------------- + +8 VALUE mps-bulk-out +8 VALUE mps-bulk-in +8 VALUE mps-dcp +0 VALUE bulk-in-ep +0 VALUE bulk-out-ep +0 VALUE bulk-in-toggle +0 VALUE bulk-out-toggle +0 VALUE lun +0 VALUE my-usb-address + + +\ ---------------------------------------------------------- +\ Instance specific values +\ ---------------------------------------------------------- + +0 VALUE csw-buffer +0e VALUE cfg-buffer +0 VALUE response-buffer +0 VALUE command-buffer +0 VALUE resp-size +0 VALUE resp-buffer +INSTANCE VARIABLE ihandle-bulk +INSTANCE VARIABLE ihandle-scsi +INSTANCE VARIABLE ihandle-deblocker +INSTANCE VARIABLE flag +INSTANCE VARIABLE count +0 VALUE max-transfer +0 VALUE block-size + + +\ ------------------------------------------------------- +\ General Constants +\ ------------------------------------------------------- + +0f CONSTANT SCSI-COMMAND-OFFSET + + +\ ------------------------------------------------------- +\ All support methods inherited from parent or imported +\ from support packages are included here. Also included +\ are the internal methods +\ ------------------------------------------------------- + +s" usb-storage-support.fs" INCLUDED + +\ --------------------------------------------------------------- +\ COLON Definitions: Implementation of Standard SCSI commands +\ over USB OHCI +\ --------------------------------------------------------------- + + +\ to use the general bulk command a lot of global variables +\ must be set. See for example the inquiry command. +0 VALUE bulk-cnt +: do-bulk-command ( resp-buffer resp-size -- TRUE | FALSE ) + TO resp-size + TO resp-buffer + 2 TO bulk-cnt + FALSE dup + BEGIN 0= WHILE + drop + \ prepare and send bulk CBW + 1 1 bulk-out-toggle command-buffer 1f mps-bulk-out + ( pt ed-type toggle buffer length mps-bulk-out ) + my-usb-address bulk-out-ep 7 lshift or + ( pt ed-type toggle buffer length mps address ) + rw-endpoint swap ( TRUE toggle | FALSE toggle ) + to bulk-out-toggle ( TRUE | FALSE ) + IF + resp-size 0<> IF \ do we need a response ?! + \ read the bulk response + 0 1 bulk-in-toggle resp-buffer resp-size mps-bulk-in + ( pt ed-type toggle buffer length mps-bulk-in ) + my-usb-address bulk-in-ep 7 lshift or + ( pt ed-type toggle buffer length mps address ) + rw-endpoint swap ( TRUE toggle | FALSE toggle ) + to bulk-in-toggle ( TRUE | FALSE ) + ELSE + TRUE + THEN + IF + \ read the bulk CSW + 0 1 bulk-in-toggle csw-buffer D mps-bulk-in + ( pt ed-type toggle buffer length mps-bulk-in ) + my-usb-address bulk-in-ep 7 lshift or + ( pt ed-type toggle buffer length mps address ) + rw-endpoint swap ( TRUE toggle | FALSE toggle ) + to bulk-in-toggle ( TRUE | FALSE ) + IF + s" Command successful." usb-debug-print + TRUE dup + ELSE + s" Command failed in CSW stage" usb-debug-print + FALSE dup + THEN + ELSE + s" Command failed while receiving DATA... read CSW..." usb-debug-print + \ STALLED: Get CSW to send the CBW again + 0 1 bulk-in-toggle csw-buffer D mps-bulk-in + ( pt ed-type toggle buffer length mps-bulk-in ) + my-usb-address bulk-in-ep 7 lshift or + ( pt ed-type toggle buffer length mps address ) + rw-endpoint swap ( TRUE toggle | FALSE toggle ) + to bulk-in-toggle ( TRUE | FALSE ) + IF + s" OK evaluate the CSW ..." usb-debug-print + csw-buffer c + l@-le + 2 = IF \ Phase Error + s" do a bulk reset-recovery ..." usb-debug-print + bulk-out-ep bulk-in-ep my-usb-address + bulk-reset-recovery-procedure + THEN + \ ELSE + \ don't abort if the read fails. + THEN + FALSE dup + THEN + ELSE + s" Command failed while Sending CBW ..." usb-debug-print + FALSE dup + THEN + bulk-cnt 1 - TO bulk-cnt + bulk-cnt 0= IF + 2drop FALSE dup + THEN + REPEAT +; + +\ --------------------------------------------------------------- +\ Method to 1. Send the INQUIRY command 2. Recieve and analyse +\ (pending) INQUIRY data +\ --------------------------------------------------------------- + +: inquiry ( -- ) + s" usb-storage: inquiry" usb-debug-print + command-buffer 1 20 80 lun 0c + ( address tag transfer-len direction lun command-len ) + build-cbw + command-buffer SCSI-COMMAND-OFFSET + 20 ( address alloc-len ) + build-inquiry + response-buffer 20 + do-bulk-command + IF + s" Successfully read INQUIRY data" usb-debug-print + s" Inquiry data for 0x20 bytes availabe in Response buffer" + usb-debug-print + ELSE + \ TRUE ABORT" USB device transaction error. (inquiry)" + 5040 error" (USB) Device transaction error. (inquiry)" + ABORT + THEN +; + +\ --------------------------------------------------------------- +\ Method to 1. Send the READ CAPACITY command +\ 2. Recieve and analyse the response data +\ --------------------------------------------------------------- + +: read-capacity ( -- ) + s" usb-storage: read-capacity" usb-debug-print + command-buffer 1 8 80 lun 0c + ( address tag transfer-len direction lun command-len ) + build-cbw + command-buffer SCSI-COMMAND-OFFSET + ( address ) + build-read-capacity + response-buffer 8 do-bulk-command + IF + s" Successfully read READ CAPACITY data" usb-debug-print + ELSE + \ TRUE ABORT" USB device transaction error. (capacity)" + 5040 error" (USB) Device transaction error. (capacity)" + ABORT + THEN +; + + +\ -------------------------------------------------------------------- +\ Method to 1. Send TEST UNIT READY command 2. Analyse the status +\ of the response +\ ------------------------------------------------------------------- + +: test-unit-ready ( -- TRUE | FALSE ) + command-buffer 1 0 80 lun 0c + ( address tag transfer-len direction lun command-len ) + build-cbw + command-buffer SCSI-COMMAND-OFFSET + ( address ) + build-test-unit-ready + response-buffer 0 do-bulk-command + IF + s" Successfully read test unit ready data" usb-debug-print + s" Test Unit STATUS availabe in csw-buffer" usb-debug-print + csw-buffer 0c + c@ 0= IF + s" Test Unit Command Successfully Executed" usb-debug-print + TRUE ( TRUE ) + ELSE + s" Test Unit Command Failed to execute" usb-debug-print + FALSE ( FALSE ) + THEN + ELSE + \ TRUE ABORT" USB device transaction error. (test-unit-ready)" + 5040 error" (USB) Device transaction error. (test-unit-ready)" + ABORT + THEN +; + +\ ------------------------------------------------- +\ Method to 1. read sense data 2. analyse sesnse +\ data(pending) +\ ------------------------------------------------ + +: request-sense ( -- ) + s" request-sense: Command ready." usb-debug-print + command-buffer 1 12 80 lun 0c + ( address tag transfer-len direction lun command-len ) + build-cbw + command-buffer SCSI-COMMAND-OFFSET + 12 ( address alloc-len ) + build-request-sense + response-buffer 12 do-bulk-command + IF + s" Read Sense data successfully" usb-debug-print + ELSE + \ TRUE ABORT" USB device transaction error. (request-sense)" + 5040 error" (USB) Device transaction error. (request-sense)" + ABORT + THEN +; + +: start ( -- ) + command-buffer 1 0 80 lun 0c + ( address tag transfer-len direction lun command-len ) + build-cbw + command-buffer SCSI-COMMAND-OFFSET + ( address ) + build-start + response-buffer 0 do-bulk-command + IF + s" Start successfully" usb-debug-print + ELSE + \ TRUE ABORT" USB device transaction error. (start)" + 5040 error" (USB) Device transaction error. (start)" + ABORT + THEN +; + + +\ To transmit SCSI Stop command + +: stop ( -- ) + command-buffer 1 0 80 lun 0c + ( address tag transfer-len direction lun command-len ) + build-cbw + command-buffer SCSI-COMMAND-OFFSET + ( address ) + build-stop + response-buffer 0 do-bulk-command + IF + s" Stop successfully" usb-debug-print + ELSE + \ TRUE ABORT" USB device transaction error. (stop)" + 5040 error" (USB) Device transaction error. (stop)" + ABORT + THEN +; + + +0 VALUE temp1 +0 VALUE temp2 +0 VALUE temp3 + + +\ ------------------------------------------------------------- +\ block device's seek +\ ------------------------------------------------------------- + +: seek ( pos-hi pos-lo -- status ) + s" seek" ihandle-deblocker @ $call-method +; + + +\ ------------------------------------------------------------- +\ block device's read +\ ------------------------------------------------------------- + +: read ( address length -- actual ) + s" read" ihandle-deblocker @ $call-method +; + + +\ ------------------------------------------------------------- +\ read-blocks to be used by deblocker +\ ------------------------------------------------------------- +: read-blocks ( address block# #blocks -- #read-blocks ) + block-size * command-buffer ( address block# transfer-len command-buffer ) + 1 2 pick 80 lun 0c build-cbw ( address block# transfer-len ) + dup to temp1 ( address block# transfer-len) + block-size / ( address block# #blocks ) + command-buffer ( address block# #block command-addr ) + SCSI-COMMAND-OFFSET + -rot ( address command-addr block# #blocks ) + build-read ( address ) + temp1 do-bulk-command + IF + s" Read Sense data successfully" usb-debug-print + ELSE + \ TRUE ABORT" USB device transaction error. (read-blocks)" + 5040 error" (USB) Device transaction error. (read-blocks)" + ABORT + THEN + temp1 block-size / ( #read-blocks ) +; + +\ ------------------------------------------------ +\ To bring the the media to seekable and readable +\ condition. +\ ------------------------------------------------ + +0 VALUE temp1 +0 VALUE temp2 +0 VALUE temp3 +d# 800 CONSTANT media-ready-retry + +: make-media-ready ( -- ) + s" usb-storage: make-media-ready" usb-debug-print + 0 flag ! + 0 count ! + BEGIN + flag @ 0= + WHILE + test-unit-ready IF + s" Media ready for access." usb-debug-print + 1 flag ! + ELSE + count @ 1 + count ! + count @ media-ready-retry = IF + 1 flag ! + 5000 error" (USB) Media or drive not ready for this blade." + ABORT + THEN + request-sense + response-buffer return-request-sense + ( FALSE | ascq asc sense-key TRUE ) + IF + to temp1 ( ascq asc ) + to temp2 ( ascq ) + to temp3 + temp1 2 = temp2 3a = and ( TRUE | FALSE ) + IF + 5010 error" (USB) No Media found! Check for the drawer/inserted media." + ABORT + THEN + temp1 2 = temp2 06 = and ( TRUE | FALSE ) + IF + 5020 error" (USB) Unknown media format." + ABORT + THEN + temp1 0<> temp2 4 = temp3 2 = and and ( TRUE | FALSE ) + IF + start stop + THEN + THEN + THEN + d# 10 ms + REPEAT + usb-debug-flag IF + ." make-media-ready finished after " + count @ decimal . hex ." tries." cr + THEN +; + + +\ Set up the block-size of the device, using the READ CAPACITY command. +\ Note: Media must be ready (=> make-media-ready) or READ CAPACITY +\ might fail! + +: (init-block-size) + read-capacity + response-buffer 4 + + l@ to block-size + s" usb-storage: block-size=" block-size usb-debug-print-val +; + + +\ Standard OF methods + +: open ( -- TRUE ) + s" usb-storage: open" usb-debug-print + ihandle-bulk s" bulk" (open-package) + ihandle-scsi s" scsi" (open-package) + + make-media-ready + (init-block-size) \ Init block-size before opening the deblocker + + ihandle-deblocker s" deblocker" (open-package) + + s" disk-label" find-package IF ( phandle ) + usb-debug-flag IF ." my-args for disk-label = " my-args swap . . cr THEN + my-args rot interpose + THEN + TRUE ( TRUE ) +; + + +: close ( -- ) + ihandle-deblocker (close-package) + ihandle-scsi (close-package) + ihandle-bulk (close-package) +; + + +\ Set device name according to type + +: (init-device-name) ( -- ) + inquiry + response-buffer c@ + CASE + 1 OF s" tape" device-name ENDOF + 5 OF s" cdrom" device-name ENDOF + \ dup OF s" storage" device-name ENDOF + ENDCASE +; + + +\ Initial device node setup + +: (initial-setup) + ihandle-bulk s" bulk" (open-package) + ihandle-scsi s" scsi" (open-package) + + device-init + (init-device-name) + set-cdrom-alias + 200 to block-size \ Default block-size, will be overwritten in "open" + 10000 to max-transfer + + ihandle-bulk (close-package) + ihandle-scsi (close-package) +; + +(initial-setup) diff --git a/slof/fs/usb/usb-support.fs b/slof/fs/usb/usb-support.fs new file mode 100644 index 0000000..1326a04 --- /dev/null +++ b/slof/fs/usb/usb-support.fs @@ -0,0 +1,628 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2007 IBM Corporation +\ * All rights reserved. +\ * This program and the accompanying materials +\ * are made available under the terms of the BSD License +\ * which accompanies this distribution, and is available at +\ * http://www.opensource.org/licenses/bsd-license.php +\ * +\ * Contributors: +\ * IBM Corporation - initial implementation +\ ****************************************************************************/ + +0 value NEXT-TD + +0 VALUE num-tds +0 VALUE td-retire-count +0 VALUE saved-tail +0 VALUE poll-timer +VARIABLE controlxfer-cmd + +\ Allocate an ED and populate it + +: (ed-prepare) ( dir addr dlen setup-packet MPS ep-fun -- + FALSE | dir addr dlen ed-ptr setup-ptr ) + allocate-ed dup 0= IF ( dir addr dlen setup-packet MPS ep-fun ed-ptr ) + drop 3drop 2drop FALSE EXIT ( FALSE ) + THEN + TO temp1 ( dir addr dlen setup-packet MPS ep-fun ) + \ s" controlxfer: Allocated ED: " temp1 usb-debug-print-val + temp1 zero-out-an-ed-except-link ( dir addr dlen setup-packet MPS ep-fun ) + temp1 ed>eattr l@-le or temp1 ed>eattr l!-le ( dir addr dlen setup-ptr MPS ) + dup TO temp2 10 lshift temp1 ed>eattr l@-le or temp1 ed>eattr l!-le + ( dir addr dlen setup-packet-address ) + temp1 swap TRUE ( dir addr dlen ed-ptr setup-ptr TRUE ) +; + + +\ Allocate TD list + + +: (td-prepare) ( dir addr dlen ed-ptr setup-ptr -- + dir FALSE | dir addr dlen ed-ptr setup-ptr td-head td-tail ) + 2 pick ( dir addr dlen ed-ptr setup-ptr dlen ) + temp2 ( dir addr dlen ed-ptr setup-ptr dlen MPS ) + /mod ( dir addr dlen ed-ptr setup-ptr rem quo ) + swap 0<> IF ( dir addr dlen ed-ptr setup-ptr quo ) + 1+ + THEN + 2+ + dup TO num-tds ( dir addr dlen ed-ptr setup-ptr quo+2 ) + allocate-td-list dup 0= IF ( dir addr dlen ed-ptr setup-ptr quo+2 ) + 2drop ( dir addr dlen ed-ptr setup-ptr ) + drop ( dir addr dlen ed-ptr ) + free-ed ( dir addr dlen ) + 2drop ( dir ) + FALSE ( dir FALSE ) + EXIT + THEN TRUE +; + + +\ Fill in the ED structure completely. + + +: (td-ready) ( dir addr dlen ed-ptr setup-ptr td-head td-tail -- ) + ( dir addr dlen ed-ptr setup-ptr ) + 3 pick ( dir addr dlen ed-ptr setup-ptr td-head td-tail ed-ptr ) + tuck ( dir addr dlen ed-ptr setup-ptr td-head ed-ptr td-tail ed-ptr ) + ed>tdqtp l!-le ( dir addr dlen ed-ptr setup-ptr td-head ed-ptr ) + ed>tdqhp l!-le ( dir addr dlen ed-ptr setup-ptr ) + over ed>ned 0 swap l!-le ( dir addr dlen ed-ptr setup-ptr ) +; + + +\ Initialize the HEAD and TAIL TDs for SETUP and +\ STATUS phase respectively. + + +: (td-setup-status) ( dir addr dlen ed-ptr setup-ptr -- dir addr dlen ed-ptr ) + over ed>tdqhp l@-le ( dir addr dlen ed-ptr setup-ptr td-head ) + dup zero-out-a-td-except-link ( dir addr dlen ed-ptr setup-ptr td-head ) + dup td>tattr DATA0-TOGGLE CC-FRESH-TD or swap l!-le + ( dir addr dlen ed-ptr setup-ptr td-head ) + 2dup td>cbptr l!-le ( dir addr dlen ed-ptr setup-ptr td-head ) + 2dup td>bfrend swap STD-REQUEST-SETUP-SIZE 1- + swap l!-le + ( dir addr dlen ed-ptr setup-ptr td-head ) + 2drop ( dir addr dlen ed-ptr ) +; + +\ Initialize the TD TAIL pointer. + + +: (td-tailpointer) ( dir addr dlen ed-ptr -- dir addr dlen ed-ptr ) + dup ed>tdqtp l@-le ( dir addr dlen ed-ptr td-tail ) + dup zero-out-a-td-except-link ( dir addr dlen ed-ptr td-tail ) + dup td>tattr dup l@-le DATA1-TOGGLE CC-FRESH-TD or or swap l!-le + ( dir addr dlen ed-ptr td-tail ) + 4 pick 0= ( dir addr dlen ed-ptr td-tail flag ) + 3 pick 0<> ( dir addr dlen ed-ptr td-tail flag flag ) + and IF ( dir addr dlen ed-ptr td-tail ) + dup td>tattr dup l@-le TD-DP-OUT or swap l!-le + ( dir addr dlen ed-ptr td-tail ) + ELSE + dup td>tattr dup l@-le TD-DP-IN or swap l!-le + ( dir addr dlen ed-ptr td-tail ) + THEN + drop ( dir addr dlen ed-ptr ) +; + +\ Initialize the Data TDs. + + +: (td-data) ( dir addr dlen ed-ptr -- ed-ptr ) + -rot ( dir ed-ptr addr dlen ) + dup 0<> IF ( dir ed-ptr addr dlen ) + >r >r >r TO temp1 r> r> r> temp1 ( ed-ptr addr dlen dir ) + 3 pick ( ed-ptr addr dlen dir ed-ptr ) + ed>tdqhp l@-le td>ntd l@-le ( ed-ptr addr dlen dir td-datahead ) + 4 pick ( ed-ptr addr dlen dir td-datahead ed-ptr ) + td>tattr l@-le 10 rshift ( ed-ptr addr dlen dir td-head-data MPS ) + swap ( ed-ptr addr dlen dir MPS td-head-data ) + >r >r >r >r >r 1 r> r> r> r> r> + ( ed-ptr 1 addr dlen dir MPS td-head-data ) + >r >r 0= IF ( ed-ptr 1 addr dlen dir ) + OHCI-DP-IN ( ed-ptr 1 addr dlen dir OHCI-DP-IN ) + ELSE + OHCI-DP-OUT ( ed-ptr 1 addr dlen dir OHCI-DP-OUT ) + THEN + r> r> ( ed-ptr 1 addr dlen dir OHCI-DP- MPS td-head-data ) + fill-TD-list + ELSE + 2drop nip ( ed-ptr ) + THEN +; + + +\ Program the HC with the ed-ptr value and wait for status to +\ from the HC. +\ Free the ED and TDs associated with it. +\ PENDING: Above said. + + +: (transfer-wait-for-doneq) ( ed-ptr -- TRUE | FALSE ) + dup ( ed-ptr ed-ptr ) + hcctrhead rl!-le ( ed-ptr ) + HC-enable-control-list-processing ( ed-ptr ) + 0 TO td-retire-count ( ed-ptr ) + 0 TO poll-timer BEGIN ( ed-ptr ) + td-retire-count num-tds <> ( ed-ptr TRUE | FALSE ) + poll-timer d# 5000 < and ( ed-ptr TRUE | FALSE ) + WHILE + (HC-CHECK-WDH) IF ( ed-ptr ) + hchccadneq rl@-le find-td-list-tail-and-size nip ( ed-ptr n ) + td-retire-count + TO td-retire-count ( ed-ptr ) + hchccadneq rl@-le dup ( ed-ptr done-td done-td ) + (td-list-status) IF ( ed-ptr done-td failed-td CCcode ) + \ keep condition code of TD on return stack + dup >r + s" (transfer-wait-for-doneq: USB device communication error." + usb-debug-print ( ed-ptr done-td failed-td CCcode R: CCcode ) + dup 4 = swap dup 5 = rot or IF ( ed-ptr done-td failed-td CCcode R: CCcode ) + d# 5000 TO poll-timer ( ed-ptr done-td failed-td CCcode R: CCcode ) + THEN + ( ed-ptr done-td failed-td CCcode R: CCcode) + usb-debug-flag IF + s" CC code ->" type . cr + s" Failing TD contents:" type cr display-td + ELSE + 2drop + THEN ( ed-ptr done-td R: CCcode) + controlxfer-cmd @ GET-MAX-LUN = r> 4 = and IF + s" (transfer-wait-for-doneq): GET-MAX-LUN ControlXfer STALLed" + usb-debug-print + \ Condition Code = 4 means that the device does not support multiple LUNS + \ see USB Massbulk 1.0 Standard + ELSE + drop + 5030 error" (USB) Device communication error." + ABORT + \ FIXME: ABORTing here might leave the HC in an unusable state. + \ We should maybe rather ABORT at the end of this Forth + \ word, when clean-up has been done (or not ABORT at all) + THEN + THEN ( ed-ptr done-td ) + (free-td-list) ( ed-ptr ) + 0 hchccadneq rl!-le ( ed-ptr ) + (HC-ACK-WDH) \ TDs were written to DOne queue. ACK the HC. + \ s" Retired = " td-retire-count usb-debug-print-val + \ s" Total = " num-tds usb-debug-print-val + THEN + poll-timer 1+ TO poll-timer + 1 ms + REPEAT ( ed-ptr ) + disable-control-list-processing ( ed-ptr ) + td-retire-count num-tds <> IF ( ed-ptr ) + dup display-descriptors ( ed-ptr ) + THEN + free-ed + td-retire-count num-tds <> IF + FALSE ( FALSE ) + ELSE + TRUE ( TRUE ) + THEN +; + + +\ COLON DEFINITION: controlxfer +\ INTERFACE FUNCTION + +\ ARGUMENTS: +\ (from the bottom OF stack) +\ 1. dir -- This is the direction OF data transfer associated with +\ the DATA STAGE OF the control xfer. +\ If there is no data transfer (argument dlen is zero) +\ THEN this argument DOes not matter, nonethless it has +\ to be passed. +\ A "0" represents an IN and "1" represents an "OUT". +\ 2. addr -- If therez a data stage associated with the transfer, +\ THEN, this argument holds the address OF the data buffer +\ 3. dlen -- This arg holds the length OF the data buffer discussed +\ in previous step (addr) +\ 4. setup-packet -- This holds the pointer to the setup packet that +\ will be transmitted during the SETUP stage OF +\ the control xfer. The function assumes the length +\ OF the status packet to be 8 bytes. +\ 5. MPS -- This is the MAX PACKET SIZE OF the endpoint. +\ 6. ep-fun -- This is the 11-bit value that holds the Endpoint and +\ the function address. bit 7 to bit 10 holds the Endpoint +\ address. Bits 0 to Bit 6 holds the Function Address. +\ The BIT numbering followed : The left most bit is referred +\ as bit 0. (not the one followed by PPC) +\ Bit 13 must be set for low-speed devices. + +\ RETURN VALUE: +\ Returns TRUE | FALSE depending on the success OF the transaction. + +\ ASSUMPTIONS: +\ 1. Function assumes that the setup packet is 8-bytes in length. +\ If in future, IF we need to add a new argument, we need to change +\ the function in lot OF places. + +\ RISKS: +\ 1. If for some reason, the USB controller DOes not retire all the TDs +\ THEN, the status checking part OF this "word" can spin forever. + + +: controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE | FALSE ) + 2 pick @ controlxfer-cmd ! + (ed-prepare) ( FALSE | dir addr dlen ed-ptr setup-ptr ) + invert IF FALSE EXIT THEN + (td-prepare) ( pt ed-type toggle buffer length mps head ) + invert IF FALSE EXIT THEN + (td-ready) ( dir addr dlen ed-ptr setup-ptr ) + (td-setup-status) ( dir addr dlen ed-ptr ) + (td-tailpointer) ( dir addr dlen ed-ptr ) + (td-data) ( ed-ptr ) + + + \ FIXME: + \ Clear the TAIL pointer in ED. This has got sthg to DO with how + \ the HC finds an EMPTY queue condition. Refer spec. + + + dup ed>tdqtp l@-le TO saved-tail ( ed-ptr ) + dup ed>tdqtp 0 swap l!-le ( ed-ptr ) + (transfer-wait-for-doneq) ( TRUE | FALSE ) +; + +0201000000000000 CONSTANT CLEARHALTFEATURE +0 VALUE endpt-num +0 VALUE usb-addr-contr-req +: control-std-clear-feature ( endpoint-nr usb-addr -- TRUE|FALSE ) + TO usb-addr-contr-req \ usb address + TO endpt-num \ endpoint number + CLEARHALTFEATURE setup-packet ! + endpt-num setup-packet 4 + c! \ endpoint number + 0 0 0 setup-packet DEFAULT-CONTROL-MPS usb-addr-contr-req controlxfer + ( TRUE|FALSE ) +; + +\ It resets the usb bulk-device +21FF000000000000 CONSTANT BULK-RESET +: control-std-bulk-reset ( usb-addr -- TRUE|FALSE ) + TO usb-addr-contr-req + BULK-RESET setup-packet ! + 0 0 0 setup-packet DEFAULT-CONTROL-MPS usb-addr-contr-req controlxfer + ( TRUE|FALSE ) +; + +: bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- ) + >r ( bulk-out-endp bulk-in-endp R: usb-addr ) + \ perform a bulk reset + r@ control-std-bulk-reset + IF s" bulk reset OK" + ELSE s" bulk reset failed" + THEN usb-debug-print + + \ clear bulk-in endpoint ( bulk-out-endp bulk-in-endp R: usb-addr ) + 80 or r@ control-std-clear-feature + IF s" control-std-clear IN endpoint OK" + ELSE s" control-std-clear-IN endpoint failed" + THEN usb-debug-print + + \ clear bulk-out endpoint ( bulk-out-endp R: usb-addr ) + r@ control-std-clear-feature + IF s" control-std-clear OUT endpoint OK" + ELSE s" control-std-clear-OUT endpoint failed" + THEN usb-debug-print + r> drop +; + +0 VALUE saved-rw-ed +0 VALUE num-rw-tds +0 VALUE num-rw-retired-tds +0 VALUE saved-rw-start-toggle +0 VALUE saved-list-type + +\ Allocate an ED and populate what you can. + + +: (ed-prepare-rw) + ( pt ed-type toggle buffer length mps address ed-ptr -- + FALSE | pt ed-type toggle buffer length mps ) + allocate-ed dup 0= IF + ( pt ed-type toggle buffer length mps address ed-ptr ) + drop 2drop 2drop 2drop drop + saved-rw-start-toggle FALSE EXIT ( toggle FALSE ) + THEN + TO saved-rw-ed ( pt ed-type toggle buffer length mps address ) + saved-rw-ed zero-out-an-ed-except-link + ( pt ed-type toggle buffer length mps address ) + saved-rw-ed ed>eattr l!-le ( pt ed-type toggle buffer length mps ) + dup 10 lshift saved-rw-ed ed>eattr l@-le or + ( pt ed-type toggle buffer length mps mps~ ) + saved-rw-ed ed>eattr l!-le TRUE ( pt ed-type toggle buffer length mps TRUE ) +; + + +\ Allocate TD List + + +: (td-prepare-rw) + ( pt ed-type toggle buffer length mps -- + FALSE | pt ed-type toggle buffer length mps head ) + 2dup ( pt ed-type toggle buffer length mps length mps ) + /mod ( pt ed-type toggle buffer length mps num-tds rem ) + swap 0<> IF ( pt ed-type toggle buffer length mps num-tds ) + 1+ ( pt ed-type toggle buffer length mps num-tds+1 ) + THEN + dup TO num-rw-tds ( pt ed-type toggle buffer length mps num-tds ) + allocate-td-list ( pt ed-type toggle buffer length mps head tail ) + dup 0= IF + 2drop 2drop 2drop 2drop + saved-rw-ed free-ed + ." rw-endpoint: TD list allocation failed" cr + saved-rw-start-toggle FALSE ( FALSE ) + EXIT + THEN + drop TRUE ( pt ed-type toggle buffer length mps head TRUE ) +; + + +\ Populate TD list with data buffers and toggle info. + + +: (td-data-rw) + ( pt ed-type toggle buffer length mps head -- FALSE | pt et head ) + 6 pick ( pt ed-type toggle buffer length mps head pt ) + FALSE TO case-failed CASE + 0 OF OHCI-DP-IN ENDOF + 1 OF OHCI-DP-OUT ENDOF + 2 OF OHCI-DP-SETUP ENDOF + dup OF TRUE TO case-failed + ." rw-endpoint: Invalid Packet Type!" cr + ENDOF + ENDCASE ( pt ed-type toggle buffer length mps head dp ) + case-failed IF + saved-rw-ed free-ed ( pt ed-type toggle buffer length mps head dp ) + drop (free-td-list) ( pt ed-type toggle buffer length mps head ) + 2drop 2drop 2drop + saved-rw-start-toggle FALSE ( FALSE ) + EXIT ( FALSE ) + THEN + -rot ( pt ed-type toggle buffer length dp mps head ) + dup >r ( pt ed-type toggle buffer length dp mps head ) + fill-TD-list r> TRUE ( pt et head TRUE ) +; + + +\ Enqueue the ED with the appropriate list + + +: (ed-ready-rw) ( pt et -- - | toggle FALSE ) + nip ( et ) + FALSE TO case-failed CASE + 0 OF \ Control List. Queue the ED to control list + 0 TO saved-list-type + saved-rw-ed hcctrhead rl!-le + HC-enable-control-list-processing + ENDOF + 1 OF \ Bulk List. Queue the ED to bulk list + 1 TO saved-list-type + saved-rw-ed hcbulkhead rl!-le + HC-enable-bulk-list-processing + ENDOF + 2 OF \ Interrupt List. + 2 TO saved-list-type + saved-rw-ed hchccareg rl@-le rl!-le + HC-enable-interrupt-list-processing + ENDOF + dup OF + saved-rw-ed ed>tdqhp l@-le (free-td-list) + saved-rw-ed free-ed + TRUE TO case-failed + ENDOF + ENDCASE + case-failed IF + saved-rw-start-toggle FALSE ( toggle FALSE ) + EXIT + THEN + TRUE ( TRUE ) +; + +\ Wait for TDs to return to the Done Q. + +: (wait-td-retire) ( -- ) + 0 TO num-rw-retired-tds + FALSE TO while-failed BEGIN + num-rw-retired-tds num-rw-tds < ( TRUE | FALSE ) + while-failed FALSE = and ( TRUE | FALSE ) + WHILE + d# 5000 (wait-for-DOne-q) IF ( TD-list ) + dup find-td-list-tail-and-size nip ( td-list size ) + num-rw-retired-tds + TO num-rw-retired-tds ( td-list ) + dup (td-list-status) IF ( td-list failed-TD CC ) + dup 4 = IF + saved-list-type CASE + 0 OF 0 0 control-std-clear-feature + ENDOF + 1 OF \ clean bulk stalled + disable-bulk-list-processing \ disable procesing + saved-rw-ed ed>eattr l@-le dup \ extract + 780 and 7 rshift 80 or \ endpoint and + swap 7f and \ usb addr + control-std-clear-feature + ENDOF + 2 OF 0 saved-rw-ed ed>eattr l@-le + control-std-clear-feature ENDOF + ENDCASE + ELSE + usb-debug-flag IF + s" TD failed with CC code: " type . cr + THEN + drop drop + \ TRUE ABORT" USB device transaction error." + 5040 error" (USB) device transaction error." + ABORT + THEN + 2drop drop + TRUE TO while-failed \ transaction failed + NEXT-TD 0<> IF \ clean the TD if we + NEXT-TD (free-td-list) \ had a stalled + THEN + THEN + (free-td-list) + ELSE + drop \ drop td-list pointer + TRUE TO while-failed + THEN + REPEAT +; + + +\ Process retired TDs + + +: (process-retired-td) ( -- TRUE | FALSE ) + saved-list-type CASE + 0 OF disable-control-list-processing ENDOF + 1 OF disable-bulk-list-processing ENDOF + 2 OF disable-interrupt-list-processing ENDOF + ENDCASE + saved-rw-ed ed>tdqhp l@-le 2 and 0<> IF + 1 + ELSE + 0 + THEN + WHILE-failed IF + FALSE ( FALSE ) + ELSE + TRUE ( TRUE ) + THEN + saved-rw-ed free-ed +; + + +\ (DO-rw-endpoint): T1 12 80 0 0chis method is an privately visible function +\ to be used by the "rw-endpoint" the required +\ number OF times based on the actual length +\ to be transferred + +\ Arguments: +\ pt: Packet type +\ 0 -> IN +\ 1 -> OUT +\ 2 -> SETUP +\ et: Endpoint type +\ 0 -> Control +\ 1 -> Bulk +\ toggle: Starting toggle for this transfer +\ buffer length: Data buffer associated with the transfer limited +\ accordingly by the "rw-endpoint" method to the +\ value OF max packet size +\ mps: Max Packet Size. +\ address: Address OF endpoint. 11-bit address. The lower 7-bits represent +\ the USB addres and the upper 4-bits represent the Endpoint +\ number. + + + +: (do-rw-endpoint) + ( pt ed-type toggle buffer length mps address -- toggle TRUE|toggle FALSE ) + 4 pick ( pt ed-type toggle buffer length mps address toggle ) + TO saved-rw-start-toggle ( pt ed-type toggle buffer length mps address) + (ed-prepare-rw) ( FALSE | pt ed-type toggle buffer length mps ) + invert IF FALSE EXIT THEN + (td-prepare-rw) ( FALSE | pt ed-type toggle buffer length mps head ) + invert IF FALSE EXIT THEN + (td-data-rw) ( FALSE | pt et head ) + invert IF FALSE EXIT THEN + saved-rw-ed ed>tdqhp l!-le ( pt et ) + saved-rw-ed ed>tdqhp l@-le td>ntd l@-le TO NEXT-TD \ save for a stalled + (ed-ready-rw) + invert IF FALSE EXIT THEN + (wait-td-retire) + (process-retired-td) ( TRUE | FALSE ) +; + + +\ rw-endpoint: The method is an externally visible method to be exported +\ to the child nodes. It uses the internal method +\ "(DO-rw-endpoint)", the required number OF times based on the +\ actual length OF transfer, so that the limitataion OF MAX-TDS +\ DO not hinder the transfer. + +\ Arguments: +\ pt: Packet type +\ 0 -> IN +\ 1 -> OUT +\ 2 -> SETUP +\ et: Endpoint type +\ 0 -> Control +\ 1 -> Bulk +\ toggle: Starting toggle for this transfer +\ buffer length: Data buffer associated with the transfer +\ mps: Max Packet Size. +\ address: Address OF endpoint. 11-bit address. The lower 7-bits represent +\ the USB addres and the upper 4-bits represent the Endpoint +\ number. + + +0 VALUE transfer-len +0 VALUE mps-current +0 VALUE addr-current +0 VALUE usb-addr +0 VALUE toggle-current +0 VALUE type-current +0 VALUE pt-current +0 VALUE read-status +0 VALUE counter +0 VALUE residue + + +: rw-endpoint + ( pt ed-type toggle buffer length mps address -- ) + ( toggle TRUE |toggle FALSE ) + + \ a single transfer descriptor can point to a buffer OF + \ 8192 bytes a block on the CDROM has 2048 bytes + \ but a single transfer is constrained by the MPS + + 2 pick TO transfer-len ( pt ed-type toggle buffer length mps address ) + 1 pick TO mps-current ( pt ed-type toggle buffer length mps address ) + TRUE TO read-status ( pt ed-type toggle buffer length mps address ) + transfer-len mps-current num-free-tds * <= IF + (do-rw-endpoint) ( toggle TRUE | toggle FALSE ) + TO read-status ( toggle ) + TO toggle-current + ELSE + TO usb-addr ( pt ed-type toggle buffer length mps ) + 2drop ( pt ed-type toggle buffer ) + TO addr-current ( pt ed-type toggle ) + TO toggle-current ( pt ed-type ) + TO type-current ( pt ) + TO pt-current + transfer-len mps-current num-free-tds * /mod ( residue count ) + ( remainder=residue quotient=count ) + TO counter ( residue ) + TO residue + mps-current num-free-tds * TO transfer-len BEGIN + counter 0 > ( TRUE | FALSE ) + read-status TRUE = and ( TRUE | FALSE ) + WHILE + pt-current type-current toggle-current ( pt ed-type toggle ) + addr-current transfer-len ( pt ed-type toggle buffer length ) + mps-current ( pt ed-type toggle buffer length mps ) + usb-addr (do-rw-endpoint) ( toggle TRUE | toggle FALSE ) + TO read-status ( toggle ) + TO toggle-current + addr-current transfer-len + TO addr-current + counter 1- TO counter + REPEAT + residue 0<> ( TRUE |FALSE ) + read-status TRUE = and IF + residue TO transfer-len + pt-current type-current toggle-current ( pt ed-type toggle ) + addr-current transfer-len ( pt ed-type toggle buffer length ) + mps-current ( pt ed-type toggle buffer length mps ) + usb-addr (do-rw-endpoint) ( toggle TRUE | toggle FALSE ) + TO read-status + TO toggle-current + THEN + THEN + read-status invert IF + THEN + toggle-current ( toggle ) + read-status ( TRUE | FALSE ) +; |