diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-12-01 09:51:44 +1100 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2010-12-01 09:51:44 +1100 |
commit | aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f (patch) | |
tree | dfffc0d8f3d21f6736b7f09219c95e2370052d8a /slof/fs/usb | |
download | SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.zip SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.tar.gz SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.tar.bz2 |
Initial import of slof-JX-1.7.0-4
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'slof/fs/usb')
-rw-r--r-- | slof/fs/usb/usb-enumerate.fs | 324 | ||||
-rw-r--r-- | slof/fs/usb/usb-hub.fs | 459 | ||||
-rw-r--r-- | slof/fs/usb/usb-kbd-device-support.fs | 102 | ||||
-rw-r--r-- | slof/fs/usb/usb-keyboard.fs | 371 | ||||
-rw-r--r-- | slof/fs/usb/usb-mouse.fs | 28 | ||||
-rw-r--r-- | slof/fs/usb/usb-ohci.fs | 1190 | ||||
-rw-r--r-- | slof/fs/usb/usb-static.fs | 297 | ||||
-rw-r--r-- | slof/fs/usb/usb-storage-support.fs | 155 | ||||
-rw-r--r-- | slof/fs/usb/usb-storage-wrapper.fs | 181 | ||||
-rw-r--r-- | slof/fs/usb/usb-storage.fs | 639 | ||||
-rw-r--r-- | slof/fs/usb/usb-support.fs | 651 |
11 files changed, 4397 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..7118f17 --- /dev/null +++ b/slof/fs/usb/usb-enumerate.fs @@ -0,0 +1,324 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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) ( -- ) + s" SCSI-CREATE " usb-debug-print + +\ *********************************************************************** +\ a problem was encountered on Media-Tray (REV-0): +\ The CDROM is connected to USB via an ATA/USB-Bridge (U38: CYPRESS CY7C68300) +\ The C-Revision of this chip has an malfunction which results in a +\ hanging IORD Signal at the ATA-Interface and so prevents from reading. +\ The B-Revision doesn't have this problem (populated on Media-Tray REV-5) +\ Two additional Mass-Storage-Resets are necessary to reset the ATA-Interface. +\ (see CYPRESS Application Notes to CY7C68300) +\ (see USB-Spec: 'Bulk-Only-Transport') +\ *********************************************************************** +\ a mounted ISO image (via USB) doesn't accept this bulk-reset-command! +\ *********************************************************************** + + dd-buffer @ 8 + w@-le 4b4 = \ VendorID = CYPRESS ? + IF + dd-buffer @ a + w@-le 6830 = \ Device = CY7C68300 ? + IF + \ here a Cypress ATA/USB Bridge is detected + d# 20 ms + mps new-device-address 0 0 0 ( MPS fun-addr dir data-buff data-len ) + control-bulk-reset ( TRUE|FALSE ) + d# 100 ms + mps new-device-address 0 0 0 ( TRUE|FALSE MPS fun-addr dir data-buff data-len ) + control-bulk-reset ( TRUE|FALSE TRUE|FALSE ) + and invert + IF + ." ** BULK-RESET failed **" cr + THEN + d# 20 ms + THEN + THEN + + 0 ch-buffer ! \ preset a clean response + mps new-device-address 0 ch-buffer 1 control-std-get-maxlun ( TRUE|FALSE ) + IF +\ s" GET-MAX-LUN IS WORKING :" usb-debug-print +\ ch-buffer 5 dump cr \ dump the responsed message + ELSE + s" ERROR in GET-MAX-LUN " usb-debug-print + 0 ch-buffer ! \ clear invalid numbers + 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. + \ + \ Concerns: "FUJITSU MHV2040AT" (VendorID: 0x984 / DeviceID: 0x70) + \ + \ MR: This Device reports an invalid MaxLUN number within the first + \ three seconds after power-on or USB-Reset. The following loop repeats + \ the MaxLUN request up to 8 times until a valid ( <15 ) value is responded. + \ This can last up to four seconds as there is a delay of 500ms in every loop + + 0 ( counter ) + begin + dup 8 < ( counter flag ) \ max 8 * 500 ms + ch-buffer c@ f > ( counter flag flag ) \ is MuxLUN above limit ? + AND ( counter flag ) + while + d# 500 ms \ this device is not yet ready + 0 ch-buffer ! \ preset a clean response + mps new-device-address 0 ch-buffer 1 control-std-get-maxlun ( TRUE|FALSE ) + not + IF + s" ** ERROR in GET-MAX-LUN ** " usb-debug-print + drop 10 \ replace counter to force loop end + THEN + 1+ ( counter+1 ) + repeat + drop + + \ here is still the workaround to handle invalid MaxLUNs as '0' + \ + 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" ATAPI Interface " usb-debug-print ENDOF + 05 OF (atapi-8070-create) s" ATAPI Interface " usb-debug-print ENDOF + 06 OF (scsi-create) s" SCSI Interface " 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 + uDOC-present 0f and to uDOC-present \ remove uDOC processing flag +; diff --git a/slof/fs/usb/usb-hub.fs b/slof/fs/usb/usb-hub.fs new file mode 100644 index 0000000..106b680 --- /dev/null +++ b/slof/fs/usb/usb-hub.fs @@ -0,0 +1,459 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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 +; + +\ *** NEW **** +: control-bulk-reset ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE ) + s" control-bulk-reset" $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# -- ) + +\ this port has been powered on +\ send reset to enable port and +\ start device detection by hub +\ some devices require a long timeout here (10s) + + \ Step 1: check if reset state ended + + 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 + + \ STEP 2: Reset the port. + \ (this also enables 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 ) + WHILE ( port# ) + REPEAT ( port# ) + + \ 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 + + + \ 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 invert + IF + s" ** reading dev-descriptor failed ** " usb-debug-print + THEN + 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 \ number of downstream ports + + s" HUB: Found " usb-debug-print + s" number of downstream hub ports! : " temp2 usb-debug-print-val + hd-buffer 5 + c@ to po2pg \ get bPwrOn2PwrGood + + \ power on all present hub ports + \ to allow slow devices to set up + + temp2 1+ 1 DO + i control-hub-port-power-set drop + d# 20 ms + LOOP + + d# 200 ms \ some devices need a long time (10s) + + \ now start detection and configuration for these ports + + temp2 1+ 1 DO + s" hub-configure-port: " i usb-debug-print-val + 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..9fa4236 --- /dev/null +++ b/slof/fs/usb/usb-kbd-device-support.fs @@ -0,0 +1,102 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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-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..fd96e6e --- /dev/null +++ b/slof/fs/usb/usb-keyboard.fs @@ -0,0 +1,371 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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 + +." USB Keyboard" cr + +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 +; + +: 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 +; + +: key-available? ( -- true|false ) + multi-key 0 <> IF + true \ multi scan code key was pressed... so key is available + EXIT \ done + THEN + kbd-scan 0 = IF \ if no kbd-scan code is currently available + int-get-report \ check for one using int-get-report + THEN + kbd-scan 0 <> \ if a kbd-scan is available, report true, else false +; + +: 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 + \ check for new scan code only, if kbd-scan is not set, e.g. + \ by a previous call to key-available? + kbd-scan 0 = IF + \ 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 + THEN + 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 + kbd-scan 8 rshift to kbd-scan \ handled scan-code + 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 + +: open ( -- true ) + 7 set-led + 100 ms + 3 set-led + 100 ms + 1 set-led + 100 ms + \ read once from keyboard before actually using it + usb-kread drop + 0 set-led + true +; + +: close ; diff --git a/slof/fs/usb/usb-mouse.fs b/slof/fs/usb/usb-mouse.fs new file mode 100644 index 0000000..bd6fa50 --- /dev/null +++ b/slof/fs/usb/usb-mouse.fs @@ -0,0 +1,28 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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 + +." USB Mouse" cr + +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..f4d9670 --- /dev/null +++ b/slof/fs/usb/usb-ohci.fs @@ -0,0 +1,1190 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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 CONSTANT HcRevision +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 40 + CONSTANT HcPeriodicStart +baseaddrs 48 + CONSTANT hcrhdescA +baseaddrs 4c + CONSTANT hcrhdescB +baseaddrs 50 + CONSTANT HcRhStatus +baseaddrs 54 + CONSTANT hcrhpstat +baseaddrs 58 + CONSTANT hcrhpstat2 +baseaddrs 5c + CONSTANT hcrhpstat3 + +usb-debug-flag IF + 0 config-l@ ." - VENDOR: " 8 .r cr + 40 config-l@ ." - PMC : " 8 .r + 44 config-l@ ." PMCSR : " 8 .r cr + E0 config-l@ ." - EXT1 : " 8 .r + E4 config-l@ ." EXT2 : " 8 .r cr +THEN + +\ Constants for INTSTAT register + +2 CONSTANT WDH + +\ Constants for RH Port Status Register + +1 CONSTANT RHP-CCS \ Current Connect Status +2 CONSTANT RHP-PES \ Port Enable Status +10 CONSTANT RHP-PRS \ Port Reset Status +100 CONSTANT RHP-PPS \ Port Power Status +10000 CONSTANT RHP-CSC \ Connect Status Changed +100000 CONSTANT RHP-PRSC \ Port Reset Status Changed + + +\ 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 +0 VALUE max-rh-ports +0 VALUE current-stat + +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. + +: Show-OHCI-Register + ." -> OHCI-Register: " cr + ." - HcControl : " hccontrol rl@-le 8 .r + ." CmdStat : " hccomstat rl@-le 8 .r + ." HcInterr. : " hcintstat rl@-le 8 .r cr + + ." - HcFmIntval: " hcintrval rl@-le 8 .r + ." Per. Start: " HcPeriodicStart rl@-le 8 .r cr + + ." - PortStat-1: " hcrhpstat rl@-le 8 .r + ." PortStat-2: " hcrhpstat2 rl@-le 8 .r + ." PortStat-3: " hcrhpstat3 rl@-le 8 .r cr + + ." Descr-A : " hcrhdescA rl@-le 8 .r + ." Descr-B : " hcrhdescB rl@-le 8 .r + ." HcRhStat : " HcRhStatus rl@-le 8 .r cr +; + +: 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 ) + (HC-CHECK-WDH) NOT ( timeout TRUE|FALSE TRUE|FALSE ) + AND \ not timed out AND WDH-bit not set + WHILE + 1 ms \ wait + 1- ( timeout ) + dup ff and 0= IF show-proceed THEN + REPEAT ( timeout ) + drop + hchccadneq l@-le \ read last HcDoneHead (RAM) + (HC-CHECK-WDH) \ HcDoneHead was updated ? + IF + (HC-ACK-WDH) \ clear register bit: WDH + TRUE ( td-list TRUE ) + ELSE + FALSE + THEN +; + + +\ 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 ( -- ) + + hccomstat dup rl@-le 01 or swap rl!-le \ issue HC reset + BEGIN + hccomstat rl@-le 01 and 0<> \ wait for reset end + WHILE + REPEAT + + 23f02edf hcintrval rl!-le \ frame-interval register + hchcca hchccareg rl!-le \ HC communication area + 0000 hcctrhead rl!-le \ control transfer head + 0000 hcbulkhead rl!-le \ bulk transfer head + 0ffff hcintdsbl rl!-le \ interrupt disable reg. + +\ all devices are still in reset-state +\ next command starts sending SOFs + 83 hccontrol rl!-le \ set USBOPERATIONAL + +\ these two repeated register settings are necessary for Bimini +\ Its OHCI controller (AM8111) behaves different to NEC's one + 23f02edf hcintrval rl!-le \ frame-interval register + hchcca hchccareg rl!-le \ HC communication area + + d# 50 ms + + hcrhdescA rl@-le ff and ( total-rh-ports ) + to max-rh-ports + +\ if no hardware-reset was issued (rescan) +\ switch off all ports first ! + hcrhpstat TO current-stat \ start with first port status reg + 0 \ port status default + max-rh-ports 0 \ checking all ports + DO + current-stat rl@-le or \ OR-ing all stats + 200 current-stat rl!-le \ Clear Port Power (CPP) + current-stat 4 + TO current-stat \ check next RH-Port + LOOP + 100 and 0<> \ any of the ports had power ? + IF + d# 750 wait-proceed \ wait for power discharge + THEN + +\ now power on all ports of this root-hub + hcrhpstat TO current-stat \ start with first port status reg + max-rh-ports 0 + DO + 102 current-stat rl!-le \ power on and enable + hcrhdescA 3 + rb@ 2 * ms \ startup delay 30 ms (2 * POTPGT) + current-stat 4 + TO current-stat \ check next RH-Port + LOOP + d# 500 wait-proceed \ STEC device needs 300 ms +; + +: 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 +; + +\ Fetches 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 ) +; + +\ Bulk-Only Mass Storage Reset +\ fixed to interface #0 +: control-bulk-reset ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE ) + 21FF000000000000 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. +\ ========================================================================== +: rhport-initialize ( -- ) + + hcrhpstat TO current-stat \ start with first port status reg + max-rh-ports 1+ 1 + DO + \ any Device connected to that port ? + current-stat rl@-le RHP-CCS and 0<> ( TRUE|FALSE ) + IF + current-stat hcrhpstat3 = \ third port of NEC ? + IF + 81 to uDOC-present \ uDOC is present and now processed + THEN + + s" Device connected to this port!" usb-debug-print + RHP-PRS current-stat rl!-le \ issue a port reset + BEGIN + current-stat rl@-le RHP-PRS AND \ wait for reset end + WHILE + REPEAT + hcrhdescA 3 + rb@ 2 * ms \ startup delay 30 ms (POTPGT) + d# 100 ms + + current-stat rl@-le 200 and 4 lshift + to device-speed \ store speed bit + + RHP-CSC RHP-PRSC or current-stat rl!-le + + 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 + current-stat hcrhpstat3 = \ third port of NEC ? (=ModFD) + IF \ here a ModFD should be on ELBA + current-stat rl@-le 80000 and 0<> \ is over-current detected ? + IF + uDOC-present 08 or to uDOC-present \ set flag for uDOC-check + THEN + THEN + THEN + current-stat 4 + TO current-stat \ check next RH-Port + uDOC-present 0f and to uDOC-present \ remove processing flag + LOOP +; + + +\ =================================================== +\ Enumeration at Host level +\ =================================================== + +: enumerate ( -- ) + HC-reset + ['] hc-suspend add-quiesce-xt \ Assert that HC will be supsended + 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..8732957 --- /dev/null +++ b/slof/fs/usb/usb-static.fs @@ -0,0 +1,297 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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 +\ ****************************************************************************/ + +\ #include "scsi-support.fs" + +\ Set usb-debug flag to TRUE for debugging output: +0 VALUE usb-debug-flag +false VALUE scan-time? + +VARIABLE ihandle-bulk-tran +\ -scsi-supp- VARIABLE ihandle-scsi-tran + +\ uDOC (Micro-Disk-On-Chip) is a FLASH-device +\ normally connected to usb-port 5 on ELBA +\ +0 VALUE uDOC-present \ device present and working? + +\ 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 +; + +\ show proceeding propeller only during scan process. +\ As soon USB-keyboard can be used, this must be suppressed. +0 VALUE proceed-char +: show-proceed ( -- ) + scan-time? \ are we on usb-scan ? + IF + proceed-char + CASE + 0 OF 2d ENDOF \ show '-' + 1 OF 5c ENDOF \ show '\' + 2 OF 7c ENDOF \ show '|' + dup OF 2f ENDOF \ show '/' + ENDCASE + emit 8 emit + proceed-char 1 + 3 AND to proceed-char + THEN +; + +\ delay with proceeding signs +: wait-proceed ( nl -- ) + show-proceed + BEGIN + dup d# 100 > ( nl true|false ) + WHILE + 100 - show-proceed + 100 ms \ do it in steps of 100ms + REPEAT + ms \ rest delay +; + +\ register device alias +: do-alias-setting ( num name-str name-len ) + rot $cathex strdup \ create alias name + get-node node>path \ get path string + set-alias \ and set the alias +; + + +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" + do-alias-setting +; + +0 VALUE cdrom-alias-num +0 VALUE disk-alias-num \ shall start with: pci-disk-num +FALSE VALUE ext-disk-alias \ first external disk: not yet assigned + +\ create a new ohci device alias for the current node: +: set-drive-alias ( -- ) + space 5b emit + s" cdrom" drop ( name-str ) + get-node node>name comp 0= ( true|false ) + IF \ is this a cdrom ? + cdrom-alias-num dup 1+ TO cdrom-alias-num ( num ) + s" cdrom" \ yes, alias = cdrom + ELSE + s" sbc-dev" drop \ is this a scsi-block-device? + get-node node>name comp 0= ( true|false ) + IF + disk-alias-num dup 1 + to disk-alias-num + s" disk" \ all block devices will be named "disk" + + \ this is a block-device. + \ check if parent is 'usb' and not 'hub' + \ if so this block-device is directly connected + \ to root-hub and must be the uDOC-device in Elba + s" usb" drop \ parent = usb controller ? (not hub) + get-node node>parent @ node>name + comp 0= \ parent node starts with 'usb' ? + IF ( true|false ) + 1 s" hdd" \ add extra alias hdd1 for IntFlash + 2dup type 2 pick . + 8 emit 2f emit + do-alias-setting + uDOC-present 1 and + IF + uDOC-present 2 or to uDOC-present \ present and ready + THEN + ELSE + ext-disk-alias not \ flag for first ext. disk already assigned + IF + TRUE to ext-disk-alias + 2 s" hdd" \ add extra alias hdd2 for first USB disk + 2dup type 2 pick . + 8 emit 2f emit + do-alias-setting + THEN + THEN + ELSE + 0 s" ??? " \ unknown device + THEN + THEN ( num name-str name-len ) + 2dup type 2 pick . + 8 emit 5d emit cr + do-alias-setting +; + +: 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: ) +; + + +\ ***************************************************** +\ This is a final check to see, if a uDOC-device +\ is ready for booting +\ If physically present, but not working, an +\ Error-LED must be activated (on ELBA only!) +\ ***************************************************** +\ uDOC is now replaced by ModFD (Modular-Flash-Drive) +\ due to right properties +\ 'sys-signal-modfd-fault' sends an IPMI-Message to +\ aMM for generating a log entry and to switch on +\ an error LED (call to libsystem->libipmi) +\ ***************************************************** +\ although there are IPMI-warnings defined concerning +\ detected media errors, it doesn't make sense to send +\ a warning when booting from this device is impossible. +\ The decision was made to send an error call in this +\ case as well +\ ***************************************************** +\ uDOC-present bits: +\ ***************************************************** +\ D0: any device is connected on port 3 of root-hub +\ D1: device on port 3 is directly connected (no hub) +\ D2: warnings were received (scancodes) +\ D3: OverCurrentIndicator on USB-Port was set +\ D7: flag, set while ModFD is beeing processed + +: uDOC-check ( -- ) +#ifdef ELBA + uDOC-present 7 and \ flags concerning ModFD device + CASE + 0 OF \ not present not detected + uDOC-present 8 and 0<> \ not detected due to OverCurrent? + IF + 0d emit ." * OverCurrent on ModFD *" cr + sys-signal-modfd-fault ( -- ) \ send IPMI-call to BMC + ELSE + 0d emit ." ModFD not present" cr + THEN + ENDOF + + 1 OF \ present but not detected by USB + 0d emit ." * ModFD not accessible *" cr + sys-signal-modfd-fault ( -- ) \ send IPMI-call to BMC + ENDOF + + 3 OF \ present and detected +\ 0d emit ." ModFD OK" cr + ENDOF + + 7 OF \ present and detected but with warnings + 0d emit ." * ModFD Warnings *" cr + sys-signal-modfd-fault ( -- ) \ send IPMI-call to BMC + ENDOF + + dup OF \ we have a fault in our firmware ! + s" *** ModFD detection error ***" usb-debug-print + ENDOF + ENDCASE +#endif +; + +\ ***************************************************** +\ check if actual processed device is ModFD and +\ then sets its warning bit +\ ***************************************************** +: uDOC-failure? ( -- ) + uDOC-present 80 and 0<> \ is ModFD actual beeing processed? + IF + uDOC-present 04 or to uDOC-present \ set Warning flag + THEN +; + +\ Scan all USB host controllers for attached devices: +: usb-scan + \ Scan all OHCI chips: + space ." Scan USB... " cr + true to scan-time? \ show proceeding signs + 0 to uDOC-present \ mark as not present + 0 to disk-alias-num \ start with disk0 + s" pci-disk-num" $find \ previously detected disks ? + IF + execute to disk-alias-num \ overwrite start number + ELSE + 2drop + THEN + + 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 ( -- ) + \ cdrom-alias-num 1 + TO cdrom-alias-num + ELSE + drop ( -- ) + THEN + uDOC-check \ check if uDOC-device is present and working (ELBA only) + false to scan-time? \ suppress proceeding signs +; + +: usb-probe + + usb-scan + + cdrom-alias-num 0= IF + ." Not found CDROM! " cr + THEN + ." CDROM found " cdrom-alias-num . cr +; + + +: usb-dev-test ( -- TRUE ) + s" USB Device Test " usb-debug-print + 1 usb-create-alias-name + find-alias ?dup IF + ." * open " 2dup type . cr + ELSE + s" can't found alias " usb-debug-print + THEN + open-dev ?dup IF + dup to my-self + dup ihandle>phandle dup set-node + s" bulk" $open-package ihandle-bulk-tran ! +\ make-media-ready + s" close all " usb-debug-print + close-dev 0 set-node 0 to my-self + + ihandle-bulk-tran close-package + ELSE + s" can't open usb hub" usb-debug-print + THEN + + TRUE +; + diff --git a/slof/fs/usb/usb-storage-support.fs b/slof/fs/usb/usb-storage-support.fs new file mode 100644 index 0000000..f5033de --- /dev/null +++ b/slof/fs/usb/usb-storage-support.fs @@ -0,0 +1,155 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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 ) +; + + +\ ======================================================= +\ 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..c783541 --- /dev/null +++ b/slof/fs/usb/usb-storage-wrapper.fs @@ -0,0 +1,181 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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..f23c27a --- /dev/null +++ b/slof/fs/usb/usb-storage.fs @@ -0,0 +1,639 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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-deblocker +INSTANCE VARIABLE flag +INSTANCE VARIABLE count +0 VALUE max-transfer +200 VALUE block-size \ default (512 Bytes) +-1 VALUE max-block-num \ highest reported block-number + + +\ ------------------------------------------------------- +\ 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 +0 VALUE bulk-cmd-len +0 VALUE itest +: do-bulk-command ( resp-buffer resp-size -- TRUE | FALSE ) + TO resp-size + TO resp-buffer + \ dump buffer in debug-mode + usb-debug-flag + IF + command-buffer 0E + c@ TO bulk-cmd-len + s" cmd-length: " bulk-cmd-len usb-debug-print-val + command-buffer bulk-cmd-len 0E + dump cr + THEN + + 6 TO bulk-cnt \ 2 old value + 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 + s" resp-size : " resp-size usb-debug-print-val + 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 + c@ dup TO itest + s" CSW Status: " itest usb-debug-print-val + dup + 2 = + IF \ Phase Error + s" Phase error 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. + 1 = + IF \ Command failed + s" Command Failed do a bulk-reset-recovery" usb-debug-print + bulk-out-ep bulk-in-ep my-usb-address + bulk-reset-recovery-procedure + THEN + 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. Receive and analyse +\ (pending) INQUIRY data +\ --------------------------------------------------------------- +scsi-open +usb-debug-flag to scsi-param-debug \ copy debug flag + +24 CONSTANT inquiry-length \ was 20 + +: inquiry ( -- ) + s" usb-storage: inquiry" usb-debug-print + command-buffer 1 inquiry-length 80 lun scsi-length-inquiry + ( address tag transfer-len direction lun command-len ) + build-cbw + inquiry-length command-buffer SCSI-COMMAND-OFFSET + ( alloc-len address ) + scsi-build-inquiry + response-buffer inquiry-length erase \ provide clean buffer + response-buffer inquiry-length do-bulk-command + IF + s" Successfully read INQUIRY data" usb-debug-print + 0d emit space space + response-buffer c@ \ get 'Peripheral Device Type' (PDT) + CASE + 0 OF ." BLOCK-DEV: " ENDOF \ SCSI Block Device + 5 OF ." CD-ROM : " ENDOF + 7 OF ." OPTICAL : " ENDOF + e OF ." RED-BLOCK: " ENDOF \ SCSI Reduced Block Device + dup dup OF ." ? (" . 8 emit 29 emit 2 spaces ENDOF + ENDCASE + space + \ create vendor identification in device property + response-buffer 8 + 16 encode-string s" ident-str" property + response-buffer .inquiry-text + ELSE + 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 scsi-length-read-cap-10 + ( address tag transfer-len direction lun command-len ) + build-cbw + \ command-buffer 30 dump cr \ dump the command buffer + command-buffer SCSI-COMMAND-OFFSET + ( address ) + scsi-build-read-cap-10 + lun 5 lshift + command-buffer SCSI-COMMAND-OFFSET + ( address ) + read-cap-10>reserved1 c! + + response-buffer 8 erase \ provide clean buffer + response-buffer 8 do-bulk-command + IF + s" Successfully read READ CAPACITY data" usb-debug-print + ELSE + 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 scsi-length-test-unit-ready \ was: 0c + ( address tag transfer-len direction lun command-len ) + build-cbw + command-buffer SCSI-COMMAND-OFFSET + ( address ) + scsi-build-test-unit-ready ( cdb -- ) + 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 +; + +\ **************************************************** +\ multiple checks of 'test-unit-ready' with timeout +\ **************************************************** +: wait-for-unit-ready ( -- TRUE|FALSE ) + s" --> WAIT: test-unit-ready ... " usb-debug-print + d# 100 ( count ) \ up to 10 seconds + BEGIN ( count ) + dup 0> ( count flag ) + test-unit-ready \ dup IF 2b ELSE 2d THEN emit + not and ( count flag ) + WHILE + 1- ( count ) + d# 100 wait-proceed \ wait 100 ms + REPEAT ( count ) + 0= + IF + s" ** Device not ready ** " usb-debug-print + FALSE + ELSE + TRUE + 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 scsi-length-request-sense + ( address tag transfer-len direction lun command-len ) + build-cbw +\ -scsi-supp- command-buffer SCSI-COMMAND-OFFSET + 12 ( address alloc-len ) +\ -scsi-supp- build-request-sense + + 12 command-buffer SCSI-COMMAND-OFFSET + ( alloc-len cdb ) + scsi-build-request-sense ( alloc-len cdb -- ) + + response-buffer 12 do-bulk-command + IF + s" Read Sense data successfully" usb-debug-print + \ response-buffer 12 dump cr \ dump the rsponsed message + 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 scsi-length-start-stop-unit + ( address tag transfer-len direction lun command-len ) + build-cbw +\ -scsi-supp- command-buffer SCSI-COMMAND-OFFSET + ( address ) +\ -scsi-supp- build-start + + command-buffer SCSI-COMMAND-OFFSET + ( cdb ) + scsi-const-start scsi-build-start-stop-unit ( state# cdb -- ) + + 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 scsi-length-start-stop-unit + ( address tag transfer-len direction lun command-len ) + build-cbw +\ -scsi-supp- command-buffer SCSI-COMMAND-OFFSET + ( address ) +\ -scsi-supp- build-stop + + command-buffer SCSI-COMMAND-OFFSET + ( cdb ) + scsi-const-stop scsi-build-start-stop-unit ( state# cdb -- ) + + 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 +\ ------------------------------------------------------------- +\ if anything is wrong in the boot device, a seek-request can +\ occur that exceeds the limits of the device in the following +\ read-command. So checking is required and the appropriate +\ return-value has to be returned +\ Spec requires -1 if operation fails and 0 or 1 if it succeeds !! +\ ------------------------------------------------------------- + +: seek ( pos-lo pos-hi -- status ) + 2dup lxjoin max-block-num block-size * > + IF + ." ** Seek Error: pos too large (" + dup . over . ." -> " max-block-num block-size * . + ." ) ** " cr + -1 \ see spec-1275 page 183 + ELSE + s" seek" ihandle-deblocker @ $call-method + THEN +; + + +\ ------------------------------------------------------------- +\ 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 ) + 2dup + max-block-num > + IF + ." ** Requested block too large " + 2dup + ." (" .d ." -> " max-block-num .d + bs emit ." ) ... read aborted **" cr + nip nip \ leave #blocks on stack + ELSE + 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# #blocks command-addr ) + SCSI-COMMAND-OFFSET + ( address block# #blocks cdb ) + scsi-build-read? ( block# #blocks cdb -- length ) + command-buffer 0e + c! \ update bCBWCBLength-field with resulting CDB length + temp1 ( address length ) + do-bulk-command + IF + s" Read 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 ) + THEN +; + +\ ------------------------------------------------ +\ To bring the the media to seekable and readable +\ condition. +\ ------------------------------------------------ + +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 scsi-get-sense-ID? ( addr -- false | sense-ID true ) + IF + ffff00 AND \ remaining: sense-key ASC + CASE + 023a00 OF \ MEDIUM NOT PRESENT (02 3a 00) + 5010 error" (USB) No Media found! Check for the drawer/inserted media." + ABORT + ENDOF + + 020400 OF \ LOGICAL DRIVE NOT READY - INITIALIZATION REQUIRED + 5010 error" (USB) No Media found! Check for the drawer/inserted media." + ABORT + ENDOF + + 033000 OF \ CANNOT READ MEDIUM - UNKNOWN FORMAT + 5020 error" (USB) Unknown media format." + ABORT + ENDOF + ENDCASE + THEN + THEN + d# 10 ms \ wait maximum 10ms * 800 (=8s) + REPEAT + usb-debug-flag IF + ." make-media-ready finished after " + count @ decimal . hex ." tries." cr + THEN +; + +\ ------------------------------------------------ +\ read and show devices capacity +\ ------------------------------------------------ +: .showcap + space + test-unit-ready drop \ initial command + request-sense + response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true ) + IF + dup FFFF00 and 023a00 = ( sense-id flag ) + IF + uDOC-failure? + 023a02 = \ see sense-codes SPC-3 clause 4.5.6 + IF + ." Tray Open!" + ELSE + ." No Media" + THEN + ELSE ( sense-id ) + drop + wait-for-unit-ready + IF + read-capacity + response-buffer scsi-get-capacity-10 space .capacity-text + ELSE + request-sense + response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true ) + IF + dup ff0000 and 040000 = \ sense-code = 4 ? + IF + ." *HW-ERROR*" + uDOC-failure? + ELSE + dup FFFF00 and 023a00 = IF uDOC-failure? THEN + CASE ( sense-ID ) + \ see SPC-3 clause 4.5.6 + 023a00 OF ." No Media " ENDOF + 023a02 OF ." Tray Open! " ENDOF + dup OF ." ? " ENDOF + ENDCASE + THEN + THEN + THEN + THEN + ELSE + ." ?? " + THEN +; + + + +: init-dev-ready + test-unit-ready drop + 4 >r \ loop-counter + 0 0 + BEGIN + 2drop + request-sense + response-buffer scsi-get-sense-data ( ascq asc sense-key ) + 0<> r> 1- dup >r 0<> AND \ loop-counter or sense-key + WHILE + REPEAT + 2drop + r> drop +; + + + +scsi-close \ no further scsi words required + + +\ 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 l@ dup 0<> + IF + to max-block-num \ highest block-number + ELSE + -1 to max-block-num \ indeterminate + THEN + 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) + + 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-bulk (close-package) +; + + +\ Set device name according to type + +: (init-device-name) ( -- ) + init-dev-ready + inquiry + response-buffer c@ + CASE + 1 OF .showcap s" tape" device-name ENDOF + 5 OF .showcap s" cdrom" device-name s" CDROM found" usb-debug-print ENDOF + 0 OF .showcap s" sbc-dev" device-name s" SBC Direct access device" usb-debug-print ENDOF + 7 OF .showcap s" optical" device-name s" Optical memory found" usb-debug-print ENDOF + 0E OF .showcap s" rbc-dev" device-name s" RBC direct acces device found" usb-debug-print ENDOF + \ dup OF s" storage" device-name ENDOF + ENDCASE +; + + +\ Initial device node setup + +: (initial-setup) + ihandle-bulk s" bulk" (open-package) + device-init + (init-device-name) + set-drive-alias + 200 to block-size \ Default block-size, will be overwritten in "open" + 10000 to max-transfer + + ihandle-bulk (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..08ff9bd --- /dev/null +++ b/slof/fs/usb/usb-support.fs @@ -0,0 +1,651 @@ +\ ***************************************************************************** +\ * Copyright (c) 2004, 2008 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 ) + 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. + +10 CONSTANT max-retire-td + +: (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 ( ed-ptr ) + BEGIN + td-retire-count num-tds <> ( ed-ptr TRUE | FALSE ) + poll-timer max-retire-td < and ( ed-ptr TRUE | FALSE ) + WHILE + (HC-CHECK-WDH) ( ed-ptr ) + IF + hchccadneq l@-le find-td-list-tail-and-size nip ( ed-ptr n ) + td-retire-count + TO td-retire-count ( ed-ptr ) + hchccadneq l@-le dup ( ed-ptr done-td done-td ) + (td-list-status) ( ed-ptr done-td failed-td CCcode ) + IF + \ 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 ( ed-ptr done-td failed-td CCcode R: CCcode ) + IF + max-retire-td 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 l!-le ( ed-ptr ) + (HC-ACK-WDH) \ TDs were written to DOne queue. ACK the HC. + THEN + poll-timer 1+ TO poll-timer + 4 ms \ longer 1 ms + REPEAT ( ed-ptr ) + disable-control-list-processing ( ed-ptr ) + td-retire-count num-tds <> ( ed-ptr ) + IF + dup display-descriptors ( ed-ptr ) + s" maximum of retire " usb-debug-print + 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) ( TD-list TRUE|FALSE ) + IF + 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) ( td-list failed-TD CC ) + IF + dup 4 = + IF + saved-list-type + CASE + 0 OF + 0 0 control-std-clear-feature + s" clear feature " usb-debug-print + ENDOF + 1 OF \ clean bulk stalled + s" clear bulk when stalled " usb-debug-print + 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 + dup OF + s" unknown status " usb-debug-print + ENDOF + ENDCASE + ELSE ( td-list failed-TD CC ) + ." TD failed " 5b emit .s 5d emit cr + 5040 error" (USB) device transaction error (wait-td-retire)." + ABORT + THEN + 2drop drop + TRUE TO while-failed \ transaction failed + NEXT-TD 0<> \ clean the TD if we + IF + NEXT-TD (free-td-list) \ had a stalled + THEN + THEN + (free-td-list) + ELSE + drop \ drop td-list pointer + scan-time? IF 2e emit THEN \ show proceeding dots + TRUE TO while-failed + s" time out wait for done" usb-debug-print + 20 ms \ wait for bad device + 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 + s" retired 1" usb-debug-print + ELSE + 0 + s" retired 0" usb-debug-print + THEN + \ s" retired " usb-debug-print-val + 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 ) +; |