aboutsummaryrefslogtreecommitdiff
path: root/slof/fs/usb
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-12-01 09:51:44 +1100
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-12-01 09:51:44 +1100
commitaaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f (patch)
treedfffc0d8f3d21f6736b7f09219c95e2370052d8a /slof/fs/usb
downloadSLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.zip
SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.tar.gz
SLOF-aaad509cdca2ed5f2c92a26f5279ec0e89c4fd5f.tar.bz2
Initial import of slof-JX-1.7.0-4
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'slof/fs/usb')
-rw-r--r--slof/fs/usb/usb-enumerate.fs324
-rw-r--r--slof/fs/usb/usb-hub.fs459
-rw-r--r--slof/fs/usb/usb-kbd-device-support.fs102
-rw-r--r--slof/fs/usb/usb-keyboard.fs371
-rw-r--r--slof/fs/usb/usb-mouse.fs28
-rw-r--r--slof/fs/usb/usb-ohci.fs1190
-rw-r--r--slof/fs/usb/usb-static.fs297
-rw-r--r--slof/fs/usb/usb-storage-support.fs155
-rw-r--r--slof/fs/usb/usb-storage-wrapper.fs181
-rw-r--r--slof/fs/usb/usb-storage.fs639
-rw-r--r--slof/fs/usb/usb-support.fs651
11 files changed, 4397 insertions, 0 deletions
diff --git a/slof/fs/usb/usb-enumerate.fs b/slof/fs/usb/usb-enumerate.fs
new file mode 100644
index 0000000..7118f17
--- /dev/null
+++ b/slof/fs/usb/usb-enumerate.fs
@@ -0,0 +1,324 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ create the device tree for hub
+
+: (hub-create) ( -- )
+ mps port-number new-device-address port-number
+ ( mps port-number usb-address port-number )
+ new-device set-space ( mps port-number usb-address )
+ encode-int s" USB-ADDRESS" property ( mps port-number )
+ s" Address Set" usb-debug-print
+ encode-int s" reg" property ( mps )
+ s" Port Number Set" usb-debug-print
+ encode-int s" MPS-DCP" property
+ s" MPS Set" usb-debug-print
+ s" usb-hub.fs" INCLUDED
+ s" Driver Included" usb-debug-print
+ finish-device
+;
+
+
+\ encode properties for scsi or atapi device
+
+: (atapi-scsi-property-set) ( -- )
+ dd-buffer @ e + c@ ( Manuf )
+ dd-buffer @ f + c@ ( Manuf Prod )
+ dd-buffer @ 10 + c@ ( Manuf Prod Serial-Num )
+ cd-buffer @ 16 + w@-le ( Manuf Prod Serial-Num ep-mps )
+ cd-buffer @ 14 + c@ ( Manuf Prod Serial-Num ep-mps ep-addr )
+ cd-buffer @ 1d + w@-le ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps )
+ cd-buffer @ 1b + c@ ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr )
+ mps port-number new-device-address port-number
+ ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr
+ mps port-num usb-addr port-num )
+ new-device set-space
+ ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr
+ mps port-num usb-addr )
+ encode-int s" USB-ADDRESS" property
+ ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr
+ mps port-num )
+ encode-int s" reg" property
+ ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr
+ mps )
+ encode-int s" MPS-DCP" property
+ ( Manuf Prod Serial-Num ep-mps ep-addr ep-mps ep-addr )
+ 2 0 DO
+ dup 80 and IF
+ 7f and encode-int
+ s" BULK-IN-EP-ADDR" property
+ encode-int s" MPS-BULKIN" property
+ ELSE
+ encode-int s" BULK-OUT-EP-ADDR" property
+ encode-int s" MPS-BULKOUT" property
+ THEN
+ LOOP ( Manuf Prod Serial-Num )
+ encode-int s" iSerialNumber" property ( Manuf Prod )
+ encode-int s" iProduct" property ( Manuf )
+ encode-int s" iManufacturer" property
+;
+
+
+\ To classify device as hub/atapi/scsi/HID device
+
+: (device-classify)
+ ( -- Interface-protocol Interface-subclass Interface-class TRUE|FALSE )
+ cd-buffer @ BULK-CONFIG-DESCRIPTOR-LEN erase
+ cd-buffer @ BULK-CONFIG-DESCRIPTOR-LEN mps new-device-address
+ ( buffer descp-len mps usb-address )
+ control-std-get-configuration-descriptor
+ IF
+ cd-buffer @ 1+ c@ ( Descriptor-type )
+ 2 = IF
+ cd-buffer @ 10 + c@ ( protocol )
+ cd-buffer @ f + c@ ( protocol subclass )
+ cd-buffer @ e + c@ ( protocol subclass class )
+ TRUE
+ ELSE
+ s" Not a valid configuration descriptor!!" usb-debug-print
+ FALSE
+ THEN
+ ELSE
+ s" Unable to read configuration descriptor!!" usb-debug-print
+ FALSE
+ THEN
+;
+
+
+\ create device tree for Atapi SFF-8020 device
+
+: (atapi-8020-create) ( -- )
+ (atapi-scsi-property-set)
+ s" usb-storage.fs" INCLUDED
+ finish-device
+;
+
+\ create device tree for Atapi SFF-8070 device
+
+: (atapi-8070-create) ( -- )
+ (atapi-scsi-property-set)
+ s" usb-storage.fs" INCLUDED
+ \ s" storage" device-name
+ finish-device
+;
+
+
+\ create device tree for SCSI device
+
+: (scsi-create) ( -- )
+ s" SCSI-CREATE " usb-debug-print
+
+\ ***********************************************************************
+\ a problem was encountered on Media-Tray (REV-0):
+\ The CDROM is connected to USB via an ATA/USB-Bridge (U38: CYPRESS CY7C68300)
+\ The C-Revision of this chip has an malfunction which results in a
+\ hanging IORD Signal at the ATA-Interface and so prevents from reading.
+\ The B-Revision doesn't have this problem (populated on Media-Tray REV-5)
+\ Two additional Mass-Storage-Resets are necessary to reset the ATA-Interface.
+\ (see CYPRESS Application Notes to CY7C68300)
+\ (see USB-Spec: 'Bulk-Only-Transport')
+\ ***********************************************************************
+\ a mounted ISO image (via USB) doesn't accept this bulk-reset-command!
+\ ***********************************************************************
+
+ dd-buffer @ 8 + w@-le 4b4 = \ VendorID = CYPRESS ?
+ IF
+ dd-buffer @ a + w@-le 6830 = \ Device = CY7C68300 ?
+ IF
+ \ here a Cypress ATA/USB Bridge is detected
+ d# 20 ms
+ mps new-device-address 0 0 0 ( MPS fun-addr dir data-buff data-len )
+ control-bulk-reset ( TRUE|FALSE )
+ d# 100 ms
+ mps new-device-address 0 0 0 ( TRUE|FALSE MPS fun-addr dir data-buff data-len )
+ control-bulk-reset ( TRUE|FALSE TRUE|FALSE )
+ and invert
+ IF
+ ." ** BULK-RESET failed **" cr
+ THEN
+ d# 20 ms
+ THEN
+ THEN
+
+ 0 ch-buffer ! \ preset a clean response
+ mps new-device-address 0 ch-buffer 1 control-std-get-maxlun ( TRUE|FALSE )
+ IF
+\ s" GET-MAX-LUN IS WORKING :" usb-debug-print
+\ ch-buffer 5 dump cr \ dump the responsed message
+ ELSE
+ s" ERROR in GET-MAX-LUN " usb-debug-print
+ 0 ch-buffer ! \ clear invalid numbers
+ cd-buffer @ 5 + c@ to temp1
+ temp1 new-device-address control-std-set-configuration drop
+ THEN
+ \ FIXME: an IBM external HDD reported a number of 127 LUNs which could
+ \ not be set up. We need to understand how to set up the device
+ \ to report the correct number of LUNs.
+ \ The USB Massbulk Standard 1.0 defines a maximum of 15 mult. LUNs.
+ \ Workaround: Devices that might report a higher number are treated
+ \ as having exactly one LUN. Without this workaround the
+ \ USB scan hangs during the setup of non-available LUNs.
+ \
+ \ Concerns: "FUJITSU MHV2040AT" (VendorID: 0x984 / DeviceID: 0x70)
+ \
+ \ MR: This Device reports an invalid MaxLUN number within the first
+ \ three seconds after power-on or USB-Reset. The following loop repeats
+ \ the MaxLUN request up to 8 times until a valid ( <15 ) value is responded.
+ \ This can last up to four seconds as there is a delay of 500ms in every loop
+
+ 0 ( counter )
+ begin
+ dup 8 < ( counter flag ) \ max 8 * 500 ms
+ ch-buffer c@ f > ( counter flag flag ) \ is MuxLUN above limit ?
+ AND ( counter flag )
+ while
+ d# 500 ms \ this device is not yet ready
+ 0 ch-buffer ! \ preset a clean response
+ mps new-device-address 0 ch-buffer 1 control-std-get-maxlun ( TRUE|FALSE )
+ not
+ IF
+ s" ** ERROR in GET-MAX-LUN ** " usb-debug-print
+ drop 10 \ replace counter to force loop end
+ THEN
+ 1+ ( counter+1 )
+ repeat
+ drop
+
+ \ here is still the workaround to handle invalid MaxLUNs as '0'
+ \
+ ch-buffer c@ dup 0= swap f > or IF
+ s" + LUN: " ch-buffer c@ usb-debug-print-val
+ (atapi-scsi-property-set)
+ s" usb-storage.fs" INCLUDED
+ finish-device
+
+ ELSE
+ s" - LUN: " ch-buffer c@ usb-debug-print-val
+ (atapi-scsi-property-set)
+ s" usb-storage-wrapper.fs" INCLUDED
+ finish-device
+
+ THEN
+;
+
+
+\ Classify USB storage device by sub-class code
+
+: (classify-storage) ( interface-protocol interface-subclass -- )
+ s" USB: Mass Storage Device Found!" usb-debug-print
+ swap 50 <> IF
+ s" USB storage: Protocol is not 50." usb-debug-print
+ drop EXIT
+ THEN
+ ( interface-subclass )
+ CASE
+ 02 OF (atapi-8020-create) s" ATAPI Interface " usb-debug-print ENDOF
+ 05 OF (atapi-8070-create) s" ATAPI Interface " usb-debug-print ENDOF
+ 06 OF (scsi-create) s" SCSI Interface " usb-debug-print ENDOF
+ dup OF s" USB storage: Unsupported sub-class code." usb-debug-print ENDOF
+ ENDCASE
+;
+
+
+\ create keyboard device tree
+
+: (keyboard-create) ( -- )
+ cd-buffer @ 1f + c@ ( ep-mps )
+ cd-buffer @ 1d + c@ ( ep-mps ep-addr )
+ mps port-number new-device-address port-number
+ ( ep-mps ep-addr mps port-num usb-addr port-num )
+ new-device set-space ( ep-mps ep-addr mps port-num usb-addr )
+ encode-int s" USB-ADDRESS" property ( ep-mps ep-addr mps port-num )
+ encode-int s" reg" property ( ep-mps ep-addr mps )
+ encode-int s" MPS-DCP" property ( ep-mps ep-addr )
+ 7f and encode-int s" INT-IN-EP-ADDR" property
+ encode-int s" MPS-INTIN" property
+ new-device-address \ device-speed
+ s" usb-keyboard.fs" INCLUDED
+ finish-device
+;
+
+: (mouse-create) ( -- )
+ mps port-number new-device-address port-number
+ ( mps port-num usb-addr port-num )
+ new-device set-space ( mps port-num usb-addr )
+ encode-int s" USB-ADDRESS" property ( mps port-num )
+ encode-int s" reg" property ( mps )
+ encode-int s" MPS-DCP" property
+ s" usb-mouse.fs" INCLUDED
+ finish-device
+;
+
+
+\ Classify by interface class code
+
+: (classify-by-interface) ( -- )
+ (device-classify) IF
+ ( Interface-protocol Interface-subclass Interface-class )
+ CASE
+ 08 OF
+ ( Interface-protocol Interface-subclass )
+ (classify-storage)
+ ENDOF
+ 03 OF
+ ( Interface-protocol Interface-subclass )
+ s" USB: HID Found!" usb-debug-print
+ 01 =
+ IF
+ case
+ 01 of
+ s" USB keyboard!" usb-debug-print
+ (keyboard-create)
+ endof
+ 02 of
+ s" USB mouse!" usb-debug-print
+ (mouse-create)
+ endof
+ dup of
+ s" USB: unsupported HID!" usb-debug-print
+ endof
+ endcase
+ ELSE
+ s" USB: unsupported HID!" usb-debug-print
+ THEN
+ ENDOF
+ dup OF
+ ( Interface-protocol Interface-subclass )
+ s" USB: unsupported interface type." usb-debug-print
+ 2drop
+ ENDOF
+ ENDCASE
+ THEN
+;
+
+
+\ create usb device tree depending upon classification of the device
+\ after encoding apt properties
+
+: create-usb-device-tree ( -- )
+ dd-buffer @ DEVICE-DESCRIPTOR-DEVCLASS-OFFSET + c@ ( Device-class )
+ CASE
+ HUB-DEVICE-CLASS OF s" USB: HUB found" usb-debug-print
+ (hub-create)
+ ENDOF
+ NO-CLASS OF
+ \ In this case, the INTERFACE descriptor
+ \ tells you whats what -- Refer USB spec.
+ (classify-by-interface)
+ ENDOF
+ DUP OF
+ s" USB: Unknown device found." usb-debug-print
+ ENDOF
+ ENDCASE
+ uDOC-present 0f and to uDOC-present \ remove uDOC processing flag
+;
diff --git a/slof/fs/usb/usb-hub.fs b/slof/fs/usb/usb-hub.fs
new file mode 100644
index 0000000..106b680
--- /dev/null
+++ b/slof/fs/usb/usb-hub.fs
@@ -0,0 +1,459 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ ----------------------------------------------------------------------------
+\ On detection of a hub after reading the device descriptor this package has to
+\ be called so that the hub enumeration is done to idenitify the down stream
+\ device
+\ --------------------------------------------------------------------------
+\ OF properties
+\ --------------------------------------------------------------------------
+
+
+s" hub" device-name
+s" usb" device-type
+1 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+\ converts physical address to text unit string
+
+
+: encode-unit ( port-addr -- unit-str unit-len ) 1 hex-encode-unit ;
+
+
+\ Converts text unit string to phyical address
+
+
+: decode-unit ( addr len -- port-addr ) 1 hex-decode-unit ;
+
+0 VALUE new-device-address
+0 VALUE port-number
+0 VALUE MPS-DCP
+0 VALUE mps
+0 VALUE my-usb-address
+
+00 value device-speed
+
+
+\ Get parameters passed from the parent.
+
+: mps-property-set ( -- )
+ s" HUB Compiling mps-property-set " usb-debug-print
+ s" USB-ADDRESS" get-my-property ( TRUE | prop-addr prop-len FALSE )
+ IF
+ s" notpossible" usb-debug-print
+ ELSE
+ decode-int nip nip to my-usb-address
+ THEN
+ s" MPS-DCP" get-my-property ( TRUE | prop-addr prop-len FALSE )
+ IF
+ s" MPS-DCP property not found Assuming 8 as MAX PACKET SIZE" ( str len )
+ usb-debug-print
+ s" for the default control pipe" usb-debug-print
+ 8 to MPS-DCP
+ ELSE
+ s" MPS-DCP property found!!" usb-debug-print ( prop-addr prop-len FALSE )
+ decode-int nip nip to MPS-DCP
+ THEN
+;
+
+
+\ --------------------------------------------------------------------------
+\ Constant declarations
+\ --------------------------------------------------------------------------
+
+
+2303080000000000 CONSTANT hppwr-set
+2301080000000000 CONSTANT hppwr-clear
+2303040000000000 CONSTANT hprst-set
+A300000000000400 CONSTANT hpsta-get
+2303010000000000 CONSTANT hpena-set
+A006002900000000 CONSTANT hubds-get
+8 CONSTANT DEFAULT-CONTROL-MPS
+12 CONSTANT DEVICE-DESCRIPTOR-LEN
+9 CONSTANT CONFIG-DESCRIPTOR-LEN
+20 CONSTANT BULK-CONFIG-DESCRIPTOR-LEN
+
+
+\ TODO:
+\ CONFIG-DESCRIPTOR-LEN should be only 9. The interface
+\ and endpoint descriptors returned along with config
+\ descriptor are variable and 0x19 is a very wrong VALUE
+\ to specify for this #define.
+
+
+1 CONSTANT DEVICE-DESCRIPTOR-TYPE
+1 CONSTANT DEVICE-DESCRIPTOR-TYPE-OFFSET
+4 CONSTANT DEVICE-DESCRIPTOR-DEVCLASS-OFFSET
+7 CONSTANT DEVICE-DESCRIPTOR-MPS-OFFSET
+9 CONSTANT HUB-DEVICE-CLASS
+0 CONSTANT NO-CLASS
+
+
+\ --------------------------------------------------------------------------
+\ Temporary Variable declarations
+\ --------------------------------------------------------------------------
+
+00 VALUE temp1
+00 VALUE temp2
+00 VALUE temp3
+00 VALUE po2pg \ Power On to Power Good
+
+
+\ --------------------------------------------------------------------------
+\ Buffer allocations
+\ --------------------------------------------------------------------------
+
+
+VARIABLE setup-packet \ 8 bytes for setup packet
+VARIABLE ch-buffer \ 1 byte character buffer
+
+INSTANCE VARIABLE dd-buffer
+INSTANCE VARIABLE cd-buffer
+
+\ TODO:
+\ Should arrive a proper value for the size of the "cd-buffer"
+
+8 chars alloc-mem VALUE status-buffer
+9 chars alloc-mem VALUE hd-buffer
+
+
+: (allocate-mem) ( -- )
+ DEVICE-DESCRIPTOR-LEN chars alloc-mem dd-buffer !
+ BULK-CONFIG-DESCRIPTOR-LEN chars alloc-mem cd-buffer !
+;
+
+
+: (de-allocate-mem) ( -- )
+ dd-buffer @ ?dup IF
+ DEVICE-DESCRIPTOR-LEN free-mem
+ 0 dd-buffer !
+ THEN
+ cd-buffer @ ?dup IF
+ BULK-CONFIG-DESCRIPTOR-LEN free-mem
+ 0 cd-buffer !
+ THEN
+;
+
+
+\ standard open firmware methods
+
+: open ( -- TRUE )
+ (allocate-mem)
+ TRUE
+;
+
+: close ( -- )
+ (de-allocate-mem)
+;
+
+
+\ --------------------------------------------------------------------------
+\ Parent's method
+\ --------------------------------------------------------------------------
+
+
+: controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE|FALSE )
+ s" controlxfer" $call-parent
+;
+
+: control-std-set-address ( speedbit -- usb-address TRUE|FALSE )
+ s" control-std-set-address" $call-parent
+;
+
+: control-std-get-device-descriptor
+ ( data-buffer data-len MPS funcAddr -- TRUE|FALSE )
+ s" control-std-get-device-descriptor" $call-parent
+;
+
+: control-std-get-configuration-descriptor
+ ( data-buffer data-len MPS funcAddr -- TRUE|FALSE )
+ s" control-std-get-configuration-descriptor" $call-parent
+;
+
+: control-std-get-maxlun
+ ( MPS fun-addr dir data-buff data-len -- TRUE|FALSE )
+ s" control-std-get-maxlun" $call-parent
+;
+
+: control-std-set-configuration
+ ( configvalue FuncAddr -- TRUE|FALSE )
+ s" control-std-set-configuration" $call-parent
+;
+
+: control-std-get-string-descriptor
+ ( StringIndex data-buffer data-len MPS FuncAddr -- TRUE|FALSE )
+ s" control-std-get-string-descriptor" $call-parent
+;
+
+: rw-endpoint
+ ( pt ed-type toggle buffer length mps address -- toggle TRUE|toggle FALSE )
+ s" rw-endpoint" $call-parent
+;
+
+: debug-td ( -- )
+ s" debug-td" $call-parent
+;
+
+\ *** NEW ****
+: control-bulk-reset ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE )
+ s" control-bulk-reset" $call-parent
+;
+
+
+\ --------------------------------------------------------------------------
+\ HUB specific methods
+\ --------------------------------------------------------------------------
+\ To bring on the power on a valid port of a hub with a valid USB address
+\ --------------------------------------------------------------------------
+
+
+: control-hub-port-power-set ( port# -- TRUE|FALSE )
+ hppwr-set setup-packet ! ( port#)
+ setup-packet 4 + c!
+ 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE | FALSE )
+;
+
+
+\ --------------------------------------------------------------------------
+\ To put power off on ports where device detection or enumeration has failed
+\ --------------------------------------------------------------------------
+
+
+: control-hub-port-power-clear ( port#-- TRUE|FALSE )
+ hppwr-clear setup-packet ! ( port#)
+ setup-packet 4 + c!
+ 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+\ -------------------------------------------------------------------------
+\ To reset a valid port of a hub with a valid USB
+\ address
+\ --------------------------------------------------------------------------
+
+
+: control-hub-port-reset-set ( port# -- TRUE|FALSE )
+ hprst-set setup-packet ! ( port# )
+ setup-packet 4 + c!
+ 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+\ -------------------------------------------------------------------------
+\ To enable a particular valid port of a hub with a valid USB address
+\ -------------------------------------------------------------------------
+
+
+: control-hub-port-enable ( port# -- TRUE|FALSE )
+ hpena-set setup-packet ! ( port# )
+ setup-packet 4 + c!
+ 0 0 0 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+\ -------------------------------------------------------------------------
+\ To get the status of a valid port of a hub with
+\ a valid USB address
+\ -------------------------------------------------------------------------
+
+
+: control-hub-port-status-get ( buffer port# -- TRUE|FALSE )
+ hpsta-get setup-packet ! ( buffer port# )
+ setup-packet 4 + c! ( buffer )
+ 0 swap 4 setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+\ --------------------------------------------------------------------------
+\ To get the hub descriptor to understand how many ports are vailable and the
+\ specs of those ports
+\ ---------------------------------------------------------------------------
+
+
+: control-get-hub-descriptor ( buffer buffer-length -- TRUE|FALSE )
+ hubds-get setup-packet !
+ dup setup-packet 6 + w!-le ( buffer buffer-length )
+ 0 -rot setup-packet MPS-DCP my-usb-address controlxfer ( TRUE|FALSE )
+;
+
+
+s" usb-enumerate.fs" INCLUDED
+
+
+: hub-configure-port ( port# -- )
+
+\ this port has been powered on
+\ send reset to enable port and
+\ start device detection by hub
+\ some devices require a long timeout here (10s)
+
+ \ Step 1: check if reset state ended
+
+ BEGIN ( port# )
+ status-buffer 4 erase ( port# )
+ status-buffer over control-hub-port-status-get drop ( port# )
+ status-buffer w@-le 102 and 0= ( port# TRUE|FALSE )
+ WHILE ( port# )
+ REPEAT ( port# )
+ po2pg 3 * ms \ wait for bPwrOn2PwrGood*3 ms
+
+ \ STEP 2: Reset the port.
+ \ (this also enables the port)
+ dup control-hub-port-reset-set drop ( port# )
+ BEGIN ( port# )
+ status-buffer 4 erase ( port# )
+ status-buffer over control-hub-port-status-get drop ( port# )
+ status-buffer w@-le 10 and ( port# TRUE|FALSE )
+ WHILE ( port# )
+ REPEAT ( port# )
+
+ \ STEP 3: Check if a device is connected to the port.
+
+ status-buffer 4 erase ( port# )
+ status-buffer over control-hub-port-status-get drop ( port# )
+ status-buffer w@-le 103 and 103 <> ( port# TRUE|FALSE )
+ s" Port status bits: " status-buffer w@-le usb-debug-print-val
+ IF ( port# )
+ drop
+ s" Connect status: No device connected " usb-debug-print
+ EXIT
+ THEN
+
+
+ \ STEP 4: Assign an address to this device.
+
+ status-buffer w@-le 200 and 4 lshift \ get speed bit
+ dup to device-speed \ store speed bit
+ ( port# speedbit )
+ control-std-set-address ( port# usb-addr TRUE|FALSE )
+ 50 ms ( port# usb-addr TRUE|FALSE )
+ debug-td ( port# usb-addr TRUE|FALSE )
+ IF ( port# usb-addr )
+ device-speed or ( port# usb-addr+speedbit )
+ to new-device-address ( port# )
+ to port-number
+ dd-buffer @ DEVICE-DESCRIPTOR-LEN erase
+ dd-buffer @ DEFAULT-CONTROL-MPS DEFAULT-CONTROL-MPS new-device-address
+ ( buffer mps mps usb-addr )
+ control-std-get-device-descriptor ( TRUE|FALSE )
+ IF
+ dd-buffer @ DEVICE-DESCRIPTOR-TYPE-OFFSET + c@ ( descriptor-type )
+ DEVICE-DESCRIPTOR-TYPE <> ( TRUE|FALSE )
+ IF
+ s" HUB: ERROR!! Invalid Device Descriptor for the new device"
+ usb-debug-print
+ ELSE
+ dd-buffer @ DEVICE-DESCRIPTOR-MPS-OFFSET + c@ to mps
+
+ \ Re-read the device descriptor again with the known MPS.
+
+ dd-buffer @ DEVICE-DESCRIPTOR-LEN erase
+ dd-buffer @ DEVICE-DESCRIPTOR-LEN mps new-device-address
+ ( buffer descp-len mps usb-addr )
+ \ s" DEVICE DESCRIPTOR: " usb-debug-print
+ control-std-get-device-descriptor invert
+ IF
+ s" ** reading dev-descriptor failed ** " usb-debug-print
+ THEN
+ create-usb-device-tree
+ THEN
+ ELSE
+ s" ERROR!! Failed to get device descriptor" usb-debug-print
+ THEN
+ ELSE ( port# )
+ s" USB Set Adddress failed!!" usb-debug-print ( port# )
+ s" Clearing Port Power..." usb-debug-print ( port# )
+ control-hub-port-power-clear ( TRUE|FALSE )
+ IF
+ s" Port power down " usb-debug-print
+ ELSE
+ s" Unable to clear port power!!!" usb-debug-print
+ THEN
+ THEN
+;
+
+
+\ ---------------------------------------------------------------------------
+\ To enumerate all the valid ports of hub
+\ TODO:
+\ 1. Remove hardcoded constants.
+\ 2. Remove Endian Dependencies.
+\ 3. Return values of controlxfer should be checked.
+\ ---------------------------------------------------------------------------
+
+: hub-enumerate ( -- )
+ cd-buffer @ CONFIG-DESCRIPTOR-LEN erase
+
+ \ Get HUB configuration and SET the configuration
+ \ note: remove hard-coded constants.
+
+ cd-buffer @ CONFIG-DESCRIPTOR-LEN MPS-DCP my-usb-address
+ ( buffer descp-len mps usb-address )
+ control-std-get-configuration-descriptor drop
+ cd-buffer @ 1+ c@ 2 <> IF
+ s" Unable to read configuration descriptor" usb-debug-print
+ EXIT
+ THEN
+ cd-buffer @ 4 + c@ 1 <> IF
+ s" Not a valid HUB config descriptor" usb-debug-print
+ EXIT
+ THEN
+
+ \ TODO: Do further checkings on the returned Configuration descriptor
+ \ before proceeding to accept it.
+
+ cd-buffer @ 5 + c@ to temp1 \ Store the configuration in temp1
+ temp1 my-usb-address control-std-set-configuration drop
+ my-usb-address to temp1
+ hd-buffer 9 erase
+ hd-buffer 9 control-get-hub-descriptor drop
+
+ \ PENDING: 1. Check Return value.
+ \ 2. HUB descriptor size is variable. Currently we r hardcoding
+ \ a value of 9.
+
+ hd-buffer 2 + c@ to temp2 \ number of downstream ports
+
+ s" HUB: Found " usb-debug-print
+ s" number of downstream hub ports! : " temp2 usb-debug-print-val
+ hd-buffer 5 + c@ to po2pg \ get bPwrOn2PwrGood
+
+ \ power on all present hub ports
+ \ to allow slow devices to set up
+
+ temp2 1+ 1 DO
+ i control-hub-port-power-set drop
+ d# 20 ms
+ LOOP
+
+ d# 200 ms \ some devices need a long time (10s)
+
+ \ now start detection and configuration for these ports
+
+ temp2 1+ 1 DO
+ s" hub-configure-port: " i usb-debug-print-val
+ i hub-configure-port
+ LOOP
+;
+
+
+\ --------------------------------------------------------------------------
+\ To initialize hub
+\ --------------------------------------------------------------------------
+
+(allocate-mem)
+mps-property-set
+hub-enumerate
+(de-allocate-mem)
+
diff --git a/slof/fs/usb/usb-kbd-device-support.fs b/slof/fs/usb/usb-kbd-device-support.fs
new file mode 100644
index 0000000..9fa4236
--- /dev/null
+++ b/slof/fs/usb/usb-kbd-device-support.fs
@@ -0,0 +1,102 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+00 value kbd-addr
+to kbd-addr
+8 alloc-mem to kbd-report
+4 chars alloc-mem value kbd-data
+
+: rw-endpoint
+ s" rw-endpoint" $call-parent ;
+
+: controlxfer
+ s" controlxfer" $call-parent ;
+
+: control-std-get-device-descriptor
+ s" control-std-get-device-descriptor" $call-parent ;
+
+: control-std-get-configuration-descriptor
+ s" control-std-get-configuration-descriptor" $call-parent ;
+
+: control-std-set-configuration
+ s" control-std-set-configuration" $call-parent ;
+
+: control-cls-set-protocol ( reportvalue FuncAddr -- TRUE|FALSE )
+ to temp1
+ to temp2
+ 210b000000000100 setup-packet !
+ temp2 kbd-data l!-le
+ 1 kbd-data 1 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer
+;
+
+: control-cls-set-idle ( reportvalue FuncAddr -- TRUE|FALSE )
+ to temp1
+ to temp2
+ 210a000000000000 setup-packet !
+ temp2 kbd-data l!-le
+ 0 kbd-data 0 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer
+;
+
+: control-std-get-report-descriptor ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE )
+ to temp1
+ to temp2
+ to temp3
+ 8106002200000000 setup-packet !
+ temp3 setup-packet 6 + w!-le
+ 0 swap temp3 setup-packet temp2 temp1 controlxfer
+;
+
+: kbd-init
+ s" Starting to initialize keyboard" usb-debug-print
+ s" MPS-INTIN" get-my-property
+ if
+ s" not possible" usb-debug-print
+ else
+ decode-int nip nip to mps-int-in
+ then
+ s" INT-IN-EP-ADDR" get-my-property
+ if
+ s" not possible" usb-debug-print
+ else
+ decode-int nip nip to int-in-ep
+ then
+
+ 7f alloc-mem to cfg-buffer
+ s" Allocated buffers!!" usb-debug-print
+
+ cfg-buffer 12 8 kbd-addr \ get device descriptor
+ control-std-get-device-descriptor
+ drop
+ \ s" dev_desc=" type cfg-buffer 12 dump cr
+
+ cfg-buffer 9 8 kbd-addr \ get config descriptor
+ control-std-get-configuration-descriptor
+ drop
+ \ s" cfg_desc=" type cfg-buffer 9 dump cr
+
+ cfg-buffer 5 + c@ kbd-addr \ set configuration
+ control-std-set-configuration
+ drop
+ s" KBDS: Set config returned" usb-debug-print
+
+ 0 kbd-addr control-cls-set-idle drop \ set idle
+ s" KBDS: Set idle returned" usb-debug-print
+
+ cfg-buffer 40 8 kbd-addr \ get report descriptor
+ control-std-get-report-descriptor
+ drop
+ \ s" report_desc=" type cfg-buffer 40 dump cr
+
+ s" Finished initializing keyboard" usb-debug-print
+;
+
diff --git a/slof/fs/usb/usb-keyboard.fs b/slof/fs/usb/usb-keyboard.fs
new file mode 100644
index 0000000..fd96e6e
--- /dev/null
+++ b/slof/fs/usb/usb-keyboard.fs
@@ -0,0 +1,371 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+s" keyboard" device-name
+s" keyboard" device-type
+
+." USB Keyboard" cr
+
+3 encode-int s" assigned-addresses" property
+1 encode-int s" reg" property
+1 encode-int s" configuration#" property
+s" EN" encode-string s" language" property
+
+1 constant NumLk
+2 constant CapsLk
+4 constant ScrLk
+
+00 value kbd-addr
+to kbd-addr \ save speed bit
+8 value mps-dcp
+8 constant DEFAULT-CONTROL-MPS
+8 chars alloc-mem value setup-packet
+8 chars alloc-mem value kbd-report
+4 chars alloc-mem value multi-key
+0 value cfg-buffer
+0 value led-state
+0 value temp1
+0 value temp2
+0 value temp3
+0 value ret
+0 value scancode
+0 value kbd-shift
+0 value kbd-scan
+0 value key-old
+0 value expire-ms
+0 value mps-int-in
+0 value int-in-ep
+0 value int-in-toggle
+
+kbd-addr \ give speed bit to include file
+s" usb-kbd-device-support.fs" included
+
+: control-cls-set-report ( reportvalue FuncAddr -- TRUE|FALSE )
+ to temp1
+ to temp2
+ 2109000200000100 setup-packet !
+ temp2 kbd-data l!-le
+ 1 kbd-data 1 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer
+;
+
+: control-cls-get-report ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE )
+ to temp1
+ to temp2
+ to temp3
+ a101000100000000 setup-packet !
+ temp3 setup-packet 6 + w!-le
+ 0 swap temp3 setup-packet temp2 temp1 controlxfer
+;
+
+: int-get-report ( -- ) \ get report for interrupt transfer
+ 0 2 int-in-toggle kbd-report 8 mps-int-in
+ kbd-addr int-in-ep 7 lshift or rw-endpoint \ get report
+ swap to int-in-toggle if
+ kbd-report @ ff00000000000000 and 38 rshift to kbd-shift \ store shift status
+ kbd-report @ 0000ffffffffffff and to kbd-scan \ store scan codes
+ else
+ 0 to kbd-shift \ clear shift status
+ 0 to kbd-scan \ clear scan code buffer
+ then
+;
+
+: ctl-get-report ( -- ) \ get report for control transfer
+ kbd-report 8 8 kbd-addr control-cls-get-report if \ get report
+ kbd-report @ ff00000000000000 and 38 rshift to kbd-shift \ store shift status
+ kbd-report @ 0000ffffffffffff and to kbd-scan \ store scan codes
+ else
+ 0 to kbd-shift \ clear shift status
+ 0 to kbd-scan \ clear scan code buffer
+ then
+;
+
+: set-led ( led -- )
+ dup to led-state
+ kbd-addr control-cls-set-report drop
+;
+
+: is-shift ( -- true|false )
+ kbd-shift 22 and if
+ true
+ else
+ false
+ then
+;
+
+: is-alt ( -- true|false )
+ kbd-shift 44 and if
+ true
+ else
+ false
+ then
+;
+
+: is-ctrl ( -- true|false )
+ kbd-shift 11 and if
+ true
+ else
+ false
+ then
+;
+
+: ctrl_alt_del_key ( char -- )
+ is-ctrl if \ ctrl is pressed?
+ is-alt if \ alt is pressed?
+ 4c = if \ del is pressed?
+ s" reboot.... " usb-debug-print
+ \ reset-all \ reboot
+ drop false \ invalidate del key on top of stack
+ then
+ false \ dummy for last drop
+ then
+ then
+ drop \ clear stack
+;
+
+: get-ukbd-char ( ScanCode -- char|false )
+ dup ctrl_alt_del_key \ check ctrl+alt+del
+ dup to scancode \ store scan code
+ case \ translate scan code --> char
+ 04 of [char] a endof
+ 05 of [char] b endof
+ 06 of [char] c endof
+ 07 of [char] d endof
+ 08 of [char] e endof
+ 09 of [char] f endof
+ 0a of [char] g endof
+ 0b of [char] h endof
+ 0c of [char] i endof
+ 0d of [char] j endof
+ 0e of [char] k endof
+ 0f of [char] l endof
+ 10 of [char] m endof
+ 11 of [char] n endof
+ 12 of [char] o endof
+ 13 of [char] p endof
+ 14 of [char] q endof
+ 15 of [char] r endof
+ 16 of [char] s endof
+ 17 of [char] t endof
+ 18 of [char] u endof
+ 19 of [char] v endof
+ 1a of [char] w endof
+ 1b of [char] x endof
+ 1c of [char] y endof
+ 1d of [char] z endof
+ 1e of [char] 1 endof
+ 1f of [char] 2 endof
+ 20 of [char] 3 endof
+ 21 of [char] 4 endof
+ 22 of [char] 5 endof
+ 23 of [char] 6 endof
+ 24 of [char] 7 endof
+ 25 of [char] 8 endof
+ 26 of [char] 9 endof
+ 27 of [char] 0 endof
+ 28 of 0d endof \ Enter
+ 29 of 1b endof \ ESC
+ 2a of 08 endof \ Backsace
+ 2b of 09 endof \ Tab
+ 2c of 20 endof \ Space
+ 2d of [char] - endof
+ 2e of [char] = endof
+ 2f of [char] [ endof
+ 30 of [char] ] endof
+ 31 of [char] \ endof
+ 33 of [char] ; endof
+ 34 of [char] ' endof
+ 35 of [char] ` endof
+ 36 of [char] , endof
+ 37 of [char] . endof
+ 38 of [char] / endof
+ 39 of led-state CapsLk xor set-led false endof \ CapsLk
+ 3a of 1b 7e31315b to multi-key endof \ F1
+ 3b of 1b 7e32315b to multi-key endof \ F2
+ 3c of 1b 7e33315b to multi-key endof \ F3
+ 3d of 1b 7e34315b to multi-key endof \ F4
+ 3e of 1b 7e35315b to multi-key endof \ F5
+ 3f of 1b 7e37315b to multi-key endof \ F6
+ 40 of 1b 7e38315b to multi-key endof \ F7
+ 41 of 1b 7e39315b to multi-key endof \ F8
+ 42 of 1b 7e30315b to multi-key endof \ F9
+ 43 of 1b 7e31315b to multi-key endof \ F10
+ 44 of 1b 7e33315b to multi-key endof \ F11
+ 45 of 1b 7e34315b to multi-key endof \ F12
+ 47 of led-state ScrLk xor set-led false endof \ ScrLk
+ 49 of 1b 7e315b to multi-key endof \ Ins
+ 4a of 1b 7e325b to multi-key endof \ Home
+ 4b of 1b 7e335b to multi-key endof \ PgUp
+ 4c of 1b 7e345b to multi-key endof \ Del
+ 4d of 1b 7e355b to multi-key endof \ End
+ 4e of 1b 7e365b to multi-key endof \ PgDn
+ 4f of 1b 435b to multi-key endof \ R-arrow
+ 50 of 1b 445b to multi-key endof \ L-arrow
+ 51 of 1b 425b to multi-key endof \ D-arrow
+ 52 of 1b 415b to multi-key endof \ U-arrow
+ 53 of led-state NumLk xor set-led false endof \ NumLk
+ 54 of [char] / endof \ keypad /
+ 55 of [char] * endof \ keypad *
+ 56 of [char] - endof \ keypad -
+ 57 of [char] + endof \ keypad +
+ 58 of 0d endof \ keypad Enter
+ 89 of [char] \ endof \ japanese yen
+ dup of false endof \ other keys are false
+ endcase
+ to ret \ store char
+ led-state CapsLk and 0 <> if \ if CapsLk is on
+ scancode 03 > if \ from a to z ?
+ scancode 1e < if
+ ret 20 - to ret \ to Upper case
+ then
+ then
+ then
+ is-shift if \ if shift is on
+ scancode 03 > if \ from a to z ?
+ scancode 1e < if
+ ret 20 - to ret \ to Upper case
+ else
+ scancode
+ case \ translate scan code --> char
+ 1e of [char] ! endof
+ 1f of [char] @ endof
+ 20 of [char] # endof
+ 21 of [char] $ endof
+ 22 of [char] % endof
+ 23 of [char] ^ endof
+ 24 of [char] & endof
+ 25 of [char] * endof
+ 26 of [char] ( endof
+ 27 of [char] ) endof
+ 2d of [char] _ endof
+ 2e of [char] + endof
+ 2f of [char] { endof
+ 30 of [char] } endof
+ 31 of [char] | endof
+ 33 of [char] : endof
+ 34 of [char] " endof
+ 35 of [char] ~ endof
+ 36 of [char] < endof
+ 37 of [char] > endof
+ 38 of [char] ? endof
+ dup of ret endof \ other keys are no change
+ endcase
+ to ret \ overwrite new char
+ then
+ then
+ then
+ led-state NumLk and 0 <> if \ if NumLk is on
+ scancode
+ case \ translate scan code --> char
+ 59 of [char] 1 endof
+ 5a of [char] 2 endof
+ 5b of [char] 3 endof
+ 5c of [char] 4 endof
+ 5d of [char] 5 endof
+ 5e of [char] 6 endof
+ 5f of [char] 7 endof
+ 60 of [char] 8 endof
+ 61 of [char] 9 endof
+ 62 of [char] 0 endof
+ 63 of [char] . endof \ keypad .
+ dup of ret endof \ other keys are no change
+ endcase
+ to ret \ overwirte new char
+ then
+ ret \ return char
+;
+
+: key-available? ( -- true|false )
+ multi-key 0 <> IF
+ true \ multi scan code key was pressed... so key is available
+ EXIT \ done
+ THEN
+ kbd-scan 0 = IF \ if no kbd-scan code is currently available
+ int-get-report \ check for one using int-get-report
+ THEN
+ kbd-scan 0 <> \ if a kbd-scan is available, report true, else false
+;
+
+: usb-kread ( -- char|false ) \ usb key read for control transfer
+ multi-key 0 <> if \ if multi scan code key is pressed
+ multi-key ff and \ read one byte from buffer
+ multi-key 8 rshift to multi-key \ move to next byte
+ else \ normal key check
+ \ check for new scan code only, if kbd-scan is not set, e.g.
+ \ by a previous call to key-available?
+ kbd-scan 0 = IF
+ \ if interrupt transfer
+ int-get-report \ read report (interrupt transfer)
+ \ else control transfer
+ \ ctl-get-report \ read report (control transfer)
+ \ end of interrupt/control switch
+ THEN
+ kbd-scan 0 <> if \ scan code exist?
+ begin kbd-scan ff and dup 00 = while \ get a last scancode in report buffer
+ kbd-scan 8 rshift to kbd-scan \ This algorithm is wrong --> must be fixed!
+ drop \ KBD doesn't set scancode in pressed order!!!
+ repeat
+ dup key-old <> if \ if the scancode is new
+ dup to key-old \ save current scan code
+ get-ukbd-char \ translate scan code --> char
+ milliseconds fa + to expire-ms \ set typematic delay 250ms
+ else \ scan code is not changed
+ milliseconds expire-ms > if \ if timer is expired ... should be considered timer carry over
+ get-ukbd-char \ translate scan code --> char
+ milliseconds 21 + to expire-ms \ set typematic rate 30cps
+ else \ timer is not expired
+ drop false \ do nothing
+ then
+ then
+ kbd-scan 8 rshift to kbd-scan \ handled scan-code
+ else
+ 0 to key-old \ clear privious key
+ false \ no scan code --> return false
+ then
+ then
+;
+
+
+: key-read ( -- char )
+ 0 begin drop usb-kread dup 0 <> until \ read key input (Interrupt transfer)
+;
+
+
+: read ( addr len -- actual )
+ 0= IF drop 0 EXIT THEN
+ usb-kread ?dup IF swap c! 1 ELSE 0 swap c! -2 THEN
+;
+
+
+kbd-init \ keyboard initialize
+milliseconds to expire-ms \ Timer initialize
+0 to multi-key \ multi key buffer clear
+7 set-led \ flash leds
+250 ms
+0 set-led
+
+s" keyboard" get-node node>path set-alias
+
+: open ( -- true )
+ 7 set-led
+ 100 ms
+ 3 set-led
+ 100 ms
+ 1 set-led
+ 100 ms
+ \ read once from keyboard before actually using it
+ usb-kread drop
+ 0 set-led
+ true
+;
+
+: close ;
diff --git a/slof/fs/usb/usb-mouse.fs b/slof/fs/usb/usb-mouse.fs
new file mode 100644
index 0000000..bd6fa50
--- /dev/null
+++ b/slof/fs/usb/usb-mouse.fs
@@ -0,0 +1,28 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+s" mouse" device-name
+s" mouse" device-type
+
+." USB Mouse" cr
+
+1 encode-int s" configuration#" property
+2 encode-int s" #buttons" property
+4 encode-int s" assigned-addresses" property
+2 encode-int s" reg" property
+
+: open true ;
+: close ;
+: get-event ( msec -- pos.x pos.y buttons true|false )
+;
+
diff --git a/slof/fs/usb/usb-ohci.fs b/slof/fs/usb/usb-ohci.fs
new file mode 100644
index 0000000..f4d9670
--- /dev/null
+++ b/slof/fs/usb/usb-ohci.fs
@@ -0,0 +1,1190 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ We expect to base address of the OHCI controller on the stack:
+
+CONSTANT baseaddrs
+
+s" OHCI base address = " baseaddrs usb-debug-print-val
+
+
+\ Open Firmware Properties
+
+
+s" usb" 2dup device-name device-type
+1 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+
+\ converts physical address to text unit string
+
+
+: encode-unit ( port -- unit-str unit-len ) 1 hex-encode-unit ;
+
+
+\ Converts text unit string to phyical address
+
+
+: decode-unit ( addr len -- port ) 1 hex-decode-unit ;
+
+
+\ Data Structure Definitions
+\ OHCI Task Descriptor Structure.
+
+
+STRUCT
+ /l field td>tattr
+ /l field td>cbptr
+ /l field td>ntd
+ /l field td>bfrend
+CONSTANT /tdlen
+
+
+\ OHCI Endpoint Descriptor Structure.
+
+
+STRUCT
+ /l field ed>eattr
+ /l field ed>tdqtp
+ /l field ed>tdqhp
+ /l field ed>ned
+CONSTANT /edlen
+
+
+\ HCCA Done queue location packaged as a structure for ease OF use.
+
+
+STRUCT
+ /l field hc>hcattr
+ /l field hc>hcdone
+CONSTANT /hclen
+
+
+\ OHCI Memory Mapped Registers
+
+
+\ : get-base-address ( -- baseaddr )
+\ s" assigned-addresses" get-my-property IF
+\ s" not possible" usb-debug-print
+\ -1
+\ ELSE ( addr len )
+\ decode-int drop ( addr len )
+\ decode-int drop ( addr len )
+\ decode-int nip nip ( n )
+\ THEN
+\ \ TODO: Use translate-address here
+\ ;
+
+\ get-base-address CONSTANT baseaddrs
+
+baseaddrs CONSTANT HcRevision
+baseaddrs 4 + CONSTANT hccontrol
+baseaddrs 8 + CONSTANT hccomstat
+baseaddrs 0c + CONSTANT hcintstat
+baseaddrs 14 + CONSTANT hcintdsbl
+baseaddrs 18 + CONSTANT hchccareg
+baseaddrs 20 + CONSTANT hcctrhead
+baseaddrs 24 + CONSTANT hccurcont
+baseaddrs 28 + CONSTANT hcbulkhead
+baseaddrs 2c + CONSTANT hccurbulk
+baseaddrs 30 + CONSTANT hcdnehead
+baseaddrs 34 + CONSTANT hcintrval
+baseaddrs 40 + CONSTANT HcPeriodicStart
+baseaddrs 48 + CONSTANT hcrhdescA
+baseaddrs 4c + CONSTANT hcrhdescB
+baseaddrs 50 + CONSTANT HcRhStatus
+baseaddrs 54 + CONSTANT hcrhpstat
+baseaddrs 58 + CONSTANT hcrhpstat2
+baseaddrs 5c + CONSTANT hcrhpstat3
+
+usb-debug-flag IF
+ 0 config-l@ ." - VENDOR: " 8 .r cr
+ 40 config-l@ ." - PMC : " 8 .r
+ 44 config-l@ ." PMCSR : " 8 .r cr
+ E0 config-l@ ." - EXT1 : " 8 .r
+ E4 config-l@ ." EXT2 : " 8 .r cr
+THEN
+
+\ Constants for INTSTAT register
+
+2 CONSTANT WDH
+
+\ Constants for RH Port Status Register
+
+1 CONSTANT RHP-CCS \ Current Connect Status
+2 CONSTANT RHP-PES \ Port Enable Status
+10 CONSTANT RHP-PRS \ Port Reset Status
+100 CONSTANT RHP-PPS \ Port Power Status
+10000 CONSTANT RHP-CSC \ Connect Status Changed
+100000 CONSTANT RHP-PRSC \ Port Reset Status Changed
+
+
+\ Constants for OHCI
+
+0 CONSTANT OHCI-DP-SETUP
+1 CONSTANT OHCI-DP-OUT
+2 CONSTANT OHCI-DP-IN
+3 CONSTANT OHCI-DP-INVALID
+
+\ 8-byte Standard Device Requests + Hub class specific requests.
+
+8006000100001200 CONSTANT get-ddescp
+8006000200000900 CONSTANT get-cdescp
+8006000400000900 CONSTANT get-idescp
+8006000500000700 CONSTANT get-edescp
+A006000000001000 CONSTANT get-hdescp
+0009010000000000 CONSTANT set-cdescp
+2303010004000000 CONSTANT hpenable-set
+2303040001000000 CONSTANT hp1rst-set
+2303040002000000 CONSTANT hp2rst-set
+2303040003000000 CONSTANT hp3rst-set
+2303040004000000 CONSTANT hp4rst-set
+2303080001000000 CONSTANT hp1pwr-set
+2303080002000000 CONSTANT hp2pwr-set
+2303080003000000 CONSTANT hp3pwr-set
+2303080004000000 CONSTANT hp4pwr-set
+A003000000000400 CONSTANT hstatus-get
+A300000001000400 CONSTANT hp1sta-get
+A300000002000400 CONSTANT hp2sta-get
+A300000003000400 CONSTANT hp3sta-get
+A300000004000400 CONSTANT hp4sta-get
+8008000000000100 CONSTANT get-config
+
+A1FE000000000100 CONSTANT GET-MAX-LUN
+
+2 18 lshift CONSTANT DATA0-TOGGLE
+3 18 lshift CONSTANT DATA1-TOGGLE
+0f 1c lshift CONSTANT CC-FRESH-TD
+8 CONSTANT STD-REQUEST-SETUP-SIZE
+0 13 lshift CONSTANT TD-DP-SETUP
+1 13 lshift CONSTANT TD-DP-OUT
+2 13 lshift CONSTANT TD-DP-IN
+
+400001 CONSTANT ed-cntatr
+400002 CONSTANT ed-cntatr1
+80081 CONSTANT ed-hubatr
+80000 CONSTANT ed-defatr
+0f0e40000 CONSTANT td-attr
+00 VALUE ptr
+
+
+\ TD Management constants and Data structures.
+
+
+200 CONSTANT MAX-TDS
+0 VALUE td-freelist-head
+0 VALUE td-freelist-tail
+0 VALUE num-free-tds
+0 VALUE max-rh-ports
+0 VALUE current-stat
+
+INSTANCE VARIABLE td-list-region
+
+\ ED Management constants
+
+
+14 CONSTANT MAX-EDS
+0 VALUE ed-freelist-head
+0 VALUE num-free-eds
+INSTANCE VARIABLE ed-list-region
+0 VALUE usb-address
+0 VALUE initial-hub-address
+0 VALUE new-device-address
+0 VALUE mps
+0 VALUE DEBUG-TDS
+0 VALUE case-failed \ available for general use to see IF a CASE statement
+ \ failed or not.
+0 VALUE WHILE-failed \ available for general use to see IF a WHILE LOOP
+ \ failed in the middle. Used to break from the
+ \ WHILE LOOP
+
+8 CONSTANT DEFAULT-CONTROL-MPS
+12 CONSTANT DEVICE-DESCRIPTOR-LEN
+1 CONSTANT DEVICE-DESCRIPTOR-TYPE
+1 CONSTANT DEVICE-DESCRIPTOR-TYPE-OFFSET
+4 CONSTANT DEVICE-DESCRIPTOR-DEVCLASS-OFFSET
+7 CONSTANT DEVICE-DESCRIPTOR-MPS-OFFSET
+
+20 CONSTANT BULK-CONFIG-DESCRIPTOR-LEN
+
+9 CONSTANT HUB-DEVICE-CLASS
+0 CONSTANT NO-CLASS
+
+VARIABLE setup-packet \ 8 bytes for setup packet
+VARIABLE ch-buffer \ 1 byte character buffer
+
+INSTANCE VARIABLE dd-buffer
+INSTANCE VARIABLE cd-buffer
+
+
+\ Temporary variables for functions. These variables have to be initialized
+\ before usage in functions and their values assume significance only during
+\ the function's execution time. Should be used like local variables.
+\ CAUTION:
+\ If you are calling functions that destroy contents OF these variables, be
+\ smart enuf to save the values before calling them.
+\ It is recommended that these temporary variables are used only amidst normal
+\ FORTH words -- not among the vicinity OF any OF the functions OF this node.
+
+
+0 VALUE temp1
+0 VALUE temp2
+0 VALUE temp3
+0 VALUE extra-bytes
+0 VALUE num-td
+0 VALUE current
+
+0 VALUE device-speed
+
+
+\ Debug functions for displaying ED, TD and their combo list.
+
+: Show-OHCI-Register
+ ." -> OHCI-Register: " cr
+ ." - HcControl : " hccontrol rl@-le 8 .r
+ ." CmdStat : " hccomstat rl@-le 8 .r
+ ." HcInterr. : " hcintstat rl@-le 8 .r cr
+
+ ." - HcFmIntval: " hcintrval rl@-le 8 .r
+ ." Per. Start: " HcPeriodicStart rl@-le 8 .r cr
+
+ ." - PortStat-1: " hcrhpstat rl@-le 8 .r
+ ." PortStat-2: " hcrhpstat2 rl@-le 8 .r
+ ." PortStat-3: " hcrhpstat3 rl@-le 8 .r cr
+
+ ." Descr-A : " hcrhdescA rl@-le 8 .r
+ ." Descr-B : " hcrhdescB rl@-le 8 .r
+ ." HcRhStat : " HcRhStatus rl@-le 8 .r cr
+;
+
+: display-ed ( ED-ADDRESS -- )
+ TO temp1
+ usb-debug-flag IF
+ s" Dump OF ED " type temp1 u. cr
+ s" eattr : " type temp1 ed>eattr l@-le u. cr
+ s" tdqhp : " type temp1 ed>tdqhp l@-le u. cr
+ s" tdqtp : " type temp1 ed>tdqtp l@-le u. cr
+ s" ned : " type temp1 ed>ned l@-le u. cr
+ THEN
+;
+
+
+\ Displays the transfer descriptors
+
+: display-td ( TD-ADDRESS -- )
+ TO temp1
+ usb-debug-flag IF
+ s" TD " type temp1 u. s" dump: " type cr
+ s" td>tattr : " type temp1 td>tattr l@-le u. cr
+ s" td>cbptr : " type temp1 td>cbptr l@-le u. cr
+ s" td>ntd : " type temp1 td>ntd l@-le u. cr
+ s" td>bfrend : " type temp1 td>bfrend l@-le u. cr
+ THEN
+;
+
+
+\ display's the descriptors
+
+
+: display-descriptors ( ED-ADDRESS -- )
+ 10 1- not and ( ED-ADDRESS~ )
+ dup display-ed ed>tdqhp l@-le BEGIN ( ED-ADDRESS~ )
+ 10 1- not and ( ED-ADDRESS~ )
+ dup 0<> ( ED-ADDRESS~ TRUE | FALSE )
+ WHILE
+ dup display-td td>ntd l@-le ( ED-ADDRESS~ )
+ REPEAT
+ drop
+;
+
+
+\ ---------------------------------------------------------------------------
+\ TD LIST MANAGEMENT WORDS
+\ ------------------------
+\ The following are WORDS internal to this node. They are supposed to
+\ be used by other WORDS inside this device node.
+\ The first three WORDS below form the interface. The fourth and fifth
+\ word is a helper function and is not exposed to other portions OF this
+\ device node.
+\ a) initialize-td-free-list
+\ b) allocate-td-list
+\ c) (free-td-list)
+\ d) find-td-list-tail-and-size
+\ e) zero-out-a-td-except-link
+\ ----------------------------------------------------------------------------
+
+
+: zero-out-a-td-except-link ( td -- )
+
+
+ \ There r definitely smarter ways to DO it especially
+ \ on a 64-bit machine.
+
+ \ Optimization, Portability:
+ \ --------------------------
+ \ Replace the following code by two "!" OF zeroes. Since
+ \ we know that an "td" is actually 16 bytes and that we
+ \ will be executing on a 64-bit machine, we can finish OFf
+ \ with 2 stores. But that WONT be portable.
+
+
+ dup 0 swap td>tattr l!-le ( td )
+ dup 0 swap td>cbptr l!-le ( td )
+ dup 0 swap td>bfrend l!-le ( td )
+ drop
+;
+
+
+\ COLON DEFINITION: initialize-td-free-list - Internal Function
+
+\ Initialize the TD Free List Region and create a linked list OF successive
+\ TDs. Note that the NEXT pointers are all in little-endian and they
+\ can be directly used for HC purposes.
+
+
+: initialize-td-free-list ( -- )
+ MAX-TDS 0= IF EXIT THEN
+ td-list-region @ 0= IF EXIT THEN
+ td-list-region @ TO temp1
+ 0 TO temp2 BEGIN
+ temp1 zero-out-a-td-except-link
+ temp1 /tdlen + dup temp1 td>ntd l!-le TO temp1
+ temp2 1+ TO temp2
+ temp2 MAX-TDS = ( TRUE | FALSE )
+ UNTIL
+ temp1 /tdlen - dup 0 swap td>ntd l!-le TO td-freelist-tail
+ td-list-region @ TO td-freelist-head
+ MAX-TDS TO num-free-tds
+;
+
+
+\ COLON DEFINITION: allocate-td-list -- Internal function
+\ Argument:
+\ The function accepts a non-negative number and allocates
+\ a TD-LIST containing that many TDs. A TD-LIST is a list
+\ OF TDs that are linked by the next-td field. The next-td
+\ field is in little-endian mode so that the TD list can
+\ be directly re-used by the HC.
+\ Return value:
+\ The function returns "head" and "tail" OF the allocated
+\ TD-LIST. If for any reason, the function cannot allocate
+\ the TD-LIST, the function returns 2 NULL pointers in the
+\ stack indicating that the allocation failed.
+
+\ Note that the TD list returned is NULL terminated. i.e
+\ the nextTd field OF the tail is NULL.
+
+
+
+: allocate-td-list ( n -- head tail )
+ dup 0= IF drop 0 0 EXIT THEN ( 0 0 )
+ dup num-free-tds > IF drop 0 0 EXIT THEN ( 0 0 )
+ dup num-free-tds = IF ( n )
+ drop td-freelist-head td-freelist-tail ( td-freelist-head td-freelist-tail )
+ 0 TO td-freelist-head ( td-freelist-head td-freelist-tail )
+ 0 TO td-freelist-tail ( td-freelist-head td-freelist-tail )
+ 0 TO num-free-tds ( td-freelist-head td-freelist-tail )
+ EXIT
+ THEN
+
+ \ If we are here THEN we know that the requested number OF TDs is less
+ \ than what we actually have. We need TO traverse the list and find the
+ \ new Head pointer position and THEN update the head pointer accordingly.
+ \ Update num-free-tds
+
+ dup num-free-tds swap - TO num-free-tds ( n )
+
+ \ Traverse through the Free list to identify the element that exists after
+ \ "n" TDs. Use the info to return the head and tail pointer and update
+ \ the new td-list-head
+
+ td-freelist-head ( n td-list-head )
+ dup TO temp1 ( n td-list-head )
+ swap ( td-list-head n )
+ 0 DO ( td-list-head )
+ temp1 TO temp2 ( td-list-head )
+ temp1 td>ntd l@-le TO temp1 ( td-list-head )
+ LOOP ( td-list-head )
+ temp2 ( td-list-head td-list-tail )
+ dup td>ntd 0 swap l!-le ( td-list-head td-list-tail )
+ temp1 TO td-freelist-head ( td-list-head td-list-tail )
+;
+
+
+\ COLON DEFINITION: find-td-list-tail-and-size
+\ This function counts the number OF TD elements
+\ in the given list. It also returns the last tail
+\ TD OF the TD list.
+
+\ ASSUMPTION:
+\ A NULL terminated TD list is assumed. A not-well formed
+\ list can result in in-determinate behaviour.
+
+\ ROOM FOR ENHANCEMENT:
+\ We could arrive at a generic function for counting
+\ list elements to which the next-ptr OFfset can also
+\ be passed as an argument (in this case it is >ntd)
+\ This function can THEN be changed to call the
+\ function with "0 >ntd" as an additional argument
+\ (apart from head and tail)
+
+
+: find-td-list-tail-and-size ( head -- tail n )
+ TO temp1
+ 0 TO temp2
+ 0 TO temp3
+ DEBUG-TDS IF
+ s" BEGIN find-td-list-tail-and-size: " usb-debug-print
+ THEN
+ BEGIN
+ temp1 0<> ( TRUE|FALSE )
+ WHILE
+ DEBUG-TDS IF
+ temp1 u. cr
+ THEN
+ temp1 TO temp3
+ temp1 td>ntd l@-le TO temp1
+ temp2 1+ TO temp2
+ REPEAT
+ temp3 temp2 ( tail n )
+ DEBUG-TDS IF
+ s" END find-td-list-tail-and-size" usb-debug-print
+ THEN
+;
+
+
+\ COLON DEFINITION: (free-td-list)
+
+\ Arguments: (head --)
+\ The "head" pointer OF the TD-LIST to be freed is passed as
+\ an argument to this function. The function merely adds the list to the
+\ already existing TD-LIST
+
+\ Assumptions:
+\ The function assumes that the TD-LIST passed as argument is a well-formed
+\ list. The function does not DO any check on it.
+\ But since, the "TD-LIST" is generally freed from the DONE-QUEUE which is
+\ a well-formed list, the interface makes much sense.
+
+\ Return values:
+\ Nothing is returned. The arguments passed are popped OFf.
+
+
+: (free-td-list) ( head -- )
+
+ \ Enhancement:
+ \ We could zero-out-a-td-except-link for the TD list that is being freed.
+ \ This way, we could prevent some nasty repercussions OF bugs (that r yet
+ \ to be discovered). but we can include this enhancement during the testing
+ \ phase.
+
+ dup find-td-list-tail-and-size num-free-tds + TO num-free-tds ( head tail )
+ td-freelist-tail 0= IF ( head tail )
+ dup TO td-freelist-tail ( head tail )
+ THEN ( head tail )
+ td>ntd td-freelist-head swap l!-le ( head )
+ TO td-freelist-head
+;
+
+
+\ END OF TD LIST MANAGEMENT WORDS
+\ ED Management section BEGINs
+\ ----------------------------
+
+
+: zero-out-an-ed-except-link ( ed -- )
+
+ \ There are definitely smarter ways to do it especially
+ \ on a 64-bit machine.
+
+ \ Optimization, Portability:
+ \ --------------------------
+ \ Replace by a "!" and "l!". we know that an "ed" is
+ \ actually 16 bytes and that we will be executing on
+ \ a 64-bit machine, we can finish OFf with 2 stores.
+ \ But that WONT be portable.
+
+ dup 0 swap ed>eattr l!-le ( ed )
+ dup 0 swap ed>tdqtp l!-le ( ed )
+ dup 0 swap ed>tdqhp l!-le ( ed )
+ drop
+;
+
+\ Intialises ed-list afresh
+
+: initialize-ed-free-list ( -- )
+ MAX-EDS 0= IF EXIT THEN
+ ed-list-region @ 0= IF
+ s" init-ed-list: ed-list-region is not allocated!" usb-debug-print
+ EXIT
+ THEN
+ ed-list-region @ TO temp1
+ 0 TO temp2 BEGIN
+ temp1 zero-out-an-ed-except-link
+ temp1 /edlen + dup temp1 ed>ned l!-le TO temp1
+ temp2 1+ TO temp2
+ temp2 MAX-EDS =
+ UNTIL
+ temp1 /edlen - ed>ned 0 swap l!-le
+ ed-list-region @ TO ed-freelist-head
+ MAX-EDS TO num-free-eds
+;
+
+
+\ allocate an ed and return ed address
+
+
+: allocate-ed ( -- ed-ptr )
+ num-free-eds 0= IF 0 EXIT THEN
+ ed-freelist-head ( ed-freelist-head )
+ ed-freelist-head ed>ned l@-le TO ed-freelist-head ( ed-freelist-head )
+ num-free-eds 1- TO num-free-eds ( ed-freelist-head )
+ dup ed>ned 0 swap l!-le \ Terminate the Link. ( ed-freelist-head )
+;
+
+
+\ free the given ed pointer
+
+: free-ed ( ed-ptr -- )
+ dup zero-out-an-ed-except-link ( ed-ptr )
+ dup ed>ned ed-freelist-head swap l!-le ( ed-ptr )
+ TO ed-freelist-head
+ num-free-eds 1+ TO num-free-eds
+;
+
+
+\ Buffer allocations
+\ ------------------
+\ Note:
+\ -----
+\ 1. What should we DO IF alloc-mem fails ?
+\ 2. alloc-mem must return aligned memory addresses.
+\ 3. alloc-mem must return DMAable memory!
+
+\ Memory for the HCCA - must stay allocated as long as the HC is operational!
+100 alloc-mem VALUE hchcca
+hchcca ff and IF
+ \ This should never happen - alloc-mem always aligns
+ s" Warning: hchcca not aligned!" usb-debug-print
+THEN
+
+84 hchcca + CONSTANT hchccadneq
+
+
+: (allocate-mem) ( -- )
+ /tdlen MAX-TDS * 10 + alloc-mem dup td-list-region ! ( td-list-region-ptr )
+ f and IF
+ s" Warning: td-list-region not aligned!" usb-debug-print
+ THEN
+ initialize-td-free-list
+
+ /edlen MAX-EDS * 10 + alloc-mem dup ed-list-region ! ( ed-list-region-ptr )
+ f and IF
+ s" Warning: ed-list-region not aligned!" usb-debug-print
+ THEN
+ initialize-ed-free-list
+
+ DEVICE-DESCRIPTOR-LEN chars alloc-mem dd-buffer !
+ BULK-CONFIG-DESCRIPTOR-LEN chars alloc-mem cd-buffer !
+;
+
+
+\ The method makes sure that when the host node is closed all
+\ associated buffer allocations made for data-structures as
+\ well as data-buffers are freed
+
+: (de-allocate-mem) ( -- )
+ td-list-region @ ?dup IF
+ /tdlen MAX-TDS * 10 + free-mem
+ 0 td-list-region !
+ THEN
+ ed-list-region @ ?dup IF
+ /edlen MAX-EDS * 10 + free-mem
+ 0 ed-list-region !
+ THEN
+ dd-buffer @ ?dup IF
+ DEVICE-DESCRIPTOR-LEN free-mem
+ 0 dd-buffer !
+ THEN
+ cd-buffer @ ?dup IF
+ BULK-CONFIG-DESCRIPTOR-LEN free-mem
+ 0 cd-buffer !
+ THEN
+;
+
+
+\ Suspend hostcontroller (and the bus).
+\ This method must be called before the operating system starts.
+\ It prevents the HC from doing DMA in the background during boot
+\ (e.g. updating its frame number counter in the HCCA)
+
+: hc-suspend ( -- )
+ \ s" USB HC suspend with hccontrol=" type hccontrol . cr
+ 00C3 hccontrol rl!-le \ Suspend USB host controller
+;
+
+
+\ OF methods
+
+: open ( -- TRUE|FALSE )
+ (allocate-mem)
+ TRUE
+;
+
+: close ( -- )
+ (de-allocate-mem)
+;
+
+
+\ COLON DEFINITION: HC-enable-control-list-processing
+\ Enables USB HC transactions on control list.
+
+: HC-enable-control-list-processing ( -- )
+ hccomstat dup rl@-le 02 or swap rl!-le
+ hccontrol dup rl@-le 10 or swap rl!-le
+;
+
+
+\ COLON DEFINTION: HC-enable-bulk-list-processing
+\ PENDING: Remove Hard coded constants.
+
+: HC-enable-bulk-list-processing ( -- )
+ hccomstat dup rl@-le 04 or swap rl!-le
+ hccontrol dup rl@-le 20 or swap rl!-le
+;
+
+
+: HC-enable-interrupt-list-processing ( -- )
+ hccontrol dup rl@-le 04 or swap rl!-le
+;
+
+
+\ Clearing WDH to allow HC to write into DOne queue again
+
+: (HC-ACK-WDH) ( -- ) WDH hcintstat rl!-le ;
+
+\ Checking whether anything has been written into DOne queue
+
+: (HC-CHECK-WDH) ( -- ) hcintstat rl@-le WDH and 0<> ;
+
+
+\ Disable USB transaction and keep it ready
+
+: disable-control-list-processing ( -- )
+ hccontrol dup rl@-le ffffffef and swap rl!-le
+ hccomstat dup rl@-le fffffffd and swap rl!-le
+;
+
+: disable-bulk-list-processing ( -- )
+ hccontrol dup rl@-le ffffffdf and swap rl!-le
+ hccomstat dup rl@-le fffffffb and swap rl!-le
+;
+
+
+: disable-interrupt-list-processing ( -- )
+ hccontrol dup rl@-le fffffffb and swap rl!-le
+;
+
+
+\ COLON DEFINITION: fill-TD-list
+
+\ This function accepts a TD list and a data-buffer and
+\ distributes this data buffer over the TD list depending
+\ on the Max Packet Size.
+
+\ Arguments:
+\ ----------
+\ (from bottom OF stack)
+\ 1. addr -- Address OF the data buffer
+\ 2. dlen -- Length OF the data buffer above.
+\ 3. dir -- Tells whether the TDs r for an IN or
+\ OUT transaction.
+\ 4. MPS -- Maximum Packet Size associated with the endpoint
+\ that will use this TD list.
+\ 5. TD-List-Head - Head pointer OF the List OF TDs.
+\ This list is NOT expected to be NULL terminated.
+
+\ Assumptions:
+\ -----------
+\ 1. TD-List for data is well-formed and has sufficient entries
+\ to hold "dlen".
+\ 2. The TDs toggle field is assumed to be taken from the endpoint
+\ descriptor's "toggle carry" field.
+\ 3. Assumes that the caller specifies the correct start-toggle.
+\ If the caller specifies a wrong data toggle OF 1 for a SETUP
+\ PACKET, this method will not find it out.
+
+\ COLON DEFINTION: (toggle-current-toggle)
+\ Scope: Internal to fill-TD-list
+\ Functionality:
+\ Toggles the "T" field that is passed as argument.
+\ "T" as in the "T" field OF the TD.
+
+0 VALUE current-toggle
+: fill-TD-list ( start-toggle addr dlen dp MPS TD-List-Head -- )
+ TO temp1 ( start-toggle addr dlen dp MPS )
+ TO temp2 ( start-toggle addr dlen dp )
+ CASE ( start-toggle addr dlen )
+ OHCI-DP-SETUP OF TD-DP-SETUP TO temp3 ENDOF ( start-toggle addr dlen )
+ OHCI-DP-IN OF TD-DP-IN TO temp3 ENDOF ( start-toggle addr dlen )
+ OHCI-DP-OUT OF TD-DP-OUT TO temp3 ENDOF ( start-toggle addr dlen )
+ dup OF -1 TO temp3 ( start-toggle addr dlen )
+ s" fill-TD-list: Invalid DP specified" usb-debug-print
+ ENDOF
+ ENDCASE
+ temp3 -1 = IF EXIT THEN ( start-toggle addr dlen )
+
+
+\ temp1 -- TD-List-Head
+\ temp2 -- Max Packet Size
+\ temp3 -- TD-DP-IN or TD-DP-OUT or TD-DP-SETUP
+
+ rot ( addr dlen start-toggle )
+ TO current-toggle swap ( dlen addr )
+ BEGIN
+ over temp2 >= ( dlen addr TRUE|FALSE )
+ WHILE ( dlen addr )
+ dup temp1 td>cbptr l!-le ( dlen addr )
+ current-toggle 18 lshift ( dlen addr current-toggle~ )
+ DATA0-TOGGLE ( dlen addr current-toggle~ toggle )
+ CC-FRESH-TD temp3 or or or ( dlen addr or-result )
+ temp1 td>tattr l!-le ( dlen addr~ )
+ dup temp2 1- + temp1 td>bfrend l!-le ( dlen addr~ )
+ temp2 + ( dlen next-addr )
+ swap temp2 - swap
+ temp1 td>ntd l@-le TO temp1 ( dlen next-addr )
+ current-toggle ( dlen next-addr current-toggle )
+ CASE
+ 0 OF 1 TO current-toggle ENDOF
+ 1 OF 0 TO current-toggle ENDOF
+ ENDCASE
+ REPEAT ( dlen addr )
+ over 0<> IF
+ dup temp1 td>cbptr l!-le ( dlen addr )
+ current-toggle 18 lshift ( dlen addr curent-toggle~ )
+ DATA0-TOGGLE ( dlen addr curent-toggle~ toggle )
+ CC-FRESH-TD temp3 or or or ( dlen addr or-result )
+ temp1 td>tattr l!-le ( dlen addr )
+ + 1- temp1 td>bfrend l!-le
+ ELSE
+ 2drop
+ THEN
+;
+
+
+\ COLON DEFINITION: (td-list-status )
+\ FUNCTIONALITY:
+\ To traverse the TD list to check for a TD carrying non-zero CC return the
+\ respective TD address and CC ELSE 0
+\ SCOPE:
+\ Internal method
+
+: (td-list-status) ( PointerToTDlist -- failingTD CCode TRUE | 0 )
+ BEGIN ( PointerToTDlist )
+ dup 0<> ( PointerToTDlist TRUE|FALSE )
+ IF ( PointerToTDlist )
+ dup td>tattr l@-le f0000000 and 1c rshift dup 0= TRUE swap
+ ( PointerToTDlist CCode TRUE TRUE|FALSE )
+ ELSE
+ drop FALSE dup ( FALSE )
+ THEN
+ WHILE
+ drop drop td>ntd l@-le
+ REPEAT
+;
+
+
+\ ==================================================================
+\ COLON DEFINITION: (wait-for-done-q)
+\ FUNCTIONALITY:
+\ To DO a timed polling OF the DOne queue and acknowledge and return
+\ the address OF the last retired Td list
+\ SCOPE:
+\ Internal method
+\ ==================================================================
+
+: (wait-for-done-q) ( timeout -- TD-list TRUE | FALSE )
+ BEGIN ( timeout )
+ dup 0<> ( timeout TRUE|FALSE )
+ (HC-CHECK-WDH) NOT ( timeout TRUE|FALSE TRUE|FALSE )
+ AND \ not timed out AND WDH-bit not set
+ WHILE
+ 1 ms \ wait
+ 1- ( timeout )
+ dup ff and 0= IF show-proceed THEN
+ REPEAT ( timeout )
+ drop
+ hchccadneq l@-le \ read last HcDoneHead (RAM)
+ (HC-CHECK-WDH) \ HcDoneHead was updated ?
+ IF
+ (HC-ACK-WDH) \ clear register bit: WDH
+ TRUE ( td-list TRUE )
+ ELSE
+ FALSE
+ THEN
+;
+
+
+\ displays free tds
+
+
+: debug-td ( -- )
+ s" Num Free TDs = " num-free-tds usb-debug-print-val
+;
+
+
+\ display content of frame counter
+
+\ : debug-frame-counter ( -- )
+\ 40 1 DO
+\ ." Frame ct at HCCA at end OF enumeration = "
+\ hchcca 80 + rl@-le .
+\ LOOP
+\ ;
+
+\ ============================================================================
+\ COLON DEFINITION: HC-reset
+\ This routine should be the first to be executed.
+\ This routine will reset the HC and will bring it to Operational
+\ state.
+\ PENDING:
+\ Arrive at the right value OF FrameInterval. Currently we are hardcoding
+\ it.
+\ ==========================================================================
+: HC-reset ( -- )
+
+ hccomstat dup rl@-le 01 or swap rl!-le \ issue HC reset
+ BEGIN
+ hccomstat rl@-le 01 and 0<> \ wait for reset end
+ WHILE
+ REPEAT
+
+ 23f02edf hcintrval rl!-le \ frame-interval register
+ hchcca hchccareg rl!-le \ HC communication area
+ 0000 hcctrhead rl!-le \ control transfer head
+ 0000 hcbulkhead rl!-le \ bulk transfer head
+ 0ffff hcintdsbl rl!-le \ interrupt disable reg.
+
+\ all devices are still in reset-state
+\ next command starts sending SOFs
+ 83 hccontrol rl!-le \ set USBOPERATIONAL
+
+\ these two repeated register settings are necessary for Bimini
+\ Its OHCI controller (AM8111) behaves different to NEC's one
+ 23f02edf hcintrval rl!-le \ frame-interval register
+ hchcca hchccareg rl!-le \ HC communication area
+
+ d# 50 ms
+
+ hcrhdescA rl@-le ff and ( total-rh-ports )
+ to max-rh-ports
+
+\ if no hardware-reset was issued (rescan)
+\ switch off all ports first !
+ hcrhpstat TO current-stat \ start with first port status reg
+ 0 \ port status default
+ max-rh-ports 0 \ checking all ports
+ DO
+ current-stat rl@-le or \ OR-ing all stats
+ 200 current-stat rl!-le \ Clear Port Power (CPP)
+ current-stat 4 + TO current-stat \ check next RH-Port
+ LOOP
+ 100 and 0<> \ any of the ports had power ?
+ IF
+ d# 750 wait-proceed \ wait for power discharge
+ THEN
+
+\ now power on all ports of this root-hub
+ hcrhpstat TO current-stat \ start with first port status reg
+ max-rh-ports 0
+ DO
+ 102 current-stat rl!-le \ power on and enable
+ hcrhdescA 3 + rb@ 2 * ms \ startup delay 30 ms (2 * POTPGT)
+ current-stat 4 + TO current-stat \ check next RH-Port
+ LOOP
+ d# 500 wait-proceed \ STEC device needs 300 ms
+;
+
+: error-recovery ( -- )
+ initialize-td-free-list
+ initialize-ed-free-list
+ HC-reset
+;
+
+\ ================================================================
+: store-initial-usb-hub-address ( -- )
+ usb-address TO initial-hub-address
+;
+
+: reset-to-initial-usb-hub-address ( -- )
+ initial-hub-address TO usb-address
+;
+
+\ allocate-usb-address:
+\ Function allocates an USB address.
+\ See RISK below.
+
+
+: allocate-usb-address ( -- usb-address )
+ usb-address 7f <> ( TRUE|FALSE )
+ IF
+ usb-address 1+ TO usb-address \ RISK: Check to see IF it overflows 127
+ usb-address ( usb-address )
+ THEN ( usb-address )
+;
+
+s" usb-support.fs" INCLUDED
+
+
+
+\ =====================================================================
+\ COLON DEFINTION: control-std-set-address
+\ INTERFACE FUNCTION
+\ Function allocates an USB addrss and uses it to send SET-ADDRESS packet
+\ to the default USB address.
+\ This is an interface function available to child nodes.
+
+: control-std-set-address ( speedbit -- usb-address TRUE | FALSE )
+ >r ( R: speedbit )
+ 0005000000000000 setup-packet !
+ allocate-usb-address dup setup-packet 2 + c! ( usb-addr R: speedbit )
+ s" USB set-address: " 2 pick usb-debug-print-val ( usb-addr R: speedbit )
+ 0 0 0 setup-packet 8 r> controlxfer ( usb-addr TRUE | FALSE )
+ IF ( TRUE | FALSE )
+ TRUE ( TRUE )
+ ELSE
+ drop FALSE \ PENDING: Return the allocated address back. ( FALSE )
+ THEN ( TRUE | FALSE )
+;
+
+
+\ Fetches the device decriptor of the usb-device
+
+
+: control-std-get-device-descriptor
+ ( data-buffer data-len MPS fa -- TRUE|FALSE )
+
+ 8006000100000000 setup-packet !
+ 2 pick setup-packet 6 + w!-le
+ ( data-buffer data-len MPS fa )
+ setup-packet -rot ( data-buffer data-len setup-packet MPS fa )
+ >r >r >r >r >r 0 r> r> r> r> r>
+ ( 0 data-buffer data-len setup-packet MPS fa )
+ controlxfer ( TRUE | FALSE )
+;
+
+
+\ ==================================================================
+\ To retrieve the configuration descriptor OF a device
+\ with a valid USB address
+
+
+: control-std-get-configuration-descriptor
+ ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE )
+ TO temp1 ( data-buffer data-len MPS )
+ TO temp2 ( data-buffer data-len )
+ TO temp3 ( data-buffer )
+ 8006000200000000 setup-packet !
+ temp3 setup-packet 6 + w!-le
+ 0 swap temp3 setup-packet temp2 temp1 controlxfer
+;
+
+\ Fetches num of logical units available for a device
+: control-std-get-maxlun ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE )
+ GET-MAX-LUN setup-packet ! ( MPS fun-addr dir data-buff data-len )
+ setup-packet 5 pick 5 pick
+ ( MPS fun-addr dir data-buff data-len setup-packet MPS fun-addr )
+ controlxfer ( MPS fun-addr TRUE | FALSE )
+ nip nip ( TRUE | FALSE )
+;
+
+\ Bulk-Only Mass Storage Reset
+\ fixed to interface #0
+: control-bulk-reset ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE )
+ 21FF000000000000 setup-packet ! ( MPS fun-addr dir data-buff data-len )
+ setup-packet 5 pick 5 pick
+ ( MPS fun-addr dir data-buff data-len setup-packet MPS fun-addr )
+ controlxfer ( MPS fun-addr TRUE | FALSE )
+ nip nip ( TRUE | FALSE )
+;
+
+
+
+\ get the string descriptor of the usb device
+
+
+: control-std-get-string-descriptor
+ ( StringIndex data-buffer data-len MPS FuncAddr -- TRUE | FALSE )
+ TO temp1 ( StringIndex data-buffer data-len MPS )
+ TO temp2 ( StringIndex data-buffer data-len )
+ TO temp3 ( StringIndex )
+ 8006000300000000 setup-packet !
+ temp3 setup-packet 6 + w!-le
+ 409 setup-packet 4 + w!-le \ US English Language code.
+ swap ( data buffer StringIndex )
+ setup-packet 2 + c! ( data-buffer )
+ 0 swap temp3 setup-packet temp2 temp1 controlxfer ( TRUE | FALSE )
+;
+
+\ sets a valid usb configaration for a device
+
+: control-std-set-configuration ( configvalue FuncAddr -- TRUE|FALSE )
+ TO temp1 ( configvalue )
+ TO temp2
+ 0009000000000000 setup-packet ! \ RISK: Endian and 64-bit assumptions
+ temp2 setup-packet 2 + w!-le
+ 0 0 0 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer
+
+ \ NOTE: We could use DEFAULT-CONTROL-MPS because there is no data phase
+ \ associated with this control xfer. Its a dont care.
+;
+
+
+\ To set the device address retrive the device descriptor and build the
+\ usb device tree by passing device class
+
+
+0 VALUE port-number
+
+s" usb-enumerate.fs" INCLUDED
+
+: rhport-enumerate ( port-num -- )
+ TO port-number
+ device-speed control-std-set-address ( usb-addr TRUE | FALSE )
+ IF
+ device-speed or ( usb-addr+speedbit )
+ TO new-device-address
+ dd-buffer @ 8 erase
+
+ \ Read Device Descriptor - First 8 bytes.
+
+ dd-buffer @ DEFAULT-CONTROL-MPS DEFAULT-CONTROL-MPS ( buffer mps mps )
+ new-device-address control-std-get-device-descriptor ( TRUE | FALSE )
+ IF
+ ELSE
+ s" USB: Read Dev Descriptor failed" usb-debug-print EXIT
+
+ \ NOTE: Tomorrow, IF there is a LOOP here,we may need to UNLOOP before
+ \ "EXIT"ing. Beware. Much depends on what LOOPing construct is used.
+
+ THEN
+
+ \ Read the Descriptor Type and check IF we have read correctly.
+
+ dd-buffer @ DEVICE-DESCRIPTOR-TYPE-OFFSET + c@ ( Descriptor-type )
+ DEVICE-DESCRIPTOR-TYPE <> IF
+ s" USB: Error Reading Device Descriptor" usb-debug-print
+ s" Read descriptor is not OF the right type" usb-debug-print
+ s" Aborting enumeration" usb-debug-print
+ EXIT
+ \ NOTE: Tomorrow, IF u have a LOOP here THEN we may need to
+ \ UNLOOP before EXITing. Depends on what type OF LOOPing construct
+ \ is used. Beware.
+
+ THEN
+
+ \ Read the MPS and store it.
+
+ dd-buffer @ DEVICE-DESCRIPTOR-MPS-OFFSET + c@ TO mps
+
+ \ NOTE: Probably, we could check MPS for only 8/16/32/64
+ \ hmm.. not now...
+
+ \ Read the device class to see what type OF device it is and create an
+ \ appropriate child node here.
+ create-usb-device-tree
+ ELSE
+ s" Set address failed on port " port-number usb-debug-print-val
+ s" Aborting Enumeration." usb-debug-print
+ EXIT
+
+ \ NOTE: Tomorrow , IF u have a LOOP here THEN we may need to
+ \ UNLOOP before EXITing. Depends on what type OF LOOPing construct
+ \ is used. Beware.
+
+ THEN
+;
+
+
+\ =========================================================================
+\ PROTOTYPE FUNCTION: "rhport-initialize"
+\ Detect Device, reset and enable the respective port.
+\ COLON Definition rhport-initialize accepts the total number OF root hub
+\ ports as an argument and probes every available root hub port and initiates
+\ the build OF the USB devie sub-tree so is effectively the mother OF all
+\ USB device nodes that are to be detected and instantiated.
+\ ==========================================================================
+: rhport-initialize ( -- )
+
+ hcrhpstat TO current-stat \ start with first port status reg
+ max-rh-ports 1+ 1
+ DO
+ \ any Device connected to that port ?
+ current-stat rl@-le RHP-CCS and 0<> ( TRUE|FALSE )
+ IF
+ current-stat hcrhpstat3 = \ third port of NEC ?
+ IF
+ 81 to uDOC-present \ uDOC is present and now processed
+ THEN
+
+ s" Device connected to this port!" usb-debug-print
+ RHP-PRS current-stat rl!-le \ issue a port reset
+ BEGIN
+ current-stat rl@-le RHP-PRS AND \ wait for reset end
+ WHILE
+ REPEAT
+ hcrhdescA 3 + rb@ 2 * ms \ startup delay 30 ms (POTPGT)
+ d# 100 ms
+
+ current-stat rl@-le 200 and 4 lshift
+ to device-speed \ store speed bit
+
+ RHP-CSC RHP-PRSC or current-stat rl!-le
+
+ I ['] rhport-enumerate CATCH IF \ Scan port
+ s" USB scan failed on root hub port: " rot usb-debug-print-val
+ reset-to-initial-usb-hub-address
+ THEN
+
+ ELSE
+ s" No device detected at this port." usb-debug-print
+ current-stat hcrhpstat3 = \ third port of NEC ? (=ModFD)
+ IF \ here a ModFD should be on ELBA
+ current-stat rl@-le 80000 and 0<> \ is over-current detected ?
+ IF
+ uDOC-present 08 or to uDOC-present \ set flag for uDOC-check
+ THEN
+ THEN
+ THEN
+ current-stat 4 + TO current-stat \ check next RH-Port
+ uDOC-present 0f and to uDOC-present \ remove processing flag
+ LOOP
+;
+
+
+\ ===================================================
+\ Enumeration at Host level
+\ ===================================================
+
+: enumerate ( -- )
+ HC-reset
+ ['] hc-suspend add-quiesce-xt \ Assert that HC will be supsended
+ store-initial-usb-hub-address
+ rhport-initialize \ Probe all available RH ports
+ reset-to-initial-usb-hub-address
+;
+
+
+\ Create an alias for this controller:
+set-ohci-alias
+
diff --git a/slof/fs/usb/usb-static.fs b/slof/fs/usb/usb-static.fs
new file mode 100644
index 0000000..8732957
--- /dev/null
+++ b/slof/fs/usb/usb-static.fs
@@ -0,0 +1,297 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ #include "scsi-support.fs"
+
+\ Set usb-debug flag to TRUE for debugging output:
+0 VALUE usb-debug-flag
+false VALUE scan-time?
+
+VARIABLE ihandle-bulk-tran
+\ -scsi-supp- VARIABLE ihandle-scsi-tran
+
+\ uDOC (Micro-Disk-On-Chip) is a FLASH-device
+\ normally connected to usb-port 5 on ELBA
+\
+0 VALUE uDOC-present \ device present and working?
+
+\ Print a debug message when usb-debug-flag is set
+: usb-debug-print ( str len -- )
+ usb-debug-flag IF type cr ELSE 2drop THEN
+;
+
+\ Print a debug message with corresponding value when usb-debug-flag is set
+: usb-debug-print-val ( str len val -- )
+ usb-debug-flag IF -ROT type . cr ELSE drop 2drop THEN
+;
+
+\ show proceeding propeller only during scan process.
+\ As soon USB-keyboard can be used, this must be suppressed.
+0 VALUE proceed-char
+: show-proceed ( -- )
+ scan-time? \ are we on usb-scan ?
+ IF
+ proceed-char
+ CASE
+ 0 OF 2d ENDOF \ show '-'
+ 1 OF 5c ENDOF \ show '\'
+ 2 OF 7c ENDOF \ show '|'
+ dup OF 2f ENDOF \ show '/'
+ ENDCASE
+ emit 8 emit
+ proceed-char 1 + 3 AND to proceed-char
+ THEN
+;
+
+\ delay with proceeding signs
+: wait-proceed ( nl -- )
+ show-proceed
+ BEGIN
+ dup d# 100 > ( nl true|false )
+ WHILE
+ 100 - show-proceed
+ 100 ms \ do it in steps of 100ms
+ REPEAT
+ ms \ rest delay
+;
+
+\ register device alias
+: do-alias-setting ( num name-str name-len )
+ rot $cathex strdup \ create alias name
+ get-node node>path \ get path string
+ set-alias \ and set the alias
+;
+
+
+0 VALUE ohci-alias-num
+
+\ create a new ohci device alias for the current node:
+: set-ohci-alias ( -- )
+ ohci-alias-num dup 1+ TO ohci-alias-num ( num )
+ s" ohci"
+ do-alias-setting
+;
+
+0 VALUE cdrom-alias-num
+0 VALUE disk-alias-num \ shall start with: pci-disk-num
+FALSE VALUE ext-disk-alias \ first external disk: not yet assigned
+
+\ create a new ohci device alias for the current node:
+: set-drive-alias ( -- )
+ space 5b emit
+ s" cdrom" drop ( name-str )
+ get-node node>name comp 0= ( true|false )
+ IF \ is this a cdrom ?
+ cdrom-alias-num dup 1+ TO cdrom-alias-num ( num )
+ s" cdrom" \ yes, alias = cdrom
+ ELSE
+ s" sbc-dev" drop \ is this a scsi-block-device?
+ get-node node>name comp 0= ( true|false )
+ IF
+ disk-alias-num dup 1 + to disk-alias-num
+ s" disk" \ all block devices will be named "disk"
+
+ \ this is a block-device.
+ \ check if parent is 'usb' and not 'hub'
+ \ if so this block-device is directly connected
+ \ to root-hub and must be the uDOC-device in Elba
+ s" usb" drop \ parent = usb controller ? (not hub)
+ get-node node>parent @ node>name
+ comp 0= \ parent node starts with 'usb' ?
+ IF ( true|false )
+ 1 s" hdd" \ add extra alias hdd1 for IntFlash
+ 2dup type 2 pick .
+ 8 emit 2f emit
+ do-alias-setting
+ uDOC-present 1 and
+ IF
+ uDOC-present 2 or to uDOC-present \ present and ready
+ THEN
+ ELSE
+ ext-disk-alias not \ flag for first ext. disk already assigned
+ IF
+ TRUE to ext-disk-alias
+ 2 s" hdd" \ add extra alias hdd2 for first USB disk
+ 2dup type 2 pick .
+ 8 emit 2f emit
+ do-alias-setting
+ THEN
+ THEN
+ ELSE
+ 0 s" ??? " \ unknown device
+ THEN
+ THEN ( num name-str name-len )
+ 2dup type 2 pick .
+ 8 emit 5d emit cr
+ do-alias-setting
+;
+
+: usb-create-alias-name ( num -- str len )
+ >r s" ohciX" 2dup + 1- ( str len last-char-ptr R: num )
+ r> [char] 0 + swap c! ( str len R: )
+;
+
+
+\ *****************************************************
+\ This is a final check to see, if a uDOC-device
+\ is ready for booting
+\ If physically present, but not working, an
+\ Error-LED must be activated (on ELBA only!)
+\ *****************************************************
+\ uDOC is now replaced by ModFD (Modular-Flash-Drive)
+\ due to right properties
+\ 'sys-signal-modfd-fault' sends an IPMI-Message to
+\ aMM for generating a log entry and to switch on
+\ an error LED (call to libsystem->libipmi)
+\ *****************************************************
+\ although there are IPMI-warnings defined concerning
+\ detected media errors, it doesn't make sense to send
+\ a warning when booting from this device is impossible.
+\ The decision was made to send an error call in this
+\ case as well
+\ *****************************************************
+\ uDOC-present bits:
+\ *****************************************************
+\ D0: any device is connected on port 3 of root-hub
+\ D1: device on port 3 is directly connected (no hub)
+\ D2: warnings were received (scancodes)
+\ D3: OverCurrentIndicator on USB-Port was set
+\ D7: flag, set while ModFD is beeing processed
+
+: uDOC-check ( -- )
+#ifdef ELBA
+ uDOC-present 7 and \ flags concerning ModFD device
+ CASE
+ 0 OF \ not present not detected
+ uDOC-present 8 and 0<> \ not detected due to OverCurrent?
+ IF
+ 0d emit ." * OverCurrent on ModFD *" cr
+ sys-signal-modfd-fault ( -- ) \ send IPMI-call to BMC
+ ELSE
+ 0d emit ." ModFD not present" cr
+ THEN
+ ENDOF
+
+ 1 OF \ present but not detected by USB
+ 0d emit ." * ModFD not accessible *" cr
+ sys-signal-modfd-fault ( -- ) \ send IPMI-call to BMC
+ ENDOF
+
+ 3 OF \ present and detected
+\ 0d emit ." ModFD OK" cr
+ ENDOF
+
+ 7 OF \ present and detected but with warnings
+ 0d emit ." * ModFD Warnings *" cr
+ sys-signal-modfd-fault ( -- ) \ send IPMI-call to BMC
+ ENDOF
+
+ dup OF \ we have a fault in our firmware !
+ s" *** ModFD detection error ***" usb-debug-print
+ ENDOF
+ ENDCASE
+#endif
+;
+
+\ *****************************************************
+\ check if actual processed device is ModFD and
+\ then sets its warning bit
+\ *****************************************************
+: uDOC-failure? ( -- )
+ uDOC-present 80 and 0<> \ is ModFD actual beeing processed?
+ IF
+ uDOC-present 04 or to uDOC-present \ set Warning flag
+ THEN
+;
+
+\ Scan all USB host controllers for attached devices:
+: usb-scan
+ \ Scan all OHCI chips:
+ space ." Scan USB... " cr
+ true to scan-time? \ show proceeding signs
+ 0 to uDOC-present \ mark as not present
+ 0 to disk-alias-num \ start with disk0
+ s" pci-disk-num" $find \ previously detected disks ?
+ IF
+ execute to disk-alias-num \ overwrite start number
+ ELSE
+ 2drop
+ THEN
+
+ 0 >r \ Counter for alias
+ BEGIN
+ r@ usb-create-alias-name
+ find-alias ?dup ( false | str len len R: num )
+ WHILE
+ usb-debug-flag IF
+ ." * Scanning hub " 2dup type ." ..." cr
+ THEN
+ open-dev ?dup IF ( ihandle R: num )
+ dup to my-self
+ dup ihandle>phandle dup set-node
+ child ?dup IF
+ delete-node s" Deleting node" usb-debug-print
+ THEN
+ >r s" enumerate" r@ $call-method \ Scan host controller
+ r> close-dev 0 set-node 0 to my-self
+ THEN ( R: num )
+ r> 1+ >r ( R: num+1 )
+ REPEAT r> drop
+ 0 TO ohci-alias-num
+ 0 TO cdrom-alias-num
+ s" cdrom0" find-alias ( false | dev-path len )
+ dup IF
+ s" cdrom" 2swap ( alias-name len' dev-path len )
+ set-alias ( -- )
+ \ cdrom-alias-num 1 + TO cdrom-alias-num
+ ELSE
+ drop ( -- )
+ THEN
+ uDOC-check \ check if uDOC-device is present and working (ELBA only)
+ false to scan-time? \ suppress proceeding signs
+;
+
+: usb-probe
+
+ usb-scan
+
+ cdrom-alias-num 0= IF
+ ." Not found CDROM! " cr
+ THEN
+ ." CDROM found " cdrom-alias-num . cr
+;
+
+
+: usb-dev-test ( -- TRUE )
+ s" USB Device Test " usb-debug-print
+ 1 usb-create-alias-name
+ find-alias ?dup IF
+ ." * open " 2dup type . cr
+ ELSE
+ s" can't found alias " usb-debug-print
+ THEN
+ open-dev ?dup IF
+ dup to my-self
+ dup ihandle>phandle dup set-node
+ s" bulk" $open-package ihandle-bulk-tran !
+\ make-media-ready
+ s" close all " usb-debug-print
+ close-dev 0 set-node 0 to my-self
+
+ ihandle-bulk-tran close-package
+ ELSE
+ s" can't open usb hub" usb-debug-print
+ THEN
+
+ TRUE
+;
+
diff --git a/slof/fs/usb/usb-storage-support.fs b/slof/fs/usb/usb-storage-support.fs
new file mode 100644
index 0000000..f5033de
--- /dev/null
+++ b/slof/fs/usb/usb-storage-support.fs
@@ -0,0 +1,155 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ ---------------------------------------------------------------------------
+\ Parent methods
+\ ---------------------------------------------------------------------------
+
+: rw-endpoint
+ ( pt ed-type toggle buffer length mps addres -- toggle TRUE | toggle FALSE )
+ s" rw-endpoint" $call-parent
+ ( toggle TRUE | toggle FALSE )
+;
+
+: controlxfer ( dir addr dlen setup-packet MPS ep-fun --- TRUE|FALSE )
+ s" controlxfer" $call-parent
+ ( TRUE | FALSE )
+;
+
+: control-std-get-configuration-descriptor
+ ( data-buffer data-len MPS FuncAddr -- TRUE | FALSE )
+ s" control-std-get-configuration-descriptor" $call-parent
+ ( TRUE | FALSE )
+;
+
+: control-std-set-configuration ( configvalue FuncAddr -- TRUE | FALSE )
+ s" control-std-set-configuration" $call-parent ( TRUE | FALSE )
+;
+
+: bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- )
+ s" bulk-reset-recovery-procedure" $call-parent
+;
+
+
+\ ---------------------------------------------------------------------------
+\ Bulk support package methods
+\ ---------------------------------------------------------------------------
+
+: build-cbw ( address tag transfer-len direction lun command-len -- )
+ s" build-cbw" ihandle-bulk @ $call-method
+;
+
+: analyze-csw ( address -- residue tag TRUE | reason FALSE )
+ s" analyze-csw" ihandle-bulk @ $call-method
+ ( residue tag TRUE | reason FALSE )
+;
+
+
+\ =======================================================
+\ NATIVE METHODS USED EITHER AT PROBE TIME OR TIME
+\ WHEN INSTANCE IS CREATED
+\ =======================================================
+
+
+\ --------------------------------------------------------
+\ COLON DEFINITION: the method is a probe-time method
+\ used to:
+\ 1. decode the properties and store in variables
+\ 2. allocat buffers required for the device and
+\ 3. set the right configuration after extracting the
+\ configuration descriptor
+\ --------------------------------------------------------
+
+: device-init ( -- )
+ s" Starting to initialize usb-storage device" usb-debug-print
+ s" USB-ADDRESS" get-my-property ( TRUE | propaddr proplen FALSE )
+ IF
+ s" not possible" usb-debug-print
+ ELSE
+ decode-int nip nip to my-usb-address
+ THEN
+ s" MPS-BULKOUT" get-my-property ( TRUE | propaddr proplen FALSE )
+ IF
+ s" not possible" usb-debug-print
+ ELSE
+ decode-int nip nip to mps-bulk-out
+ THEN
+ s" MPS-BULKIN" get-my-property ( TRUE | propaddr proplen FALSE )
+ IF
+ s" not possible" usb-debug-print
+ ELSE
+ decode-int nip nip to mps-bulk-in
+ THEN
+ s" BULK-IN-EP-ADDR" get-my-property ( TRUE | propaddr proplen FALSE )
+ IF
+ s" not possible" usb-debug-print
+ ELSE
+ decode-int nip nip to bulk-in-ep
+ THEN
+ s" BULK-OUT-EP-ADDR" get-my-property ( TRUE | propaddr proplen FALSE )
+ IF
+ s" not possible" usb-debug-print
+ ELSE
+ decode-int nip nip to bulk-out-ep
+ THEN
+ s" MPS-DCP" get-my-property ( TRUE | propaddr proplen FALSE )
+ IF
+ s" Not possible" usb-debug-print
+ ELSE
+ decode-int nip nip to mps-dcp
+ THEN
+ s" LUN" get-my-property ( TRUE | propaddr proplen FALSE )
+ IF
+ s" NOT Possible to extract LUN" usb-debug-print
+ ELSE
+ decode-int nip nip to lun
+ THEN
+ s" Extracted properties inherited from parent." usb-debug-print
+
+ \ PENDING:
+ \ Do some return value check here...
+
+ 40 alloc-mem to command-buffer
+ 80 alloc-mem to response-buffer
+ 10 alloc-mem to csw-buffer
+ 8 alloc-mem to cfg-buffer
+ s" Allocated buffers." usb-debug-print
+ cfg-buffer 8 mps-dcp my-usb-address ( buffer len mps fun-addr )
+ control-std-get-configuration-descriptor ( TRUE | FALSE )
+ drop
+ s" Configuration descriptor extracted." usb-debug-print
+ cfg-buffer 5 + c@ my-usb-address ( configvalue fun-addr )
+ control-std-set-configuration ( TRUE | FALSE )
+ s" usb-storage: Set config returned: " rot usb-debug-print-val
+;
+
+
+\ ----------------------------------------------------
+\ Internal methods
+\ ----------------------------------------------------
+
+
+: (open-package) ( ihandle-var name-str name-len -- )
+ find-package IF ( ihandle-var phandle )
+ 0 0 rot open-package ( ihandle-var ihandle )
+ swap !
+ ELSE
+ s" Support package not found" usb-debug-print
+ THEN
+;
+
+: (close-package) ( ihandle-var -- )
+ dup @ close-package
+ 0 swap !
+;
+
diff --git a/slof/fs/usb/usb-storage-wrapper.fs b/slof/fs/usb/usb-storage-wrapper.fs
new file mode 100644
index 0000000..c783541
--- /dev/null
+++ b/slof/fs/usb/usb-storage-wrapper.fs
@@ -0,0 +1,181 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+\ -----------------------------------------------------------
+\ OF properties
+\ -----------------------------------------------------------
+
+s" scsi" device-name
+s" block-type" device-type
+1 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+
+: encode-unit 1 hex-encode-unit ;
+
+: decode-unit 1 hex-decode-unit ;
+
+
+\ -----------------------------------------------------------
+\ Specific properties
+\ -----------------------------------------------------------
+
+1 chars alloc-mem VALUE ch-buffer
+8 VALUE mps-dcp
+0 VALUE port-number
+0 VALUE my-usb-address
+
+
+: control-std-get-maxlun
+ ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE )
+ s" control-std-get-maxlun" $call-parent
+;
+
+
+: control-std-get-configuration-descriptor
+ ( data-buffer data-len MPS funcAddr -- TRUE|FALSE )
+ s" control-std-get-configuration-descriptor" $call-parent
+;
+
+: rw-endpoint
+ ( pt ed-type toggle buffer length mps address -- toggle TRUE|toggle FALSE )
+ s" rw-endpoint" $call-parent
+;
+
+: controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE|FALSE )
+ s" controlxfer" $call-parent
+;
+
+: control-std-set-configuration
+ ( configvalue FuncAddr -- TRUE|FALSE )
+ s" control-std-set-configuration" $call-parent
+;
+
+\ This method is used for extracting the properties from it's parent and
+\ storing these value to temporary variable so that they can used later.
+
+: extract-properties ( -- )
+ s" USB-ADDRESS" get-inherited-property ( prop-addr prop-len FALSE | TRUE )
+ IF
+ s" notpossible" usb-debug-print
+ ELSE
+ decode-int nip nip to my-usb-address
+ THEN
+ s" MPS-DCP" get-inherited-property ( prop-addr prop-len FALSE | TRUE )
+ IF
+ s" MPS-DCP property not found.Assume 8 as MAX PACKET SIZE" usb-debug-print
+ s" for the default control pipe" usb-debug-print
+ 8 to mps-dcp
+ ELSE
+ s" MPS-DCP property found!!" usb-debug-print
+ decode-int nip nip to mps-dcp
+ THEN
+ s" reg" get-inherited-property ( prop-addr prop-len FLASE | TRUE )
+ IF
+ s" notpossible" usb-debug-print
+ ELSE
+ decode-int nip nip to port-number
+ THEN
+;
+
+
+\ This method is used for creating the child nodes for every Logical unit
+\ available in the device, this method will call control-std-get-maxlun for
+\ for finding the maximum Logical units supported by the device and along with
+\ the creation of nodes this method encodes the properties of the node also.
+
+: create-tree ( -- )
+ mps-dcp my-usb-address 0 ch-buffer 1 ( MPS fun-addr dir data-buff data-len )
+ control-std-get-maxlun ( TRUE | FALSE )
+
+ \ This method extracts the maximum number of Logical Units Supported by
+ \ the Device . if no Logical Units are present then 0 will be taken as the
+ \ max logical units. if the device doesn't support the GET-MAX-LUN command
+ \ then the device may can be stalled as a temporary fix to come out from
+ \ the stalling situations we can issue the control-std-set-configuration with
+ \ appropriate arguments
+
+
+ IF
+ s" GET-MAX-LUN IS WORKING :" usb-debug-print
+ ELSE
+ s" ERROR in GET-MAX-LUN " usb-debug-print
+ THEN
+ ch-buffer c@ 1 + 0 ( max-lun+1 0 )
+ DO
+ s" iManufacturer" get-inherited-property drop ( prop-addr prop-len TRUE )
+ decode-int nip nip ( iManu )
+ s" iProduct" get-inherited-property drop
+ ( iManu prop-addr prop-len TRUE | FALSE )
+ decode-int nip nip ( iManu iProd )
+ s" iSerialNumber" get-inherited-property drop
+ ( iManu iProd prop-addr prop-len TRUE | FALSE )
+ decode-int nip nip ( iManu iProd iSerNum )
+ s" MPS-BULKOUT" get-inherited-property drop
+ ( iManu iProd iSerNum prop-len prop-addr TRUE | FALSE )
+ decode-int nip nip ( iManu iProd iSerNum MPS-BULKOUT )
+ s" BULK-OUT-EP-ADDR" get-inherited-property drop
+ ( iManu iProd iSerNum MPS-BULKOUT prop-addr prop-len TRUE|FALSE )
+ decode-int nip nip ( iManu iProd iSerNum MPS-BULKOUT BULK-OUT-EP-ADDR )
+ s" MPS-BULKIN" get-inherited-property drop
+ ( iManu iProd iSerNum MPS-BULKOUT BULK-OUT-EP-ADDR prop-addr prop-len
+ TRUE | FALSE )
+ decode-int nip nip
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN )
+ s" BULK-IN-EP-ADDR" get-inherited-property drop
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN prop-addr
+ prop-len TRUE | FALSE )
+ decode-int nip nip
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+ BULKIN-EP-ADDR )
+ mps-dcp port-number my-usb-address I
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+ BULKIN-EP-ADDR mps-dcp port-address my-usb-address lun-number )
+ new-device
+
+ \ creates new device child node, doesn't consume any argument from stack
+
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+ BULKIN-EP-ADDR mps-dcp port-address my-usb-address lun-number )
+
+ set-space
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+ BULKIN-EP-ADDR mps-dcp port-number my-usb-address )
+ encode-int s" USB-ADDRESS" property
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+ BULKIN-EP-ADDR mps-dcp port-number )
+ encode-int s" reg" property
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN )
+ ( BULKIN-EP-ADDR mps-dcp port-number )
+ encode-int s" MPS-DCP" property
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+ BULKIN-EP-ADDR )
+ I encode-int s" LUN" property
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN
+ BULKIN-EP-ADDR )
+ encode-int s" BULK-IN-EP-ADDR" property
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR MPS-BULKIN )
+ encode-int s" MPS-BULKIN" property
+ ( iManu iProd iSernum MPS-BULKOUT BULK-OUT-EP-ADDR )
+ encode-int s" BULK-OUT-EP-ADDR" property
+ ( iManu iProd iSernum MPS-BULKOUT )
+ encode-int s" MPS-BULKOUT" property ( iManu iProd iSerNum )
+ encode-int s" iSerialNumber" property ( iManu iProd )
+ encode-int s" iProduct" property ( iManu )
+ encode-int s" iManufacturer" property ( -- )
+ s" usb-storage.fs" INCLUDED
+ finish-device
+ LOOP
+;
+
+extract-properties \ Extract the properties from parent
+create-tree \ this method creates the node for every lun with properties
diff --git a/slof/fs/usb/usb-storage.fs b/slof/fs/usb/usb-storage.fs
new file mode 100644
index 0000000..f23c27a
--- /dev/null
+++ b/slof/fs/usb/usb-storage.fs
@@ -0,0 +1,639 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+
+\ -----------------------------------------------------------
+\ OF properties
+\ -----------------------------------------------------------
+
+s" storage" device-name
+s" block" device-type
+
+2 encode-int s" #address-cells" property
+0 encode-int s" #size-cells" property
+
+\ -----------------------------------------------------------
+\ Specific properties
+\ -----------------------------------------------------------
+
+8 VALUE mps-bulk-out
+8 VALUE mps-bulk-in
+8 VALUE mps-dcp
+0 VALUE bulk-in-ep
+0 VALUE bulk-out-ep
+0 VALUE bulk-in-toggle
+0 VALUE bulk-out-toggle
+0 VALUE lun
+0 VALUE my-usb-address
+
+
+\ ----------------------------------------------------------
+\ Instance specific values
+\ ----------------------------------------------------------
+
+0 VALUE csw-buffer
+0e VALUE cfg-buffer
+0 VALUE response-buffer
+0 VALUE command-buffer
+0 VALUE resp-size
+0 VALUE resp-buffer
+INSTANCE VARIABLE ihandle-bulk
+INSTANCE VARIABLE ihandle-deblocker
+INSTANCE VARIABLE flag
+INSTANCE VARIABLE count
+0 VALUE max-transfer
+200 VALUE block-size \ default (512 Bytes)
+-1 VALUE max-block-num \ highest reported block-number
+
+
+\ -------------------------------------------------------
+\ General Constants
+\ -------------------------------------------------------
+
+0f CONSTANT SCSI-COMMAND-OFFSET
+
+
+\ -------------------------------------------------------
+\ All support methods inherited from parent or imported
+\ from support packages are included here. Also included
+\ are the internal methods
+\ -------------------------------------------------------
+
+s" usb-storage-support.fs" INCLUDED
+
+\ ---------------------------------------------------------------
+\ COLON Definitions: Implementation of Standard SCSI commands
+\ over USB OHCI
+\ ---------------------------------------------------------------
+
+
+\ to use the general bulk command a lot of global variables
+\ must be set. See for example the inquiry command.
+0 VALUE bulk-cnt
+0 VALUE bulk-cmd-len
+0 VALUE itest
+: do-bulk-command ( resp-buffer resp-size -- TRUE | FALSE )
+ TO resp-size
+ TO resp-buffer
+ \ dump buffer in debug-mode
+ usb-debug-flag
+ IF
+ command-buffer 0E + c@ TO bulk-cmd-len
+ s" cmd-length: " bulk-cmd-len usb-debug-print-val
+ command-buffer bulk-cmd-len 0E + dump cr
+ THEN
+
+ 6 TO bulk-cnt \ 2 old value
+ FALSE dup
+ BEGIN
+ 0=
+ WHILE
+ drop
+ \ prepare and send bulk CBW
+ 1 1 bulk-out-toggle command-buffer 1f mps-bulk-out
+ ( pt ed-type toggle buffer length mps-bulk-out )
+ my-usb-address bulk-out-ep 7 lshift or
+ ( pt ed-type toggle buffer length mps address )
+ rw-endpoint swap ( TRUE toggle | FALSE toggle )
+ to bulk-out-toggle ( TRUE | FALSE )
+ IF
+ s" resp-size : " resp-size usb-debug-print-val
+ resp-size 0<>
+ IF \ do we need a response ?!
+ \ read the bulk response
+ 0 1 bulk-in-toggle resp-buffer resp-size mps-bulk-in
+ ( pt ed-type toggle buffer length mps-bulk-in )
+ my-usb-address bulk-in-ep 7 lshift or
+ ( pt ed-type toggle buffer length mps address )
+ rw-endpoint swap ( TRUE toggle | FALSE toggle )
+ to bulk-in-toggle ( TRUE | FALSE )
+ ELSE
+ TRUE
+ THEN
+ IF \ read the bulk CSW
+ 0 1 bulk-in-toggle csw-buffer D mps-bulk-in
+ ( pt ed-type toggle buffer length mps-bulk-in )
+ my-usb-address bulk-in-ep 7 lshift or
+ ( pt ed-type toggle buffer length mps address )
+ rw-endpoint swap ( TRUE toggle | FALSE toggle )
+ to bulk-in-toggle ( TRUE | FALSE )
+ IF
+ s" Command successful." usb-debug-print
+ TRUE dup
+ ELSE
+ s" Command failed in CSW stage" usb-debug-print
+ FALSE dup
+ THEN
+ ELSE
+ s" Command failed while receiving DATA... read CSW..." usb-debug-print
+ \ STALLED: Get CSW to send the CBW again
+ 0 1 bulk-in-toggle csw-buffer D mps-bulk-in
+ ( pt ed-type toggle buffer length mps-bulk-in )
+ my-usb-address bulk-in-ep 7 lshift or
+ ( pt ed-type toggle buffer length mps address )
+ rw-endpoint swap ( TRUE toggle | FALSE toggle )
+ to bulk-in-toggle ( TRUE | FALSE )
+ IF
+ s" OK evaluate the CSW ..." usb-debug-print
+ csw-buffer c + c@ dup TO itest
+ s" CSW Status: " itest usb-debug-print-val
+ dup
+ 2 =
+ IF \ Phase Error
+ s" Phase error do a bulk reset-recovery ..." usb-debug-print
+ bulk-out-ep bulk-in-ep my-usb-address
+ bulk-reset-recovery-procedure
+ THEN
+ \ ELSE
+ \ don't abort if the read fails.
+ 1 =
+ IF \ Command failed
+ s" Command Failed do a bulk-reset-recovery" usb-debug-print
+ bulk-out-ep bulk-in-ep my-usb-address
+ bulk-reset-recovery-procedure
+ THEN
+ THEN
+ FALSE dup
+ THEN
+ ELSE
+ s" Command failed while Sending CBW ..." usb-debug-print
+ FALSE dup
+ THEN
+ bulk-cnt 1 - TO bulk-cnt
+ bulk-cnt 0=
+ IF
+ 2drop FALSE dup
+ THEN
+ REPEAT
+;
+
+
+\ ---------------------------------------------------------------
+\ Method to 1. Send the INQUIRY command 2. Receive and analyse
+\ (pending) INQUIRY data
+\ ---------------------------------------------------------------
+scsi-open
+usb-debug-flag to scsi-param-debug \ copy debug flag
+
+24 CONSTANT inquiry-length \ was 20
+
+: inquiry ( -- )
+ s" usb-storage: inquiry" usb-debug-print
+ command-buffer 1 inquiry-length 80 lun scsi-length-inquiry
+ ( address tag transfer-len direction lun command-len )
+ build-cbw
+ inquiry-length command-buffer SCSI-COMMAND-OFFSET + ( alloc-len address )
+ scsi-build-inquiry
+ response-buffer inquiry-length erase \ provide clean buffer
+ response-buffer inquiry-length do-bulk-command
+ IF
+ s" Successfully read INQUIRY data" usb-debug-print
+ 0d emit space space
+ response-buffer c@ \ get 'Peripheral Device Type' (PDT)
+ CASE
+ 0 OF ." BLOCK-DEV: " ENDOF \ SCSI Block Device
+ 5 OF ." CD-ROM : " ENDOF
+ 7 OF ." OPTICAL : " ENDOF
+ e OF ." RED-BLOCK: " ENDOF \ SCSI Reduced Block Device
+ dup dup OF ." ? (" . 8 emit 29 emit 2 spaces ENDOF
+ ENDCASE
+ space
+ \ create vendor identification in device property
+ response-buffer 8 + 16 encode-string s" ident-str" property
+ response-buffer .inquiry-text
+ ELSE
+ 5040 error" (USB) Device transaction error. (inquiry)"
+ ABORT
+ THEN
+;
+
+\ ---------------------------------------------------------------
+\ Method to 1. Send the READ CAPACITY command
+\ 2. Recieve and analyse the response data
+\ ---------------------------------------------------------------
+
+: read-capacity ( -- )
+ s" usb-storage: read-capacity" usb-debug-print
+ command-buffer 1 8 80 lun scsi-length-read-cap-10
+ ( address tag transfer-len direction lun command-len )
+ build-cbw
+ \ command-buffer 30 dump cr \ dump the command buffer
+ command-buffer SCSI-COMMAND-OFFSET + ( address )
+ scsi-build-read-cap-10
+ lun 5 lshift
+ command-buffer SCSI-COMMAND-OFFSET + ( address )
+ read-cap-10>reserved1 c!
+
+ response-buffer 8 erase \ provide clean buffer
+ response-buffer 8 do-bulk-command
+ IF
+ s" Successfully read READ CAPACITY data" usb-debug-print
+ ELSE
+ 5040 error" (USB) Device transaction error. (capacity)"
+ ABORT
+ THEN
+;
+
+
+\ -------------------------------------------------------------------
+\ Method to 1. Send TEST UNIT READY command 2. Analyse the status
+\ of the response
+\ -------------------------------------------------------------------
+
+: test-unit-ready ( -- TRUE | FALSE )
+ command-buffer 1 0 80 lun scsi-length-test-unit-ready \ was: 0c
+ ( address tag transfer-len direction lun command-len )
+ build-cbw
+ command-buffer SCSI-COMMAND-OFFSET + ( address )
+ scsi-build-test-unit-ready ( cdb -- )
+ response-buffer 0 do-bulk-command
+ IF
+ s" Successfully read test unit ready data" usb-debug-print
+ s" Test Unit STATUS availabe in csw-buffer" usb-debug-print
+ csw-buffer 0c + c@ 0= IF
+ s" Test Unit Command Successfully Executed" usb-debug-print
+ TRUE ( TRUE )
+ ELSE
+ s" Test Unit Command Failed to execute" usb-debug-print
+ FALSE ( FALSE )
+ THEN
+ ELSE
+ \ TRUE ABORT" USB device transaction error. (test-unit-ready)"
+ 5040 error" (USB) Device transaction error. (test-unit-ready)"
+ ABORT
+ THEN
+;
+
+\ ****************************************************
+\ multiple checks of 'test-unit-ready' with timeout
+\ ****************************************************
+: wait-for-unit-ready ( -- TRUE|FALSE )
+ s" --> WAIT: test-unit-ready ... " usb-debug-print
+ d# 100 ( count ) \ up to 10 seconds
+ BEGIN ( count )
+ dup 0> ( count flag )
+ test-unit-ready \ dup IF 2b ELSE 2d THEN emit
+ not and ( count flag )
+ WHILE
+ 1- ( count )
+ d# 100 wait-proceed \ wait 100 ms
+ REPEAT ( count )
+ 0=
+ IF
+ s" ** Device not ready ** " usb-debug-print
+ FALSE
+ ELSE
+ TRUE
+ THEN
+;
+
+
+\ -------------------------------------------------
+\ Method to 1. read sense data 2. analyse sesnse
+\ data(pending)
+\ ------------------------------------------------
+
+: request-sense ( -- )
+ s" request-sense: Command ready." usb-debug-print
+ command-buffer 1 12 80 lun scsi-length-request-sense
+ ( address tag transfer-len direction lun command-len )
+ build-cbw
+\ -scsi-supp- command-buffer SCSI-COMMAND-OFFSET + 12 ( address alloc-len )
+\ -scsi-supp- build-request-sense
+
+ 12 command-buffer SCSI-COMMAND-OFFSET + ( alloc-len cdb )
+ scsi-build-request-sense ( alloc-len cdb -- )
+
+ response-buffer 12 do-bulk-command
+ IF
+ s" Read Sense data successfully" usb-debug-print
+ \ response-buffer 12 dump cr \ dump the rsponsed message
+ ELSE
+ \ TRUE ABORT" USB device transaction error. (request-sense)"
+ 5040 error" (USB) Device transaction error. (request-sense)"
+ ABORT
+ THEN
+;
+
+: start ( -- )
+ command-buffer 1 0 80 lun scsi-length-start-stop-unit
+ ( address tag transfer-len direction lun command-len )
+ build-cbw
+\ -scsi-supp- command-buffer SCSI-COMMAND-OFFSET + ( address )
+\ -scsi-supp- build-start
+
+ command-buffer SCSI-COMMAND-OFFSET + ( cdb )
+ scsi-const-start scsi-build-start-stop-unit ( state# cdb -- )
+
+ response-buffer 0 do-bulk-command
+ IF
+ s" Start successfully" usb-debug-print
+ ELSE
+ \ TRUE ABORT" USB device transaction error. (start)"
+ 5040 error" (USB) Device transaction error. (start)"
+ ABORT
+ THEN
+;
+
+
+\ To transmit SCSI Stop command
+
+: stop ( -- )
+ command-buffer 1 0 80 lun scsi-length-start-stop-unit
+ ( address tag transfer-len direction lun command-len )
+ build-cbw
+\ -scsi-supp- command-buffer SCSI-COMMAND-OFFSET + ( address )
+\ -scsi-supp- build-stop
+
+ command-buffer SCSI-COMMAND-OFFSET + ( cdb )
+ scsi-const-stop scsi-build-start-stop-unit ( state# cdb -- )
+
+ response-buffer 0 do-bulk-command
+ IF
+ s" Stop successfully" usb-debug-print
+ ELSE
+ \ TRUE ABORT" USB device transaction error. (stop)"
+ 5040 error" (USB) Device transaction error. (stop)"
+ ABORT
+ THEN
+;
+
+
+0 VALUE temp1
+0 VALUE temp2
+0 VALUE temp3
+
+
+\ -------------------------------------------------------------
+\ block device's seek
+\ -------------------------------------------------------------
+\ if anything is wrong in the boot device, a seek-request can
+\ occur that exceeds the limits of the device in the following
+\ read-command. So checking is required and the appropriate
+\ return-value has to be returned
+\ Spec requires -1 if operation fails and 0 or 1 if it succeeds !!
+\ -------------------------------------------------------------
+
+: seek ( pos-lo pos-hi -- status )
+ 2dup lxjoin max-block-num block-size * >
+ IF
+ ." ** Seek Error: pos too large ("
+ dup . over . ." -> " max-block-num block-size * .
+ ." ) ** " cr
+ -1 \ see spec-1275 page 183
+ ELSE
+ s" seek" ihandle-deblocker @ $call-method
+ THEN
+;
+
+
+\ -------------------------------------------------------------
+\ block device's read
+\ -------------------------------------------------------------
+
+: read ( address length -- actual )
+ s" read" ihandle-deblocker @ $call-method
+;
+
+
+\ -------------------------------------------------------------
+\ read-blocks to be used by deblocker
+\ -------------------------------------------------------------
+: read-blocks ( address block# #blocks -- #read-blocks )
+ 2dup + max-block-num >
+ IF
+ ." ** Requested block too large "
+ 2dup + ." (" .d ." -> " max-block-num .d
+ bs emit ." ) ... read aborted **" cr
+ nip nip \ leave #blocks on stack
+ ELSE
+ block-size * command-buffer ( address block# transfer-len command-buffer )
+ 1 2 pick 80 lun 0c build-cbw ( address block# transfer-len )
+ dup to temp1 ( address block# transfer-len )
+ block-size / ( address block# #blocks )
+ command-buffer ( address block# #blocks command-addr )
+ SCSI-COMMAND-OFFSET + ( address block# #blocks cdb )
+ scsi-build-read? ( block# #blocks cdb -- length )
+ command-buffer 0e + c! \ update bCBWCBLength-field with resulting CDB length
+ temp1 ( address length )
+ do-bulk-command
+ IF
+ s" Read data successfully" usb-debug-print
+ ELSE
+ \ TRUE ABORT" USB device transaction error. (read-blocks)"
+ 5040 error" (USB) Device transaction error. (read-blocks)"
+ ABORT
+ THEN
+ temp1 block-size / ( #read-blocks )
+ THEN
+;
+
+\ ------------------------------------------------
+\ To bring the the media to seekable and readable
+\ condition.
+\ ------------------------------------------------
+
+d# 800 CONSTANT media-ready-retry
+
+: make-media-ready ( -- )
+ s" usb-storage: make-media-ready" usb-debug-print
+ 0 flag !
+ 0 count !
+ BEGIN
+ flag @ 0=
+ WHILE
+ test-unit-ready IF
+ s" Media ready for access." usb-debug-print
+ 1 flag !
+ ELSE
+ count @ 1 + count !
+ count @ media-ready-retry = IF
+ 1 flag !
+ 5000 error" (USB) Media or drive not ready for this blade."
+ ABORT
+ THEN
+ request-sense
+ response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true )
+ IF
+ ffff00 AND \ remaining: sense-key ASC
+ CASE
+ 023a00 OF \ MEDIUM NOT PRESENT (02 3a 00)
+ 5010 error" (USB) No Media found! Check for the drawer/inserted media."
+ ABORT
+ ENDOF
+
+ 020400 OF \ LOGICAL DRIVE NOT READY - INITIALIZATION REQUIRED
+ 5010 error" (USB) No Media found! Check for the drawer/inserted media."
+ ABORT
+ ENDOF
+
+ 033000 OF \ CANNOT READ MEDIUM - UNKNOWN FORMAT
+ 5020 error" (USB) Unknown media format."
+ ABORT
+ ENDOF
+ ENDCASE
+ THEN
+ THEN
+ d# 10 ms \ wait maximum 10ms * 800 (=8s)
+ REPEAT
+ usb-debug-flag IF
+ ." make-media-ready finished after "
+ count @ decimal . hex ." tries." cr
+ THEN
+;
+
+\ ------------------------------------------------
+\ read and show devices capacity
+\ ------------------------------------------------
+: .showcap
+ space
+ test-unit-ready drop \ initial command
+ request-sense
+ response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true )
+ IF
+ dup FFFF00 and 023a00 = ( sense-id flag )
+ IF
+ uDOC-failure?
+ 023a02 = \ see sense-codes SPC-3 clause 4.5.6
+ IF
+ ." Tray Open!"
+ ELSE
+ ." No Media"
+ THEN
+ ELSE ( sense-id )
+ drop
+ wait-for-unit-ready
+ IF
+ read-capacity
+ response-buffer scsi-get-capacity-10 space .capacity-text
+ ELSE
+ request-sense
+ response-buffer scsi-get-sense-ID? ( addr -- false | sense-ID true )
+ IF
+ dup ff0000 and 040000 = \ sense-code = 4 ?
+ IF
+ ." *HW-ERROR*"
+ uDOC-failure?
+ ELSE
+ dup FFFF00 and 023a00 = IF uDOC-failure? THEN
+ CASE ( sense-ID )
+ \ see SPC-3 clause 4.5.6
+ 023a00 OF ." No Media " ENDOF
+ 023a02 OF ." Tray Open! " ENDOF
+ dup OF ." ? " ENDOF
+ ENDCASE
+ THEN
+ THEN
+ THEN
+ THEN
+ ELSE
+ ." ?? "
+ THEN
+;
+
+
+
+: init-dev-ready
+ test-unit-ready drop
+ 4 >r \ loop-counter
+ 0 0
+ BEGIN
+ 2drop
+ request-sense
+ response-buffer scsi-get-sense-data ( ascq asc sense-key )
+ 0<> r> 1- dup >r 0<> AND \ loop-counter or sense-key
+ WHILE
+ REPEAT
+ 2drop
+ r> drop
+;
+
+
+
+scsi-close \ no further scsi words required
+
+
+\ Set up the block-size of the device, using the READ CAPACITY command.
+\ Note: Media must be ready (=> make-media-ready) or READ CAPACITY
+\ might fail!
+
+: (init-block-size)
+ read-capacity
+ response-buffer l@ dup 0<>
+ IF
+ to max-block-num \ highest block-number
+ ELSE
+ -1 to max-block-num \ indeterminate
+ THEN
+ response-buffer 4 +
+ l@ to block-size
+ s" usb-storage: block-size=" block-size usb-debug-print-val
+;
+
+
+\ Standard OF methods
+
+: open ( -- TRUE )
+ s" usb-storage: open" usb-debug-print
+ ihandle-bulk s" bulk" (open-package)
+
+ make-media-ready
+ (init-block-size) \ Init block-size before opening the deblocker
+
+ ihandle-deblocker s" deblocker" (open-package)
+
+ s" disk-label" find-package IF ( phandle )
+ usb-debug-flag IF ." my-args for disk-label = " my-args swap . . cr THEN
+ my-args rot interpose
+ THEN
+ TRUE ( TRUE )
+;
+
+
+: close ( -- )
+ ihandle-deblocker (close-package)
+ ihandle-bulk (close-package)
+;
+
+
+\ Set device name according to type
+
+: (init-device-name) ( -- )
+ init-dev-ready
+ inquiry
+ response-buffer c@
+ CASE
+ 1 OF .showcap s" tape" device-name ENDOF
+ 5 OF .showcap s" cdrom" device-name s" CDROM found" usb-debug-print ENDOF
+ 0 OF .showcap s" sbc-dev" device-name s" SBC Direct access device" usb-debug-print ENDOF
+ 7 OF .showcap s" optical" device-name s" Optical memory found" usb-debug-print ENDOF
+ 0E OF .showcap s" rbc-dev" device-name s" RBC direct acces device found" usb-debug-print ENDOF
+ \ dup OF s" storage" device-name ENDOF
+ ENDCASE
+;
+
+
+\ Initial device node setup
+
+: (initial-setup)
+ ihandle-bulk s" bulk" (open-package)
+ device-init
+ (init-device-name)
+ set-drive-alias
+ 200 to block-size \ Default block-size, will be overwritten in "open"
+ 10000 to max-transfer
+
+ ihandle-bulk (close-package)
+;
+
+(initial-setup)
+
diff --git a/slof/fs/usb/usb-support.fs b/slof/fs/usb/usb-support.fs
new file mode 100644
index 0000000..08ff9bd
--- /dev/null
+++ b/slof/fs/usb/usb-support.fs
@@ -0,0 +1,651 @@
+\ *****************************************************************************
+\ * Copyright (c) 2004, 2008 IBM Corporation
+\ * All rights reserved.
+\ * This program and the accompanying materials
+\ * are made available under the terms of the BSD License
+\ * which accompanies this distribution, and is available at
+\ * http://www.opensource.org/licenses/bsd-license.php
+\ *
+\ * Contributors:
+\ * IBM Corporation - initial implementation
+\ ****************************************************************************/
+
+0 value NEXT-TD
+
+0 VALUE num-tds
+0 VALUE td-retire-count
+0 VALUE saved-tail
+0 VALUE poll-timer
+VARIABLE controlxfer-cmd
+
+\ Allocate an ED and populate it
+
+: (ed-prepare) ( dir addr dlen setup-packet MPS ep-fun --
+ FALSE | dir addr dlen ed-ptr setup-ptr )
+ allocate-ed dup 0= IF ( dir addr dlen setup-packet MPS ep-fun ed-ptr )
+ drop 3drop 2drop FALSE EXIT ( FALSE )
+ THEN
+ TO temp1 ( dir addr dlen setup-packet MPS ep-fun )
+ temp1 zero-out-an-ed-except-link ( dir addr dlen setup-packet MPS ep-fun )
+ temp1 ed>eattr l@-le or temp1 ed>eattr l!-le ( dir addr dlen setup-ptr MPS )
+ dup TO temp2 10 lshift temp1 ed>eattr l@-le or temp1 ed>eattr l!-le
+ ( dir addr dlen setup-packet-address )
+ temp1 swap TRUE ( dir addr dlen ed-ptr setup-ptr TRUE )
+;
+
+
+\ Allocate TD list
+
+
+: (td-prepare) ( dir addr dlen ed-ptr setup-ptr --
+ dir FALSE | dir addr dlen ed-ptr setup-ptr td-head td-tail )
+ 2 pick ( dir addr dlen ed-ptr setup-ptr dlen )
+ temp2 ( dir addr dlen ed-ptr setup-ptr dlen MPS )
+ /mod ( dir addr dlen ed-ptr setup-ptr rem quo )
+ swap 0<> IF ( dir addr dlen ed-ptr setup-ptr quo )
+ 1+
+ THEN
+ 2+
+ dup TO num-tds ( dir addr dlen ed-ptr setup-ptr quo+2 )
+ allocate-td-list dup 0= IF ( dir addr dlen ed-ptr setup-ptr quo+2 )
+ 2drop ( dir addr dlen ed-ptr setup-ptr )
+ drop ( dir addr dlen ed-ptr )
+ free-ed ( dir addr dlen )
+ 2drop ( dir )
+ FALSE ( dir FALSE )
+ EXIT
+ THEN TRUE
+;
+
+
+\ Fill in the ED structure completely.
+
+
+: (td-ready) ( dir addr dlen ed-ptr setup-ptr td-head td-tail -- )
+ ( dir addr dlen ed-ptr setup-ptr )
+ 3 pick ( dir addr dlen ed-ptr setup-ptr td-head td-tail ed-ptr )
+ tuck ( dir addr dlen ed-ptr setup-ptr td-head ed-ptr td-tail ed-ptr )
+ ed>tdqtp l!-le ( dir addr dlen ed-ptr setup-ptr td-head ed-ptr )
+ ed>tdqhp l!-le ( dir addr dlen ed-ptr setup-ptr )
+ over ed>ned 0 swap l!-le ( dir addr dlen ed-ptr setup-ptr )
+;
+
+
+\ Initialize the HEAD and TAIL TDs for SETUP and
+\ STATUS phase respectively.
+
+
+: (td-setup-status) ( dir addr dlen ed-ptr setup-ptr -- dir addr dlen ed-ptr )
+ over ed>tdqhp l@-le ( dir addr dlen ed-ptr setup-ptr td-head )
+ dup zero-out-a-td-except-link ( dir addr dlen ed-ptr setup-ptr td-head )
+ dup td>tattr DATA0-TOGGLE CC-FRESH-TD or swap l!-le
+ ( dir addr dlen ed-ptr setup-ptr td-head )
+ 2dup td>cbptr l!-le ( dir addr dlen ed-ptr setup-ptr td-head )
+ 2dup td>bfrend swap STD-REQUEST-SETUP-SIZE 1- + swap l!-le
+ ( dir addr dlen ed-ptr setup-ptr td-head )
+ 2drop ( dir addr dlen ed-ptr )
+;
+
+\ Initialize the TD TAIL pointer.
+
+
+: (td-tailpointer) ( dir addr dlen ed-ptr -- dir addr dlen ed-ptr )
+ dup ed>tdqtp l@-le ( dir addr dlen ed-ptr td-tail )
+ dup zero-out-a-td-except-link ( dir addr dlen ed-ptr td-tail )
+ dup td>tattr dup l@-le DATA1-TOGGLE CC-FRESH-TD or or swap l!-le
+ ( dir addr dlen ed-ptr td-tail )
+ 4 pick 0= ( dir addr dlen ed-ptr td-tail flag )
+ 3 pick 0<> ( dir addr dlen ed-ptr td-tail flag flag )
+ and IF ( dir addr dlen ed-ptr td-tail )
+ dup td>tattr dup l@-le TD-DP-OUT or swap l!-le
+ ( dir addr dlen ed-ptr td-tail )
+ ELSE
+ dup td>tattr dup l@-le TD-DP-IN or swap l!-le
+ ( dir addr dlen ed-ptr td-tail )
+ THEN
+ drop ( dir addr dlen ed-ptr )
+;
+
+\ Initialize the Data TDs.
+
+
+: (td-data) ( dir addr dlen ed-ptr -- ed-ptr )
+ -rot ( dir ed-ptr addr dlen )
+ dup 0<> IF ( dir ed-ptr addr dlen )
+ >r >r >r TO temp1 r> r> r> temp1 ( ed-ptr addr dlen dir )
+ 3 pick ( ed-ptr addr dlen dir ed-ptr )
+ ed>tdqhp l@-le td>ntd l@-le ( ed-ptr addr dlen dir td-datahead )
+ 4 pick ( ed-ptr addr dlen dir td-datahead ed-ptr )
+ td>tattr l@-le 10 rshift ( ed-ptr addr dlen dir td-head-data MPS )
+ swap ( ed-ptr addr dlen dir MPS td-head-data )
+ >r >r >r >r >r 1 r> r> r> r> r>
+ ( ed-ptr 1 addr dlen dir MPS td-head-data )
+ >r >r 0= IF ( ed-ptr 1 addr dlen dir )
+ OHCI-DP-IN ( ed-ptr 1 addr dlen dir OHCI-DP-IN )
+ ELSE
+ OHCI-DP-OUT ( ed-ptr 1 addr dlen dir OHCI-DP-OUT )
+ THEN
+ r> r> ( ed-ptr 1 addr dlen dir OHCI-DP- MPS td-head-data )
+ fill-TD-list
+ ELSE
+ 2drop nip ( ed-ptr )
+ THEN
+;
+
+
+\ Program the HC with the ed-ptr value and wait for status to
+\ from the HC.
+\ Free the ED and TDs associated with it.
+\ PENDING: Above said.
+
+10 CONSTANT max-retire-td
+
+: (transfer-wait-for-doneq) ( ed-ptr -- TRUE | FALSE )
+ dup ( ed-ptr ed-ptr )
+ hcctrhead rl!-le ( ed-ptr )
+ HC-enable-control-list-processing ( ed-ptr )
+ 0 TO td-retire-count ( ed-ptr )
+ 0 TO poll-timer ( ed-ptr )
+ BEGIN
+ td-retire-count num-tds <> ( ed-ptr TRUE | FALSE )
+ poll-timer max-retire-td < and ( ed-ptr TRUE | FALSE )
+ WHILE
+ (HC-CHECK-WDH) ( ed-ptr )
+ IF
+ hchccadneq l@-le find-td-list-tail-and-size nip ( ed-ptr n )
+ td-retire-count + TO td-retire-count ( ed-ptr )
+ hchccadneq l@-le dup ( ed-ptr done-td done-td )
+ (td-list-status) ( ed-ptr done-td failed-td CCcode )
+ IF
+ \ keep condition code of TD on return stack
+ dup >r
+ s" (transfer-wait-for-doneq: USB device communication error."
+ usb-debug-print ( ed-ptr done-td failed-td CCcode R: CCcode )
+ dup 4 = swap dup 5 = rot or ( ed-ptr done-td failed-td CCcode R: CCcode )
+ IF
+ max-retire-td TO poll-timer ( ed-ptr done-td failed-td CCcode R: CCcode )
+ THEN
+ ( ed-ptr done-td failed-td CCcode R: CCcode )
+ usb-debug-flag
+ IF
+ s" CC code ->" type . cr
+ s" Failing TD contents:" type cr display-td
+ ELSE
+ 2drop
+ THEN ( ed-ptr done-td R: CCcode )
+ controlxfer-cmd @ GET-MAX-LUN = r> 4 = and
+ IF
+ s" (transfer-wait-for-doneq): GET-MAX-LUN ControlXfer STALLed"
+ usb-debug-print
+ \ Condition Code = 4 means that the device does not support multiple LUNS
+ \ see USB Massbulk 1.0 Standard
+ ELSE
+ drop
+ 5030 error" (USB) Device communication error."
+ ABORT
+ \ FIXME: ABORTing here might leave the HC in an unusable state.
+ \ We should maybe rather ABORT at the end of this Forth
+ \ word, when clean-up has been done (or not ABORT at all)
+ THEN
+ THEN ( ed-ptr done-td )
+ (free-td-list) ( ed-ptr )
+ 0 hchccadneq l!-le ( ed-ptr )
+ (HC-ACK-WDH) \ TDs were written to DOne queue. ACK the HC.
+ THEN
+ poll-timer 1+ TO poll-timer
+ 4 ms \ longer 1 ms
+ REPEAT ( ed-ptr )
+ disable-control-list-processing ( ed-ptr )
+ td-retire-count num-tds <> ( ed-ptr )
+ IF
+ dup display-descriptors ( ed-ptr )
+ s" maximum of retire " usb-debug-print
+ THEN
+ free-ed
+ td-retire-count num-tds <>
+ IF
+ FALSE ( FALSE )
+ ELSE
+ TRUE ( TRUE )
+ THEN
+;
+
+
+\ COLON DEFINITION: controlxfer
+\ INTERFACE FUNCTION
+
+\ ARGUMENTS:
+\ (from the bottom OF stack)
+\ 1. dir -- This is the direction OF data transfer associated with
+\ the DATA STAGE OF the control xfer.
+\ If there is no data transfer (argument dlen is zero)
+\ THEN this argument DOes not matter, nonethless it has
+\ to be passed.
+\ A "0" represents an IN and "1" represents an "OUT".
+\ 2. addr -- If therez a data stage associated with the transfer,
+\ THEN, this argument holds the address OF the data buffer
+\ 3. dlen -- This arg holds the length OF the data buffer discussed
+\ in previous step (addr)
+\ 4. setup-packet -- This holds the pointer to the setup packet that
+\ will be transmitted during the SETUP stage OF
+\ the control xfer. The function assumes the length
+\ OF the status packet to be 8 bytes.
+\ 5. MPS -- This is the MAX PACKET SIZE OF the endpoint.
+\ 6. ep-fun -- This is the 11-bit value that holds the Endpoint and
+\ the function address. bit 7 to bit 10 holds the Endpoint
+\ address. Bits 0 to Bit 6 holds the Function Address.
+\ The BIT numbering followed : The left most bit is referred
+\ as bit 0. (not the one followed by PPC)
+\ Bit 13 must be set for low-speed devices.
+
+\ RETURN VALUE:
+\ Returns TRUE | FALSE depending on the success OF the transaction.
+
+\ ASSUMPTIONS:
+\ 1. Function assumes that the setup packet is 8-bytes in length.
+\ If in future, IF we need to add a new argument, we need to change
+\ the function in lot OF places.
+
+\ RISKS:
+\ 1. If for some reason, the USB controller DOes not retire all the TDs
+\ THEN, the status checking part OF this "word" can spin forever.
+
+
+: controlxfer ( dir addr dlen setup-packet MPS ep-fun -- TRUE | FALSE )
+ 2 pick @ controlxfer-cmd !
+ (ed-prepare) ( FALSE | dir addr dlen ed-ptr setup-ptr )
+ invert IF FALSE EXIT THEN
+ (td-prepare) ( pt ed-type toggle buffer length mps head )
+ invert IF FALSE EXIT THEN
+ (td-ready) ( dir addr dlen ed-ptr setup-ptr )
+ (td-setup-status) ( dir addr dlen ed-ptr )
+ (td-tailpointer) ( dir addr dlen ed-ptr )
+ (td-data) ( ed-ptr )
+
+
+ \ FIXME:
+ \ Clear the TAIL pointer in ED. This has got sthg to DO with how
+ \ the HC finds an EMPTY queue condition. Refer spec.
+
+
+ dup ed>tdqtp l@-le TO saved-tail ( ed-ptr )
+ dup ed>tdqtp 0 swap l!-le ( ed-ptr )
+ (transfer-wait-for-doneq) ( TRUE | FALSE )
+;
+
+0201000000000000 CONSTANT CLEARHALTFEATURE
+0 VALUE endpt-num
+0 VALUE usb-addr-contr-req
+: control-std-clear-feature ( endpoint-nr usb-addr -- TRUE|FALSE )
+ TO usb-addr-contr-req \ usb address
+ TO endpt-num \ endpoint number
+ CLEARHALTFEATURE setup-packet !
+ endpt-num setup-packet 4 + c! \ endpoint number
+ 0 0 0 setup-packet DEFAULT-CONTROL-MPS usb-addr-contr-req controlxfer
+ ( TRUE|FALSE )
+;
+
+\ It resets the usb bulk-device
+21FF000000000000 CONSTANT BULK-RESET
+: control-std-bulk-reset ( usb-addr -- TRUE|FALSE )
+ TO usb-addr-contr-req
+ BULK-RESET setup-packet !
+ 0 0 0 setup-packet DEFAULT-CONTROL-MPS usb-addr-contr-req controlxfer
+ ( TRUE|FALSE )
+;
+
+: bulk-reset-recovery-procedure ( bulk-out-endp bulk-in-endp usb-addr -- )
+ >r ( bulk-out-endp bulk-in-endp R: usb-addr )
+ \ perform a bulk reset
+ r@ control-std-bulk-reset
+ IF s" bulk reset OK"
+ ELSE s" bulk reset failed"
+ THEN usb-debug-print
+
+ \ clear bulk-in endpoint ( bulk-out-endp bulk-in-endp R: usb-addr )
+ 80 or r@ control-std-clear-feature
+ IF s" control-std-clear IN endpoint OK"
+ ELSE s" control-std-clear-IN endpoint failed"
+ THEN usb-debug-print
+
+ \ clear bulk-out endpoint ( bulk-out-endp R: usb-addr )
+ r@ control-std-clear-feature
+ IF s" control-std-clear OUT endpoint OK"
+ ELSE s" control-std-clear-OUT endpoint failed"
+ THEN usb-debug-print
+ r> drop
+;
+
+0 VALUE saved-rw-ed
+0 VALUE num-rw-tds
+0 VALUE num-rw-retired-tds
+0 VALUE saved-rw-start-toggle
+0 VALUE saved-list-type
+
+\ Allocate an ED and populate what you can.
+
+
+: (ed-prepare-rw)
+ ( pt ed-type toggle buffer length mps address ed-ptr --
+ FALSE | pt ed-type toggle buffer length mps )
+ allocate-ed dup 0= IF
+ ( pt ed-type toggle buffer length mps address ed-ptr )
+ drop 2drop 2drop 2drop drop
+ saved-rw-start-toggle FALSE EXIT ( toggle FALSE )
+ THEN
+ TO saved-rw-ed ( pt ed-type toggle buffer length mps address )
+ saved-rw-ed zero-out-an-ed-except-link
+ ( pt ed-type toggle buffer length mps address )
+ saved-rw-ed ed>eattr l!-le ( pt ed-type toggle buffer length mps )
+ dup 10 lshift saved-rw-ed ed>eattr l@-le or
+ ( pt ed-type toggle buffer length mps mps~ )
+ saved-rw-ed ed>eattr l!-le TRUE ( pt ed-type toggle buffer length mps TRUE )
+;
+
+
+\ Allocate TD List
+
+
+: (td-prepare-rw)
+ ( pt ed-type toggle buffer length mps --
+ FALSE | pt ed-type toggle buffer length mps head )
+ 2dup ( pt ed-type toggle buffer length mps length mps )
+ /mod ( pt ed-type toggle buffer length mps num-tds rem )
+ swap 0<> IF ( pt ed-type toggle buffer length mps num-tds )
+ 1+ ( pt ed-type toggle buffer length mps num-tds+1 )
+ THEN
+ dup TO num-rw-tds ( pt ed-type toggle buffer length mps num-tds )
+ allocate-td-list ( pt ed-type toggle buffer length mps head tail )
+ dup 0= IF
+ 2drop 2drop 2drop 2drop
+ saved-rw-ed free-ed
+ ." rw-endpoint: TD list allocation failed" cr
+ saved-rw-start-toggle FALSE ( FALSE )
+ EXIT
+ THEN
+ drop TRUE ( pt ed-type toggle buffer length mps head TRUE )
+;
+
+
+\ Populate TD list with data buffers and toggle info.
+
+
+: (td-data-rw)
+ ( pt ed-type toggle buffer length mps head -- FALSE | pt et head )
+ 6 pick ( pt ed-type toggle buffer length mps head pt )
+ FALSE TO case-failed CASE
+ 0 OF OHCI-DP-IN ENDOF
+ 1 OF OHCI-DP-OUT ENDOF
+ 2 OF OHCI-DP-SETUP ENDOF
+ dup OF TRUE TO case-failed
+ ." rw-endpoint: Invalid Packet Type!" cr
+ ENDOF
+ ENDCASE ( pt ed-type toggle buffer length mps head dp )
+ case-failed IF
+ saved-rw-ed free-ed ( pt ed-type toggle buffer length mps head dp )
+ drop (free-td-list) ( pt ed-type toggle buffer length mps head )
+ 2drop 2drop 2drop
+ saved-rw-start-toggle FALSE ( FALSE )
+ EXIT ( FALSE )
+ THEN
+ -rot ( pt ed-type toggle buffer length dp mps head )
+ dup >r ( pt ed-type toggle buffer length dp mps head )
+ fill-TD-list r> TRUE ( pt et head TRUE )
+;
+
+
+\ Enqueue the ED with the appropriate list
+
+
+: (ed-ready-rw) ( pt et -- - | toggle FALSE )
+ nip ( et )
+ FALSE TO case-failed CASE
+ 0 OF \ Control List. Queue the ED to control list
+ 0 TO saved-list-type
+ saved-rw-ed hcctrhead rl!-le
+ HC-enable-control-list-processing
+ ENDOF
+ 1 OF \ Bulk List. Queue the ED to bulk list
+ 1 TO saved-list-type
+ saved-rw-ed hcbulkhead rl!-le
+ HC-enable-bulk-list-processing
+ ENDOF
+ 2 OF \ Interrupt List.
+ 2 TO saved-list-type
+ saved-rw-ed hchccareg rl@-le rl!-le
+ HC-enable-interrupt-list-processing
+ ENDOF
+ dup OF
+ saved-rw-ed ed>tdqhp l@-le (free-td-list)
+ saved-rw-ed free-ed
+ TRUE TO case-failed
+ ENDOF
+ ENDCASE
+ case-failed IF
+ saved-rw-start-toggle FALSE ( toggle FALSE )
+ EXIT
+ THEN
+ TRUE ( TRUE )
+;
+
+\ Wait for TDs to return to the Done Q.
+
+: (wait-td-retire) ( -- )
+ 0 TO num-rw-retired-tds
+ FALSE TO while-failed
+ BEGIN
+ num-rw-retired-tds num-rw-tds < ( TRUE | FALSE )
+ while-failed FALSE = and ( TRUE | FALSE )
+ WHILE
+ d# 5000 (wait-for-done-q) ( TD-list TRUE|FALSE )
+ IF
+ dup find-td-list-tail-and-size nip ( td-list size )
+ num-rw-retired-tds + TO num-rw-retired-tds ( td-list )
+ dup (td-list-status) ( td-list failed-TD CC )
+ IF
+ dup 4 =
+ IF
+ saved-list-type
+ CASE
+ 0 OF
+ 0 0 control-std-clear-feature
+ s" clear feature " usb-debug-print
+ ENDOF
+ 1 OF \ clean bulk stalled
+ s" clear bulk when stalled " usb-debug-print
+ disable-bulk-list-processing \ disable procesing
+ saved-rw-ed ed>eattr l@-le dup \ extract
+ 780 and 7 rshift 80 or \ endpoint and
+ swap 7f and \ usb addr
+ control-std-clear-feature
+ ENDOF
+ 2 OF
+ 0 saved-rw-ed ed>eattr l@-le
+ control-std-clear-feature
+ ENDOF
+ dup OF
+ s" unknown status " usb-debug-print
+ ENDOF
+ ENDCASE
+ ELSE ( td-list failed-TD CC )
+ ." TD failed " 5b emit .s 5d emit cr
+ 5040 error" (USB) device transaction error (wait-td-retire)."
+ ABORT
+ THEN
+ 2drop drop
+ TRUE TO while-failed \ transaction failed
+ NEXT-TD 0<> \ clean the TD if we
+ IF
+ NEXT-TD (free-td-list) \ had a stalled
+ THEN
+ THEN
+ (free-td-list)
+ ELSE
+ drop \ drop td-list pointer
+ scan-time? IF 2e emit THEN \ show proceeding dots
+ TRUE TO while-failed
+ s" time out wait for done" usb-debug-print
+ 20 ms \ wait for bad device
+ THEN
+ REPEAT
+;
+
+
+\ Process retired TDs
+
+
+: (process-retired-td) ( -- TRUE | FALSE )
+ saved-list-type CASE
+ 0 OF disable-control-list-processing ENDOF
+ 1 OF disable-bulk-list-processing ENDOF
+ 2 OF disable-interrupt-list-processing ENDOF
+ ENDCASE
+ saved-rw-ed ed>tdqhp l@-le 2 and 0<> IF
+ 1
+ s" retired 1" usb-debug-print
+ ELSE
+ 0
+ s" retired 0" usb-debug-print
+ THEN
+ \ s" retired " usb-debug-print-val
+ WHILE-failed IF
+ FALSE ( FALSE )
+ ELSE
+ TRUE ( TRUE )
+ THEN
+ saved-rw-ed free-ed
+;
+
+
+\ (DO-rw-endpoint): T1 12 80 0 0chis method is an privately visible function
+\ to be used by the "rw-endpoint" the required
+\ number OF times based on the actual length
+\ to be transferred
+
+\ Arguments:
+\ pt: Packet type
+\ 0 -> IN
+\ 1 -> OUT
+\ 2 -> SETUP
+\ et: Endpoint type
+\ 0 -> Control
+\ 1 -> Bulk
+\ toggle: Starting toggle for this transfer
+\ buffer length: Data buffer associated with the transfer limited
+\ accordingly by the "rw-endpoint" method to the
+\ value OF max packet size
+\ mps: Max Packet Size.
+\ address: Address OF endpoint. 11-bit address. The lower 7-bits represent
+\ the USB addres and the upper 4-bits represent the Endpoint
+\ number.
+
+
+
+: (do-rw-endpoint)
+ ( pt ed-type toggle buffer length mps address -- toggle TRUE|toggle FALSE )
+ 4 pick ( pt ed-type toggle buffer length mps address toggle )
+ TO saved-rw-start-toggle ( pt ed-type toggle buffer length mps address )
+ (ed-prepare-rw) ( FALSE | pt ed-type toggle buffer length mps )
+ invert IF FALSE EXIT THEN
+ (td-prepare-rw) ( FALSE | pt ed-type toggle buffer length mps head )
+ invert IF FALSE EXIT THEN
+ (td-data-rw) ( FALSE | pt et head )
+ invert IF FALSE EXIT THEN
+ saved-rw-ed ed>tdqhp l!-le ( pt et )
+ saved-rw-ed ed>tdqhp l@-le td>ntd l@-le TO NEXT-TD \ save for a stalled
+ (ed-ready-rw)
+ invert IF FALSE EXIT THEN
+ (wait-td-retire)
+ (process-retired-td) ( TRUE | FALSE )
+;
+
+
+\ rw-endpoint: The method is an externally visible method to be exported
+\ to the child nodes. It uses the internal method
+\ "(DO-rw-endpoint)", the required number OF times based on the
+\ actual length OF transfer, so that the limitataion OF MAX-TDS
+\ DO not hinder the transfer.
+
+\ Arguments:
+\ pt: Packet type
+\ 0 -> IN
+\ 1 -> OUT
+\ 2 -> SETUP
+\ et: Endpoint type
+\ 0 -> Control
+\ 1 -> Bulk
+\ toggle: Starting toggle for this transfer
+\ buffer length: Data buffer associated with the transfer
+\ mps: Max Packet Size.
+\ address: Address OF endpoint. 11-bit address. The lower 7-bits represent
+\ the USB addres and the upper 4-bits represent the Endpoint
+\ number.
+
+
+0 VALUE transfer-len
+0 VALUE mps-current
+0 VALUE addr-current
+0 VALUE usb-addr
+0 VALUE toggle-current
+0 VALUE type-current
+0 VALUE pt-current
+0 VALUE read-status
+0 VALUE counter
+0 VALUE residue
+
+
+: rw-endpoint
+ ( pt ed-type toggle buffer length mps address -- )
+ ( toggle TRUE |toggle FALSE )
+
+ \ a single transfer descriptor can point to a buffer OF
+ \ 8192 bytes a block on the CDROM has 2048 bytes
+ \ but a single transfer is constrained by the MPS
+
+ 2 pick TO transfer-len ( pt ed-type toggle buffer length mps address )
+ 1 pick TO mps-current ( pt ed-type toggle buffer length mps address )
+ TRUE TO read-status ( pt ed-type toggle buffer length mps address )
+ transfer-len mps-current num-free-tds * <= IF
+ (do-rw-endpoint) ( toggle TRUE | toggle FALSE )
+ TO read-status ( toggle )
+ TO toggle-current
+ ELSE
+ TO usb-addr ( pt ed-type toggle buffer length mps )
+ 2drop ( pt ed-type toggle buffer )
+ TO addr-current ( pt ed-type toggle )
+ TO toggle-current ( pt ed-type )
+ TO type-current ( pt )
+ TO pt-current
+ transfer-len mps-current num-free-tds * /mod ( residue count )
+ ( remainder=residue quotient=count )
+ TO counter ( residue )
+ TO residue
+ mps-current num-free-tds * TO transfer-len BEGIN
+ counter 0 > ( TRUE | FALSE )
+ read-status TRUE = and ( TRUE | FALSE )
+ WHILE
+ pt-current type-current toggle-current ( pt ed-type toggle )
+ addr-current transfer-len ( pt ed-type toggle buffer length )
+ mps-current ( pt ed-type toggle buffer length mps )
+ usb-addr (do-rw-endpoint) ( toggle TRUE | toggle FALSE )
+ TO read-status ( toggle )
+ TO toggle-current
+ addr-current transfer-len + TO addr-current
+ counter 1- TO counter
+ REPEAT
+ residue 0<> ( TRUE |FALSE )
+ read-status TRUE = and IF
+ residue TO transfer-len
+ pt-current type-current toggle-current ( pt ed-type toggle )
+ addr-current transfer-len ( pt ed-type toggle buffer length )
+ mps-current ( pt ed-type toggle buffer length mps )
+ usb-addr (do-rw-endpoint) ( toggle TRUE | toggle FALSE )
+ TO read-status
+ TO toggle-current
+ THEN
+ THEN
+ read-status invert IF
+ THEN
+ toggle-current ( toggle )
+ read-status ( TRUE | FALSE )
+;