Author: wmb
Date: 2008-12-04 10:17:50 +0100 (Thu, 04 Dec 2008)
New Revision: 1014
Modified:
dev/usb2/device/wlan/common.fth
dev/usb2/device/wlan/fw8388.fth
dev/usb2/device/wlan/usb8388.fth
dev/usb2/device/wlan/wlan.fth
dev/usb2/hcd/ehci/bulk.fth
dev/usb2/hcd/ehci/control.fth
dev/usb2/hcd/ehci/ehci.fth
dev/usb2/hcd/ehci/qhtd.fth
dev/usb2/hcd/hcd-call.fth
dev/usb2/hcd/ohci/bulk.fth
Log:
USB speedups by using ring buffers for bulk in and out.
Modified: dev/usb2/device/wlan/common.fth
===================================================================
--- dev/usb2/device/wlan/common.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/device/wlan/common.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -72,17 +72,14 @@
d# 2048 value /outbuf \ Power of 2 larger than max-frame-size
\ Override as necessary
-0 value inbuf
d# 2048 value /inbuf \ Power of 2 larger than max-frame-size
\ Override as necessary
: init-buf ( -- )
outbuf 0= if /outbuf dma-alloc to outbuf then
- inbuf 0= if /inbuf dma-alloc to inbuf then
;
: free-buf ( -- )
outbuf if outbuf /outbuf dma-free 0 to outbuf then
- inbuf if inbuf /inbuf dma-free 0 to inbuf then
;
: property-or-abort ( name$ -- n )
@@ -98,6 +95,12 @@
" device-id" property-or-abort to pid
;
+: bulk-out ( adr len pipe -- error? )
+ drop
+ " send-out" $call-parent ( qtd )
+ " wait-out" $call-parent ( error? )
+;
+
headers
\ LICENSE_BEGIN
Modified: dev/usb2/device/wlan/fw8388.fth
===================================================================
--- dev/usb2/device/wlan/fw8388.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/device/wlan/fw8388.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -67,26 +67,35 @@
: dl-seq++ ( -- ) dl-seq 1+ to dl-seq ;
-: cmd-fw-dl-ok? ( len -- flag )
- inbuf over vldump
- /boot-ack <> if " Bad command status length" vtype false exit then
- inbuf >boot-magic le-l@ boot-magic <> if " Bad signature" vtype false exit then
- inbuf >cmd-status c@ boot-ack-ok =
+: cmd-fw-dl-ok? ( adr len -- flag )
+ 2dup vldump ( adr len )
+ /boot-ack <> if ( adr )
+ drop ( )
+ " Bad command status length" vtype
+ false exit
+ then ( adr )
+ dup >boot-magic le-l@ boot-magic <> if ( adr )
+ drop ( )
+ " Bad signature" vtype ( )
+ false exit
+ then ( adr )
+ >cmd-status c@ boot-ack-ok = ( ok? )
;
: wait-cmd-fw-dl-ack ( -- acked? )
- false d# 100 0 do
- bulk-in? if
- restart-bulk-in drop leave \ USB error
- else
- ?dup if
- cmd-fw-dl-ok? nip
- restart-bulk-in
- leave
- then
- then
- 1 ms
- loop
+ d# 100 0 do ( )
+ bulk-in-ready? if ( error | buf len 0 )
+ if ( )
+ false ( acked? )
+ else ( buf len )
+ cmd-fw-dl-ok? ( acked? )
+ then ( acked? )
+ restart-bulk-in ( acked? )
+ unloop exit
+ then ( )
+ 1 ms ( )
+ loop ( )
+ false ( acked? )
;
: download-fw-init ( -- )
@@ -94,34 +103,28 @@
boot-magic outbuf >boot-magic le-l!
cmd-fw-dl outbuf >boot-cmd c!
- inbuf /inbuf bulk-in-pipe begin-bulk-in
5 0 do
outbuf /boot-cmd bulk-out-pipe bulk-out drop
wait-cmd-fw-dl-ack if leave then
loop
;
-: process-dl-resp ( len -- )
- inbuf over vldump
+: process-dl-resp ( adr len -- )
+ 2dup vldump
h# 8 < if ." Response too short" abort then
- inbuf >dl-sync-seq le-l@ dl-seq <> if ." Bad sequence" abort then
- inbuf >dl-sync-ack le-l@ if ." Image download failed" abort then
+ dup >dl-sync-seq le-l@ dl-seq <> if drop ." Bad sequence" abort then
+ >dl-sync-ack le-l@ if ." Image download failed" abort then
;
: wait-fw-dl-ack ( -- )
- d# 500 0 do
- bulk-in? if
- drop restart-bulk-in leave
- else
- ?dup if
- process-dl-resp
- restart-bulk-in
- leave
- else
- 1 ms
- then
- then
- loop
+ d# 500 0 do ( )
+ bulk-in-ready? if ( error | buf len 0 )
+ 0= if process-dl-resp then ( )
+ restart-bulk-in ( )
+ leave
+ then ( )
+ 1 ms ( )
+ loop ( )
;
: (download-fw) ( adr len -- )
@@ -149,14 +152,33 @@
until 2drop
;
+: wait-fw ( -- )
+ \ We first get a response packet saying that the download completed
+ wait-cmd-resp if
+ ." No firmware download response; continuing anyway" cr
+ d# 200 ms \ Backwards compatibility with old firmware
+ exit
+ then
+
+ \ Wait for the "started" indicator
+ wait-event if
+ ." Timeout waiting for firmware-started event" cr
+ exit
+ then ( event )
+
+ h# 30 <> if
+ ." Unexpected event while waiting for firmware-started" cr
+ then
+;
: download-fw ( adr len -- )
driver-state ds-not-ready <> if " Firmware downloaded" vtype 2drop exit then
- 2dup fw-image-ok? 0= if ." Bad WLAN firmware image" abort then
+ 2dup fw-image-ok? 0= if ." Bad WLAN firmware image" cr exit then
download-fw-init
(download-fw)
- wait-cmd-resp drop \ A packet is sent after download completes
+
+ wait-fw
+
ds-ready to driver-state
- d# 200 ms
marvel-get-mac-address
;
Modified: dev/usb2/device/wlan/usb8388.fth
===================================================================
--- dev/usb2/device/wlan/usb8388.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/device/wlan/usb8388.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -112,7 +112,7 @@
0 value preamble \ 0=long, 2=short, 4=auto
0 value auth-mode \ 0: open; 1: shared key; 2: EAP
h# 401 value cap \ Capabilities
-3 value mac-ctrl \ MAC control
+3 instance value mac-ctrl \ MAC control
external
: set-preamble ( preamble -- ) to preamble ;
@@ -155,12 +155,13 @@
: fw-seq++ ( -- ) fw-seq 1+ to fw-seq ;
+d# 30 constant resp-wait-tiny
d# 1,000 constant resp-wait-short
d# 10,000 constant resp-wait-long
-resp-wait-short value resp-wait
+resp-wait-short instance value resp-wait
-/inbuf buffer: respbuf
-0 value /respbuf
+/inbuf instance buffer: respbuf
+0 instance value /respbuf
\ =========================================================================
\ Transmit Packet Descriptor
@@ -177,22 +178,34 @@
1 field >tx-pwr
1 field >tx-delay \ in 2ms
1+
+ 1+ \ tx-mesh must be 0
+ 1+ \ tx-mesh must be 0
+ 1 field >tx-mesh-ttl
+ 1+ \ Just for alignment
0 field >tx-pkt
-dup constant /tx-hdr
-4 - constant /tx-desc
+constant /tx-hdr
0 constant tx-ctrl \ Tx rates, etc
+\ The Libertas FW is currently abusing the WDS flag to mean "send on the mesh".
+\ At some point a separate mesh flag might be defined ...
+h# 20000 constant TX_WDS
+
+: mesh-on? ( -- flag ) tx-ctrl TX_WDS and 0<> ;
+
: wrap-pkt ( adr len -- adr' len' )
- dup /tx-hdr + -rot ( len' adr len )
- outbuf /tx-hdr erase ( len' adr len )
- 2dup outbuf >tx-pkt swap move ( len' adr len )
- CMD_TYPE_DATA outbuf >fw-req le-l! ( len' adr len )
- ( len ) outbuf >tx-len le-w! ( len' adr )
- /tx-desc outbuf >tx-offset le-l! ( len' adr )
- tx-ctrl outbuf >tx-ctrl le-l! ( len' adr )
- ( adr ) outbuf >tx-mac /mac-adr move ( len' )
- outbuf swap ( adr' len' )
+ outbuf /tx-hdr erase ( adr len )
+ over outbuf >tx-mac /mac-adr move ( adr len )
+ dup outbuf >tx-len le-w! ( adr len )
+ tuck outbuf >tx-pkt swap move ( len )
+
+ CMD_TYPE_DATA outbuf >fw-req le-l! ( len )
+ /tx-hdr 4 - outbuf >tx-offset le-l! ( len ) \ Offset from >tx-ctrl field
+ tx-ctrl outbuf >tx-ctrl le-l! ( len )
+
+ mesh-on? if 1 outbuf >tx-mesh-ttl c! then ( len )
+
+ outbuf swap /tx-hdr + ( adr' len' )
;
' wrap-pkt to wrap-msg
@@ -200,10 +213,11 @@
\ Receive Packet Descriptor
\ =========================================================================
-true value got-data?
-0 value /data
-0 value data
+true instance value got-data?
+0 instance value /data
+0 instance value data
+\ Receive packet descriptor
struct
4 + \ >fw-req
2 field >rx-stat
@@ -216,14 +230,15 @@
4 +
1 field >rx-priority
3 +
-dup constant /rx-desc
- 6 field >rx-dst-mac
- 6 field >rx-src-mac
- 0 field >rx-data-no-snap
- 2 field >rx-pkt-len \ pkt len from >rx-snap-hdr
- 6 field >rx-snap-hdr
- 0 field >rx-data
-constant /rx-min
+\ dup constant /rx-desc
+\ 6 field >rx-dst-mac
+\ 6 field >rx-src-mac
+\ 0 field >rx-data-no-snap
+\ 2 field >rx-pkt-len \ pkt len from >rx-snap-hdr
+\ 6 field >rx-snap-hdr
+\ 0 field >rx-data
+d# 22 + \ Size of an Ethernet header with SNAP
+constant /rx-min
\ >rx-stat constants
1 constant rx-stat-ok
@@ -247,24 +262,32 @@
drop
;
-: unwrap-pkt ( adr len -- adr' len' )
+: unwrap-pkt ( adr len -- data-adr data-len )
/rx-min < if drop 0 0 then \ Invalid packet: too small
- dup >rx-snap-hdr snap-header comp 0= if \ Remove snap header
- dup >rx-data over >rx-data-no-snap 2 pick >rx-pkt-len be-w@ move
- dup >rx-len le-w@ 8 - \ Less snap-header and len field
- else
- dup >rx-len le-w@ ( adr len' )
+
+ \ Go to the payload, skipping the descriptor header
+ dup dup >rx-offset le-l@ + la1+ ( adr data-adr )
+ swap >rx-len le-w@ ( data-adr data-len )
+
+ \ Remove snap header by moving the MAC addresses up
+ \ That's faster than moving the contents down
+ over d# 14 + snap-header comp 0= if ( data-adr data-len )
+ over dup 8 + d# 12 move ( data-adr data-len )
+ 8 /string ( adr' len' )
then
- swap dup >rx-offset le-l@ + 4 + swap ( adr' len' )
;
: process-data ( adr len -- )
- 2dup vdump
- over .rx-desc
+ 2dup vdump ( adr len )
+ over .rx-desc ( adr len )
+
over >rx-stat le-w@ rx-stat-ok <> if 2drop exit then
- true to got-data?
- unwrap-pkt ( adr' len' )
- to /data to data
+
+ unwrap-pkt to /data to data ( )
+
+ true to got-data? \ do-process-eapol may unset this
+
+ \ Check the Ethernet type field for EAPOL messages
data d# 12 + be-w@ h# 888e = if \ Pass EAPOL messages to supplicant
data /data ?process-eapol
then
@@ -289,7 +312,9 @@
: +xbl ( n -- ) 'x be-l! /l +x ;
: outbuf-bulk-out ( dlen -- error? )
- /fw-cmd + outbuf swap 2dup vdump bulk-out-pipe bulk-out
+ /fw-cmd + outbuf swap ( adr len )
+ 2dup vdump bulk-out-pipe ( adr len )
+ bulk-out ( error? )
;
: .cmd ( cmd -- )
@@ -359,28 +384,18 @@
: prepare-cmd ( len cmd -- )
dup .cmd
resp-wait-short to resp-wait
- outbuf 2 pick /fw-cmd + erase
- bulk-in? ?dup if
- nip
- USB_ERR_INV_OP = if
- inbuf /inbuf bulk-in-pipe begin-bulk-in
- else
- restart-bulk-in \ USB error
- then
- else
- if restart-bulk-in then
- then
- fw-seq++
- CMD_TYPE_REQUEST outbuf >fw-req le-l!
- ( cmd ) outbuf >fw-cmd le-w!
- ( len ) /fw-cmd-hdr + outbuf >fw-len le-w!
- fw-seq outbuf >fw-seq le-w!
- 0 outbuf >fw-result le-w!
- set-fw-data-x
+ outbuf 2 pick /fw-cmd + erase ( len cmd )
+ fw-seq++ ( len cmd )
+ CMD_TYPE_REQUEST outbuf >fw-req le-l! ( len cmd )
+ ( cmd ) outbuf >fw-cmd le-w! ( len )
+ ( len ) /fw-cmd-hdr + outbuf >fw-len le-w! ( )
+ fw-seq outbuf >fw-seq le-w! ( )
+ 0 outbuf >fw-result le-w! ( )
+ set-fw-data-x ( )
;
-true value cmd-resp-error?
true value got-response?
+true value got-indicator?
: process-disconnect ( -- ) ds-disconnected set-driver-state ;
: process-wakeup ( -- ) ;
@@ -389,9 +404,12 @@
: process-gmic-failure ( -- ) ;
: .event ?cr ." Event: " type cr ;
+0 instance value last-event
: process-ind ( adr len -- )
drop
- 4 + le-l@ case
+ true to got-indicator?
+ 4 + le-l@ dup to last-event
+ case
h# 00 of " Tx PPA Free" .event endof \ n
h# 01 of " Tx DMA Done" .event endof \ n
h# 02 of " Link Loss with scan" .event process-disconnect endof
@@ -415,16 +433,17 @@
h# 1d of " SNR high" .event endof
h# 23 of endof \ Suppress this; the user doesn't need to see it
\ h# 23 of ." Mesh auto-started" endof
- h# 30 of " Firmware ready" .event endof
+ h# 30 of endof \ Handle this silently
+\ h# 30 of " Firmware ready" .event endof
( default ) ." Unknown " dup u.
endcase
;
: process-request ( adr len -- )
- 2dup vdump
- drop
- true to got-response?
- >fw-result le-w@ to cmd-resp-error?
+ 2dup vdump ( adr len )
+ to /respbuf ( adr )
+ respbuf /respbuf move ( )
+ true to got-response? ( )
;
: process-rx ( adr len -- )
@@ -437,36 +456,56 @@
;
: check-for-rx ( -- )
- bulk-in? if
- restart-bulk-in exit \ USB error
- else
- ?dup if
- inbuf respbuf rot dup to /respbuf move
- restart-bulk-in
- respbuf /respbuf process-rx
- then
- then
+ bulk-in-ready? if ( error | buf len 0 )
+ 0= if process-rx then ( )
+ restart-bulk-in ( )
+ then ( )
;
+
+\ : xcheck-for-rx ( -- )
+\ bulk-in? if ( actual )
+\ drop restart-bulk-in exit \ USB error
+\ else ( actual )
+\ ?dup if ( actual )
+\ inbuf respbuf rot dup to /respbuf move
+\ restart-bulk-in
+\ respbuf /respbuf process-rx
+\ then
+\ then
+\ ;
+
\ -1 error, 0 okay, 1 retry
: wait-cmd-resp ( -- -1|0|1 )
false to got-response?
- false to got-data?
resp-wait 0 do
check-for-rx
got-response? if leave then
1 ms
loop
got-response? if
- cmd-resp-error? case
+ respbuf >fw-result le-w@ case
0 of 0 endof \ No error
4 of 1 endof \ Busy, so retry
( default ) ." Result = " dup u. cr dup
endcase
else
- ." Timeout or USB error" cr
+\ ." Timeout or USB error" cr
true
then
;
+: wait-event ( -- true | event false )
+ false to got-indicator?
+ d# 1000 0 do
+ check-for-rx
+ got-indicator? if last-event false unloop exit then
+ 1 ms
+ loop
+ true
+;
+: outbuf-wait ( len -- error? )
+ outbuf-bulk-out ?dup if exit then
+ wait-cmd-resp
+;
\ =========================================================================
@@ -493,17 +532,6 @@
endcase
;
-: .hw-spec ( adr -- )
- ." HW interface version: " dup >fw-data le-w@ u. cr
- ." HW version: " dup >fw-data 2 + le-w@ u. cr
- ." Max multicast addr: " dup >fw-data 6 + le-w@ .d cr
- ." MAC address: " dup >fw-data 8 + .enaddr cr
- ." Region code: " dup >fw-data d# 14 + le-w@ u. cr
- ." # antenna: " dup >fw-data d# 16 + le-w@ .d cr
- ." FW release: " dup >fw-data d# 18 + le-l@ u. cr
- ." FW capability:" >fw-data d# 34 + le-l@ .fw-cap cr
-;
-
: .log ( adr -- )
dup >fw-len le-w@ /fw-cmd-hdr = if drop exit then
." Multicast txed: " dup >fw-data le-l@ u. cr
@@ -529,6 +557,23 @@
: reset-wlan ( -- ) " wlan-reset" evaluate ;
+: marvel-get-hw-spec ( -- true | adr false )
+ d# 38 h# 03 ( CMD_GET_HW_SPEC ) prepare-cmd
+ d# 38 outbuf-bulk-out ?dup if true exit then
+ resp-wait-tiny to resp-wait
+ wait-cmd-resp if true exit then
+
+ respbuf >fw-data false
+;
+
+\ The purpose of this is to work around a problem that I don't fully understand.
+\ For some reason, when you reopen the device without re-downloading the
+\ firmware, the first command silently fails - you don't get a response.
+\ This is a "throwaway" command to handle that case without a long timeout
+\ or a warning message.
+
+: nonce-cmd ( -- ) marvel-get-hw-spec 0= if drop then ;
+
\ =========================================================================
\ MAC address
\ =========================================================================
@@ -536,9 +581,7 @@
: marvel-get-mac-address ( -- )
8 h# 4d ( CMD_802_11_MAC_ADDRESS ) prepare-cmd
ACTION_GET +xw
- 8 outbuf-bulk-out
- ?dup if ." Failed to send get mac address command: " u. cr exit then
- wait-cmd-resp if exit then
+ 8 outbuf-wait if ." marvel-get-mac-address failed" cr exit then
respbuf >fw-data 2 + mac-adr$ move
;
@@ -546,15 +589,13 @@
8 h# 4d ( CMD_802_11_MAC_ADDRESS ) prepare-cmd
ACTION_SET +xw
mac-adr$ +x$
- 8 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 8 outbuf-wait if exit then
;
: marvel-get-mc-address ( -- )
4 /mc-adrs + h# 10 ( CMD_MAC_MULTICAST_ADR ) prepare-cmd
ACTION_GET +xw
- 4 /mc-adrs + outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 4 /mc-adrs + outbuf-wait if exit then
respbuf >fw-data 2 + le-w@ to #mc-adr
respbuf >fw-data 4 + mc-adrs #mc-adr /mac-adr * move
;
@@ -566,8 +607,7 @@
to #mc-adr
( adr len ) 2dup +x$ \ Multicast addresses
mc-adrs swap move
- 4 /mc-adrs + outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 4 /mc-adrs + outbuf-wait if exit then
;
\ =========================================================================
@@ -578,8 +618,7 @@
8 swap prepare-cmd
ACTION_GET +xw
( reg ) +xw
- 8 outbuf-bulk-out if 0 exit then
- wait-cmd-resp if 0 exit then
+ 8 outbuf-wait if 0 exit then
respbuf >fw-data 4 + le-l@
;
@@ -597,8 +636,7 @@
ACTION_GET +xw
( idx ) +xw
4 +xw
- a outbuf-bulk-out if 0 exit then
- wait-cmd-resp if 0 exit then
+ a outbuf-wait if 0 exit then
respbuf >fw-data 6 + le-l@
;
@@ -610,8 +648,7 @@
4 h# 1c ( CMD_802_11_RADIO_CONTROL ) prepare-cmd
ACTION_SET +xw
preamble 1 or +xw \ Preamble, RF on
- 4 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 4 outbuf-wait if exit then
;
: (set-bss-type) ( bsstype -- ok? )
@@ -620,29 +657,32 @@
0 +xw \ Object = desiredBSSType
1 +xw \ Size of object
( bssType ) +xb
- 6 d# 128 + outbuf-bulk-out if false exit then
- wait-cmd-resp 0=
+ 6 d# 128 + outbuf-wait 0=
;
external
: set-bss-type ( bssType -- ok? ) dup to bss-type (set-bss-type) ;
headers
-: set-mac-control ( -- )
+: (set-mac-control) ( -- error? )
4 h# 28 ( CMD_MAC_CONTROL ) prepare-cmd
mac-ctrl +xw \ WEP type, WMM, protection, multicast, promiscous, WEP, tx, rx
- 4 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 4 outbuf-wait
;
+: set-mac-control ( -- error? )
+ (set-mac-control) if
+ (set-mac-control) drop
+ then
+;
+
: set-domain-info ( adr len -- )
dup 6 + h# 5b ( CMD_802_11D_DOMAIN_INFO ) prepare-cmd
ACTION_SET +xw
7 +xw \ Type = MrvlIETypes_DomainParam_t
( len ) dup +xw \ Length of payload
( adr len ) tuck +x$ \ Country IE
- ( len ) 6 + outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ ( len ) 6 + outbuf-wait if exit then
;
: enable-11d ( -- )
@@ -651,8 +691,7 @@
9 +xw \ Object = enable 11D
2 +xw \ Size of object
1 +xw \ Enable 11D
- 6 d# 128 + outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 6 d# 128 + outbuf-wait if exit then
;
external
@@ -691,6 +730,10 @@
set-mac-control
;
: set-multicast ( adr len -- ) marvel-set-mc-address enable-multicast ;
+
+: mac-off ( -- )
+ 0 to mac-ctrl set-mac-control 3 to mac-ctrl
+;
headers
\ =========================================================================
@@ -749,18 +792,22 @@
d# 34 instance buffer: ssid
+0 value scan-type
+: active-scan ( -- ) 0 to scan-type ;
+: passive-scan ( -- ) 1 to scan-type ;
+
: make-chan-list-param ( adr -- )
#channels 0 do
dup i /chan-list * +
0 over >radio-type c!
i 1+ over >channel# c!
- 0 over >scan-type c!
+ scan-type over >scan-type c!
d# 100 over >min-scan-time le-w!
d# 100 swap >max-scan-time le-w!
loop drop
;
-: (scan) ( -- error? )
+: (scan) ( -- error? | adr len 0 )
/cmd_802_11_scan ssid c@ if
/marvel-IE-hdr + ssid c@ +
then
@@ -790,19 +837,29 @@
/cmd_802_11_scan ( cmdlen )
then ( cmdlen )
- outbuf-bulk-out if true exit then
- wait-cmd-resp
+ outbuf-wait ( error? )
+ dup 0= if ( error? )
+ respbuf /respbuf /fw-cmd /string rot ( adr len 0 )
+ then
;
external
\ Ask the device to look for the indicated SSID.
-: set-ssid ( adr len -- ) h# 32 min ssid pack drop ;
+: set-ssid ( adr len -- )
+ \ This is an optimization for NAND update over the mesh.
+ \ It prevents listening stations, of which there can be many,
+ \ from transmitting when they come on-line.
+ 2dup " olpc-mesh" $= if passive-scan then
+ h# 32 min ssid pack drop
+;
+
: scan ( adr len -- actual )
begin (scan) dup 1 = while drop d# 1000 ms repeat \ Retry while busy
- if 2drop 0 exit then
- respbuf /respbuf /fw-cmd /string ( adr len radr rlen )
- rot min -rot swap 2 pick move ( actual )
+ if 2drop 0 exit then ( adr len scan-adr scan-len )
+ rot min >r ( adr scan-adr r: len )
+ swap r@ move ( r: len )
+ r>
;
headers
@@ -833,8 +890,7 @@
?dup if x /x + swap move else drop then
d# 16 /x + to /x
loop
- d# 72 outbuf-bulk-out if false exit then
- wait-cmd-resp 0=
+ d# 72 outbuf-wait 0=
;
: set-wep ( wep4$ wep3$ wep2$ wep1$ idx -- ok? )
to wep-idx
@@ -855,8 +911,7 @@
d# 72 h# 13 ( CMD_802_11_SET_WEP ) prepare-cmd
ACTION_REMOVE +xw
0 +xw \ TxKeyIndex
- d# 72 outbuf-bulk-out if false exit then
- wait-cmd-resp 0=
+ d# 72 outbuf-wait 0=
;
headers
@@ -868,8 +923,7 @@
4 h# 2f ( CMD_802_11_ENABLE_RSN ) prepare-cmd
ACTION_SET +xw
( enable? ) +xw \ 1: enable; 0: disable
- 4 outbuf-bulk-out if false exit then
- wait-cmd-resp 0=
+ 4 outbuf-wait 0=
;
external
@@ -887,8 +941,7 @@
dup +xw \ Key length
( key$ ) +x$ \ key$
/x dup /fw-cmd-hdr + outbuf >fw-len le-w! \ Finally set the length
- outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ outbuf-wait if exit then
;
external
@@ -944,8 +997,7 @@
0 +xw \ Probe delay time
/x dup /fw-cmd-hdr + outbuf >fw-len le-w! \ Finally set the length
- outbuf-bulk-out if false exit then
- wait-cmd-resp if ." Failed to join adhoc network" cr false exit then
+ outbuf-wait if ." Failed to join adhoc network" cr false exit then
true
;
@@ -961,19 +1013,104 @@
7 h# 11 ( CMD_802_11_AUTHENTICATE ) prepare-cmd
( target-mac$ ) +x$ \ Peer MAC address
auth-mode +xb \ Authentication mode
- 7 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 7 outbuf-wait if exit then
;
: deauthenticate ( mac$ -- )
8 h# 24 ( CMD_802_11_DEAUTHENTICATE ) prepare-cmd
( mac$ ) +x$ \ AP MAC address
3 +xw \ Reason code: station is leaving
- 8 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 8 outbuf-wait if exit then
ds-disconnected set-driver-state
;
+\ Mesh
+
+: mesh-access! ( value cmd -- )
+ h# 82 h# 9b ( CMD_MESH_ACCESS ) prepare-cmd ( value cmd )
+ +xw +xl ( )
+
+ h# 82 outbuf-wait if exit then
+;
+: mesh-access@ ( cmd -- value )
+ h# 82 h# 9b ( CMD_MESH_ACCESS ) prepare-cmd ( value cmd )
+ +xw ( )
+
+ h# 82 outbuf-wait if -1 exit then
+ respbuf >fw-data wa1+ le-l@
+;
+
+: mesh-config-set ( adr len type channel action -- error? )
+ h# 88 h# a3 ( CMD_MESH_CONFIG ) prepare-cmd ( adr len type channel action )
+ +xw +xw +xw ( adr len )
+ dup +xw +x$ ( )
+
+ h# 88 outbuf-wait
+;
+: mesh-config-get ( -- true | buf false )
+ h# 88 h# a3 ( CMD_MESH_CONFIG ) prepare-cmd ( )
+ 3 +xw 0 +xw 5 +xw ( )
+
+ h# 88 outbuf-wait if true exit then
+ respbuf >fw-data false
+;
+: (mesh-start) ( channel tlv -- error? )
+ " "(dd 0e 00 50 43 04 00 00 00 00 00 04)mesh" ( channel tlv adr len )
+ 2swap swap 1 ( adr len tlv channel action ) \ 1 is CMD_ACT_MESH_CONFIG_START
+ mesh-config-set
+;
+
+: mesh-stop ( -- error? )
+ mesh-on? if
+ " " 0 0 0 mesh-config-set ( error? )
+ tx-ctrl TX_WDS invert and to tx-ctrl ( error? )
+ ds-associated reset-driver-state ( error? )
+ else
+ false ( error? )
+ then
+;
+
+: mesh-start ( channel -- error? )
+ \ h# 223 (0x100 + 291) is an old value
+ \ h# 125 (0x100 + 37) is an "official" value that doesn't work
+ h# 223 (mesh-start) dup 0= if ( error? )
+ tx-ctrl TX_WDS or to tx-ctrl ( error? )
+ ds-associated set-driver-state ( error? )
+ then ( error? )
+;
+
+instance variable mesh-param
+: mesh-set-bootflag ( bootflag -- error? )
+ mesh-param le-l! mesh-param 4 1 0 3 mesh-config-set
+;
+: mesh-set-boottime ( boottime -- error? )
+ mesh-param le-w! mesh-param 2 2 0 3 mesh-config-set
+;
+: mesh-set-def-channel ( boottime -- error? )
+ mesh-param le-w! mesh-param 2 3 0 3 mesh-config-set
+;
+: mesh-set-ie ( adr len -- error? ) 4 0 3 mesh-config-set ;
+: mesh-set-ttl ( ttl -- ) 2 mesh-access! ;
+: mesh-get-ttl ( -- ttl ) 1 mesh-access@ ;
+: mesh-set-bcast ( index -- ) 8 mesh-access! ;
+: mesh-get-bcast ( -- index ) 9 mesh-access@ ;
+
+[ifdef] notdef
+: mesh-set-anycast ( mask -- ) 5 mesh-access! ;
+: mesh-get-anycast ( -- mask ) 4 mesh-access@ ;
+
+: mesh-set-rreq-delay ( n -- ) d# 10 mesh-access! ;
+: mesh-get-rreq-delay ( -- n ) d# 11 mesh-access@ ;
+
+: mesh-set-route-exp ( n -- ) d# 12 mesh-access! ;
+: mesh-get-route-exp ( -- n ) d# 13 mesh-access@ ;
+
+: mesh-set-autostart ( n -- ) d# 14 mesh-access! ;
+: mesh-get-autostart ( -- n ) d# 15 mesh-access@ ;
+
+: mesh-set-prb-rsp-retry-limit ( n -- ) d# 17 mesh-access! ;
+[then]
+
\ =========================================================================
\ Associate/disassociate
\ =========================================================================
@@ -1060,8 +1197,7 @@
\ XXX pass thru IEs (optional)
/x dup /fw-cmd-hdr + outbuf >fw-len le-w! \ Finally set the length
- outbuf-bulk-out if false exit then
- wait-cmd-resp if false exit then
+ outbuf-wait if false exit then
respbuf >fw-data 2 + le-w@ ?dup if \ This is the IEEE Status Code
." Failed to associate: " u. cr
@@ -1074,7 +1210,20 @@
;
external
+instance defer mesh-default-modes
+' noop to mesh-default-modes
+: nandcast-mesh-modes ( -- )
+ 1 mesh-set-ttl
+ d# 12 mesh-set-bcast
+;
+' nandcast-mesh-modes to mesh-default-modes
+
: associate ( ch ssid$ target-mac$ -- ok? )
+ 2over " olpc-mesh" $= if ( ch ssid$ target-mac$ )
+ 2drop 2drop mesh-start 0= ( ok? )
+ dup if mesh-default-modes then
+ exit
+ then
?set-wep \ Set WEP keys again, if ktype is WEP
set-mac-control
2dup authenticate
@@ -1090,15 +1239,15 @@
;
: ?reassociate ( -- )
- driver-state ds-disconnected and if do-associate drop then ;
+ driver-state ds-disconnected and if do-associate drop then
+;
' ?reassociate to start-nic
: disassociate ( mac$ -- )
8 h# 26 ( CMD_802_11_DISASSOCIATE ) prepare-cmd
( mac$ ) +x$ \ AP MAC address
3 +xw \ Reason code: station is leaving
- 8 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 8 outbuf-wait if exit then
ds-disconnected set-driver-state
;
@@ -1110,39 +1259,76 @@
: get-rf-channel ( -- )
d# 40 h# 1d ( CMD_802_11_RF_CHANNEL ) prepare-cmd
ACTION_GET +xw
- d# 40 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ d# 40 outbuf-wait if exit then
." Current channel = " respbuf >fw-data 2 + le-w@ .d cr
;
+: get-beacon ( -- interval enabled? )
+ 6 h# b0 ( CMD_802_11_BEACON_CTRL ) prepare-cmd
+ ACTION_GET +xw
+ 6 outbuf-wait if exit then
+ respbuf >fw-data dup 2 wa+ le-w@ swap wa1+ le-w@
+;
+
+: set-beacon ( interval enabled? -- )
+ 6 h# b0 ( CMD_802_11_BEACON_CTRL ) prepare-cmd
+ ACTION_SET +xw ( interval enabled? )
+ +xw +xw
+ 6 outbuf-wait drop
+;
+
+
: get-log ( -- )
0 h# b ( CMD_802_11_GET_LOG ) prepare-cmd
- 0 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 0 outbuf-wait if exit then
respbuf .log
;
: get-rssi ( -- )
2 h# 1f ( CMD_802_11_RSSI ) prepare-cmd
8 +xw \ Value used for exp averaging
- 2 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 2 outbuf-wait drop
\ XXX What to do with the result?
;
-: get-hw-spec ( -- )
- d# 38 3 ( CMD_802_11_GET_HW_SPEC ) prepare-cmd
- ACTION_GET +xw
- d# 38 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
- respbuf .hw-spec
+: .hw-spec ( -- )
+ marvel-get-hw-spec if
+ ." marvel-get-hw-spec command failed" cr
+ else
+ ." HW interface version: " dup le-w@ u. cr
+ ." HW version: " dup 2 + le-w@ u. cr
+ ." Max multicast addr: " dup 6 + le-w@ .d cr
+ ." MAC address: " dup 8 + .enaddr cr
+ ." Region code: " dup d# 14 + le-w@ u. cr
+ ." # antenna: " dup d# 16 + le-w@ .d cr
+ ." FW release: " dup d# 18 + le-l@ u. cr
+ ." FW capability:" d# 34 + le-l@ .fw-cap cr
+ then
;
+: set-data-rate ( rate-code -- )
+ #rates 4 + h# 22 ( CMD_802_11_DATA_RATE ) prepare-cmd
+
+ 1 ( CMD_ACT_SET_TX_FIX_RATE ) +xw
+ 0 +xw \ reserved field
+ ( rate-code ) +xb
+
+ #rates 4 + outbuf-wait drop
+;
+: auto-data-rate ( -- )
+ #rates 4 + h# 22 ( CMD_802_11_DATA_RATE ) prepare-cmd
+
+ 0 ( CMD_ACT_SET_TX_FIX_RATE ) +xw
+ 0 +xw \ reserved field
+
+ #rates 4 + outbuf-wait drop
+;
+
+
: get-data-rates ( -- )
#rates 4 + h# 22 ( CMD_802_11_DATA_RATE ) prepare-cmd
2 ( HostCmd_ACT_GET_TX_RATE ) +xw
- #rates 4 + outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ #rates 4 + outbuf-wait drop
;
2 constant gpio-pin
@@ -1156,8 +1342,7 @@
: host-sleep-activate ( -- )
0 h# 45 ( CMD_802_11_HOST_SLEEP_ACTIVATE ) prepare-cmd
- 0 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 0 outbuf-wait drop
;
: host-sleep-config ( conditions -- )
@@ -1169,22 +1354,91 @@
gpio-pin +xb
wake-gap +xb
- 6 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ 6 outbuf-wait drop
;
: unicast-wakeup ( -- ) wake-on-unicast host-sleep-config ;
: broadcast-wakeup ( -- ) wake-on-unicast wake-on-broadcast or host-sleep-config ;
: sleep ( -- ) host-sleep-activate ;
+[ifdef] notdef
+ CMD_ACT_MESH_...
+ 1 GET_TTL 2 SET_TTL 3 GET_STATS 4 GET_ANYCAST 5 SET_ANYCAST
+ 6 SET_LINK_COSTS 7 GET_LINK_COSTS 8 SET_BCAST_RATE 9 GET_BCAST_RATE
+10 SET_RREQ_DELAY 11 GET_RREQ_DELAY 12 SET_ROUTE_EXP 13 GET_ROUTE_EXP
+14 SET_AUTOSTART_ENABLED 15 GET_AUTOSTART_ENABLED 16 not used
+17 SET_PRB_RSP_RETRY_LIMIT
+
+CMD_TYPE_MESH_
+1 SET_BOOTFLAG 2 SET_BOOTTIME 3 SET_DEF_CHANNEL 4 SET_MESH_IE
+5 GET_DEFAULTS 6 GET_MESH_IE /* GET_DEFAULTS is superset of GET_MESHIE */
+
+CMD_ACT_MESH_CONFIG_.. 0 STOP 1 START 2 SET 3 GET
+
+struct cmd_ds_mesh_config {
+ struct cmd_header hdr;
+ __le16 action; __le16 channel; __le16 type; __le16 length;
+ u8 data[128]; /* last position reserved */
+}
+struct mrvl_meshie_val {
+ uint8_t oui[P80211_OUI_LEN];
+ uint8_t type;
+ uint8_t subtype;
+ uint8_t version;
+ uint8_t active_protocol_id;
+ uint8_t active_metric_id;
+ uint8_t mesh_capability;
+ uint8_t mesh_id_len;
+ uint8_t mesh_id[IW_ESSID_MAX_SIZE]; 32
+}
+struct ieee80211_info_element {
+ u8 id; u8 len; u8 data[0];
+}
+struct mrvl_meshie {
+ struct ieee80211_info_element hdr;
+ struct mrvl_meshie_val val;
+}
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.channel = cpu_to_le16(chan);
+ ie = (struct mrvl_meshie *)cmd.data;
+
+ switch (action) {
+ case CMD_ACT_MESH_CONFIG_START:
+0.b 221 ie->hdr.id = MFIE_TYPE_GENERIC;
+2.b h# 00 ie->val.oui[0] = 0x00;
+3.b h# 50 ie->val.oui[1] = 0x50;
+4.b h# 43 ie->val.oui[2] = 0x43;
+5.b 4 ie->val.type = MARVELL_MESH_IE_TYPE;
+6.b 0 ie->val.subtype = MARVELL_MESH_IE_SUBTYPE;
+7.b 0 ie->val.version = MARVELL_MESH_IE_VERSION;
+8.b 0 ie->val.active_protocol_id = MARVELL_MESH_PROTO_ID_HWMP;
+9.b 0 ie->val.active_metric_id = MARVELL_MESH_METRIC_ID;
+10.b 0 ie->val.mesh_capability = MARVELL_MESH_CAPABILITY;
+11.b ssid_len ie->val.mesh_id_len = priv->mesh_ssid_len;
+12 memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len);
+1 10+ssid_len ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + priv->mesh_ssid_len;
+
+ 42 (32+10) cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val));
+
+config_start: action is 1 (...CONFIG_START), type = mesh_tlv which is either h# 100 d# 291 + or h# 100 d# 37 +
+[then]
+
+[ifdef] notdef
+create mesh_start_cmd
+ \ MFIE_TYPE_GENERIC ielen (10 + sizeof("mesh"))
+ d# 221 c, d# 14 c,
+
+ \ OUI.................... type subtyp vers proto metric cap
+ h# 00 c, h# 50 c, h# 43 c, 4 c, 0 c, 0 c, 0 c, 0 c, 0 c,
+
+ \ ssidlen ssid (set@12)
+ d# 04 c, here 4 allot " mesh" rot swap move
+here mesh_start_cmd - constant /mesh_start_cmd
+[then]
+
[ifdef] wlan-wackup \ This is test code that only works with a special debug version of the Libertas firmware
: autostart ( -- )
- h# 82 h# 9b ( CMD_MESH_ACCESS ) prepare-cmd
- 5 +xw \ CMD_ACT_SET_ANYCAST
- h# 700000 +xl
-
- h# 82 outbuf-bulk-out if exit then
- wait-cmd-resp if exit then
+ h# 700000 h# 5 mesh-access!
;
[then]
Modified: dev/usb2/device/wlan/wlan.fth
===================================================================
--- dev/usb2/device/wlan/wlan.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/device/wlan/wlan.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -54,6 +54,8 @@
false instance value use-promiscuous?
+: end-out-ring ( -- ) " end-out-ring" $call-parent ;
+
external
\ Set to true to force open the driver without association.
@@ -76,9 +78,12 @@
device set-target
opencount @ 0= if
init-buf
- ?load-fw 0= if free-buf false exit then
+ /outbuf 4 bulk-out-pipe " begin-out-ring" $call-parent
+ /inbuf h# 40 bulk-in-pipe " begin-in-ring" $call-parent
+ ?load-fw 0= if end-bulk-in end-out-ring free-buf false exit then
my-args " supplicant" $open-package to supplicant-ih
- supplicant-ih 0= if free-buf false exit then
+ supplicant-ih 0= if end-bulk-in end-out-ring free-buf false exit then
+ nonce-cmd
force-open? if true exit then
link-up? 0= if
['] 2drop to ?process-eapol
@@ -86,8 +91,6 @@
ds-disconnected reset-driver-state
ds-associated set-driver-state
['] do-process-eapol to ?process-eapol
- else
- inbuf /inbuf bulk-in-pipe begin-bulk-in
then
start-nic
then
@@ -100,10 +103,13 @@
opencount @ 1- 0 max opencount !
opencount @ 0= if
disable-multicast
+ mesh-stop drop
link-up? if target-mac$ deauthenticate then
['] 2drop to ?process-eapol
+ stop-nic
+ mac-off
end-bulk-in
- stop-nic
+ end-out-ring
free-buf
supplicant-ih ?dup if close-package 0 to supplicant-ih then
then
@@ -113,26 +119,28 @@
\ Used by the /supplicant support package to perform key handshaking.
: write-force ( adr len -- actual )
tuck wrap-msg ( actual adr' len' )
- bulk-out-pipe bulk-out ( actual usberr )
- if drop -1 then ( actual )
+ " send-out" $call-parent drop ( actual )
;
: read-force ( adr len -- actual )
- false to got-data?
- bulk-in? if
- restart-bulk-in -1 exit \ USB error
- else
- ?dup if
- inbuf respbuf rot dup to /respbuf move
- restart-bulk-in
- respbuf /respbuf process-rx
- then
- then
+ bulk-in-ready? 0= if ( adr len )
+ 2drop -2 exit
+ then ( adr len [ error | buf actual 0 ] )
- got-data? if
+ if ( adr len )
+ restart-bulk-in ( adr len )
+ 2drop -1 exit
+ then ( adr len buf actual )
+
+ false to got-data? ( adr len buf actual )
+ process-rx ( adr len )
+
+ got-data? if ( adr len )
/data min tuck data -rot move ( actual )
- else
+ else ( adr len )
2drop -2 \ No data
- then
+ then ( actual )
+
+ restart-bulk-in
;
\ Normal read and write methods.
@@ -178,8 +186,8 @@
(scan) if
." Failed to scan" true cr
- else
- respbuf /fw-cmd + .scan false
+ else ( adr len )
+ drop .scan false
then
close
Modified: dev/usb2/hcd/ehci/bulk.fth
===================================================================
--- dev/usb2/hcd/ehci/bulk.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/hcd/ehci/bulk.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -17,21 +17,27 @@
0 instance value bulk-in-qh \ For begin-bulk-in, bulk-in?,...
0 instance value bulk-in-qtd \ For begin-bulk-in, bulk-in?,...
+0 instance value bulk-out-qh \ For begin-bulk-out-ring ...
+0 instance value bulk-out-qtd \ For begin-bulk-out-ring ...
+
: bulk-in-data@ ( -- n ) bulk-in-pipe target di-in-data@ di-data>td-data ;
: bulk-out-data@ ( -- n ) bulk-out-pipe target di-out-data@ di-data>td-data ;
: bulk-in-data! ( n -- ) td-data>di-data bulk-in-pipe target di-in-data! ;
: bulk-out-data! ( n -- ) td-data>di-data bulk-out-pipe target di-out-data! ;
: toggle-bulk-in-data ( -- ) bulk-in-pipe target di-in-data-toggle ;
: toggle-bulk-out-data ( -- ) bulk-out-pipe target di-out-data-toggle ;
-: fixup-bulk-in-data ( qh -- data )
+
+: qtd-fixup-bulk-in-data ( qtd -- data )
usb-error USB_ERR_STALL and if
drop bulk-in-pipe h# 80 or unstall-pipe
TD_TOGGLE_DATA0
else
- >hcqh-overlay >hcqtd-token le-l@
+ >hcqtd-token le-l@
then
bulk-in-data!
;
+: fixup-bulk-in-data ( qh -- data ) >hcqh-overlay qtd-fixup-bulk-in-data ;
+
: fixup-bulk-out-data ( qh -- data )
usb-error USB_ERR_STALL and if
drop bulk-out-pipe unstall-pipe
@@ -42,34 +48,34 @@
bulk-out-data!
;
-: process-bulk-args ( buf len pipe timeout -- )
- to timeout
- clear-usb-error
- set-my-dev
- set-my-char
+: set-bulk-vars ( pipe -- )
+ clear-usb-error ( pipe )
+ set-my-dev ( pipe )
+ set-my-char ( )
+;
+
+: process-bulk-args ( buf len pipe -- )
+ set-bulk-vars ( buf len )
2dup hcd-map-in to my-buf-phys to /my-buf to my-buf
;
: alloc-bulk-qhqtds ( -- qh qtd )
- my-buf-phys /my-buf cal-#qtd dup to my-#qtds
- alloc-qhqtds
+ my-buf-phys /my-buf cal-#qtd dup to my-#qtds ( #qtds )
+ alloc-qhqtds ( qh qtd )
;
: ?alloc-bulk-qhqtds ( -- qh qtd )
- my-buf-phys /my-buf cal-#qtd dup to my-#qtds
- dup #bulk-qtd-max > if ." Requested bulk transfer is too big." cr abort then
+ my-buf-phys /my-buf cal-#qtd dup to my-#qtds ( #qtds )
+ dup #bulk-qtd-max > if ." Requested bulk transfer is too big." cr abort then ( #qtds )
- bulk-qh 0= if
- #bulk-qtd-max alloc-qhqtds drop to bulk-qh
- then
- ( #qtd ) bulk-qh reuse-qhqtds
+ bulk-qh 0= if ( #qtds )
+ #bulk-qtd-max alloc-qhqtds drop to bulk-qh ( )
+ then ( #qtds )
+ bulk-qh reuse-qhqtds
;
: free-bulk-qhqtds ( -- )
- bulk-qh ?dup if
- dup >qh-unaligned l@ swap ( qh.u,v )
- dup >qh-phys l@ ( qh.u,v,p )
- #bulk-qtd-max /qtd * /qh + ( qh.u,v,p size )
- aligned32-free-map-out ( )
+ bulk-qh ?dup if ( qh )
+ free-qhqtds ( )
0 to bulk-qh
then
;
@@ -94,92 +100,351 @@
loop 2drop ( )
;
-external
+: more-qtds? ( qtd -- qtd flag )
+ dup >hcqtd-next le-l@ ( qtd next )
+ over >hcqtd-next-alt le-l@ <> ( qtd more? )
+;
-: set-bulk-in-timeout ( t -- ) ?dup if to bulk-in-timeout then ;
+: activate-in-ring ( qtd -- )
+ \ Start with the second entry in the ring so the first entry
+ \ is the last to be activated, thus deferring host controller
+ \ activity until all qtds are active.
+ >qtd-next l@ dup ( qtd0 qtd )
+ begin ( qtd0 qtd )
+ TD_C_ERR3 TD_PID_IN or TD_STAT_ACTIVE or ( qtd0 qtd token )
+ over >hcqtd-token le-w! ( qtd0 qtd )
+ >qtd-next l@ ( qtd0 qtd' )
+ 2dup = until ( qtd0 qtd' )
+ 2drop
+;
-: begin-bulk-in ( buf len pipe -- )
- debug? if ." begin-bulk-in" cr then
- bulk-in-qh if 3drop exit then \ Already started
+: new-fill-bulk-io-qtds ( /buf qtd -- )
+ swap to /my-buf ( qtd )
+ my-buf-phys /my-buf cal-#qtd to my-#qtds ( /buf qtd )
+ my-#qtds 0 do ( qtd )
+ >r ( r: qtd )
+ my-buf my-buf-phys /my-buf r@ fill-qtd-bptrs ( /bptr r: qtd )
+ dup r@ >hcqtd-token 2+ le-w! ( /bptr r: qtd )
+ my-buf++ ( r: qtd )
+ r> >qtd-next l@ ( qtd' )
+ loop drop ( )
+;
- dup to bulk-in-pipe ( buf len pipe )
- bulk-in-timeout process-bulk-args ( )
- alloc-bulk-qhqtds to bulk-in-qtd to bulk-in-qh
+\ Attach the qtd transaction chain beginning at "qtd" to "successor-qtd".
+: attach-qtds ( successor-qtd qtd -- )
+ begin ( succ qtd )
+ \ Test before setting "next-alt"
+ more-qtds? >r ( succ qtd r: flag )
- \ IN qTDs
- TD_PID_IN bulk-in-qtd fill-bulk-io-qtds
+ \ Point each next-alt field to the successor
+ over >qtd-phys l@ ( succ qtd succ-phys )
+ over >hcqtd-next-alt le-l! ( succ qtd r: flag )
+ r> while ( succ qtd )
+ >qtd-next l@ ( succ qtd' )
+ repeat ( succ last-qtd )
+ \ Only the final qtd's next field points to the successor
+ over >qtd-phys l@ over >hcqtd-next le-l! ( succ last-qtd )
+ >qtd-next l! ( )
+;
+
+: alloc-ring-qhqtds ( buf-pa /buf #bufs -- qh qtd )
+ 0 swap 0 ?do ( pa /buf #qtds )
+ >r 2dup cal-#qtd >r ( pa /buf r: #qtds this-#qtds )
+ tuck + swap ( pa' /buf r: #qtds this-#qtds )
+ r> r> + ( pa' /buf #qtds' )
+ loop ( pa' /buf #qtds' )
+ nip nip alloc-qhqtds ( qh qtd0 )
+;
+
+: unmap&free ( va pa len -- )
+ >r ( va pa r: len )
+ over swap ( va va pa r: len )
+ r@ hcd-map-out ( va r: len )
+ r> dma-free ( )
+;
+: alloc&map ( len -- va pa )
+ dup dma-alloc ( totlen va )
+ dup rot hcd-map-in ( va pa )
+;
+
+\ It would be better to put these fields in the qh extension
+\ so we don't need separate ones for in and out.
+
+: free-ring ( qh -- )
+ >r r@ >qh-buf l@ r@ >qh-buf-pa l@
+ r@ >qh-#bufs l@ r> >qh-/buf l@ *
+ unmap&free
+;
+
+: set-bulk-in-timeout ( ms -- ) ?dup if bulk-in-qh >qh-timeout l! then ;
+
+: alloc-ring-bufs ( /buf #bufs qh -- )
+ >r
+ 2dup r@ >qh-#bufs l! r@ >qh-/buf l! ( /buf #bufs )
+ * alloc&map r@ >qh-buf-pa l! r> >qh-buf l! ( )
+;
+: link-ring ( qh qtd -- )
+ swap >r ( qtd r: qh )
+ r@ >qh-buf-pa l@ to my-buf-phys ( qtd r: qh )
+ r@ >qh-buf l@ to my-buf ( qtd r: qh )
+ r@ >qh-/buf l@ swap ( /buf qtd r: qh )
+ r> >qh-#bufs l@ ( /buf qtd #bufs )
+
+ over >r ( /buf qtd #bufs r: qtd0 )
+
+ 1- 0 ?do ( /buf qtd )
+ 2dup new-fill-bulk-io-qtds ( /buf qtd )
+
+ dup my-#qtds /qtd * + ( /buf qtd next-qtd )
+ dup rot attach-qtds ( /buf next-qtd )
+ loop ( /buf qtd r: qtd0 )
+
+ tuck new-fill-bulk-io-qtds ( qtd r: qtd0 )
+ r> swap attach-qtds ( )
+;
+
+: make-ring ( /buf #bufs -- qh qtd )
+ 2dup * alloc&map ( /buf #bufs va pa )
+ dup 4 pick 4 pick alloc-ring-qhqtds ( /buf #bufs va pa qh qtd )
+ >r >r ( /buf #bufs va pa r: qtd qh )
+ r@ >qh-buf-pa l! r@ >qh-buf l! ( /buf #bufs )
+ r@ >qh-#bufs l! r@ >qh-/buf l! ( r: qtd qh )
+
\ Start bulk in transaction
- bulk-in-qh pt-bulk fill-qh
- bulk-in-qh insert-qh
+ r@ pt-bulk fill-qh ( r: qtd qh )
+
+ \ Let the QH keep track of the data toggle
+ r@ >hcqh-endp-char dup le-l@ QH_TD_TOGGLE invert and swap le-l!
+
+ r> r> ( qh qtd )
+ 2dup link-ring ( qh qtd )
+ over insert-qh ( qh qtd )
;
-: bulk-in? ( -- actual usberr )
- bulk-in-qh 0= if 0 USB_ERR_INV_OP exit then
+\ Find the last qtd in a chain of qtds for the same transaction.
+: transaction-last-qtd ( qtd -- qtd' )
+ begin more-qtds? while >qtd-next l@ repeat ( qtd' )
+;
+
+: qtd-successor ( qtd -- qtd' ) transaction-last-qtd >qtd-next l@ ;
+
+\ Insert the qtd transaction chain "new-qtd" in the circular list
+\ after "qtd". This is safe only if qtd is inactive.
+: qtd-insert-after ( new-qtd qtd -- )
+ \ First make qtd's successor new-qtd's successor
+ 2dup qtd-successor swap attach-qtds ( new-qtd qtd )
+
+ \ Then make new-qtd qtd's successor
+ attach-qtds ( )
+;
+
+external
+
+0 value bulk-out-pending
+: activate-out ( qtd len -- )
+ over to bulk-out-pending ( qtd len )
+ over >hcqtd-token ( qtd len token-adr )
+ tuck 2+ le-w! ( qtd token-adr )
+ TD_C_ERR3 TD_PID_OUT or TD_STAT_PING or TD_STAT_ACTIVE or swap le-w! ( qtd )
+ sync-qtd
+;
+
+: wait-out ( qtd -- error? )
+ begin dup qtd-done? until ( qtd )
+ >hcqtd-token c@ h# fc and
+;
+
+\ Possible enhancement: pass in a size argument so that a chain of qtds can be
+\ allocated, with more total buffer space than can be represented by one qtd.
+\ That can get complicated though - if the chain wraps around the ring, the
+\ buffer space would be discontiguous.
+
+: get-out-buffer ( -- qtd buf )
+ bulk-out-qtd begin dup qtd-done? until ( qtd )
+ dup >qtd-next l@ to bulk-out-qtd ( qtd )
+ dup >qtd-buf l@ ( qtd buf )
+;
+
+: send-out ( adr len -- qtd )
+ >r get-out-buffer ( adr qtd buf r: len )
+ rot swap r@ move ( qtd r: len )
+ dup r> activate-out
+;
+
+: begin-out-ring ( /buf #bufs pipe -- )
+ debug? if ." begin-out-ring" cr then
+ bulk-out-qh if 3drop exit then \ Already started
+
+ dup to bulk-out-pipe ( /buf #bufs pipe )
+ set-bulk-vars ( /buf #bufs )
+
+ make-ring ( qh qtd )
+ to bulk-out-qtd to bulk-out-qh ( )
+ bulk-out-timeout bulk-out-qh >qh-timeout l! ( )
+;
+
+: begin-in-ring ( /buf #bufs pipe -- )
+ debug? if ." begin-bulk-in-ring" cr then
+ bulk-in-qh if 3drop exit then \ Already started
+
+ dup to bulk-in-pipe ( /buf #bufs pipe )
+ set-bulk-vars ( /buf #bufs )
+
+ make-ring ( qh qtd )
+ dup activate-in-ring ( qh qtd )
+ to bulk-in-qtd to bulk-in-qh ( )
+ bulk-in-timeout bulk-in-qh >qh-timeout l! ( )
+;
+
+: bulk-in-ready? ( -- false | error true | buf actual 0 true )
clear-usb-error
- bulk-in-qh dup sync-qhqtds
- qh-done? if
- bulk-in-qh error? if
- 0
- else
- bulk-in-qtd dup bulk-in-qh >qh-#qtds l@ get-actual
- over >qtd-buf rot >qtd-pbuf l@ 2 pick dma-sync
- then
- usb-error
- bulk-in-qh fixup-bulk-in-data
+ bulk-in-qtd >r
+ r@ sync-qtd
+ r@ qtd-done? if ( )
+ r@ bulk-in-qh qtd-error? ?dup 0= if ( )
+ r@ >qtd-buf l@ ( buf actual )
+ r@ qtd-get-actual ( buf actual )
+ 2dup r@ >qtd-pbuf l@ swap dma-sync ( buf actual )
+ 0 ( buf actual 0 )
+ then ( error | buf actual 0 )
+ true ( ... )
+ \ Possibly unnecessary
+ r@ qtd-fixup-bulk-in-data ( ... )
+
\ XXX Ethernet does not like process-hc-status!
\ process-hc-status
- else
- 0 usb-error
- then
+ else ( )
+ false ( false )
+ then ( ... )
+ r> drop
;
headers
+: recycle-one-qtd ( qtd -- )
+ \ Clear "Current Offset" field in first buffer pointer
+ dup >qtd-pbuf l@ over >hcqtd-bptr0 le-l! ( qtd )
+
+ \ Reset the "token" word which contains various transfer control bits
+ dup >qtd-/buf l@ d# 16 << ( qtd token_word )
+ TD_STAT_ACTIVE or TD_C_ERR3 or TD_PID_IN or ( qtd token_word' )
+
+ \ Not doing data toggles here!
+
+ swap >hcqtd-token le-l!
+;
+: recycle-bulk-in-qtd ( qtd -- )
+ dup
+ begin more-qtds? while ( qtd0 qtd )
+ >qtd-next l@ ( qtd0 qtd' )
+ dup recycle-one-qtd ( qtd0 qtd )
+ repeat ( qtd0 qtd )
+
+ \ Recycle the first qtd last so the transaction is atomic WRT the HC
+ drop dup recycle-one-qtd ( qtd0 )
+ sync-qtds
+;
+
\ Fixup the host-controller-writable fields in the chain of qTDs -
\ current offset, bytes_to_transfer, and status
: restart-bulk-in-qtd ( qtd -- )
- begin ?dup while ( qtd )
+ begin ( qtd )
\ Clear "Current Offset" field in first buffer pointer
dup >hcqtd-bptr0 dup le-l@ h# ffff.f000 and swap le-l! ( qtd )
\ Reset the "token" word which contains various transfer control bits
dup >qtd-/buf l@ d# 16 << ( qtd token_word )
TD_STAT_ACTIVE or TD_C_ERR3 or TD_PID_IN or ( qtd token_word' )
+
+ \ Maybe unnecessary based on using dt in QH
bulk-in-data@ or toggle-bulk-in-data ( qtd token_word' )
+
over >hcqtd-token le-l! ( qtd )
-
+ more-qtds? while ( qtd )
>qtd-next l@ ( qtd' )
- repeat
+ repeat ( qtd )
+ drop
;
external
-: restart-bulk-in ( -- )
- debug? if ." restart-bulk-in" cr then
- bulk-in-qh 0= if exit then
+\ Wait for the hardware next pointer to catch up with the software pointer.
+: drain-bulk-out ( -- )
+ debug? if ." drain-bulk-out" cr then
+ bulk-out-qtd >qtd-phys l@ ( qtd-pa )
+ bulk-out-qh >hcqh-overlay >hcqtd-next ( qtd-pa 'qh-next )
+ begin 2dup le-l@ = until ( qtd-pa 'qh-next )
+ 2drop
+;
- \ Setup qTD again
- bulk-in-qtd restart-bulk-in-qtd
+: end-out-ring ( -- )
+ debug? if ." end-out-ring" cr then
+ bulk-out-qh 0= if exit then
+ drain-bulk-out
- \ Setup QH again
- bulk-in-qh >hcqh-endp-char dup le-l@ QH_TD_TOGGLE invert and swap le-l!
- bulk-in-qtd >qtd-phys l@ bulk-in-qh >hcqh-overlay >hcqtd-next le-l!
- bulk-in-qh sync-qhqtds
+ bulk-out-qh remove-qh
+ bulk-out-qh free-ring
+ bulk-out-qh free-qh
+
+ 0 to bulk-out-qh 0 to bulk-out-qtd
;
: end-bulk-in ( -- )
debug? if ." end-bulk-in" cr then
bulk-in-qh 0= if exit then
- bulk-in-qtd map-out-bptrs
- bulk-in-qh dup fixup-bulk-in-data
- dup remove-qh free-qhqtds
+
+ bulk-in-qh remove-qh
+ bulk-in-qh fixup-bulk-in-data
+ bulk-in-qh free-ring
+ bulk-in-qh free-qh
+
0 to bulk-in-qh 0 to bulk-in-qtd
;
+0 instance value app-buf
+
+: begin-bulk-in ( buf len pipe -- )
+ rot to app-buf
+ h# 20 swap begin-in-ring
+;
+
+: bulk-in? ( -- actual usberr )
+ bulk-in-ready? if ( usberr | buf actual 0 )
+ ?dup if ( usberr )
+ 0 swap ( actual usberr )
+ else ( buf actual )
+ tuck ( actual buf actual )
+ app-buf swap move ( actual )
+ 0 ( actual usberr )
+ then ( actual usberr )
+ else ( )
+ 0 0 ( actual usberr )
+ then
+;
+
+: restart-bulk-in ( -- )
+ debug? if ." recycle buffer" cr then
+ bulk-in-qh 0= if exit then
+
+ \ Setup qTD again
+ bulk-in-qtd recycle-bulk-in-qtd
+
+ bulk-in-qtd qtd-successor to bulk-in-qtd
+;
+
+: bulk-read? ( -- [ buf ] actual )
+ bulk-in? if restart-bulk-in -1 exit then ( actual )
+ dup 0= if drop -2 exit then ( actual )
+ bulk-in-qtd >qtd-buf l@ swap ( buf actual )
+;
+
+: recycle-buffer restart-bulk-in ;
+
: bulk-in ( buf len pipe -- actual usberr )
debug? if ." bulk-in" cr then
dup to bulk-in-pipe
- bulk-in-timeout process-bulk-args
+ process-bulk-args
?alloc-bulk-qhqtds to my-qtd to my-qh
+ bulk-in-timeout my-qh >qh-timeout l!
\ IN qTDs
TD_PID_IN my-qtd fill-bulk-io-qtds
@@ -206,28 +471,41 @@
remove-qh
;
-: bulk-out ( buf len pipe -- usberr )
+0 instance value bulk-out-busy?
+: done-bulk-out ( -- error? )
+ \ Process results
+ my-qh done? 0= if my-qh error? drop then
+
+ usb-error ( usberr )
+ my-qtd map-out-bptrs ( usberr )
+ my-qh fixup-bulk-out-data ( usberr )
+ my-qh remove-qh ( usberr )
+ false to bulk-out-busy? ( usberr )
+;
+: start-bulk-out ( buf len pipe -- usberr )
+ bulk-out-busy? if ( buf len pipe )
+ done-bulk-out ?dup if nip nip nip exit then
+ then ( buf len pipe )
+
debug? if ." bulk-out" cr then
- dup to bulk-out-pipe
- bulk-out-timeout process-bulk-args
- ?alloc-bulk-qhqtds to my-qtd to my-qh
+ dup to bulk-out-pipe ( buf len pipe )
+ process-bulk-args ( )
+ ?alloc-bulk-qhqtds to my-qtd to my-qh ( )
+ bulk-out-timeout my-qh >qh-timeout l! ( )
my-qh >hcqh-overlay >hcqtd-token dup le-l@ TD_STAT_PING or swap le-l!
\ OUT qTDs
- TD_PID_OUT my-qtd fill-bulk-io-qtds
+ TD_PID_OUT my-qtd fill-bulk-io-qtds ( )
\ Start bulk out transaction
- my-qh pt-bulk fill-qh
- my-qh insert-qh
-
- \ Process results
- my-qh done? 0= if my-qh error? drop then
-
- usb-error ( actual usberr )
- my-qtd map-out-bptrs
- my-qh dup fixup-bulk-out-data
- remove-qh
+ my-qh pt-bulk fill-qh ( )
+ my-qh insert-qh ( )
+ true to bulk-out-busy? ( )
+ 0 ( usberr )
;
+: bulk-out ( buf len pipe -- usberr )
+ start-bulk-out drop done-bulk-out
+;
headers
Modified: dev/usb2/hcd/ehci/control.fth
===================================================================
--- dev/usb2/hcd/ehci/control.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/hcd/ehci/control.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -24,6 +24,7 @@
0 value my-buf \ Virtual address of data buffer
0 value my-buf-phys \ Physical address of data buffer
0 value /my-buf \ Size of data buffer
+0 value my-dir \ Direction (in or out)
0 value my-qtd \ Current TD head
0 value my-qh \ Current QH
@@ -49,10 +50,11 @@
;
: alloc-control-qhqtds ( extra-qtds -- )
- >r
- my-buf-phys /my-buf cal-#qtd dup to my-#qtds
- dup if data-timeout else nodata-timeout then to timeout
- r> + alloc-qhqtds to my-qtd to my-qh
+ >r ( r: extra-qtds )
+ my-buf-phys /my-buf cal-#qtd dup to my-#qtds ( #data-qtds r: extra-qtds )
+ dup r> + alloc-qhqtds to my-qtd to my-qh ( #data-qtds )
+ if data-timeout else nodata-timeout then ( timeout )
+ my-qh >qh-timeout l! ( )
;
: fill-qh ( qh pipetype -- )
@@ -85,10 +87,11 @@
fill-qtd-bptrs drop
;
-: my-buf++ ( len -- )
- /my-buf over - to /my-buf
- my-buf-phys over + to my-buf-phys
- my-buf swap + to my-buf
+: my-buf++ ( len -- )
+ /my-buf min ( len' )
+ /my-buf over - to /my-buf ( len )
+ my-buf-phys over + to my-buf-phys ( len )
+ my-buf swap + to my-buf ( )
;
: fixup-last-qtd ( td -- )
/my-buf if drop exit then
Modified: dev/usb2/hcd/ehci/ehci.fth
===================================================================
--- dev/usb2/hcd/ehci/ehci.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/hcd/ehci/ehci.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -75,14 +75,18 @@
: halted? ( -- flag ) usbsts@ h# 1000 and ;
: halt-wait ( -- ) begin halted? until ;
-: process-hc-status ( -- )
+: process-hc-status ( -- )
usbsts@ dup usbsts! \ Clear interrupts and errors
h# 10 and if " Host system error" USB_ERR_HCHALTED set-usb-error then
;
+: get-hc-status ( -- status )
+ usbsts@ dup usbsts! \ Clear interrupts and errors
+ dup h# 10 and if " Host system error" USB_ERR_HCHALTED set-usb-error then
+;
: doorbell-wait ( -- )
- \ Wait until interupt on async advance bit is set.
- \ But, some HC fails to set the async advance bit sometimes. Therefore,
+ \ Wait until interrupt on async advance bit is set.
+ \ But, some HCs fail to set the async advance bit sometimes. Therefore,
\ we add a timeout and clear the status all the same.
h# 100 0 do usbsts@ h# 20 and if leave then loop
h# 20 usbsts! \ Clear status
Modified: dev/usb2/hcd/ehci/qhtd.fth
===================================================================
--- dev/usb2/hcd/ehci/qhtd.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/hcd/ehci/qhtd.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -105,6 +105,8 @@
4 field >qtd-/buf-all \ Buffer length (size of the entire buffer)
\ Only the first qTD has the entire size of buffer
\ For bulk and intr qTDs
+ 4 field >qtd-unaligned \ Unaligned buffer address
+ 4 field >qtd-size \ Unaligned buffer size
d# 32 round-up
constant /qtd
@@ -154,6 +156,11 @@
4 field >qh-unaligned \ QH's unaligned address
4 field >qh-size \ Size of QH+qTDs
4 field >qh-#qtds \ # of qTDs in the list
+ 4 field >qh-#bufs \ # of bufs
+ 4 field >qh-/buf \ size of each buf
+ 4 field >qh-buf \ buf start va
+ 4 field >qh-buf-pa \ buf start pa
+ 4 field >qh-timeout \ Timeout
d# 32 round-up
constant /qh
@@ -180,34 +187,50 @@
: sync-qh ( qh -- ) dup >qh-phys l@ /hcqh dma-sync ;
: sync-qtd ( qtd -- ) dup >qtd-phys l@ /hcqtd dma-sync ;
-: sync-qhqtds ( qh -- ) dup >qh-phys l@ over >qh-size l@ dma-sync ;
+: sync-qtds ( qtd -- ) dup >qtd-phys l@ over >qtd-size l@ dma-sync ;
+: sync-qhqtds ( qh -- ) dup >qh-phys l@ over >qh-size l@ dma-sync ;
: map-out-bptrs ( qtd -- )
dup >qtd-buf l@ over >qtd-pbuf l@ rot >qtd-/buf-all l@ hcd-map-out
;
-: init-qh ( qh.u,v,p len #qtds -- )
- 3 pick >qh-#qtds l! ( qh.u,v,p len )
- 2 pick >qh-size l! ( qh.u,v,p )
- over >qh-phys l! ( qh.u,v )
- TERMINATE 2 pick >hcqh-next le-l! ( qh.u,v )
- >qh-unaligned l! ( )
-;
: link-qtds ( qtd.v qtd.p #qtds -- )
- 1- 0 ?do ( qtd.v qtd.p )
- TERMINATE 2 pick >hcqtd-next-alt le-l! ( qtd.v qtd.p )
- 2dup swap >qtd-phys l! ( qtd.v qtd.p )
- /qtd + ( qtd.v qtd.p' )
- 2dup swap >hcqtd-next le-l! ( qtd.v qtd.p )
- swap dup /qtd + tuck swap >qtd-next l! ( qtd.p qtd.v' )
- swap ( qtd.v qtd.p )
+ 1- 0 ?do ( v p )
+ TERMINATE 2 pick >hcqtd-next-alt le-l! ( v p )
+ 2dup swap >qtd-phys l! ( v p )
+ /qtd + ( v p' )
+ 2dup swap >hcqtd-next le-l! ( v p )
+ swap dup /qtd + tuck swap >qtd-next l! ( p v' )
+ swap ( v p )
loop
\ Fix up the last qTD
- over >qtd-phys l! ( qtd.v )
- TERMINATE over >hcqtd-next le-l! ( qtd.v )
- TERMINATE swap >hcqtd-next-alt le-l! ( )
+ over >qtd-phys l! ( v )
+ TERMINATE over >hcqtd-next le-l! ( v )
+ TERMINATE swap >hcqtd-next-alt le-l! ( )
;
+
+: alloc-qtds ( #qtds -- qtd )
+ dup >r /qtd * dup >r ( len ) ( R: #qtds len )
+ aligned32-alloc-map-in ( u v p ) ( R: #qtds len )
+ swap ( u p v ) ( R: #qtds len )
+ dup r@ erase ( u p v ) ( R: #qtds len )
+
+ \ Record QTD size for later freeing
+ rot over >qtd-unaligned l! ( p v ) ( R: #qtds len )
+ r> over >qtd-size l! ( p v ) ( R: #qtds )
+
+ dup rot r> link-qtds ( qtd.v )
+;
+
+: free-qtds ( qtd -- )
+ >r ( R: qtd )
+ r@ >qtd-unaligned l@ ( u ) ( R: qtd )
+ r@ dup >qtd-phys l@ ( u v p ) ( R: qtd )
+ r> >qtd-size l@ ( u v p size )
+ aligned32-free-map-out ( )
+;
+
: link-qhqtd ( qtd.p qh -- )
>hcqh-overlay tuck ( qh.overlay qtd.p qh.overlay )
>hcqtd-next le-l! ( qh.overlay )
@@ -223,6 +246,30 @@
link-qtds ( ) \ Link qTDs
;
+: init-qh ( qh.u,v,p len #qtds -- )
+ 3 pick >qh-#qtds l! ( qh.u,v,p len )
+ 2 pick >qh-size l! ( qh.u,v,p )
+ over >qh-phys l! ( qh.u,v )
+ TERMINATE 2 pick >hcqh-next le-l! ( qh.u,v )
+ >qh-unaligned l! ( )
+;
+
+: alloc-qh ( -- qh )
+ /qh aligned32-alloc-map-in ( u v p )
+ over /qh erase ( u v p )
+ over >r ( u v p r: v )
+ /qh 0 init-qh ( r: v )
+ TERMINATE r@ link-qhqtd ( r: v )
+ r> ( qh.v )
+;
+: free-qh ( qh -- )
+ >r ( R: qh )
+ r@ >qh-unaligned l@ ( qh.u ) ( R: qh )
+ r@ dup >qh-phys l@ ( qh.u,v,p ) ( R: qh )
+ r> >qh-size l@ ( qh.u,v,p size )
+ aligned32-free-map-out ( )
+;
+
: alloc-qhqtds ( #qtds -- qh qtd )
dup >r /qtd * /qh + dup >r ( len ) ( R: #qtds len )
aligned32-alloc-map-in ( qh.u,v,p ) ( R: #qtds len )
@@ -234,13 +281,17 @@
r> 4 pick link-qhqtds ( qh qtd )
;
-: free-qhqtds ( qh -- )
+: free-qh ( qh -- )
>r ( R: qh )
r@ >qh-unaligned l@ ( qh.u ) ( R: qh )
r@ dup >qh-phys l@ ( qh.u,v,p ) ( R: qh )
r> >qh-size l@ ( qh.u,v,p size )
aligned32-free-map-out ( )
;
+
+\ Same as free-qh because the size field tells all
+: free-qhqtds ( qh -- ) free-qh ;
+
: reuse-qhqtds ( #qtds qh -- qh qtd )
swap dup >r /qtd * /qh + >r ( qh ) ( R: #qtds len )
dup >qh-unaligned l@ swap ( qh.u,v ) ( R: #qtds len )
@@ -332,6 +383,7 @@
qh-ptr >hcqh-next le-l@ r@ >hcqh-next le-l!
r@ qh-ptr >qh-next l!
r@ >qh-phys l@ qh-ptr >hcqh-next le-l!
+
r> sync-qhqtds
qh-ptr sync-qh
else
@@ -345,7 +397,26 @@
enable-async
then
;
+: fix-wraparound-qh ( qh -- )
+ \ Find the end of the list, the node that points back to the beginning
+ dup >r ( thisqh r: qh0 )
+ begin ( thisqh r: qh0 )
+ dup >qh-next l@ ( thisqh nextqh r: qh0 )
+ dup r@ <> while ( thisqh nextqh r: qh0 )
+ nip ( thisqh' r: qh0 )
+ repeat ( thisqh nextqh r: qh0 )
+ drop
+ \ Change that node's next pointers to skip the removed qh
+ r> >qh-next l@ ( lastqh nextqh )
+ swap ( nextqh lastqh )
+ over >qh-phys l@ ( nextqh lastqh next-phys )
+ over >hcqh-next le-l@ ( nextqh lastqh next-phys last-phys )
+ TYP_QH and or ( nextqh lastqh next-phys' )
+ over >hcqh-next le-l! ( nextqh lastqh next-phys' )
+ >qh-next l! ( )
+;
+
: remove-qh ( qh -- )
dup >qh-next l@ over = if
\ If qh is the only qh in the system, disable-async and exit
@@ -364,10 +435,11 @@
else
drop
then
- else
- >qh-next l@ to qh-ptr
- qh-ptr >hcqh-endp-char dup le-l@ QH_HEAD or swap le-l!
- 0 qh-ptr >qh-prev l!
+ else ( qh )
+ dup >qh-next l@ to qh-ptr ( qh )
+ qh-ptr >hcqh-endp-char dup le-l@ QH_HEAD or swap le-l! ( qh )
+ fix-wraparound-qh ( )
+ 0 qh-ptr >qh-prev l! ( )
qh-ptr sync-qh
then
ring-doorbell
@@ -450,8 +522,6 @@
\ were found in the TDs.
\ ---------------------------------------------------------------------------
-0 value timeout
-
: .qtd-error ( cc -- )
dup TD_STAT_HALTED and if " Stalled; " USB_ERR_STALL set-usb-error then
dup TD_STAT_DBUFF and if " Data Buffer Error; " USB_ERR_DBUFERR set-usb-error then
@@ -461,22 +531,25 @@
TD_STAT_SPLIT_ERR and if " Periodic split-x error; " USB_ERR_SPLIT set-usb-error then
;
-: qh-done? ( qh -- done? )
- >hcqh-overlay ( olay )
- dup >hcqtd-next le-l@ ( olay pnext )
- swap >hcqtd-token le-l@ ( pnext token )
- dup TD_STAT_HALTED and -rot ( halted? pnext token )
- TD_STAT_ACTIVE and 0= swap ( halted? inactive? pnext )
- TERMINATE = and ( halted? done? )
+: qtd-done? ( qtd -- done? )
+ >hcqtd-token le-l@ ( token )
+ dup TD_STAT_HALTED and ( token halted? )
+ swap TD_STAT_ACTIVE and 0= ( halted? inactive? )
or ( done?' )
;
+
+: qh-done? ( qh -- done? ) >hcqh-overlay qtd-done? ;
+
: done? ( qh -- usberr )
begin
- process-hc-status
- ( qh ) dup sync-qh
- ( qh ) dup qh-done? ?dup 0= if
+ process-hc-status ( qh )
+ dup sync-qh ( qh )
+ dup qh-done? ?dup 0= if ( qh )
1 ms
- timeout 1- dup to timeout 0=
+ dup >qh-timeout ( qh timeout-adr )
+ dup l@ 1- ( qh timeout-adr timeout' )
+ dup rot l! ( qh timeout' )
+ 0=
then
until
@@ -484,13 +557,15 @@
usb-error
;
-: error? ( qh -- usberr )
- dup >hcqh-endp-char le-l@ d# 12 >> 3 and
- speed-high = if h# fc else h# fd then
- swap >hcqh-overlay >hcqtd-token le-l@ and ?dup if .qtd-error then
+: qtd-error? ( qtd qh -- usberr )
+ >hcqh-endp-char le-l@ d# 12 >> 3 and ( qtd speed )
+ speed-high = if h# fc else h# fd then ( qtd error-mask )
+ swap >hcqtd-token le-l@ and ?dup if .qtd-error then
usb-error
;
+: error? ( qh -- usberr ) dup >hcqh-overlay swap qtd-error? ;
+
: get-actual ( qtd #qtd -- actual )
0 -rot 0 ?do ( actual qtd )
dup sync-qtd ( actual qtd )
@@ -505,6 +580,25 @@
loop drop ( qtd )
;
+: qtd-get-actual ( qtd -- actual )
+ 0 swap begin ( actual qtd )
+ dup sync-qtd ( actual qtd )
+ dup >hcqtd-token le-l@ dup TD_STAT_ACTIVE and 0= if
+ over >qtd-/buf l@ ( actual qtd token len )
+ swap d# 16 >> h# 7fff and - ( actual qtd len' )
+ rot + swap ( actual' qtd )
+ else
+ drop ( actual qtd )
+ then
+ dup >hcqtd-next l@ ( actual qtd next )
+ over >hcqtd-next-alt l@ ( actual qtd next alt-next )
+ <> while
+ \ If next and alt differ, the next one is part of the same transaction.
+ \ If they are the same, it's a different transaction
+ >qtd-next l@ ( actual qtd' )
+ repeat drop ( actual )
+;
+
\ ---------------------------------------------------------------------------
\ Allocate a dummy qh to be head of the queue to get around the fact that
\ the VIA 2.0 controller does not stop async when told to.
Modified: dev/usb2/hcd/hcd-call.fth
===================================================================
--- dev/usb2/hcd/hcd-call.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/hcd/hcd-call.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -66,7 +66,11 @@
: set-bulk-in-timeout ( t -- )
" set-bulk-in-timeout" $call-parent
;
+: bulk-in-ready? ( -- false | error true | buf len 0 true )
+ " bulk-in-ready?" $call-parent
+;
+
\ Interrupt pipe operations
: begin-intr-in ( buf len pipe interval -- )
" begin-intr-in" $call-parent
Modified: dev/usb2/hcd/ohci/bulk.fth
===================================================================
--- dev/usb2/hcd/ohci/bulk.fth 2008-12-04 09:17:43 UTC (rev 1013)
+++ dev/usb2/hcd/ohci/bulk.fth 2008-12-04 09:17:50 UTC (rev 1014)
@@ -105,6 +105,23 @@
bulk-in-ed insert-my-bulk-in
;
+: bulk-in-ready? ( -- false | error true | buf actual 0 true )
+ clear-usb-error ( )
+ process-hc-status ( )
+ bulk-in-ed dup sync-edtds ( ed )
+ ed-done? if ( )
+ bulk-in-td error? ?dup 0= if ( )
+ bulk-in-td >td-cbp l@ ( buf )
+ bulk-in-td get-actual ( buf actual )
+ 2dup bulk-in-td >td-pcbp l@ swap dma-sync ( buf actual )
+ 0 ( buf actual 0 )
+ then ( error | buf actual 0 )
+ bulk-in-ed fixup-bulk-in-data ( error | buf actual 0 )
+ else
+ false ( false )
+ then
+;
+
: bulk-in? ( -- actual usberr )
bulk-in-ed 0= if 0 USB_ERR_INV_OP exit then
clear-usb-error ( )