|
|
1.1 root 1: \ ***************************************************************************** 1.1.1.2 ! root 2: \ * Copyright (c) 2004, 2011 IBM Corporation 1.1 root 3: \ * All rights reserved. 4: \ * This program and the accompanying materials 5: \ * are made available under the terms of the BSD License 6: \ * which accompanies this distribution, and is available at 7: \ * http://www.opensource.org/licenses/bsd-license.php 8: \ * 9: \ * Contributors: 10: \ * IBM Corporation - initial implementation 11: \ ****************************************************************************/ 12: 13: 14: \ Open Firmware Properties 15: 1.1.1.2 ! root 16: s" usb" device-type 1.1 root 17: 1 encode-int s" #address-cells" property 18: 0 encode-int s" #size-cells" property 19: 20: 21: \ converts physical address to text unit string 22: 23: : encode-unit ( port -- unit-str unit-len ) 1 hex-encode-unit ; 24: 25: 26: \ Converts text unit string to phyical address 27: 28: : decode-unit ( addr len -- port ) 1 hex-decode-unit ; 29: 30: 31: \ Data Structure Definitions 32: \ OHCI Task Descriptor Structure. 33: 34: STRUCT 35: /l field td>tattr 36: /l field td>cbptr 37: /l field td>ntd 38: /l field td>bfrend 39: CONSTANT /tdlen 40: 41: 42: \ OHCI Endpoint Descriptor Structure. 43: 44: STRUCT 45: /l field ed>eattr 46: /l field ed>tdqtp 47: /l field ed>tdqhp 48: /l field ed>ned 49: CONSTANT /edlen 50: 51: 1.1.1.2 ! root 52: \ HCCA Done queue location packaged as a structure for ease of use. 1.1 root 53: 54: STRUCT 55: /l field hc>hcattr 56: /l field hc>hcdone 57: CONSTANT /hclen 58: 59: 60: \ OHCI Memory Mapped Registers 61: 1.1.1.2 ! root 62: : get-base-address ( -- baseaddr ) ! 63: s" assigned-addresses" get-node get-property ! 64: ABORT" Could not get OHCI base address" ! 65: decode-int drop ( addr len ) ! 66: decode-64 nip nip ( n ) ! 67: translate-my-address ! 68: ; 1.1 root 69: 1.1.1.2 ! root 70: get-base-address CONSTANT baseaddrs 1.1 root 71: 72: baseaddrs CONSTANT HcRevision 73: baseaddrs 4 + CONSTANT hccontrol 74: baseaddrs 8 + CONSTANT hccomstat 75: baseaddrs 0c + CONSTANT hcintstat 76: baseaddrs 14 + CONSTANT hcintdsbl 77: baseaddrs 18 + CONSTANT hchccareg 78: baseaddrs 20 + CONSTANT hcctrhead 79: baseaddrs 24 + CONSTANT hccurcont 80: baseaddrs 28 + CONSTANT hcbulkhead 81: baseaddrs 2c + CONSTANT hccurbulk 82: baseaddrs 30 + CONSTANT hcdnehead 83: baseaddrs 34 + CONSTANT hcintrval 84: baseaddrs 40 + CONSTANT HcPeriodicStart 85: baseaddrs 48 + CONSTANT hcrhdescA 86: baseaddrs 4c + CONSTANT hcrhdescB 87: baseaddrs 50 + CONSTANT HcRhStatus 88: baseaddrs 54 + CONSTANT hcrhpstat 89: baseaddrs 58 + CONSTANT hcrhpstat2 90: baseaddrs 5c + CONSTANT hcrhpstat3 91: 92: usb-debug-flag IF 93: 0 config-l@ ." - VENDOR: " 8 .r cr 94: 40 config-l@ ." - PMC : " 8 .r 95: 44 config-l@ ." PMCSR : " 8 .r cr 96: E0 config-l@ ." - EXT1 : " 8 .r 97: E4 config-l@ ." EXT2 : " 8 .r cr 98: THEN 99: 100: \ Constants for INTSTAT register 101: 102: 2 CONSTANT WDH 103: 104: \ Constants for RH Port Status Register 105: 106: 1 CONSTANT RHP-CCS \ Current Connect Status 107: 2 CONSTANT RHP-PES \ Port Enable Status 108: 10 CONSTANT RHP-PRS \ Port Reset Status 109: 100 CONSTANT RHP-PPS \ Port Power Status 110: 10000 CONSTANT RHP-CSC \ Connect Status Changed 111: 100000 CONSTANT RHP-PRSC \ Port Reset Status Changed 112: 113: 114: \ Constants for OHCI 115: 116: 0 CONSTANT OHCI-DP-SETUP 117: 1 CONSTANT OHCI-DP-OUT 118: 2 CONSTANT OHCI-DP-IN 119: 3 CONSTANT OHCI-DP-INVALID 120: 121: \ 8-byte Standard Device Requests + Hub class specific requests. 122: 123: 8006000100001200 CONSTANT get-ddescp 124: 8006000200000900 CONSTANT get-cdescp 125: 8006000400000900 CONSTANT get-idescp 126: 8006000500000700 CONSTANT get-edescp 127: A006000000001000 CONSTANT get-hdescp 128: 0009010000000000 CONSTANT set-cdescp 129: 2303010004000000 CONSTANT hpenable-set 130: 2303040001000000 CONSTANT hp1rst-set 131: 2303040002000000 CONSTANT hp2rst-set 132: 2303040003000000 CONSTANT hp3rst-set 133: 2303040004000000 CONSTANT hp4rst-set 134: 2303080001000000 CONSTANT hp1pwr-set 135: 2303080002000000 CONSTANT hp2pwr-set 136: 2303080003000000 CONSTANT hp3pwr-set 137: 2303080004000000 CONSTANT hp4pwr-set 138: A003000000000400 CONSTANT hstatus-get 139: A300000001000400 CONSTANT hp1sta-get 140: A300000002000400 CONSTANT hp2sta-get 141: A300000003000400 CONSTANT hp3sta-get 142: A300000004000400 CONSTANT hp4sta-get 143: 8008000000000100 CONSTANT get-config 144: 145: A1FE000000000100 CONSTANT GET-MAX-LUN 146: 147: 2 18 lshift CONSTANT DATA0-TOGGLE 148: 3 18 lshift CONSTANT DATA1-TOGGLE 149: 0f 1c lshift CONSTANT CC-FRESH-TD 150: 8 CONSTANT STD-REQUEST-SETUP-SIZE 151: 0 13 lshift CONSTANT TD-DP-SETUP 152: 1 13 lshift CONSTANT TD-DP-OUT 153: 2 13 lshift CONSTANT TD-DP-IN 154: 155: 400001 CONSTANT ed-cntatr 156: 400002 CONSTANT ed-cntatr1 157: 80081 CONSTANT ed-hubatr 158: 80000 CONSTANT ed-defatr 159: 0f0e40000 CONSTANT td-attr 160: 00 VALUE ptr 161: 162: 1.1.1.2 ! root 163: 0 VALUE instance-count ! 164: 1.1 root 165: \ TD Management constants and Data structures. 166: 167: 168: 200 CONSTANT MAX-TDS 169: 0 VALUE td-freelist-head 170: 0 VALUE td-freelist-tail 171: 0 VALUE num-free-tds 172: 0 VALUE max-rh-ports 173: 0 VALUE current-stat 174: 1.1.1.2 ! root 175: VARIABLE td-list-region ! 176: VARIABLE td-list-region-dma 1.1 root 177: 178: \ ED Management constants 179: 180: 181: 14 CONSTANT MAX-EDS 182: 0 VALUE ed-freelist-head 183: 0 VALUE num-free-eds 1.1.1.2 ! root 184: VARIABLE ed-list-region ! 185: VARIABLE ed-list-region-dma 1.1 root 186: 0 VALUE usb-address 187: 0 VALUE initial-hub-address 188: 0 VALUE new-device-address 189: 0 VALUE mps 190: 0 VALUE DEBUG-TDS 191: 0 VALUE case-failed \ available for general use to see IF a CASE statement 192: \ failed or not. 193: 0 VALUE WHILE-failed \ available for general use to see IF a WHILE LOOP 194: \ failed in the middle. Used to break from the 195: \ WHILE LOOP 196: 197: 8 CONSTANT DEFAULT-CONTROL-MPS 198: 12 CONSTANT DEVICE-DESCRIPTOR-LEN 199: 1 CONSTANT DEVICE-DESCRIPTOR-TYPE 200: 1 CONSTANT DEVICE-DESCRIPTOR-TYPE-OFFSET 201: 4 CONSTANT DEVICE-DESCRIPTOR-DEVCLASS-OFFSET 202: 7 CONSTANT DEVICE-DESCRIPTOR-MPS-OFFSET 203: 204: 20 CONSTANT BULK-CONFIG-DESCRIPTOR-LEN 205: 206: 9 CONSTANT HUB-DEVICE-CLASS 207: 0 CONSTANT NO-CLASS 208: 209: 210: \ Temporary variables for functions. These variables have to be initialized 211: \ before usage in functions and their values assume significance only during 212: \ the function's execution time. Should be used like local variables. 213: \ CAUTION: 1.1.1.2 ! root 214: \ If you are calling functions that destroy contents of these variables, be 1.1 root 215: \ smart enuf to save the values before calling them. 216: \ It is recommended that these temporary variables are used only amidst normal 1.1.1.2 ! root 217: \ FORTH words -- not among the vicinity of any of the functions of this node. 1.1 root 218: 219: 0 VALUE temp1 220: 0 VALUE temp2 221: 0 VALUE temp3 222: 0 VALUE extra-bytes 223: 0 VALUE num-td 224: 0 VALUE current 225: 226: 0 VALUE device-speed 227: 228: 1.1.1.2 ! root 229: \ DMA-able buffers: ! 230: ! 231: 0 VALUE setup-packet \ 8 bytes for setup packet ! 232: 0 VALUE ch-buffer \ 1 byte character buffer ! 233: ! 234: VARIABLE dd-buffer ! 235: VARIABLE dd-buffer-dma ! 236: VARIABLE cd-buffer ! 237: VARIABLE cd-buffer-dma ! 238: ! 239: ! 240: \ Global buffer allocation ! 241: \ ------------------------ ! 242: ! 243: \ Memory size for HCCA (0x100), setup-packet (8) and ch-buf (1) ! 244: 109 CONSTANT OHCI-GLOBAL-DMA-BUF-SIZE ! 245: ! 246: \ Memory for the HCCA - must stay allocated as long as the HC is operational! ! 247: ! 248: 0 VALUE hchcca ! 249: 0 VALUE hchcca-dma ! 250: ! 251: : (init-global-dma-bufs) ! 252: \ Allocate memory for HCCA (0x100), setup-packet (8) and ch-buf (1) ! 253: OHCI-GLOBAL-DMA-BUF-SIZE dma-alloc TO hchcca ! 254: hchcca OHCI-GLOBAL-DMA-BUF-SIZE 0 dma-map-in TO hchcca-dma ! 255: hchcca ff and IF ! 256: \ This should never happen - alloc-mem always aligns ! 257: s" Warning: hchcca not aligned!" usb-debug-print ! 258: THEN ! 259: hchcca 8 + TO setup-packet ! 260: setup-packet 1 + TO ch-buffer ! 261: ! 262: s" hchcca = " hchcca usb-debug-print-val ! 263: ; ! 264: (init-global-dma-bufs) ! 265: ! 266: 84 hchcca + CONSTANT hchccadneq \ HccaDoneHead ! 267: ! 268: \ Convert virtual address to physical ! 269: hchcca-dma hchcca - CONSTANT virt2phys-offset ! 270: : virt2phys ( virt -- phys ) ! 271: dup 0<> IF ! 272: virt2phys-offset + ! 273: THEN ! 274: ; ! 275: ! 276: \ Convert physical address to virtual ! 277: : phys2virt ( phys -- virt ) ! 278: dup 0<> IF ! 279: virt2phys-offset - ! 280: THEN ! 281: ; ! 282: ! 283: 1.1 root 284: \ Debug functions for displaying ED, TD and their combo list. 285: 286: : Show-OHCI-Register 287: ." -> OHCI-Register: " cr 288: ." - HcControl : " hccontrol rl@-le 8 .r 289: ." CmdStat : " hccomstat rl@-le 8 .r 290: ." HcInterr. : " hcintstat rl@-le 8 .r cr 291: 292: ." - HcFmIntval: " hcintrval rl@-le 8 .r 293: ." Per. Start: " HcPeriodicStart rl@-le 8 .r cr 294: 295: ." - PortStat-1: " hcrhpstat rl@-le 8 .r 296: ." PortStat-2: " hcrhpstat2 rl@-le 8 .r 297: ." PortStat-3: " hcrhpstat3 rl@-le 8 .r cr 298: 299: ." Descr-A : " hcrhdescA rl@-le 8 .r 300: ." Descr-B : " hcrhdescB rl@-le 8 .r 301: ." HcRhStat : " HcRhStatus rl@-le 8 .r cr 302: ; 303: 304: : display-ed ( ED-ADDRESS -- ) 305: TO temp1 306: usb-debug-flag IF 307: s" Dump OF ED " type temp1 u. cr 308: s" eattr : " type temp1 ed>eattr l@-le u. cr 309: s" tdqhp : " type temp1 ed>tdqhp l@-le u. cr 310: s" tdqtp : " type temp1 ed>tdqtp l@-le u. cr 311: s" ned : " type temp1 ed>ned l@-le u. cr 312: THEN 313: ; 314: 315: 316: \ Displays the transfer descriptors 317: 318: : display-td ( TD-ADDRESS -- ) 319: TO temp1 320: usb-debug-flag IF 321: s" TD " type temp1 u. s" dump: " type cr 322: s" td>tattr : " type temp1 td>tattr l@-le u. cr 323: s" td>cbptr : " type temp1 td>cbptr l@-le u. cr 324: s" td>ntd : " type temp1 td>ntd l@-le u. cr 325: s" td>bfrend : " type temp1 td>bfrend l@-le u. cr 326: THEN 327: ; 328: 329: 330: \ display's the descriptors 331: 332: : display-descriptors ( ED-ADDRESS -- ) 1.1.1.2 ! root 333: 10 1- not and ( ED-ADDRESS~ ) ! 334: dup display-ed ed>tdqhp l@-le phys2virt ( ED-ADDRESS~ ) ! 335: BEGIN ! 336: 10 1- not and ( ED-ADDRESS~ ) ! 337: dup 0<> ( ED-ADDRESS~ TRUE | FALSE ) 1.1 root 338: WHILE 1.1.1.2 ! root 339: dup display-td td>ntd l@-le phys2virt ( ED-ADDRESS~ ) 1.1 root 340: REPEAT 341: drop 342: ; 343: 344: 345: \ --------------------------------------------------------------------------- 346: \ TD LIST MANAGEMENT WORDS 347: \ ------------------------ 348: \ The following are WORDS internal to this node. They are supposed to 349: \ be used by other WORDS inside this device node. 350: \ The first three WORDS below form the interface. The fourth and fifth 1.1.1.2 ! root 351: \ word is a helper function and is not exposed to other portions of this 1.1 root 352: \ device node. 353: \ a) initialize-td-free-list 354: \ b) allocate-td-list 355: \ c) (free-td-list) 356: \ d) find-td-list-tail-and-size 357: \ e) zero-out-a-td-except-link 358: \ ---------------------------------------------------------------------------- 359: 360: 361: : zero-out-a-td-except-link ( td -- ) 362: 1.1.1.2 ! root 363: \ There are definitely smarter ways to do it especially 1.1 root 364: \ on a 64-bit machine. 365: 366: \ Optimization, Portability: 367: \ -------------------------- 1.1.1.2 ! root 368: \ Replace the following code by two "!" of zeroes. Since 1.1 root 369: \ we know that an "td" is actually 16 bytes and that we 1.1.1.2 ! root 370: \ will be executing on a 64-bit machine, we can finish off 1.1 root 371: \ with 2 stores. But that WONT be portable. 372: 373: dup 0 swap td>tattr l!-le ( td ) 374: dup 0 swap td>cbptr l!-le ( td ) 375: dup 0 swap td>bfrend l!-le ( td ) 376: drop 377: ; 378: 379: 380: \ COLON DEFINITION: initialize-td-free-list - Internal Function 381: 1.1.1.2 ! root 382: \ Initialize the TD Free List Region and create a linked list of successive 1.1 root 383: \ TDs. Note that the NEXT pointers are all in little-endian and they 384: \ can be directly used for HC purposes. 385: 386: 387: : initialize-td-free-list ( -- ) 388: MAX-TDS 0= IF EXIT THEN 389: td-list-region @ 0= IF EXIT THEN 390: td-list-region @ TO temp1 391: 0 TO temp2 BEGIN 392: temp1 zero-out-a-td-except-link 1.1.1.2 ! root 393: temp1 /tdlen + dup virt2phys temp1 td>ntd l!-le TO temp1 1.1 root 394: temp2 1+ TO temp2 395: temp2 MAX-TDS = ( TRUE | FALSE ) 396: UNTIL 397: temp1 /tdlen - dup 0 swap td>ntd l!-le TO td-freelist-tail 398: td-list-region @ TO td-freelist-head 399: MAX-TDS TO num-free-tds 400: ; 401: 402: 403: \ COLON DEFINITION: allocate-td-list -- Internal function 404: \ Argument: 405: \ The function accepts a non-negative number and allocates 406: \ a TD-LIST containing that many TDs. A TD-LIST is a list 1.1.1.2 ! root 407: \ of TDs that are linked by the next-td field. The next-td 1.1 root 408: \ field is in little-endian mode so that the TD list can 409: \ be directly re-used by the HC. 410: \ Return value: 1.1.1.2 ! root 411: \ The function returns "head" and "tail" of the allocated 1.1 root 412: \ TD-LIST. If for any reason, the function cannot allocate 413: \ the TD-LIST, the function returns 2 NULL pointers in the 414: \ stack indicating that the allocation failed. 415: 416: \ Note that the TD list returned is NULL terminated. i.e 1.1.1.2 ! root 417: \ the nextTd field of the tail is NULL. 1.1 root 418: 419: : allocate-td-list ( n -- head tail ) 420: dup 0= IF drop 0 0 EXIT THEN ( 0 0 ) 421: dup num-free-tds > IF drop 0 0 EXIT THEN ( 0 0 ) 422: dup num-free-tds = IF ( n ) 423: drop td-freelist-head td-freelist-tail ( td-freelist-head td-freelist-tail ) 424: 0 TO td-freelist-head ( td-freelist-head td-freelist-tail ) 425: 0 TO td-freelist-tail ( td-freelist-head td-freelist-tail ) 426: 0 TO num-free-tds ( td-freelist-head td-freelist-tail ) 427: EXIT 428: THEN 429: 1.1.1.2 ! root 430: \ If we are here then we know that the requested number of TDs is less ! 431: \ than what we actually have. We need to traverse the list and find the ! 432: \ new Head pointer position and then update the head pointer accordingly. 1.1 root 433: \ Update num-free-tds 434: 435: dup num-free-tds swap - TO num-free-tds ( n ) 436: 437: \ Traverse through the Free list to identify the element that exists after 438: \ "n" TDs. Use the info to return the head and tail pointer and update 439: \ the new td-list-head 440: 441: td-freelist-head ( n td-list-head ) 442: dup TO temp1 ( n td-list-head ) 443: swap ( td-list-head n ) 444: 0 DO ( td-list-head ) 445: temp1 TO temp2 ( td-list-head ) 1.1.1.2 ! root 446: temp1 td>ntd l@-le phys2virt TO temp1 ( td-list-head ) 1.1 root 447: LOOP ( td-list-head ) 448: temp2 ( td-list-head td-list-tail ) 449: dup td>ntd 0 swap l!-le ( td-list-head td-list-tail ) 450: temp1 TO td-freelist-head ( td-list-head td-list-tail ) 451: ; 452: 453: 454: \ COLON DEFINITION: find-td-list-tail-and-size 1.1.1.2 ! root 455: \ This function counts the number of TD elements 1.1 root 456: \ in the given list. It also returns the last tail 1.1.1.2 ! root 457: \ TD of the TD list. 1.1 root 458: 459: \ ASSUMPTION: 460: \ A NULL terminated TD list is assumed. A not-well formed 461: \ list can result in in-determinate behaviour. 462: 463: \ ROOM FOR ENHANCEMENT: 464: \ We could arrive at a generic function for counting 1.1.1.2 ! root 465: \ list elements to which the next-ptr offset can also 1.1 root 466: \ be passed as an argument (in this case it is >ntd) 1.1.1.2 ! root 467: \ This function can then be changed to call the 1.1 root 468: \ function with "0 >ntd" as an additional argument 469: \ (apart from head and tail) 470: 471: 472: : find-td-list-tail-and-size ( head -- tail n ) 473: TO temp1 474: 0 TO temp2 475: 0 TO temp3 476: DEBUG-TDS IF 477: s" BEGIN find-td-list-tail-and-size: " usb-debug-print 478: THEN 479: BEGIN 480: temp1 0<> ( TRUE|FALSE ) 481: WHILE 482: DEBUG-TDS IF 483: temp1 u. cr 484: THEN 485: temp1 TO temp3 1.1.1.2 ! root 486: temp1 td>ntd l@-le phys2virt TO temp1 1.1 root 487: temp2 1+ TO temp2 488: REPEAT 489: temp3 temp2 ( tail n ) 490: DEBUG-TDS IF 491: s" END find-td-list-tail-and-size" usb-debug-print 492: THEN 493: ; 494: 495: 496: \ COLON DEFINITION: (free-td-list) 497: 498: \ Arguments: (head --) 1.1.1.2 ! root 499: \ The "head" pointer of the TD-LIST to be freed is passed as 1.1 root 500: \ an argument to this function. The function merely adds the list to the 501: \ already existing TD-LIST 502: 503: \ Assumptions: 504: \ The function assumes that the TD-LIST passed as argument is a well-formed 1.1.1.2 ! root 505: \ list. The function does not do any check on it. 1.1 root 506: \ But since, the "TD-LIST" is generally freed from the DONE-QUEUE which is 507: \ a well-formed list, the interface makes much sense. 508: 509: \ Return values: 1.1.1.2 ! root 510: \ Nothing is returned. The arguments passed are popped off. 1.1 root 511: 512: 513: : (free-td-list) ( head -- ) 514: 515: \ Enhancement: 516: \ We could zero-out-a-td-except-link for the TD list that is being freed. 1.1.1.2 ! root 517: \ This way, we could prevent some nasty repercussions of bugs (that are yet 1.1 root 518: \ to be discovered). but we can include this enhancement during the testing 519: \ phase. 520: 521: dup find-td-list-tail-and-size num-free-tds + TO num-free-tds ( head tail ) 522: td-freelist-tail 0= IF ( head tail ) 523: dup TO td-freelist-tail ( head tail ) 524: THEN ( head tail ) 1.1.1.2 ! root 525: td>ntd td-freelist-head virt2phys swap l!-le ( head ) 1.1 root 526: TO td-freelist-head 527: ; 528: 529: 530: \ END OF TD LIST MANAGEMENT WORDS 531: \ ED Management section BEGINs 532: \ ---------------------------- 533: 534: 535: : zero-out-an-ed-except-link ( ed -- ) 536: dup 0 swap ed>eattr l!-le ( ed ) 537: dup 0 swap ed>tdqtp l!-le ( ed ) 538: dup 0 swap ed>tdqhp l!-le ( ed ) 539: drop 540: ; 541: 542: \ Intialises ed-list afresh 543: 544: : initialize-ed-free-list ( -- ) 545: MAX-EDS 0= IF EXIT THEN 546: ed-list-region @ 0= IF 547: s" init-ed-list: ed-list-region is not allocated!" usb-debug-print 548: EXIT 549: THEN 550: ed-list-region @ TO temp1 551: 0 TO temp2 BEGIN 552: temp1 zero-out-an-ed-except-link 1.1.1.2 ! root 553: usb-debug-flag IF ! 554: ." ED " temp2 . ." v: " temp1 . ." p: " temp1 virt2phys . cr ! 555: THEN ! 556: temp1 /edlen + dup virt2phys temp1 ed>ned l!-le TO temp1 1.1 root 557: temp2 1+ TO temp2 558: temp2 MAX-EDS = 559: UNTIL 560: temp1 /edlen - ed>ned 0 swap l!-le 561: ed-list-region @ TO ed-freelist-head 562: MAX-EDS TO num-free-eds 563: ; 564: 565: 566: \ allocate an ed and return ed address 567: 568: 569: : allocate-ed ( -- ed-ptr ) 570: num-free-eds 0= IF 0 EXIT THEN 571: ed-freelist-head ( ed-freelist-head ) 1.1.1.2 ! root 572: ed-freelist-head ed>ned ( ed-freelist-head ned ) ! 573: l@-le phys2virt TO ed-freelist-head ( ed-freelist-head ) 1.1 root 574: num-free-eds 1- TO num-free-eds ( ed-freelist-head ) 575: dup ed>ned 0 swap l!-le \ Terminate the Link. ( ed-freelist-head ) 576: ; 577: 578: 579: \ free the given ed pointer 580: 581: : free-ed ( ed-ptr -- ) 582: dup zero-out-an-ed-except-link ( ed-ptr ) 1.1.1.2 ! root 583: dup ed>ned ed-freelist-head virt2phys swap l!-le ( ed-ptr ) 1.1 root 584: TO ed-freelist-head 585: num-free-eds 1+ TO num-free-eds 586: ; 587: 588: 1.1.1.2 ! root 589: \ Instance buffer allocation ! 590: \ -------------------------- 1.1 root 591: 592: : (allocate-mem) ( -- ) 1.1.1.2 ! root 593: /tdlen MAX-TDS * 10 + ! 594: dup dma-alloc ( td-region-size td-list-region-ptr ) ! 595: dup td-list-region ! ! 596: dup f and IF 1.1 root 597: s" Warning: td-list-region not aligned!" usb-debug-print 598: THEN 1.1.1.2 ! root 599: swap 0 dma-map-in td-list-region-dma ! 1.1 root 600: initialize-td-free-list 601: 1.1.1.2 ! root 602: /edlen MAX-EDS * 10 + ! 603: dup dma-alloc ( ed-region-size ed-list-region-ptr ) ! 604: dup ed-list-region ! ! 605: dup f and IF 1.1 root 606: s" Warning: ed-list-region not aligned!" usb-debug-print 607: THEN 1.1.1.2 ! root 608: swap 0 dma-map-in ed-list-region-dma ! 1.1 root 609: initialize-ed-free-list 610: 1.1.1.2 ! root 611: DEVICE-DESCRIPTOR-LEN chars dup dma-alloc ! 612: dup dd-buffer ! ( dd-len dd-buf ) ! 613: swap 0 dma-map-in dd-buffer-dma ! ! 614: ! 615: BULK-CONFIG-DESCRIPTOR-LEN chars dup dma-alloc ! 616: dup cd-buffer ! ( cd-len cd-buf ) ! 617: swap 0 dma-map-in cd-buffer-dma ! ! 618: ! 619: s" td-list-region = " td-list-region @ usb-debug-print-val ! 620: s" ed-list-region = " ed-list-region @ usb-debug-print-val ! 621: s" dd-buffer = " dd-buffer @ usb-debug-print-val ! 622: s" cd-buffer-dma = " cd-buffer-dma @ usb-debug-print-val 1.1 root 623: ; 624: 625: 626: \ The method makes sure that when the host node is closed all 627: \ associated buffer allocations made for data-structures as 628: \ well as data-buffers are freed 629: 630: : (de-allocate-mem) ( -- ) 631: td-list-region @ ?dup IF 1.1.1.2 ! root 632: /tdlen MAX-TDS * 10 + ( td-list-region td-region-size ) ! 633: 2dup td-list-region-dma @ swap dma-map-out ! 634: dma-free 1.1 root 635: 0 td-list-region ! 1.1.1.2 ! root 636: 0 td-list-region-dma ! 1.1 root 637: THEN 638: ed-list-region @ ?dup IF 1.1.1.2 ! root 639: /edlen MAX-EDS * 10 + ! 640: 2dup ed-list-region-dma @ swap dma-map-out ! 641: dma-free 1.1 root 642: 0 ed-list-region ! 1.1.1.2 ! root 643: 0 ed-list-region-dma ! 1.1 root 644: THEN 645: dd-buffer @ ?dup IF 1.1.1.2 ! root 646: DEVICE-DESCRIPTOR-LEN ! 647: 2dup dd-buffer-dma @ swap dma-map-out ! 648: dma-free 1.1 root 649: 0 dd-buffer ! 1.1.1.2 ! root 650: 0 dd-buffer-dma ! 1.1 root 651: THEN 652: cd-buffer @ ?dup IF 1.1.1.2 ! root 653: BULK-CONFIG-DESCRIPTOR-LEN ! 654: 2dup cd-buffer-dma @ swap dma-map-out ! 655: dma-free 1.1 root 656: 0 cd-buffer ! 1.1.1.2 ! root 657: 0 cd-buffer-dma ! 1.1 root 658: THEN 659: ; 660: 661: 662: \ Suspend hostcontroller (and the bus). 663: \ This method must be called before the operating system starts. 664: \ It prevents the HC from doing DMA in the background during boot 665: \ (e.g. updating its frame number counter in the HCCA) 666: 1.1.1.2 ! root 667: : hc-quiesce ( -- ) 1.1 root 668: \ s" USB HC suspend with hccontrol=" type hccontrol . cr 669: 00C3 hccontrol rl!-le \ Suspend USB host controller 1.1.1.2 ! root 670: \ Release memory for HCCA etc: ! 671: hchcca hchcca-dma OHCI-GLOBAL-DMA-BUF-SIZE dma-map-out ! 672: hchcca OHCI-GLOBAL-DMA-BUF-SIZE dma-free 1.1 root 673: ; 674: 1.1.1.2 ! root 675: ' hc-quiesce add-quiesce-xt \ Assert that HC will be supsended ! 676: 1.1 root 677: 678: \ OF methods 679: 680: : open ( -- TRUE|FALSE ) 1.1.1.2 ! root 681: instance-count dup 0= IF ! 682: s" OHCI First open" usb-debug-print ! 683: (allocate-mem) ! 684: THEN ! 685: 1 + TO instance-count ! 686: s" OHCI Open instance count now: " instance-count usb-debug-print-val 1.1 root 687: TRUE 688: ; 689: 690: : close ( -- ) 1.1.1.2 ! root 691: instance-count dup 1 = IF ! 692: s" OHCI Last close" usb-debug-print ! 693: (de-allocate-mem) ! 694: THEN ! 695: 1 - TO instance-count ! 696: s" OHCI Close instance count now: " instance-count usb-debug-print-val 1.1 root 697: ; 698: 699: 700: \ COLON DEFINITION: HC-enable-control-list-processing 701: \ Enables USB HC transactions on control list. 702: 703: : HC-enable-control-list-processing ( -- ) 704: hccomstat dup rl@-le 02 or swap rl!-le 705: hccontrol dup rl@-le 10 or swap rl!-le 706: ; 707: 708: 709: \ COLON DEFINTION: HC-enable-bulk-list-processing 710: \ PENDING: Remove Hard coded constants. 711: 712: : HC-enable-bulk-list-processing ( -- ) 713: hccomstat dup rl@-le 04 or swap rl!-le 714: hccontrol dup rl@-le 20 or swap rl!-le 715: ; 716: 717: 718: : HC-enable-interrupt-list-processing ( -- ) 719: hccontrol dup rl@-le 04 or swap rl!-le 720: ; 721: 722: 1.1.1.2 ! root 723: \ Clearing WDH to allow HC to write into done queue again 1.1 root 724: 1.1.1.2 ! root 725: : (HC-ACK-WDH) ( -- ) ! 726: WDH hcintstat rl!-le ! 727: ; 1.1 root 728: 1.1.1.2 ! root 729: \ Checking whether anything has been written into done queue 1.1 root 730: 1.1.1.2 ! root 731: : (HC-CHECK-WDH) ( -- updated? ) ! 732: hcintstat rl@-le WDH and 0<> ! 733: ; 1.1 root 734: 735: 736: \ Disable USB transaction and keep it ready 737: 738: : disable-control-list-processing ( -- ) 739: hccontrol dup rl@-le ffffffef and swap rl!-le 740: hccomstat dup rl@-le fffffffd and swap rl!-le 741: ; 742: 743: : disable-bulk-list-processing ( -- ) 744: hccontrol dup rl@-le ffffffdf and swap rl!-le 745: hccomstat dup rl@-le fffffffb and swap rl!-le 746: ; 747: 748: 749: : disable-interrupt-list-processing ( -- ) 750: hccontrol dup rl@-le fffffffb and swap rl!-le 751: ; 752: 753: 754: \ COLON DEFINITION: fill-TD-list 755: 756: \ This function accepts a TD list and a data-buffer and 757: \ distributes this data buffer over the TD list depending 758: \ on the Max Packet Size. 759: 760: \ Arguments: 761: \ ---------- 1.1.1.2 ! root 762: \ (from bottom of stack) ! 763: \ 1. addr -- Address of the data buffer ! 764: \ 2. dlen -- Length of the data buffer above. 1.1 root 765: \ 3. dir -- Tells whether the TDs r for an IN or 766: \ OUT transaction. 767: \ 4. MPS -- Maximum Packet Size associated with the endpoint 768: \ that will use this TD list. 1.1.1.2 ! root 769: \ 5. TD-List-Head - Head pointer of the List of TDs. 1.1 root 770: \ This list is NOT expected to be NULL terminated. 771: 772: \ Assumptions: 773: \ ----------- 774: \ 1. TD-List for data is well-formed and has sufficient entries 775: \ to hold "dlen". 776: \ 2. The TDs toggle field is assumed to be taken from the endpoint 777: \ descriptor's "toggle carry" field. 778: \ 3. Assumes that the caller specifies the correct start-toggle. 1.1.1.2 ! root 779: \ If the caller specifies a wrong data toggle of 1 for a SETUP 1.1 root 780: \ PACKET, this method will not find it out. 781: 782: \ COLON DEFINTION: (toggle-current-toggle) 783: \ Scope: Internal to fill-TD-list 784: \ Functionality: 785: \ Toggles the "T" field that is passed as argument. 1.1.1.2 ! root 786: \ "T" as in the "T" field of the TD. 1.1 root 787: 788: 0 VALUE current-toggle 789: : fill-TD-list ( start-toggle addr dlen dp MPS TD-List-Head -- ) 790: TO temp1 ( start-toggle addr dlen dp MPS ) 791: TO temp2 ( start-toggle addr dlen dp ) 792: CASE ( start-toggle addr dlen ) 793: OHCI-DP-SETUP OF TD-DP-SETUP TO temp3 ENDOF ( start-toggle addr dlen ) 794: OHCI-DP-IN OF TD-DP-IN TO temp3 ENDOF ( start-toggle addr dlen ) 795: OHCI-DP-OUT OF TD-DP-OUT TO temp3 ENDOF ( start-toggle addr dlen ) 796: dup OF -1 TO temp3 ( start-toggle addr dlen ) 797: s" fill-TD-list: Invalid DP specified" usb-debug-print 798: ENDOF 799: ENDCASE 800: temp3 -1 = IF EXIT THEN ( start-toggle addr dlen ) 801: 802: \ temp1 -- TD-List-Head 803: \ temp2 -- Max Packet Size 804: \ temp3 -- TD-DP-IN or TD-DP-OUT or TD-DP-SETUP 805: 1.1.1.2 ! root 806: rot ( addr dlen start-toggle ) ! 807: TO current-toggle swap ( dlen addr ) 1.1 root 808: BEGIN 1.1.1.2 ! root 809: over temp2 >= ( dlen addr TRUE|FALSE ) ! 810: WHILE ( dlen addr ) ! 811: dup virt2phys temp1 td>cbptr l!-le ( dlen addr ) ! 812: current-toggle 18 lshift ( dlen addr current-toggle~ ) ! 813: DATA0-TOGGLE ( dlen addr current-toggle~ toggle ) ! 814: CC-FRESH-TD temp3 or or or ( dlen addr or-result ) ! 815: temp1 td>tattr l!-le ( dlen addr~ ) ! 816: dup temp2 1- + virt2phys temp1 td>bfrend l!-le ( dlen addr~ ) ! 817: temp2 + ( dlen next-addr ) 1.1 root 818: swap temp2 - swap 1.1.1.2 ! root 819: temp1 td>ntd l@-le phys2virt TO temp1 ( dlen next-addr ) ! 820: current-toggle ( dlen next-addr current-toggle ) 1.1 root 821: CASE 822: 0 OF 1 TO current-toggle ENDOF 823: 1 OF 0 TO current-toggle ENDOF 824: ENDCASE 825: REPEAT ( dlen addr ) 826: over 0<> IF 1.1.1.2 ! root 827: dup virt2phys temp1 td>cbptr l!-le ( dlen addr ) 1.1 root 828: current-toggle 18 lshift ( dlen addr curent-toggle~ ) 829: DATA0-TOGGLE ( dlen addr curent-toggle~ toggle ) 830: CC-FRESH-TD temp3 or or or ( dlen addr or-result ) 831: temp1 td>tattr l!-le ( dlen addr ) 1.1.1.2 ! root 832: + 1- virt2phys temp1 td>bfrend l!-le 1.1 root 833: ELSE 834: 2drop 835: THEN 836: ; 837: 838: 839: \ COLON DEFINITION: (td-list-status ) 840: \ FUNCTIONALITY: 841: \ To traverse the TD list to check for a TD carrying non-zero CC return the 842: \ respective TD address and CC ELSE 0 843: \ SCOPE: 844: \ Internal method 845: 846: : (td-list-status) ( PointerToTDlist -- failingTD CCode TRUE | 0 ) 847: BEGIN ( PointerToTDlist ) 848: dup 0<> ( PointerToTDlist TRUE|FALSE ) 849: IF ( PointerToTDlist ) 850: dup td>tattr l@-le f0000000 and 1c rshift dup 0= TRUE swap 851: ( PointerToTDlist CCode TRUE TRUE|FALSE ) 852: ELSE 853: drop FALSE dup ( FALSE ) 854: THEN 855: WHILE 1.1.1.2 ! root 856: drop drop td>ntd l@-le phys2virt 1.1 root 857: REPEAT 858: ; 859: 860: 861: \ ================================================================== 862: \ COLON DEFINITION: (wait-for-done-q) 863: \ FUNCTIONALITY: 1.1.1.2 ! root 864: \ To do a timed polling of the done queue and acknowledge and return ! 865: \ the address of the last retired Td list 1.1 root 866: \ SCOPE: 867: \ Internal method 868: \ ================================================================== 869: 870: : (wait-for-done-q) ( timeout -- TD-list TRUE | FALSE ) 871: BEGIN ( timeout ) 872: dup 0<> ( timeout TRUE|FALSE ) 873: (HC-CHECK-WDH) NOT ( timeout TRUE|FALSE TRUE|FALSE ) 874: AND \ not timed out AND WDH-bit not set 875: WHILE 876: 1 ms \ wait 877: 1- ( timeout ) 878: dup ff and 0= IF show-proceed THEN 1.1.1.2 ! root 879: REPEAT ( timeout ) 1.1 root 880: drop 1.1.1.2 ! root 881: hchccadneq l@-le phys2virt \ read last HcDoneHead (RAM) ! 882: (HC-CHECK-WDH) \ HcDoneHead was updated ? 1.1 root 883: IF 1.1.1.2 ! root 884: (HC-ACK-WDH) \ clear register bit: WDH ! 885: TRUE ( td-list TRUE ) 1.1 root 886: ELSE 887: FALSE 888: THEN 889: ; 890: 891: 892: \ displays free tds 893: 894: 895: : debug-td ( -- ) 896: s" Num Free TDs = " num-free-tds usb-debug-print-val 897: ; 898: 899: 900: \ display content of frame counter 901: 902: \ : debug-frame-counter ( -- ) 903: \ 40 1 DO 1.1.1.2 ! root 904: \ ." Frame ct at HCCA at end of enumeration = " 1.1 root 905: \ hchcca 80 + rl@-le . 906: \ LOOP 907: \ ; 908: 909: \ ============================================================================ 910: \ COLON DEFINITION: HC-reset 911: \ This routine should be the first to be executed. 912: \ This routine will reset the HC and will bring it to Operational 913: \ state. 914: \ PENDING: 1.1.1.2 ! root 915: \ Arrive at the right value of FrameInterval. Currently we are hardcoding 1.1 root 916: \ it. 917: \ ========================================================================== 918: : HC-reset ( -- ) 1.1.1.2 ! root 919: hcrhdescA rl@-le ff and ( total-rh-ports ) ! 920: to max-rh-ports ! 921: ! 922: \ if no hardware-reset was issued (rescan) ! 923: \ switch off all ports first ! ! 924: hcrhpstat TO current-stat \ start with first port status reg ! 925: 0 \ port status default ! 926: max-rh-ports 0 \ checking all ports ! 927: ?DO ! 928: current-stat rl@-le or \ OR-ing all stats ! 929: 200 current-stat rl!-le \ Clear Port Power (CPP) ! 930: current-stat 4 + TO current-stat \ check next RH-Port ! 931: LOOP ! 932: 100 and 0<> \ any of the ports had power ? ! 933: IF ! 934: d# 750 wait-proceed \ wait for power discharge ! 935: THEN 1.1 root 936: 1.1.1.2 ! root 937: \ Reset HC and wait until reset has been cleared 1.1 root 938: hccomstat dup rl@-le 01 or swap rl!-le \ issue HC reset 939: BEGIN 940: hccomstat rl@-le 01 and 0<> \ wait for reset end 941: WHILE 942: REPEAT 943: 944: 23f02edf hcintrval rl!-le \ frame-interval register 1.1.1.2 ! root 945: hchcca-dma hchccareg rl!-le \ HC communication area 1.1 root 946: 0000 hcctrhead rl!-le \ control transfer head 947: 0000 hcbulkhead rl!-le \ bulk transfer head 948: 0ffff hcintdsbl rl!-le \ interrupt disable reg. 949: 1.1.1.2 ! root 950: \ all devices are still in reset-state ! 951: \ next command starts sending SOFs 1.1 root 952: 83 hccontrol rl!-le \ set USBOPERATIONAL 953: 1.1.1.2 ! root 954: \ these two repeated register settings are necessary for Bimini ! 955: \ Its OHCI controller (AM8111) behaves different to NEC's one 1.1 root 956: 23f02edf hcintrval rl!-le \ frame-interval register 1.1.1.2 ! root 957: hchcca-dma hchccareg rl!-le \ HC communication area 1.1 root 958: 1.1.1.2 ! root 959: d# 50 ms 1.1 root 960: 1.1.1.2 ! root 961: \ now power on all ports of this root-hub 1.1 root 962: hcrhpstat TO current-stat \ start with first port status reg 963: max-rh-ports 0 1.1.1.2 ! root 964: ?DO 1.1 root 965: 102 current-stat rl!-le \ power on and enable 1.1.1.2 ! root 966: hcrhdescA rl@-le 18 rshift 2 * ms \ startup delay 30 ms (2 * POTPGT) 1.1 root 967: current-stat 4 + TO current-stat \ check next RH-Port 968: LOOP 969: d# 500 wait-proceed \ STEC device needs 300 ms 970: ; 971: 972: : error-recovery ( -- ) 973: initialize-td-free-list 974: initialize-ed-free-list 975: HC-reset 976: ; 977: 978: \ ================================================================ 979: : store-initial-usb-hub-address ( -- ) 980: usb-address TO initial-hub-address 981: ; 982: 983: : reset-to-initial-usb-hub-address ( -- ) 984: initial-hub-address TO usb-address 985: ; 986: 987: \ allocate-usb-address: 988: \ Function allocates an USB address. 989: \ See RISK below. 990: 991: 992: : allocate-usb-address ( -- usb-address ) 993: usb-address 7f <> ( TRUE|FALSE ) 994: IF 995: usb-address 1+ TO usb-address \ RISK: Check to see IF it overflows 127 996: usb-address ( usb-address ) 997: THEN ( usb-address ) 998: ; 999: 1000: s" usb-support.fs" INCLUDED 1001: 1002: 1003: 1004: \ ===================================================================== 1005: \ COLON DEFINTION: control-std-set-address 1006: \ INTERFACE FUNCTION 1007: \ Function allocates an USB addrss and uses it to send SET-ADDRESS packet 1008: \ to the default USB address. 1009: \ This is an interface function available to child nodes. 1010: 1011: : control-std-set-address ( speedbit -- usb-address TRUE | FALSE ) 1012: >r ( R: speedbit ) 1013: 0005000000000000 setup-packet ! 1014: allocate-usb-address dup setup-packet 2 + c! ( usb-addr R: speedbit ) 1015: s" USB set-address: " 2 pick usb-debug-print-val ( usb-addr R: speedbit ) 1016: 0 0 0 setup-packet 8 r> controlxfer ( usb-addr TRUE | FALSE ) 1017: IF ( TRUE | FALSE ) 1018: TRUE ( TRUE ) 1019: ELSE 1020: drop FALSE \ PENDING: Return the allocated address back. ( FALSE ) 1021: THEN ( TRUE | FALSE ) 1022: ; 1023: 1024: 1025: \ Fetches the device decriptor of the usb-device 1026: 1027: 1028: : control-std-get-device-descriptor 1029: ( data-buffer data-len MPS fa -- TRUE|FALSE ) 1030: 1031: 8006000100000000 setup-packet ! 1032: 2 pick setup-packet 6 + w!-le 1033: ( data-buffer data-len MPS fa ) 1034: setup-packet -rot ( data-buffer data-len setup-packet MPS fa ) 1035: >r >r >r >r >r 0 r> r> r> r> r> 1036: ( 0 data-buffer data-len setup-packet MPS fa ) 1037: controlxfer ( TRUE | FALSE ) 1038: ; 1039: 1040: 1041: \ ================================================================== 1.1.1.2 ! root 1042: \ To retrieve the configuration descriptor of a device 1.1 root 1043: \ with a valid USB address 1044: 1045: 1046: : control-std-get-configuration-descriptor 1047: ( data-buffer data-len MPS FuncAddr -- TRUE|FALSE ) 1048: TO temp1 ( data-buffer data-len MPS ) 1049: TO temp2 ( data-buffer data-len ) 1050: TO temp3 ( data-buffer ) 1051: 8006000200000000 setup-packet ! 1052: temp3 setup-packet 6 + w!-le 1053: 0 swap temp3 setup-packet temp2 temp1 controlxfer 1054: ; 1055: 1056: \ Fetches num of logical units available for a device 1057: : control-std-get-maxlun ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE ) 1058: GET-MAX-LUN setup-packet ! ( MPS fun-addr dir data-buff data-len ) 1059: setup-packet 5 pick 5 pick 1060: ( MPS fun-addr dir data-buff data-len setup-packet MPS fun-addr ) 1061: controlxfer ( MPS fun-addr TRUE | FALSE ) 1062: nip nip ( TRUE | FALSE ) 1063: ; 1064: 1065: \ Bulk-Only Mass Storage Reset 1066: \ fixed to interface #0 1067: : control-bulk-reset ( MPS fun-addr dir data-buff data-len -- TRUE | FALSE ) 1068: 21FF000000000000 setup-packet ! ( MPS fun-addr dir data-buff data-len ) 1069: setup-packet 5 pick 5 pick 1070: ( MPS fun-addr dir data-buff data-len setup-packet MPS fun-addr ) 1071: controlxfer ( MPS fun-addr TRUE | FALSE ) 1072: nip nip ( TRUE | FALSE ) 1073: ; 1074: 1075: 1076: 1077: \ get the string descriptor of the usb device 1078: 1079: 1080: : control-std-get-string-descriptor 1081: ( StringIndex data-buffer data-len MPS FuncAddr -- TRUE | FALSE ) 1082: TO temp1 ( StringIndex data-buffer data-len MPS ) 1083: TO temp2 ( StringIndex data-buffer data-len ) 1084: TO temp3 ( StringIndex ) 1085: 8006000300000000 setup-packet ! 1086: temp3 setup-packet 6 + w!-le 1087: 409 setup-packet 4 + w!-le \ US English Language code. 1088: swap ( data buffer StringIndex ) 1089: setup-packet 2 + c! ( data-buffer ) 1090: 0 swap temp3 setup-packet temp2 temp1 controlxfer ( TRUE | FALSE ) 1091: ; 1092: 1093: \ sets a valid usb configaration for a device 1094: 1095: : control-std-set-configuration ( configvalue FuncAddr -- TRUE|FALSE ) 1096: TO temp1 ( configvalue ) 1097: TO temp2 1098: 0009000000000000 setup-packet ! \ RISK: Endian and 64-bit assumptions 1099: temp2 setup-packet 2 + w!-le 1100: 0 0 0 setup-packet DEFAULT-CONTROL-MPS temp1 controlxfer 1101: 1102: \ NOTE: We could use DEFAULT-CONTROL-MPS because there is no data phase 1103: \ associated with this control xfer. Its a dont care. 1104: ; 1105: 1106: 1107: \ To set the device address retrive the device descriptor and build the 1108: \ usb device tree by passing device class 1109: 1110: 1111: 0 VALUE port-number 1112: 1113: s" usb-enumerate.fs" INCLUDED 1114: 1115: : rhport-enumerate ( port-num -- ) 1116: TO port-number 1117: device-speed control-std-set-address ( usb-addr TRUE | FALSE ) 1118: IF 1119: device-speed or ( usb-addr+speedbit ) 1120: TO new-device-address 1121: dd-buffer @ 8 erase 1122: 1123: \ Read Device Descriptor - First 8 bytes. 1124: 1125: dd-buffer @ DEFAULT-CONTROL-MPS DEFAULT-CONTROL-MPS ( buffer mps mps ) 1126: new-device-address control-std-get-device-descriptor ( TRUE | FALSE ) 1127: IF 1128: ELSE 1129: s" USB: Read Dev Descriptor failed" usb-debug-print EXIT 1130: 1131: \ NOTE: Tomorrow, IF there is a LOOP here,we may need to UNLOOP before 1132: \ "EXIT"ing. Beware. Much depends on what LOOPing construct is used. 1133: 1134: THEN 1135: 1136: \ Read the Descriptor Type and check IF we have read correctly. 1137: 1138: dd-buffer @ DEVICE-DESCRIPTOR-TYPE-OFFSET + c@ ( Descriptor-type ) 1139: DEVICE-DESCRIPTOR-TYPE <> IF 1140: s" USB: Error Reading Device Descriptor" usb-debug-print 1.1.1.2 ! root 1141: s" Read descriptor is not of the right type" usb-debug-print 1.1 root 1142: s" Aborting enumeration" usb-debug-print 1143: EXIT 1.1.1.2 ! root 1144: \ NOTE: Tomorrow, if you have a LOOP here then we may need to ! 1145: \ UNLOOP before EXITing. Depends on what type of looping construct 1.1 root 1146: \ is used. Beware. 1147: 1148: THEN 1149: 1150: \ Read the MPS and store it. 1151: 1152: dd-buffer @ DEVICE-DESCRIPTOR-MPS-OFFSET + c@ TO mps 1153: 1154: \ NOTE: Probably, we could check MPS for only 8/16/32/64 1155: \ hmm.. not now... 1156: 1.1.1.2 ! root 1157: \ Read the device class to see what type of device it is and create an 1.1 root 1158: \ appropriate child node here. 1159: create-usb-device-tree 1160: ELSE 1161: s" Set address failed on port " port-number usb-debug-print-val 1162: s" Aborting Enumeration." usb-debug-print 1163: EXIT 1164: 1.1.1.2 ! root 1165: \ NOTE: Tomorrow , if you have a LOOP here then we may need to ! 1166: \ UNLOOP before EXITing. Depends on what type of looping construct 1.1 root 1167: \ is used. Beware. 1168: 1169: THEN 1170: ; 1171: 1172: 1173: \ ========================================================================= 1174: \ PROTOTYPE FUNCTION: "rhport-initialize" 1175: \ Detect Device, reset and enable the respective port. 1.1.1.2 ! root 1176: \ COLON Definition rhport-initialize accepts the total number of root hub 1.1 root 1177: \ ports as an argument and probes every available root hub port and initiates 1.1.1.2 ! root 1178: \ the build of the USB devie sub-tree so is effectively the mother of all 1.1 root 1179: \ USB device nodes that are to be detected and instantiated. 1180: \ ========================================================================== 1181: : rhport-initialize ( -- ) 1182: 1183: hcrhpstat TO current-stat \ start with first port status reg 1184: max-rh-ports 1+ 1 1.1.1.2 ! root 1185: ?DO ! 1186: usb-debug-flag IF ! 1187: ." Initializing RH port " i . cr ! 1188: THEN 1.1 root 1189: \ any Device connected to that port ? 1190: current-stat rl@-le RHP-CCS and 0<> ( TRUE|FALSE ) 1191: IF 1192: s" Device connected to this port!" usb-debug-print 1193: RHP-PRS current-stat rl!-le \ issue a port reset 1194: BEGIN 1195: current-stat rl@-le RHP-PRS AND \ wait for reset end 1196: WHILE 1197: REPEAT 1.1.1.2 ! root 1198: hcrhdescA rl@-le 18 rshift 2 * ms \ startup delay 30 ms (POTPGT) 1.1 root 1199: d# 100 ms 1200: 1201: current-stat rl@-le 200 and 4 lshift 1202: to device-speed \ store speed bit 1203: 1204: RHP-CSC RHP-PRSC or current-stat rl!-le 1205: 1206: I ['] rhport-enumerate CATCH IF \ Scan port 1207: s" USB scan failed on root hub port: " rot usb-debug-print-val 1208: reset-to-initial-usb-hub-address 1209: THEN 1210: 1211: ELSE 1212: s" No device detected at this port." usb-debug-print 1.1.1.2 ! root 1213: current-stat rl@-le 80000 and 0<> \ is over-current detected ? ! 1214: IF ! 1215: s" Warning: Overcurrent indicated" usb-debug-print 1.1 root 1216: THEN 1217: THEN 1218: current-stat 4 + TO current-stat \ check next RH-Port 1219: LOOP 1220: ; 1221: 1222: 1223: \ =================================================== 1224: \ Enumeration at Host level 1225: \ =================================================== 1226: 1227: : enumerate ( -- ) 1228: HC-reset 1229: store-initial-usb-hub-address 1230: rhport-initialize \ Probe all available RH ports 1231: reset-to-initial-usb-hub-address 1232: ;
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.