Branch
Hash :
1a08f436
Author :
Date :
2010-08-25T09:23:17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
\ ========== Copyright Header Begin ==========================================
\
\ Hypervisor Software File: usb.fth
\
\ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
\
\ - Do no alter or remove copyright notices
\
\ - Redistribution and use of this software in source and binary forms, with
\ or without modification, are permitted provided that the following
\ conditions are met:
\
\ - Redistribution of source code must retain the above copyright notice,
\ this list of conditions and the following disclaimer.
\
\ - Redistribution in binary form must reproduce the above copyright notice,
\ this list of conditions and the following disclaimer in the
\ documentation and/or other materials provided with the distribution.
\
\ Neither the name of Sun Microsystems, Inc. or the names of contributors
\ may be used to endorse or promote products derived from this software
\ without specific prior written permission.
\
\ This software is provided "AS IS," without a warranty of any kind.
\ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
\ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
\ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
\ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
\ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
\ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN
\ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR
\ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
\ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
\ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
\ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
\
\ You acknowledge that this software is not designed, licensed or
\ intended for use in the design, construction, operation or maintenance of
\ any nuclear facility.
\
\ ========== Copyright Header End ============================================
id: @(#)usb.fth 1.16 03/05/12
purpose:
copyright: Copyright 1997-2000, 2003 Sun Microsystems, Inc. All Rights Reserved
copyright: Use is subject to license terms.
external
\ Code for the request looks at the done-q for the endpoint. When no more
\ transfers to go out, and both done-q's dealt with, endpoint gets torn
\ down. Or if error recovery dumps the remaining transfers and deals with
\ done-q's. But how does the code know whether all the replies have been
\ received, and that there aren't more on the controller done-q waiting to
\ be distributed? Can there be any in a transition -- processed by the
\ controller, but not yet put on the done-q because the controller already
\ turned the done-q over to the code, but the code has not yet acknowledged
\ it? What do such transfer-d's look like?
\ OS folks avoid the problem by running a second list structure through
\ the transfer d's in addition to the one the chip uses, together with a
\ re-claim mark on the transfer d's. When code decides to dump an endpoint,
\ it marks each of the transfer d's to be re-claimed, using the non-controller
\ list links. Then it dumps the endpoint. When transfer d's show up on the
\ controller done q with the reclaim mark, the done-q code dumps them
\ immediately, before attempting to assign them to an endpoint.
\ Instead of double threading, try putting a count of outstanding transfer
\ d's in the endpoint. When one is added, increment the count. When one
\ is taken from one of the ping-pong done q's, decrement the count. Don't
\ include the dummy transfer d in the count. If the total of the number left
\ to do plus those on the done q's is less than the transfer d count, there
\ are some in process (or on the controller done q).
\ OHCI control transfers always start with setup stage and always end with
\ a 0 len transfer status stage. There may be a data transfer stage in
\ between.
\ req-adr req-len is the control request to be sent. endpoint usb-addr is
\ the target address. buf-adr buf-len is where accompanying data is to be
\ sent from, or return data to be put. buf-adr = 0 and/or buf-len = 0 imply
\ no data to be transferred. max-pkt is maximum packet to be transferred in
\ one transfer.
\ dir is the direction that data will flow: 0 is from target to host, 1 is
\ from host to target. If no data transfer, dir is 1. low-speed? is true for
\ low-speed target, false for normal speed.
: execute-control ( low-speed? dir max-pkt buf-adr buf-len req-adr req-len
endpoint usb-addr -- hw-err? | stat 0 )
2swap >r >r 2swap >r >r
2swap swap >r -rot
make-endpoint ( endpoint-d ) ( R: r-len r-adr b-len b-adr dir )
r> r> r> r> r> ( endpoint-d dir b-adr b-len r-adr r-len )
2swap >r >r
2swap >r >r r@ ( r-adr r-len endp-d ) ( R: blen badr dir endp-d )
add-setup-transfer ( R: b-len b-adr dir endp-d )
r> r> swap r> r>
2swap 2dup >r >r ( b-adr b-len dir endp-d ) ( R: endp-d dir )
add-data-transfer ( R: endp-d dir )
r> r@ add-ack-transfer ( R: endp-d )
r> dup enque-control ( endp-d )
dup wait-for-last-reply ( endp-d code )
dup if over wipe-endpoint then
swap deque-control ( code )
translate-code
?.error
;
headers
\ Must set skip if dir is out, as there is no data to transfer yet.
: set-endp-dir ( dir endp-adr -- )
over if dup skip-endp then
endpoint-control tuck le-l@
h# ffff.e7ff and
swap if out-bits else in-bits then
d# 11 lshift or
swap le-l!
;
\ XXX hack1 to set the toggle for the starting transfer-d in the endp-d
: set-endp-toggle ( toggle endp-adr -- )
td-head tuck le-l@
swap 1+ 2 and or swap
le-l!
;
: set-trans-toggle ( toggle transfer-d -- )
transfer-control tuck le-l@
h# fcff.ffff and swap d# 24 lshift or
swap le-l!
;
: (use-endp-toggle) ( endp-d -- )
dup td-tail@
swap td-head@ dev>virt
begin ( tail-adr next-adr )
0 over set-trans-toggle
2dup next-transfer le-l@ <>
while
next-transfer le-l@ dev>virt
repeat
2drop
;
\ XXX hack2 to set the transfer-d's to use the toggle in the endpoint-d
: use-endp-toggle ( endp-d -- )
dup td-head@ if (use-endp-toggle)
else drop
then
;
external
\ Data toggles are synchronized via a separate control endpoint transaction.
\ OHCI setup clearing an endpoint stall sets data toggle to 0.
\ Use set-feature to set an endpoint stall. Use clear-feature to clear an
\ endpoint stall.
\ Want to execute this one as quickly as possible, so attach it to the
\ every-ms interrupt q.
\ toggle1 (0 or 1) is to be used first. toggle2 is last-used.
\ mark the toggle in the endpoint-d.
\ XXX not good enough -- nak doesn't cause the transfer-d to be
\ retired. need to wait only for 1 frame (nominally) rather than until reply.
: execute-1-interrupt
( toggle1 low-speed? dir max-pkt buf-addr buf-len endpoint usb-adr
-- toggle2 hw-err? | toggle2 stat 0 )
2swap >r >r 2swap swap >r -rot
( toggle1 low-spd? max-pkt endp u-adr) ( R: blen badr dir )
make-endpoint ( toggle1 endp-adr ) ( R: blen badr dir )
tuck set-endp-toggle
r> r> r> rot 3 pick add-data-transfer
dup use-endp-toggle ( endp-adr )
dup d# 62 enque-interrupt
dup 1-try-wait
over end-toggle -rot
dup if over wipe-endpoint then
swap deque-interrupt ( toggle2 code )
translate-code
?.error
;
\ for now, token will be the endpoint descriptor address
\ token = 0 means it can't be scheduled -- possibly the interval is
\ too great or too small.
\ ms is the maximum gap between successive polls.
\ use the toggle in the endpoint-d. use the dir in the endpoint-d.
\ This uses a local buffer for data transfer. Then the report is copied into
\ the caller's buffer by int-transaction-status, and the buffer can be re-used.
\ disable-int-transactions throws away the local buffer.
\ XXX buf-adr moved to int-transaction-status implies that if dir is out,
\ there is no data to move when enable-int-transactions is executed. So the
\ transaction should be skipped until int-transaction-status is called.
\ So if dir is out, the endpoint descriptor must be marked SKIP, and
\ int-transaction-status must unmark it.
\ set dir in endpoint descriptor, mark transfer to use endpoint dir.
: enable-int-transactions ( ms toggle low-speed? dir max-pkt buf-len
endpoint usb-adr -- token )
rot >r 2swap swap >r -rot
( ms toggle speed max-pkt endp usb-addr ) ( R: blen dir )
make-endpoint ( ms toggle endp-adr ) ( R: blen dir )
tuck set-endp-toggle ( ms endp-adr ) ( R: blen dir )
r> over set-endp-dir \ may need to skip endpoint
r> over caller-len !
dup caller-len @ get-chunk over interrupt-buf !
dup dup interrupt-buf @ over caller-len @
rot 0 swap add-data-transfer \ use target to host -- really use endp for dir
dup use-endp-toggle ( ms endp-adr )
tuck swap pick-q if ( endp endp q# )
enque-interrupt
else ( endp endp ) \ couldn't pick a q
\ dump data-transfer interrupt-buf if caller-len <>0
\ dump ack-transfer, data-transfer
\ clear-endpoint
\ ( endp ) toss-endpoint
\ XXX just to get going, since there is always a q:
cr ." no q found -- error " cr
2drop \ XXX wrong
0
then
;
\ token is the address of the endpoint for the interrupt. The endpoint is
\ placed in one spot on the interrupt tree.
\ toggle is the last one used.
: disable-int-transactions ( token -- toggle )
dup skip-endp
d# 10 ms \ XXX crude; wait for the distributor to have a chance
\ to catch up with any transfers. Could check if
\ any are outstanding via transfer-count.
\ XXX needed if stuff happens on 10 ms tick timer level.
dup dump-done-q
dup ping-pong
dup dump-done-q
dup end-toggle swap
dup wipe-endpoint
dup interrupt-buf @ over caller-len @ give-chunk
deque-interrupt
;
headers
\ Possible optimization: Re-use the transfer descriptor, since it is
\ already allocated and partially ready for re-use.
\ For now, brute force: dump transfer-d and get a new one.
: re-arm-receive ( endp-d -- )
dup skip-endp next-frame \ make sure endpoint is not active
\ >r r@ take-transfer-d's \ re-use transfer-d's
dup dump-done-q
dup ping-pong
dup dump-done-q ( endp-d )
dup dup interrupt-buf @ over caller-len @
\ XXX use (add-data-transfer) to force a 0 len transfer??
rot 0 swap add-data-transfer \ dir is fake; take from endpoint
dup use-endp-toggle
unskip-endp
;
: forward-data ( buf-addr endp-d -- )
sync-mem
>r r@ interrupt-buf @ swap r> caller-len @ move
;
\ Copy data from internal buffer to buf-addr
: receive-int ( buf-addr token -- hw-err? | stat 0 )
dup done-waiting? if
dup code-done-q @ dup condition-code if \ reply had error
nip nip
condition-code translate-code
else \ reply ok
drop
dup re-arm-receive forward-data
usb-ack 0
then
else 2drop usb-nak 0
then
;
\ XXX wrong; but we have no devices needing out interrupt transactions yet
\ from memory to device.
\ Copy data from buf-addr to internal buffer. UnSKIP the endpoint.
: send-int ( buf-addr token -- hw-err? | stat 0 )
2drop 2 0
;
: receive-int? ( token -- in? )
endpoint-control le-l@
h# 0000.1800 and
h# 0000.1000 =
;
external
\ token is the address of the endpoint for the interrupt. The endpoint is
\ placed in one spot on the interrupt tree.
\ stat is ACK if interrupt fired, NACK if not, STALL if stalled.
\ Re-arms the endpoint. Use its own buffers. Copy to/from the provided buffer
\ when int-transaction-status is called. The client can copy out/in the
\ provided buffer in between calls to int-transaction-status.
\ Must be cognizant of dir in enable-int-transactions, in order to know
\ which way to copy the data -- to or from the provided buffer. Must also
\ unSKIP the endpoint if dir is out.
: int-transaction-status ( buf-addr token -- hw-err? | stat 0 )
dup receive-int? if receive-int else send-int then
?.error
;
\ OHCI bulk transfers use IN or OUT token stages. Sometimes can be followed
\ directly by a status stage with no data. Otherwise data transfer stage.
\ IN finishes with 0 len transfer (or no transfer if problem with data).
\ OUT finishes with no extra transfer from host to target. The data toggles
\ are synchronized via a separate control endpoint transaction.
: execute-bulk ( toggle1 dir max-pkt buf-adr buf-len endpoint usb-addr
-- toggle2 hw-err? | toggle2 stat 0 )
2swap >r >r >r 0 -rot r> \ always full speed
make-endpoint ( toggle dir endp-adr ) ( R: blen badr )
rot over set-endp-toggle
tuck r> r> ( endp-adr dir endp-adr badr blen )
2swap add-data-transfer
dup use-endp-toggle ( endp-adr )
dup enque-bulk
dup wait-for-last-reply
over end-toggle -rot
dup if over wipe-endpoint then
swap deque-bulk ( toggle2 code )
translate-code
?.error
;
: set-isoc-endpoint ( endp-d -- )
endpoint-control dup le-l@
h# 8000 or
swap le-l!
;
: set-isoc-direction ( dir endp-d -- )
endpoint-control tuck
le-l@ h# 1800 not and
swap if h# 800 else h# 1000 then or
swap le-l!
;
\ OHCI isoc transfers have IN or OUT token stages. Then data stage.
\ No extra status stage. No data toggles.
\ XXX not really correct, as the various packets can have their own error
\ codes.
\ XXX must be able to do 0 len transfers. Really need to be given a transfer
\ schedule. probably should have both absolute and relative schedules.
\ XXX new stack -- schedule added
\ : execute-isochronous ( buf-adrn cntn ... buf-adr1 cnt1 n absolute? frame#
\ dir max-pkt endpoint usb-addr -- hw-err? )
: execute-isochronous ( frame# dir max-pkt buf-adr buf-len endpoint usb-addr
-- hw-err? )
\ XXX static allocation implies
\ XXX need to copy the buffer to our buffer in order to get dev-addr
2swap >r >r >r 0 -rot r> \ always full speed
make-endpoint ( frame# dir endp-d ) ( R: blen badr )
dup set-isoc-endpoint
tuck set-isoc-direction ( f# endp-d ) ( R: blen badr )
r> r> ( f# endp-d badr blen )
rot dup >r ( f# badr blen endp-d ) ( R: endp-d )
add-isoc-transfer ( R: badr endp )
r@ enque-isoc
r> dup wait-for-last-isoc-reply ( endp-d code )
swap deque-isoc ( code )
translate-code
?.error
;
headers
2 value usb-address-counter
external
\ hub code needs to call up to get the next usb address to assign it
\ to a device it finds when it executes its own probe stuff at power on.
\ " next-usb-address" $call-parent.
\ Only addresses 2 thru 127 are valid to be assigned. 1 is reserved for the
\ root hub node.
: next-usb-address ( -- n )
usb-address-counter d# 127 > if
0
else
usb-address-counter
dup 1+ is usb-address-counter
then
;
: current-frame ( -- n )
hcca frame# le-w@
;
headers
\ Clear stall from endpoint via endpoint 0:
: clear-stall ( speed endpoint usb-adr -- hw-err? | stat 0 )
>r
request-blank >r ( R: usb-adr buf-adr )
clear-feature-req h# 200 or r@ request-type w!
endpoint-stall r@ req-value le-w!
r@ req-index le-w! ( speed ) ( R: usb-adr buf-adr )
1 max-packet 0 0
r> /request
0 r> 2over >r >r \ goes to endpoint 0
execute-control
r> r> give-chunk
;
\ clean up errors: endpoint should be halted. all transfer-d's should
\ be accounted for, either on the endpoint q or on one of its done-q's;
\ the controller shouldn't be fiddling with any. they should really be
\ on the endpoint q. dump all remaining transfer-d's. halt the control
\ q, dump the endpoint, restart the control q.
\ XXX Need to instancify the code.
\ XXX Need to check the size of transfers to make sure it fits in one
\ transfer-d, or else make more of them.