Subversion Repositories Kolibri OS

Rev

Rev 431 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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