Subversion Repositories Kolibri OS

Rev

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

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