Annotation of qemu/roms/SLOF/slof/fs/usb/usb-ohci.fs, revision 1.1.1.2

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: ;

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.