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