Subversion Repositories Kolibri OS

Rev

Rev 425 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. $Revision: 431 $
  2. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  3. ;;                                                                 ;;
  4. ;; Copyright (C) KolibriOS team 2004-2007. All rights reserved.    ;;
  5. ;; Distributed under terms of the GNU General Public License       ;;
  6. ;;                                                                 ;;
  7. ;;                                                                 ;;
  8. ;;  I8255X.INC                                                     ;;
  9. ;;                                                                 ;;
  10. ;;  Ethernet driver for Menuet OS                                  ;;
  11. ;;                                                                 ;;
  12. ;;  Version 0.3  11 August 2003                                    ;;
  13. ;;                                                                 ;;
  14. ;;  This driver is based on the eepro100 driver from               ;;
  15. ;;  the etherboot 5.0.6 project. The copyright statement is        ;;
  16. ;;                                                                 ;;
  17. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  18. ;;             Version 2, June 1991                                ;;
  19. ;;                                                                 ;;
  20. ;;  remaining parts Copyright 2002 Mike Hibbett,                   ;;
  21. ;;   mikeh@oceanfree.net                                           ;;
  22. ;;                                                                 ;;
  23. ;;  See file COPYING for details                                   ;;
  24. ;;                                                                 ;;
  25. ;;                                                                 ;;
  26. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  27.  
  28.  
  29. ;********************************************************************
  30. ;   Interface
  31. ;      I8255x_reset
  32. ;      I8255x_probe
  33. ;      I8255x_poll
  34. ;      I8255x_transmit
  35. ;
  36. ;      These functions are referenced in ethernet.inc
  37. ;
  38. ;********************************************************************
  39.  
  40.  
  41. rxfd_status             equ  eth_data_start
  42. rxfd_command           equ  eth_data_start + 2
  43. rxfd_link               equ  eth_data_start + 4
  44. rxfd_rx_buf_addr       equ  eth_data_start + 8
  45. rxfd_count             equ  eth_data_start + 12
  46. rxfd_size               equ  eth_data_start + 14
  47. rxfd_packet             equ  eth_data_start + 16
  48.  
  49.  
  50.  
  51. uglobal
  52. eeprom_data:  times 16  dd 0
  53.  
  54. align 4
  55.  
  56. lstats:
  57. tx_good_frames: dd 0
  58. tx_coll16_errs:  dd 0
  59. tx_late_colls: dd 0
  60. tx_underruns: dd 0
  61. tx_lost_carrier: dd 0
  62. tx_deferred: dd 0
  63. tx_one_colls: dd 0
  64. tx_multi_colls: dd 0
  65. tx_total_colls: dd 0
  66. rx_good_frames: dd 0
  67. rx_crc_errs: dd 0
  68. rx_align_errs: dd 0
  69. rx_resource_errs: dd 0
  70. rx_overrun_errs: dd 0
  71. rx_colls_errs: dd 0
  72. rx_runt_errs: dd 0
  73. done_marker: dd 0
  74.  
  75. align 4
  76.  
  77. confcmd:
  78. confcmd_status:         dw    0
  79. confcmd_command:        dw    0
  80. confcmd_link:           dd    0
  81. endg
  82.  
  83. iglobal
  84. confcmd_data:           db    22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1
  85.                         db    0, 0x2e, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2
  86.                         db    0x80, 0x3f, 0x05
  87. endg
  88.  
  89. uglobal
  90. align 4
  91.  
  92. txfd:
  93. txfd_status:            dw   0
  94. txfd_command:           dw   0
  95. txfd_link:              dd   0
  96. txfd_tx_desc_addr:      dd   0
  97. txfd_count:             dd   0
  98. txfd_tx_buf_addr0:      dd   0
  99. txfd_tx_buf_size0:      dd   0
  100. txfd_tx_buf_addr1:      dd   0
  101. txfd_tx_buf_size1:      dd   0
  102.  
  103. align 4
  104.  
  105. hdr:
  106. hdr_dst_addr:           times 6 db 0
  107. hdr_src_addr:           times 6 db 0
  108. hdr_type:               dw   0
  109. endg
  110.  
  111.  
  112. ;***************************************************************************
  113. ;   Function
  114. ;      wait_for_cmd_done
  115. ;
  116. ;   Description
  117. ;       waits for the hardware to complete a command
  118. ;       port address in edx
  119. ;
  120. ;       al destroyed
  121. ;***************************************************************************
  122. wait_for_cmd_done:
  123.    in       al, dx
  124.    cmp      al, 0
  125.    jne      wait_for_cmd_done
  126.    ret
  127.  
  128.  
  129.  
  130. ;***************************************************************************
  131. ;   Function
  132. ;      mdio_read
  133. ;
  134. ;   Description
  135. ;       This probably reads a register in the "physical media interface chip"
  136. ;         Phy_id in ebx
  137. ;         location in ecx
  138. ;
  139. ;       Data returned in eax
  140. ;
  141. ;***************************************************************************
  142. mdio_read:
  143.    mov      edx, [io_addr]
  144.    add      edx, 16         ; SCBCtrlMDI
  145.  
  146.    mov      eax, 0x08000000
  147.    shl      ecx, 16
  148.    or       eax, ecx
  149.    shl      ebx, 21
  150.    or       eax, ebx
  151.  
  152.    out      dx, eax
  153.  
  154. mrlp:
  155.    call     delay_us
  156.    in       eax, dx
  157.    mov      ecx, eax
  158.    and      ecx, 0x10000000
  159.    jz       mrlp
  160.  
  161.    and      eax, 0xffff
  162.    ret
  163.  
  164.  
  165.  
  166. ;***************************************************************************
  167. ;   Function
  168. ;      mdio_write
  169. ;
  170. ;   Description
  171. ;       This probably writes a register in the "physical media interface chip"
  172. ;         Phy_id in ebx
  173. ;         location in ecx
  174. ;         data in edx
  175. ;       Data returned in eax
  176. ;
  177. ;***************************************************************************
  178. mdio_write:
  179.    mov      eax, 0x04000000
  180.    shl      ecx, 16
  181.    or       eax, ecx
  182.    shl      ebx, 21
  183.    or       eax, ebx
  184.    or       eax, edx
  185.  
  186.    mov      edx, [io_addr]
  187.    add      edx, 16         ; SCBCtrlMDI
  188.    out      dx, eax
  189.  
  190. mwlp:
  191.    call     delay_us
  192.    in       eax, dx
  193.    mov      ecx, eax
  194.    and      ecx, 0x10000000
  195.    jz       mwlp
  196.  
  197.    and      eax, 0xffff
  198.    ret
  199.  
  200.  
  201.  
  202. ;/***********************************************************************/
  203. ;/*                       I82557 related defines                        */
  204. ;/***********************************************************************/
  205.  
  206. ; Serial EEPROM section.
  207. ;   A "bit" grungy, but we work our way through bit-by-bit :->.
  208. ;  EEPROM_Ctrl bits.
  209. EE_SHIFT_CLK   equ   0x01    ; EEPROM shift clock.
  210. EE_CS           equ   0x02    ; EEPROM chip select.
  211. EE_DATA_WRITE   equ   0x04    ; EEPROM chip data in.
  212. EE_DATA_READ   equ   0x08    ; EEPROM chip data out.
  213. EE_WRITE_0     equ   0x4802
  214. EE_WRITE_1     equ   0x4806
  215. EE_ENB         equ   0x4802
  216.  
  217.  
  218. ; The EEPROM commands include the alway-set leading bit.
  219. EE_READ_CMD     equ   6
  220.  
  221. ; The SCB accepts the following controls for the Tx and Rx units:
  222. CU_START       equ   0x0010
  223. CU_RESUME     equ   0x0020
  224. CU_STATSADDR   equ   0x0040
  225. CU_SHOWSTATS   equ   0x0050   ; Dump statistics counters.
  226. CU_CMD_BASE   equ   0x0060   ; Base address to add to add CU commands.
  227. CU_DUMPSTATS   equ   0x0070   ; Dump then reset stats counters.
  228.  
  229. RX_START       equ   0x0001
  230. RX_RESUME     equ   0x0002
  231. RX_ABORT       equ   0x0004
  232. RX_ADDR_LOAD   equ   0x0006
  233. RX_RESUMENR   equ   0x0007
  234. INT_MASK       equ   0x0100
  235. DRVR_INT       equ   0x0200   ; Driver generated interrupt.
  236.  
  237.  
  238. ;***************************************************************************
  239. ;   Function
  240. ;      do_eeprom_cmd
  241. ;
  242. ;   Description
  243. ;       writes a cmd to the ethernet cards eeprom, by bit bashing
  244. ;       cmd in ebx
  245. ;       cmd length in ecx
  246. ;       return in eax
  247. ;***************************************************************************
  248. do_eeprom_cmd:
  249.    mov      edx, [io_addr]    ; We only require the value in dx
  250.    add      dx, 14            ; the value SCBeeprom
  251.  
  252.    mov      ax, EE_ENB
  253.    out      dx, ax
  254.    call     delay_us
  255.  
  256.    mov      ax, 0x4803        ; EE_ENB | EE_SHIFT_CLK
  257.    out      dx, ax
  258.    call     delay_us
  259.  
  260.     ; dx holds ee_addr
  261.     ; ecx holds count
  262.     ; eax holds cmd
  263.    xor      edi, edi          ; this will be the receive data
  264.  
  265. dec_001:
  266.    mov      esi, 1
  267.  
  268.    dec      ecx
  269.    shl      esi, cl
  270.    inc      ecx
  271.    and      esi, ebx
  272.    mov      eax, EE_WRITE_0   ; I am assuming this doesnt affect the flags..
  273.    cmp      esi,0
  274.    jz       dec_002
  275.    mov      eax, EE_WRITE_1
  276.  
  277. dec_002:
  278.    out      dx, ax
  279.    call     delay_us
  280.  
  281.    or       ax, EE_SHIFT_CLK
  282.    out      dx, ax
  283.    call     delay_us
  284.  
  285.    shl      edi,1
  286.  
  287.    in       ax, dx
  288.    and      ax, EE_DATA_READ
  289.    cmp      ax,0
  290.    jz       dec_003
  291.    inc      edi
  292.  
  293. dec_003:
  294.    loop     dec_001
  295.  
  296.    mov      ax, EE_ENB
  297.    out      dx, ax
  298.    call     delay_us
  299.  
  300.    mov      ax, 0x4800
  301.    out      dx, ax
  302.    call     delay_us
  303.  
  304.    mov      eax, edi
  305.  
  306.    ret
  307.  
  308.  
  309.  
  310. ;***************************************************************************
  311. ;   Function
  312. ;      I8255x_reset
  313. ;   Description
  314. ;      Place the chip (ie, the ethernet card) into a virgin state
  315. ;      No inputs
  316. ;      All registers destroyed
  317. ;
  318. ;***************************************************************************
  319. I8255x_reset:
  320.    ret
  321.  
  322.  
  323.  
  324. ;***************************************************************************
  325. ;   Function
  326. ;      I8255x_probe
  327. ;   Description
  328. ;      Searches for an ethernet card, enables it and clears the rx buffer
  329. ;      If a card was found, it enables the ethernet -> TCPIP link
  330. ;
  331. ;***************************************************************************
  332. I8255x_probe:
  333.    mov      eax, [io_addr]
  334.  
  335.    mov      ebx, [pci_bus]
  336.    mov      ecx, [pci_dev]
  337.    mov      edx, 0x04      ; PCI_COMMAND
  338.    call     pcibios_read_config_word
  339.  
  340.    or       ax, 0x05
  341.    mov      ebx, [pci_bus]
  342.    mov      ecx, [pci_dev]
  343.    mov      edx, 0x04      ; PCI_COMMAND
  344.    call     pcibios_write_config_word
  345.  
  346.    mov      ebx, 0x6000000
  347.    mov      ecx, 27
  348.    call     do_eeprom_cmd
  349.    and      eax, 0xffe0000
  350.    cmp      eax, 0xffe0000
  351.    je       bige
  352.  
  353.    mov      ebx, 0x1800000
  354.    mov      ecx, 0x40
  355.    jmp      doread
  356.  
  357. bige:
  358.    mov      ebx, 0x6000000
  359.    mov      ecx, 0x100
  360.  
  361. doread:
  362.    ; do-eeprom-cmd will destroy all registers
  363.    ; we have eesize in ecx
  364.    ; read_cmd in ebx
  365.  
  366.    ; Ignore full eeprom - just load the mac address
  367.    mov      ecx, 0
  368.  
  369. drlp:
  370.    push     ecx      ; save count
  371.    push     ebx
  372.    mov      eax, ecx
  373.    shl      eax, 16
  374.    or       ebx, eax
  375.    mov      ecx, 27
  376.    call     do_eeprom_cmd
  377.  
  378.    pop      ebx
  379.    pop      ecx
  380.  
  381.    mov      edx, ecx
  382.    shl      edx, 2
  383.    mov      esi, eeprom_data
  384.    add      esi, edx
  385.    mov      [esi], eax
  386.  
  387.    inc      ecx
  388.    cmp      ecx, 16
  389.    jne      drlp
  390.  
  391.    ; OK, we have the MAC address.
  392.    ; Now reset the card
  393.  
  394.    mov      edx, [io_addr]
  395.    add      dx, 8         ; SCBPort
  396.    xor      eax, eax      ; The reset cmd == 0
  397.    out      dx, eax
  398.  
  399.    mov      esi, 10
  400.    call     delay_ms      ; Give the card time to warm up.
  401.  
  402.    mov      eax, lstats
  403.    mov      edx, [io_addr]
  404.    add      edx, 4            ; SCBPointer
  405.    out      dx, eax
  406.  
  407.    mov      eax, 0x0140         ; INT_MASK | CU_STATSADDR
  408.    mov      edx, [io_addr]
  409.    add      edx, 2            ; SCBCmd
  410.    out      dx, ax
  411.  
  412.    call     wait_for_cmd_done
  413.  
  414.    mov      eax, 0
  415.    mov      edx, [io_addr]
  416.    add      edx, 4            ; SCBPointer
  417.    out      dx, eax
  418.  
  419.    mov      eax, 0x0106         ; INT_MASK | RX_ADDR_LOAD
  420.    mov      edx, [io_addr]
  421.    add      edx, 2            ; SCBCmd
  422.    out      dx, ax
  423.  
  424.    call     wait_for_cmd_done
  425.  
  426.    ; build rxrd structure
  427.    mov      ax, 0x0001
  428.    mov      [rxfd_status], ax
  429.    mov      ax, 0x0000
  430.    mov      [rxfd_command], ax
  431.  
  432.    mov      eax, rxfd_status
  433.    mov      [rxfd_link], eax
  434.  
  435.    mov      eax, Ether_buffer
  436.    mov      [rxfd_rx_buf_addr], eax
  437.  
  438.    mov      ax, 0
  439.    mov      [rxfd_count], ax
  440.  
  441.    mov      ax, 1528
  442.    mov      [rxfd_size], ax
  443.  
  444.    mov      edx, [io_addr]
  445.    add      edx, 4           ; SCBPointer
  446.  
  447.    mov      eax, rxfd_status
  448.    out      dx, eax
  449.  
  450.    mov      edx, [io_addr]
  451.    add      edx, 2           ; SCBCmd
  452.  
  453.    mov      ax, 0x0101         ; INT_MASK | RX_START
  454.    out      dx, ax
  455.  
  456.    call     wait_for_cmd_done
  457.  
  458.    ; start the reciver
  459.  
  460.    mov      ax, 0
  461.    mov      [rxfd_status], ax
  462.  
  463.    mov      ax, 0xc000
  464.    mov      [rxfd_command], ax
  465.  
  466.    mov      edx, [io_addr]
  467.    add      edx, 4           ; SCBPointer
  468.  
  469.    mov      eax, rxfd_status
  470.    out      dx, eax
  471.  
  472.    mov      edx, [io_addr]
  473.    add      edx, 2           ; SCBCmd
  474.  
  475.    mov      ax, 0x0101         ; INT_MASK | RX_START
  476.    out      dx, ax
  477.  
  478.    ; Init TX Stuff
  479.  
  480.    mov      edx, [io_addr]
  481.    add      edx, 4           ; SCBPointer
  482.  
  483.    mov      eax, 0
  484.    out      dx, eax
  485.  
  486.    mov      edx, [io_addr]
  487.    add      edx, 2           ; SCBCmd
  488.  
  489.    mov      ax, 0x0160         ; INT_MASK | CU_CMD_BASE
  490.    out      dx, ax
  491.  
  492.    call     wait_for_cmd_done
  493.  
  494.    ; Set TX Base address
  495.  
  496.    ; First, set up confcmd values
  497.  
  498.    mov      ax, 2
  499.    mov      [confcmd_command], ax
  500.    mov      eax, txfd
  501.    mov      [confcmd_link], eax
  502.  
  503.    mov      ax, 1
  504.    mov      [txfd_command], ax         ; CmdIASetup
  505.  
  506.    mov      ax, 0
  507.    mov      [txfd_status], ax
  508.  
  509.    mov      eax, confcmd
  510.    mov      [txfd_link], eax
  511.  
  512.    ; ETH_ALEN is 6 bytes
  513.  
  514.    mov      esi, eeprom_data
  515.    mov      edi, node_addr
  516.    mov      ecx, 3
  517. drp000:
  518.    mov      eax, [esi]
  519.    mov      [edi], al
  520.    shr      eax, 8
  521.    inc      edi
  522.    mov      [edi], al
  523.    inc      edi
  524.    add      esi, 4
  525.    loop     drp000
  526.  
  527.    ; Hard code your MAC address into node_addr at this point,
  528.    ; If you cannot read the MAC address from the eeprom in the previous step.
  529.    ; You also have to write the mac address into txfd_tx_desc_addr, rather
  530.    ; than taking data from eeprom_data
  531.  
  532.    mov      esi, eeprom_data
  533.    mov      edi, txfd_tx_desc_addr
  534.    mov      ecx, 3
  535. drp001:
  536.    mov      eax, [esi]
  537.    mov      [edi], al
  538.    shr      eax, 8
  539.    inc      edi
  540.    mov      [edi], al
  541.    inc      edi
  542.    add      esi, 4
  543.    loop     drp001
  544.  
  545.    mov      esi, eeprom_data + (6 * 4)
  546.    mov      eax, [esi]
  547.    shr      eax, 8
  548.    and      eax, 0x3f
  549.    cmp      eax, 4            ; DP83840
  550.    je       drp002
  551.    cmp      eax, 10            ; DP83840A
  552.    je       drp002
  553.    jmp      drp003
  554.  
  555. drp002:
  556.    mov      ebx, [esi]
  557.    and      ebx, 0x1f
  558.    push     ebx
  559.    mov      ecx, 23
  560.    call     mdio_read
  561.    pop      ebx
  562.    or       eax, 0x0422
  563.    mov      ecx, 23
  564.    mov      edx, eax
  565.    call     mdio_write
  566.  
  567. drp003:
  568.    mov      ax, 0x4002         ; Cmdsuspend | CmdConfigure
  569.    mov      [confcmd_command], ax
  570.    mov      ax, 0
  571.    mov      [confcmd_status], ax
  572.    mov      eax, txfd
  573.    mov      [confcmd_link], eax
  574.    mov      ebx, confcmd_data
  575.    mov      al, 0x88         ; fifo of 8 each
  576.    mov      [ebx + 1], al
  577.    mov      al, 0
  578.    mov      [ebx + 4], al
  579.    mov      al, 0x80
  580.    mov      [ebx + 5], al
  581.    mov      al, 0x48
  582.    mov      [ebx + 15], al
  583.    mov      al, 0x80
  584.    mov      [ebx + 19], al
  585.    mov      al, 0x05
  586.    mov      [ebx + 21], al
  587.  
  588.    mov      eax, txfd
  589.    mov      edx, [io_addr]
  590.    add      edx, 4            ; SCBPointer
  591.    out      dx, eax
  592.  
  593.    mov      eax, 0x0110         ; INT_MASK | CU_START
  594.    mov      edx, [io_addr]
  595.    add      edx, 2            ; SCBCmd
  596.    out      dx, ax
  597.  
  598.    call     wait_for_cmd_done
  599. jmp skip
  600.  
  601.    ; wait for thing to start
  602. drp004:
  603.    mov      ax, [txfd_status]
  604.    cmp      ax, 0
  605.    je       drp004
  606.  
  607. skip:
  608.    ; Indicate that we have successfully reset the card
  609.    mov      eax, [pci_data]
  610.    mov      [eth_status], eax
  611.  
  612. I8255x_exit:
  613.    ret
  614.  
  615.  
  616.  
  617. ;***************************************************************************
  618. ; Function
  619. ;    I8255x_poll
  620. ;
  621. ; Description
  622. ;    Polls the ethernet card for a received packet
  623. ;    Received data, if any, ends up in Ether_buffer
  624. ;
  625. ;***************************************************************************
  626. I8255x_poll:
  627.    mov      ax, 0      ; assume no data
  628.    mov      [eth_rx_data_len], ax
  629.  
  630.    mov      ax, [rxfd_status]
  631.    cmp      ax, 0
  632.    je       i8p_exit
  633.  
  634.    mov      ax, 0
  635.    mov      [rxfd_status], ax
  636.  
  637.    mov      ax, 0xc000
  638.    mov      [rxfd_command], ax
  639.  
  640.    mov      edx, [io_addr]
  641.    add      edx, 4           ; SCBPointer
  642.  
  643.    mov      eax, rxfd_status
  644.    out      dx, eax
  645.  
  646.    mov      edx, [io_addr]
  647.    add      edx, 2           ; SCBCmd
  648.  
  649.    mov      ax, 0x0101         ; INT_MASK | RX_START
  650.    out      dx, ax
  651.  
  652.    call     wait_for_cmd_done
  653.  
  654.    mov      esi, rxfd_packet
  655.    mov      edi, Ether_buffer
  656.    mov      ecx, 1518
  657.    cld
  658.    rep      movsb
  659.  
  660.    mov      ax, [rxfd_count]
  661.    and      ax, 0x3fff
  662.    mov      [eth_rx_data_len], ax
  663.  
  664. i8p_exit:
  665.    ret
  666.  
  667.  
  668.  
  669. ;***************************************************************************
  670. ;   Function
  671. ;      I8255x_transmit
  672. ;
  673. ;   Description
  674. ;       Transmits a packet of data via the ethernet card
  675. ;          Pointer to 48 bit destination address in edi
  676. ;         Type of packet in bx
  677. ;         size of packet in ecx
  678. ;         pointer to packet data in esi
  679. ;
  680. ;***************************************************************************
  681. I8255x_transmit:
  682.  
  683.    mov      [hdr_type], bx
  684.  
  685.    mov      eax, [edi]
  686.    mov      [hdr_dst_addr], eax
  687.    mov      ax, [edi+4]
  688.    mov      [hdr_dst_addr+4], ax
  689.  
  690.    mov      eax, [node_addr]
  691.    mov      [hdr_src_addr], eax
  692.    mov      ax, [node_addr+4]
  693.    mov      [hdr_src_addr+4], ax
  694.  
  695.    mov      edx, [io_addr]
  696.    in       ax, dx
  697.    and      ax, 0xfc00
  698.    out      dx, ax
  699.  
  700.    xor      ax, ax
  701.    mov      [txfd_status], ax
  702.    mov      ax, 0x400C            ; Cmdsuspend | CmdTx | CmdTxFlex
  703.    mov      [txfd_command], ax
  704.    mov      eax, txfd
  705.    mov      [txfd_link], eax
  706.    mov      eax, 0x02208000
  707.    mov      [txfd_count], eax
  708.    mov      eax, txfd_tx_buf_addr0
  709.    mov      [txfd_tx_desc_addr], eax
  710.    mov      eax, hdr
  711.    mov      [txfd_tx_buf_addr0], eax
  712.    mov      eax, 14   ; sizeof hdr
  713.    mov      [txfd_tx_buf_size0], eax
  714.  
  715.    ; Copy the buffer address and size in
  716.    mov      eax, esi
  717.    mov      [txfd_tx_buf_addr1], eax
  718.    mov      eax, ecx
  719.    mov      [txfd_tx_buf_size1], eax
  720.  
  721.    mov      eax, txfd
  722.    mov      edx, [io_addr]
  723.    add      edx, 4            ; SCBPointer
  724.    out      dx, eax
  725.  
  726.    mov      ax, 0x0110         ; INT_MASK | CU_START
  727.    mov      edx, [io_addr]
  728.    add      edx, 2            ; SCBCmd
  729.    out      dx, ax
  730.  
  731.    call     wait_for_cmd_done
  732.  
  733.    mov      edx, [io_addr]
  734.    in       ax, dx
  735.  
  736. I8t_001:
  737.    mov      ax, [txfd_status]
  738.    cmp      ax, 0
  739.    je       I8t_001
  740.  
  741.    mov      edx, [io_addr]
  742.    in       ax, dx
  743.  
  744.    ret