Subversion Repositories Kolibri OS

Rev

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

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