Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | \ ========== Copyright Header Begin ========================================== |
2 | \ | |
3 | \ Hypervisor Software File: qhtd.fth | |
4 | \ | |
5 | \ Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
6 | \ | |
7 | \ - Do no alter or remove copyright notices | |
8 | \ | |
9 | \ - Redistribution and use of this software in source and binary forms, with | |
10 | \ or without modification, are permitted provided that the following | |
11 | \ conditions are met: | |
12 | \ | |
13 | \ - Redistribution of source code must retain the above copyright notice, | |
14 | \ this list of conditions and the following disclaimer. | |
15 | \ | |
16 | \ - Redistribution in binary form must reproduce the above copyright notice, | |
17 | \ this list of conditions and the following disclaimer in the | |
18 | \ documentation and/or other materials provided with the distribution. | |
19 | \ | |
20 | \ Neither the name of Sun Microsystems, Inc. or the names of contributors | |
21 | \ may be used to endorse or promote products derived from this software | |
22 | \ without specific prior written permission. | |
23 | \ | |
24 | \ This software is provided "AS IS," without a warranty of any kind. | |
25 | \ ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, | |
26 | \ INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A | |
27 | \ PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN | |
28 | \ MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR | |
29 | \ ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR | |
30 | \ DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN | |
31 | \ OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR | |
32 | \ FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE | |
33 | \ DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, | |
34 | \ ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF | |
35 | \ SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. | |
36 | \ | |
37 | \ You acknowledge that this software is not designed, licensed or | |
38 | \ intended for use in the design, construction, operation or maintenance of | |
39 | \ any nuclear facility. | |
40 | \ | |
41 | \ ========== Copyright Header End ============================================ | |
42 | id: @(#)qhtd.fth 1.1 07/01/24 | |
43 | purpose: Data structures and manuipulation routines for EHCI USB Controller | |
44 | \ See license at end of file | |
45 | ||
46 | hex | |
47 | headers | |
48 | ||
49 | \ XXX Isochronous is not supported in the current version of the EHCI driver | |
50 | ||
51 | \ --------------------------------------------------------------------------- | |
52 | \ Data structures for this implementation of the EHCI USB Driver include: | |
53 | \ - qh-ptr pointer to the asynchronous list of QHs | |
54 | \ - framelist pointer to the Periodic Frame List | |
55 | \ - intr internal array of interrupts | |
56 | \ --------------------------------------------------------------------------- | |
57 | ||
58 | \ Constants common to most EHCI data structures | |
59 | 1 constant TERMINATE | |
60 | ||
61 | 0 constant TYP_ITD | |
62 | 2 constant TYP_QH | |
63 | 4 constant TYP_SITD | |
64 | 6 constant TYP_FSTN | |
65 | ||
66 | \ Pipe type | |
67 | 0 constant pt-ctrl | |
68 | 1 constant pt-bulk | |
69 | 2 constant pt-intr | |
70 | 3 constant pt-iso | |
71 | ||
72 | \ --------------------------------------------------------------------------- | |
73 | \ Periodic Frame List as defined by the EHCI Spec; 4-KB aligned | |
74 | \ | |
75 | \ Each entry is composed of: bit 0 TERMINATE | |
76 | \ bits 2:1 Pipe type | |
77 | \ bits 31:5 Frame List Link Pointer | |
78 | \ --------------------------------------------------------------------------- | |
79 | ||
80 | h# 1000 constant /align4kb | |
81 | ||
82 | d# 1024 dup constant #framelist \ # of entries in framelist | |
83 | 4 * constant /framelist \ Size of framelist | |
84 | ||
85 | 0 value framelist | |
86 | 0 value framelist-unaligned | |
87 | 0 value framelist-phys | |
88 | ||
89 | : framelist! ( n idx -- ) 4 * framelist + le-l! ; | |
90 | ||
91 | : init-framelist ( -- ) | |
92 | \ Allocate framelist | |
93 | /framelist /align4kb aligned-alloc ( unaligned virt ) | |
94 | swap to framelist-unaligned ( virt ) | |
95 | dup to framelist ( virt ) | |
96 | /framelist true dma-map-in to framelist-phys ( ) | |
97 | ||
98 | \ Initialize framelist | |
99 | #framelist 0 do TERMINATE i framelist! loop | |
100 | framelist-phys periodic! | |
101 | ; | |
102 | ||
103 | \ --------------------------------------------------------------------------- | |
104 | \ Internal interrupt list corresponding with the Frame List | |
105 | \ --------------------------------------------------------------------------- | |
106 | ||
107 | struct | |
108 | 4 field >intr-head | |
109 | 4 field >intr-tail | |
110 | dup constant /intr-entry | |
111 | #framelist * constant /intr \ Size of intr | |
112 | ||
113 | 0 value intr \ Internal array of interrupts | |
114 | ||
115 | : 'intr ( idx -- adr ) /intr-entry * intr + ; | |
116 | : intr-head@ ( idx -- adr ) 'intr >intr-head l@ ; | |
117 | : intr-head! ( adr idx -- ) 'intr >intr-head l! ; | |
118 | : intr-tail@ ( idx -- adr ) 'intr >intr-tail l@ ; | |
119 | : intr-tail! ( adr idx -- ) 'intr >intr-tail l! ; | |
120 | ||
121 | : init-intr ( -- ) | |
122 | /intr alloc-mem dup to intr \ Allocate intr | |
123 | /intr erase \ Initialize intr | |
124 | ; | |
125 | ||
126 | \ --------------------------------------------------------------------------- | |
127 | \ Queue Element Transfer Descriptor (qTD) as defined by the EHCI Spec; 32-byte aligned | |
128 | \ --------------------------------------------------------------------------- | |
129 | ||
130 | struct \ Beginning of qTD | |
131 | 4 field >hcqtd-next \ Next qTD pointer | |
132 | 4 field >hcqtd-next-alt \ Alternate next qTD pointer | |
133 | 4 field >hcqtd-token \ qTD token | |
134 | 4 field >hcqtd-bptr0 \ Buffer pointer 0 (4KB aligned) | |
135 | 4 field >hcqtd-bptr1 \ Buffer pointer 1 | |
136 | 4 field >hcqtd-bptr2 \ Buffer pointer 2 | |
137 | 4 field >hcqtd-bptr3 \ Buffer pointer 3 | |
138 | 4 field >hcqtd-bptr4 \ Buffer pointer 4 | |
139 | 4 5 * field >hcqtd-xbptrs \ 64-bit buffer pointer extensions | |
140 | dup constant /hcqtd | |
141 | \ Driver specific fields | |
142 | 4 field >qtd-phys \ Physical address of qTD | |
143 | 4 field >qtd-next \ Next qTD virtual address | |
144 | 4 field >qtd-buf \ Buffer virtual address | |
145 | 4 field >qtd-pbuf \ Buffer physical address | |
146 | 4 field >qtd-/buf \ Buffer length (per qTD) | |
147 | 4 field >qtd-/buf-all \ Buffer length (size of the entire buffer) | |
148 | \ Only the first qTD has the entire size of buffer | |
149 | \ For bulk and intr qTDs | |
150 | d# 32 round-up | |
151 | constant /qtd | |
152 | ||
153 | \ >hcqtd-token constants | |
154 | h# 0000.0000 constant TD_TOGGLE_DATA0 | |
155 | h# 8000.0000 constant TD_TOGGLE_DATA1 | |
156 | h# 8000.0000 constant TD_TOGGLE_MASK | |
157 | h# 0000.8000 constant TD_IOC | |
158 | h# 0000.0c00 constant TD_C_ERR_MASK | |
159 | h# 0000.0400 constant TD_C_ERR1 | |
160 | h# 0000.0800 constant TD_C_ERR2 | |
161 | h# 0000.0c00 constant TD_C_ERR3 | |
162 | h# 0000.0000 constant TD_PID_OUT | |
163 | h# 0000.0100 constant TD_PID_IN | |
164 | h# 0000.0200 constant TD_PID_SETUP | |
165 | h# 0000.00ff constant TD_STAT_MASK | |
166 | h# 0000.0080 constant TD_STAT_ACTIVE | |
167 | h# 0000.0040 constant TD_STAT_HALTED \ Babble, error count=0, STALL | |
168 | h# 0000.0020 constant TD_STAT_DBUFF \ Data buffer error | |
169 | h# 0000.0010 constant TD_STAT_BABBLE \ Babble | |
170 | h# 0000.0008 constant TD_STAT_XERR \ Timeout, CRC, bad pid, etc | |
171 | h# 0000.0004 constant TD_STAT_MISS_MF \ Missed micro-frame | |
172 | h# 0000.0000 constant TD_STAT_S_SPLIT \ Start split transaction | |
173 | h# 0000.0002 constant TD_STAT_C_SPLIT \ Complete split transaction | |
174 | h# 0000.0000 constant TD_STAT_OUT \ Do OUT | |
175 | h# 0000.0001 constant TD_STAT_PING \ Do ping | |
176 | h# 0000.0001 constant TD_STAT_SPLIT_ERR \ Periodic split transaction ERR | |
177 | ||
178 | : td-data>di-data ( n -- n' ) TD_TOGGLE_MASK and if 1 else 0 then ; | |
179 | : di-data>td-data ( n -- n' ) if TD_TOGGLE_DATA1 else TD_TOGGLE_DATA0 then ; | |
180 | ||
181 | \ --------------------------------------------------------------------------- | |
182 | \ Queue Head (QH) as defined by the EHCI Spec; 32-byte aligned | |
183 | \ --------------------------------------------------------------------------- | |
184 | ||
185 | struct \ Beginning of QH fields | |
186 | 4 field >hcqh-next \ QH horizontal link pointer | |
187 | 4 field >hcqh-endp-char \ Endpoint characteristics | |
188 | 4 field >hcqh-endp-cap \ Endpoint capabilities | |
189 | 4 field >hcqh-cur-pqtd \ Current transaction descriptor pointer | |
190 | /hcqtd field >hcqh-overlay \ Transfer overlay area | |
191 | dup constant /hcqh | |
192 | \ Driver specific fields | |
193 | 4 field >qh-phys \ QH's physical address | |
194 | 4 field >qh-next \ Next QH's virtual address | |
195 | 4 field >qh-prev \ Previous QH's virtual address | |
196 | 4 field >qh-unaligned \ QH's unaligned address | |
197 | 4 field >qh-size \ Size of QH+qTDs | |
198 | 4 field >qh-#qtds \ # of qTDs in the list | |
199 | d# 32 round-up | |
200 | constant /qh | |
201 | ||
202 | \ >hcqh-endp-char constants | |
203 | h# 0800.0000 constant QH_CTRL_ENDP | |
204 | h# 0000.8000 constant QH_HEAD | |
205 | h# 0000.4000 constant QH_TD_TOGGLE | |
206 | h# 0000.0080 constant QH_INACTIVE_NEXT | |
207 | h# 0000.0000 constant QH_TUNE_RL_HS | |
208 | h# 0000.0000 constant QH_TUNE_RL_TT | |
209 | ||
210 | \ >hcqh-endp-cap constants | |
211 | h# 4000.0000 constant QH_MULT1 | |
212 | h# 8000.0000 constant QH_MULT2 | |
213 | h# c000.0000 constant QH_MULT3 | |
214 | ||
215 | ||
216 | 0 value qh-ptr \ Head of all QHs | |
217 | ||
218 | \ --------------------------------------------------------------------------- | |
219 | \ QH and TDs for bulk, control and interrupt operations. | |
220 | \ QH and its list of TDs are allocated as needed. | |
221 | \ --------------------------------------------------------------------------- | |
222 | ||
223 | : sync-qh ( qh -- ) dup >qh-phys l@ /hcqh dma-sync ; | |
224 | : sync-qtd ( qtd -- ) dup >qtd-phys l@ /hcqtd dma-sync ; | |
225 | : sync-qhqtds ( qh -- ) dup >qh-phys l@ over >qh-size l@ dma-sync ; | |
226 | ||
227 | : map-out-bptrs ( qtd -- ) | |
228 | dup >qtd-buf l@ over >qtd-pbuf l@ rot >qtd-/buf-all l@ hcd-map-out | |
229 | ; | |
230 | ||
231 | : init-qh ( qh.u,v,p len #qtds -- ) | |
232 | 3 pick >qh-#qtds l! ( qh.u,v,p len ) | |
233 | 2 pick >qh-size l! ( qh.u,v,p ) | |
234 | over >qh-phys l! ( qh.u,v ) | |
235 | TERMINATE 2 pick >hcqh-next le-l! ( qh.u,v ) | |
236 | >qh-unaligned l! ( ) | |
237 | ; | |
238 | : link-qtds ( qtd.v qtd.p #qtds -- ) | |
239 | 1- 0 ?do ( qtd.v qtd.p ) | |
240 | TERMINATE 2 pick >hcqtd-next-alt le-l! ( qtd.v qtd.p ) | |
241 | 2dup swap >qtd-phys l! ( qtd.v qtd.p ) | |
242 | /qtd + ( qtd.v qtd.p' ) | |
243 | 2dup swap >hcqtd-next le-l! ( qtd.v qtd.p ) | |
244 | swap dup /qtd + tuck swap >qtd-next l! ( qtd.p qtd.v' ) | |
245 | swap ( qtd.v qtd.p ) | |
246 | loop | |
247 | ||
248 | \ Fix up the last qTD | |
249 | over >qtd-phys l! ( qtd.v ) | |
250 | TERMINATE over >hcqtd-next le-l! ( qtd.v ) | |
251 | TERMINATE swap >hcqtd-next-alt le-l! ( ) | |
252 | ; | |
253 | : link-qhqtd ( qtd.p qh -- ) | |
254 | >hcqh-overlay tuck ( qh.overlay qtd.p qh.overlay ) | |
255 | >hcqtd-next le-l! ( qh.overlay ) | |
256 | TERMINATE over >hcqtd-next-alt le-l! ( qh.overlay) | |
257 | TD_TOGGLE_DATA1 TD_STAT_PING or swap >hcqtd-token le-l! ( ) | |
258 | ; | |
259 | ||
260 | : link-qhqtds ( qtd.v qtd.p #qtds qh -- ) | |
261 | 2 pick swap link-qhqtd ( qtd.v qtd.p #qtds ) \ Link QH to qTD | |
262 | link-qtds ( ) \ Link qTDs | |
263 | ; | |
264 | ||
265 | : alloc-qhqtds ( #qtds -- qh qtd ) | |
266 | dup >r /qtd * /qh + dup >r ( len ) ( R: #qtds len ) | |
267 | aligned32-alloc-map-in ( qh.u,v,p ) ( R: #qtds len ) | |
268 | over r@ erase ( qh.u,v,p ) ( R: #qtds ) | |
269 | 3dup r> r@ init-qh ( qh.u,v,p ) ( R: #qtds ) | |
270 | rot drop ( qh.v,p ) ( R: #qtds ) | |
271 | over /qh + dup -rot ( qh qtd qh.p qtd ) ( R: #qtds ) | |
272 | swap /qh + ( qh qtd qtd.v,p ) ( R: #qtds ) | |
273 | r> 4 pick link-qhqtds ( qh qtd ) | |
274 | ; | |
275 | ||
276 | : free-qhqtds ( qh -- ) | |
277 | >r ( R: qh ) | |
278 | r@ >qh-unaligned l@ ( qh.u ) ( R: qh ) | |
279 | r@ dup >qh-phys l@ ( qh.u,v,p ) ( R: qh ) | |
280 | r> >qh-size l@ ( qh.u,v,p size ) | |
281 | aligned32-free-map-out ( ) | |
282 | ; | |
283 | ||
284 | \ --------------------------------------------------------------------------- | |
285 | \ qTD Buffer Pointers management | |
286 | \ --------------------------------------------------------------------------- | |
287 | ||
288 | 5 constant #bptr \ There are 5 Buffer Pointers in qTD | |
289 | h# 1000 constant /bptr \ Size of buffer at each Buffer Pointer[i] | |
290 | /bptr 1- constant bptr-ofs-mask \ Current Offset mask | |
291 | bptr-ofs-mask invert constant bptr-mask \ Buffer Pointer mask | |
292 | /bptr #bptr * constant /maxbptrs \ Maximum size of transfer for a qTD | |
293 | /bptr #bptr 1- * constant /maxbptrs-1 \ Maximum size of 4 Buffer Pointers | |
294 | ||
295 | \ Determine the size of transfer for a qTD | |
296 | : cal-/bptr ( phys len -- /xfer ) | |
297 | over dup /bptr round-up = if ( phys len ) | |
298 | nip /maxbptrs min ( /xfer ) | |
299 | else | |
300 | swap bptr-ofs-mask and ( len len0 ) | |
301 | tuck - /maxbptrs-1 min + ( /xfer ) | |
302 | then | |
303 | ; | |
304 | ||
305 | \ Determine the number of Buffer Pointers necessary | |
306 | : cal-#bptr ( phys len -- #bptr ) | |
307 | dup 0= if nip exit then | |
308 | swap dup /bptr round-up swap - ?dup if | |
309 | ( len len0 ) | |
310 | - ( len-len0 ) | |
311 | /bptr round-up /bptr / 1+ ( #bptr ) | |
312 | else ( len ) | |
313 | /bptr round-up /bptr / ( #bptr ) | |
314 | then | |
315 | ; | |
316 | ||
317 | \ Determine the number of qTDs necessary for the entire transfer | |
318 | : cal-#qtd ( phys len -- #qtds ) | |
319 | dup 0= if nip exit then | |
320 | cal-#bptr #bptr /mod swap if 1+ then | |
321 | ; | |
322 | ||
323 | : fill-qtd-bptrs ( buf phys len qtd -- actual ) | |
324 | >r rot r@ >qtd-buf l! ( phys len ) ( R: qtd ) | |
325 | dup r@ >qtd-/buf-all l! ( phys len ) ( R: qtd ) | |
326 | over r@ >qtd-pbuf l! ( phys len ) ( R: qtd ) | |
327 | over swap cal-/bptr tuck ( actual phys actual ) ( R: qtd ) | |
328 | dup r@ >qtd-/buf l! ( actual phys actual ) ( R: qtd ) | |
329 | over swap cal-#bptr ( actual phys #bptr ) ( R: qtd ) | |
330 | r> swap 0 ?do ( actual phys qtd ) | |
331 | 2dup >hcqtd-bptr0 i 4 * + le-l! ( actual phys qtd ) | |
332 | swap /bptr + bptr-mask and swap ( actual phys' qtd ) | |
333 | loop 2drop ( actual ) | |
334 | ; | |
335 | ||
336 | \ --------------------------------------------------------------------------- | |
337 | \ Async scheduling | |
338 | \ --------------------------------------------------------------------------- | |
339 | ||
340 | : async-wait ( -- ) | |
341 | begin | |
342 | usbcmd@ h# 20 and 5 >> usbsts@ h# 8000 and d# 15 >> | |
343 | = until | |
344 | ; | |
345 | : enable-async ( phys -- ) | |
346 | asynclist! async-wait | |
347 | usbcmd@ h# 20 or usbcmd! async-wait | |
348 | ; | |
349 | : disable-async ( -- ) | |
350 | async-wait usbcmd@ h# 20 invert and usbcmd! async-wait | |
351 | ; | |
352 | ||
353 | : insert-qh ( qh -- ) | |
354 | >r | |
355 | qh-ptr if | |
356 | \ If there is another qh in the system, link the new qh to the existing | |
357 | \ qh head. | |
358 | qh-ptr r@ >qh-prev l! | |
359 | qh-ptr >qh-next l@ r@ >qh-next l! | |
360 | qh-ptr >hcqh-next le-l@ r@ >hcqh-next le-l! | |
361 | r@ qh-ptr >qh-next l! | |
362 | r@ >qh-phys l@ qh-ptr >hcqh-next le-l! | |
363 | r> sync-qhqtds | |
364 | qh-ptr sync-qh | |
365 | else | |
366 | \ If there is no qh in the system, link it to itself and mark it the | |
367 | \ head. | |
368 | r@ to qh-ptr | |
369 | r@ >hcqh-endp-char dup le-l@ QH_HEAD or swap le-l! | |
370 | r@ dup >qh-next l! | |
371 | r@ >qh-phys l@ dup TYP_QH or r@ >hcqh-next le-l! | |
372 | r> sync-qhqtds | |
373 | enable-async | |
374 | then | |
375 | ; | |
376 | ||
377 | : remove-qh ( qh -- ) | |
378 | dup >qh-next l@ over = if | |
379 | \ If qh is the only qh in the system, disable-async and exit | |
380 | drop disable-async | |
381 | 0 to qh-ptr | |
382 | else | |
383 | \ Otherwise, qh.prev points to qh.next, fix up reclamation bits. | |
384 | \ Ring doorbell, wait for answer. | |
385 | \ Free qh, make sure the qh-ptr is up-to-date. | |
386 | dup >qh-prev l@ ?dup if ( qh prev.qh ) | |
387 | over >hcqh-next le-l@ over >hcqh-next le-l! | |
388 | over >qh-next l@ swap >qh-next l! | |
389 | dup sync-qh | |
390 | dup >qh-next l@ qh-ptr <> if | |
391 | dup >qh-prev l@ swap >qh-next l@ >qh-prev l! | |
392 | else | |
393 | drop | |
394 | then | |
395 | else | |
396 | >qh-next l@ to qh-ptr | |
397 | qh-ptr >hcqh-endp-char dup le-l@ QH_HEAD or swap le-l! | |
398 | 0 qh-ptr >qh-prev l! | |
399 | qh-ptr sync-qh | |
400 | then | |
401 | ring-doorbell | |
402 | then | |
403 | ; | |
404 | ||
405 | \ --------------------------------------------------------------------------- | |
406 | \ Interrupt scheduling | |
407 | \ XXX Make it simple for now and igore interval and make it a fixed poll | |
408 | \ XXX interval. | |
409 | \ | |
410 | \ Empirically, the 4 ms poll interval works optimally with the usb keyboard. | |
411 | \ --------------------------------------------------------------------------- | |
412 | ||
413 | 0 value #intr | |
414 | d# 32 constant intr-interval \ 4 ms poll interval | |
415 | ||
416 | : #intr++ ( -- ) #intr 1+ to #intr ; | |
417 | : #intr-- ( -- ) #intr 1- to #intr ; | |
418 | ||
419 | : periodic-wait ( -- ) | |
420 | begin | |
421 | usbcmd@ h# 10 and 4 >> usbsts@ h# 4000 and d# 14 >> | |
422 | = until | |
423 | ; | |
424 | : enable-periodic ( -- ) | |
425 | periodic-wait usbcmd@ h# 10 or usbcmd! periodic-wait | |
426 | ; | |
427 | : disable-periodic ( -- ) | |
428 | periodic-wait usbcmd@ h# 10 invert and usbcmd! periodic-wait | |
429 | ; | |
430 | ||
431 | : (insert-intr-qh) ( qh idx -- ) | |
432 | dup >r ( qh idx ) ( R: idx ) | |
433 | intr-tail@ ?dup 0= if ( qh ) ( R: idx ) | |
434 | dup r@ intr-head! ( qh ) ( R: idx ) | |
435 | dup >qh-phys l@ TYP_QH or r@ framelist! | |
436 | ( qh ) ( R: idx ) | |
437 | else ( qh tail ) ( R: idx ) | |
438 | 2dup >qh-next l! ( qh tail ) ( R: idx ) | |
439 | over >qh-phys l@ TYP_QH or over >hcqh-next le-l! | |
440 | ( qh tail ) ( R: idx ) | |
441 | over >qh-prev l! ( qh ) ( R: idx ) | |
442 | then | |
443 | r> intr-tail! ( ) | |
444 | ; | |
445 | : insert-intr-qh ( qh speed interval -- ) | |
446 | drop ( qh speed ) | |
447 | speed-high = if h# 0020 else h# 1c01 then | |
448 | over >hcqh-endp-cap dup le-l@ rot or swap le-l! | |
449 | ( qh ) #framelist 0 do dup i (insert-intr-qh) intr-interval +loop drop | |
450 | #intr 0= if enable-periodic then | |
451 | #intr++ | |
452 | ; | |
453 | ||
454 | : (remove-intr-qh) ( qh idx -- ) | |
455 | >r ( qh ) ( R: idx ) | |
456 | dup >qh-prev l@ ?dup if over >qh-next l@ swap >qh-next l! then | |
457 | dup >qh-next l@ ?dup if over >qh-prev l@ swap >qh-prev l! then | |
458 | r@ intr-head@ over = if ( qh ) ( R: idx ) | |
459 | dup >qh-next l@ dup r@ intr-head! ( qh nqh ) ( R: idx ) | |
460 | ?dup if >qh-phys l@ TYP_QH or else TERMINATE then r@ framelist! | |
461 | ( qh ) ( R: idx ) | |
462 | then | |
463 | r@ intr-tail@ over = if ( qh ) ( R: idx ) | |
464 | dup >qh-prev l@ r@ intr-tail! ( qh ) ( R: idx ) | |
465 | then | |
466 | r> 2drop | |
467 | ; | |
468 | : remove-intr-qh ( qh -- ) | |
469 | #intr-- | |
470 | ( qh ) #framelist 0 do dup i (remove-intr-qh) intr-interval +loop drop | |
471 | #intr 0= if disable-periodic then | |
472 | ; | |
473 | ||
474 | \ --------------------------------------------------------------------------- | |
475 | \ Wait for a QH to be done and process any errors. | |
476 | \ | |
477 | \ When done? returns no error found yet, the caller should check if errors | |
478 | \ were found in the TDs. | |
479 | \ --------------------------------------------------------------------------- | |
480 | ||
481 | 0 value timeout | |
482 | ||
483 | : .qtd-error ( cc -- ) | |
484 | dup TD_STAT_HALTED and if " Stalled; " USB_ERR_STALL set-usb-error then | |
485 | dup TD_STAT_DBUFF and if " Data Buffer Error; " USB_ERR_DBUFERR set-usb-error then | |
486 | dup TD_STAT_BABBLE and if " Babble Detected; " USB_ERR_BABBLE set-usb-error then | |
487 | dup TD_STAT_XERR and if " CRC/Timeout/Bad PID; " USB_ERR_CRC set-usb-error then | |
488 | dup TD_STAT_MISS_MF and if " Missed Micro-frame; " USB_ERR_MICRO_FRAME set-usb-error then | |
489 | TD_STAT_SPLIT_ERR and if " Periodic split-x error; " USB_ERR_SPLIT set-usb-error then | |
490 | ; | |
491 | ||
492 | : qh-done? ( qh -- done? ) | |
493 | >hcqh-overlay ( olay ) | |
494 | dup >hcqtd-next le-l@ ( olay pnext ) | |
495 | swap >hcqtd-token le-l@ ( pnext token ) | |
496 | dup TD_STAT_HALTED and -rot ( halted? pnext token ) | |
497 | TD_STAT_ACTIVE and 0= swap ( halted? inactive? pnext ) | |
498 | TERMINATE = and ( halted? done? ) | |
499 | or ( done?' ) | |
500 | ; | |
501 | : done? ( qh -- usberr ) | |
502 | begin | |
503 | process-hc-status | |
504 | ( qh ) dup sync-qh | |
505 | ( qh ) dup qh-done? ?dup 0= if | |
506 | 1 ms | |
507 | timeout 1- dup to timeout 0= | |
508 | then | |
509 | until | |
510 | ||
511 | ( qh ) qh-done? 0= if " Timeout" USB_ERR_TIMEOUT set-usb-error then | |
512 | usb-error | |
513 | ; | |
514 | ||
515 | : error? ( qh -- usberr ) | |
516 | dup >hcqh-endp-char le-l@ d# 12 >> 3 and | |
517 | speed-high = if h# fc else h# fd then | |
518 | swap >hcqh-overlay >hcqtd-token le-l@ and ?dup if .qtd-error then | |
519 | usb-error | |
520 | ; | |
521 | ||
522 | : get-actual ( qtd #qtd -- actual ) | |
523 | 0 -rot 0 ?do ( actual qtd ) | |
524 | dup sync-qtd ( actual qtd ) | |
525 | dup >hcqtd-token le-l@ dup TD_STAT_ACTIVE and 0= if | |
526 | over >qtd-/buf l@ ( actual qtd token len ) | |
527 | swap d# 16 >> h# 7fff and - ( actual qtd len' ) | |
528 | rot + swap ( actual' qtd ) | |
529 | else | |
530 | drop ( actual qtd ) | |
531 | then | |
532 | >qtd-next l@ ( actual qtd ) | |
533 | loop drop ( qtd ) | |
534 | ; | |
535 | ||
536 | \ --------------------------------------------------------------------------- | |
537 | \ Allocate a dummy qh to be head of the queue to get around the fact that | |
538 | \ the VIA 2.0 controller does not stop async when told to. | |
539 | \ --------------------------------------------------------------------------- | |
540 | ||
541 | 0 value dummy-qh | |
542 | ||
543 | : alloc-dummy-qh ( -- ) | |
544 | dummy-qh 0= if | |
545 | 1 alloc-qhqtds ( qh qtd ) | |
546 | drop to dummy-qh | |
547 | TERMINATE dummy-qh >hcqh-overlay >hcqtd-next le-l! | |
548 | then | |
549 | dummy-qh insert-qh | |
550 | ; | |
551 | ||
552 | : free-dummy-qh ( -- ) | |
553 | dummy-qh ?dup if free-qhqtds 0 to dummy-qh then | |
554 | ; | |
555 | ||
556 | : ?alloc-dummy-qh ( -- ) | |
557 | 0 my-w@ h# 1106 ( VIA ) = if alloc-dummy-qh then | |
558 | ; | |
559 | ||
560 | : (init-extra) ( -- ) | |
561 | ?alloc-dummy-qh | |
562 | init-intr | |
563 | init-framelist | |
564 | ; | |
565 | ||
566 | ' (init-extra) to init-extra | |
567 | ||
568 | headers | |
569 | ||
570 | \ LICENSE_BEGIN | |
571 | \ Copyright (c) 2006 FirmWorks | |
572 | \ | |
573 | \ Permission is hereby granted, free of charge, to any person obtaining | |
574 | \ a copy of this software and associated documentation files (the | |
575 | \ "Software"), to deal in the Software without restriction, including | |
576 | \ without limitation the rights to use, copy, modify, merge, publish, | |
577 | \ distribute, sublicense, and/or sell copies of the Software, and to | |
578 | \ permit persons to whom the Software is furnished to do so, subject to | |
579 | \ the following conditions: | |
580 | \ | |
581 | \ The above copyright notice and this permission notice shall be | |
582 | \ included in all copies or substantial portions of the Software. | |
583 | \ | |
584 | \ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
585 | \ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
586 | \ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
587 | \ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
588 | \ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
589 | \ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
590 | \ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
591 | \ | |
592 | \ LICENSE_END |