Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
  4. ;; Distributed under terms of the GNU General Public License    ;;
  5. ;;                                                              ;;
  6. ;;  3Com network driver for KolibriOS                           ;;
  7. ;;                                                              ;;
  8. ;;  Ported to KolibriOS net-branch by hidnplayr                 ;;
  9. ;;                                                              ;;
  10. ;;  Thanks to: scrap metal recyclers, whom provide me with      ;;
  11. ;;                         loads of hardware                    ;;
  12. ;;             diamond: who makes me understand KolibriOS       ;;
  13. ;;                                                              ;;
  14. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  15. ;;
  16. ;; Original copyright from menuetos driver:
  17. ;;
  18. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  19. ;;                                                                         ;;
  20. ;;  3C59X.INC                                                              ;;
  21. ;;                                                                         ;;
  22. ;;  Ethernet driver for Menuet OS                                          ;;
  23. ;;                                                                         ;;
  24. ;;  Driver for 3Com fast etherlink 3c59x and                               ;;
  25. ;;         etherlink XL 3c900 and 3c905 cards                              ;;
  26. ;;  References:                                                            ;;
  27. ;;    www.3Com.com - data sheets                                           ;;
  28. ;;    DP83840A.pdf - ethernet physical layer                               ;;
  29. ;;    3c59x.c - linux driver                                               ;;
  30. ;;    ethernet driver template by Mike Hibbett                             ;;
  31. ;;                                                                         ;;
  32. ;;  Credits                                                                ;;
  33. ;;   Mike Hibbett,                                                         ;;
  34. ;;         who kindly supplied me with a 3Com905C-TX-M card                ;;
  35. ;;                                                                         ;;
  36. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  37. ;;
  38. ;; Copyright (c) 2004, Endre Kozma <endre.kozma@axelero.hu>
  39. ;; All rights reserved.
  40. ;;
  41. ;; Redistribution  and  use  in  source  and  binary  forms, with or without
  42. ;; modification, are permitted provided  that  the following  conditions are
  43. ;; met:
  44. ;;
  45. ;; 1. Redistributions of source code must retain the above  copyright notice,
  46. ;;    this list of conditions and the following disclaimer.
  47. ;;
  48. ;; 2. Redistributions  in  binary form  must  reproduce  the above copyright
  49. ;;    notice, this  list of conditions  and the  following disclaimer in the
  50. ;;    documentation and/or other  materials  provided with  the distribution.
  51. ;;
  52. ;; 3. The name of the author may not be used to  endorse or promote products
  53. ;;    derived from this software without  specific prior  written permission.
  54. ;;
  55. ;; THIS SOFTWARE IS  PROVIDED  BY  THE  AUTHOR  ``AS IS'' AND ANY EXPRESS OR
  56. ;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  57. ;; OF  MERCHANTABILITY AND FITNESS  FOR A PARTICULAR  PURPOSE ARE DISCLAIMED.
  58. ;; IN  NO  EVENT  SHALL  THE  AUTHOR  BE  LIABLE  FOR  ANY  DIRECT, INDIRECT,
  59. ;; INCIDENTAL, SPECIAL, EXEMPLARY, OR  CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  60. ;; NOT LIMITED TO, PROCUREMENT OF  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  61. ;; DATA, OR  PROFITS; OR  BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON ANY
  62. ;; THEORY OF  LIABILITY, WHETHER IN  CONTRACT,  STRICT  LIABILITY,  OR  TORT
  63. ;; (INCLUDING NEGLIGENCE OR OTHERWISE)  ARISING IN ANY WAY OUT OF THE USE OF
  64. ;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  65. ;;
  66. ;;  History
  67. ;;  =======
  68. ;;  $Log: 3C59X.INC,v $
  69. ;;  Revision 1.3  2004/07/11 12:21:12  kozma
  70. ;;  Support of vortex chips (3c59x) added.
  71. ;;  Support of 3c920 and 3c982 added.
  72. ;;  Corrections.
  73. ;;
  74. ;;  Revision 1.2  2004/06/12 19:40:20  kozma
  75. ;;  Function e3c59x_set_available_media added in order to set
  76. ;;  the default media in case auto detection finds no valid link.
  77. ;;  Incorrect mii check removed (3c900 Cyclone works now).
  78. ;;  Cleanups.
  79. ;;
  80. ;;  Revision 1.1  2004/06/12 18:27:15  kozma
  81. ;;  Initial revision
  82. ;;
  83. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  84.  
  85.  
  86. format PE DLL native
  87. entry START
  88.  
  89.         CURRENT_API             = 0x0200
  90.         COMPATIBLE_API          = 0x0100
  91.         API_VERSION             = (COMPATIBLE_API shl 16) + CURRENT_API
  92.  
  93. ; configureable area
  94.  
  95.         MAX_DEVICES             = 16    ; Maximum number of devices this driver may handle
  96.  
  97.         FORCE_FD                = 0     ; forcing full duplex mode makes sense at some cards and link types
  98.  
  99.         NUM_RX_DESC             = 32    ; Number of receive descriptors (must be power of 2)
  100.         NUM_TX_DESC             = 16    ; Number of transmit descriptors (must be power of 2)
  101.  
  102.         __DEBUG__               = 1     ; 1 = on, 0 = off
  103.         __DEBUG_LEVEL__         = 2     ; 1 = verbose, 2 = errors only
  104.  
  105. ; end configureable area
  106.  
  107. section '.flat' readable writable executable
  108.  
  109. include '../proc32.inc'
  110. include '../struct.inc'
  111. include '../macros.inc'
  112. include '../fdo.inc'
  113. include '../netdrv.inc'
  114.  
  115.  
  116. if (bsr NUM_RX_DESC)>(bsf NUM_RX_DESC)
  117.   display 'NUM_RX_DESC must be a power of two'
  118.   err
  119. end if
  120.  
  121. if (bsr NUM_TX_DESC)>(bsf NUM_TX_DESC)
  122.   display 'NUM_TX_DESC must be a power of two'
  123.   err
  124. end if
  125.  
  126. ; Registers
  127.         REG_POWER_MGMT_CTRL     = 0x7c
  128.         REG_UP_LIST_PTR         = 0x38
  129.         REG_UP_PKT_STATUS       = 0x30
  130.         REG_TX_FREE_THRESH      = 0x2f
  131.         REG_DN_LIST_PTR         = 0x24
  132.         REG_DMA_CTRL            = 0x20
  133.         REG_TX_STATUS           = 0x1b
  134.         REG_RX_STATUS           = 0x18
  135.         REG_TX_DATA             = 0x10
  136.  
  137. ; Common window registers
  138.         REG_INT_STATUS          = 0xe
  139.         REG_COMMAND             = 0xe
  140.  
  141. ; Register window 7
  142.         REG_MASTER_STATUS       = 0xc
  143.         REG_POWER_MGMT_EVENT    = 0xc
  144.         REG_MASTER_LEN          = 0x6
  145.         REG_VLAN_ETHER_TYPE     = 0x4
  146.         REG_VLAN_MASK           = 0x0
  147.         REG_MASTER_ADDRESS      = 0x0
  148.  
  149. ; Register window 6
  150.         REG_BYTES_XMITTED_OK    = 0xc
  151.         REG_BYTES_RCVD_OK       = 0xa
  152.         REG_UPPER_FRAMES_OK     = 0x9
  153.         REG_FRAMES_DEFERRED     = 0x8
  154.         REG_FRAMES_RCVD_OK      = 0x7
  155.         REG_FRAMES_XMITTED_OK   = 0x6
  156.         REG_RX_OVERRUNS         = 0x5
  157.         REG_LATE_COLLISIONS     = 0x4
  158.         REG_SINGLE_COLLISIONS   = 0x3
  159.         REG_MULTIPLE_COLLISIONS = 0x2
  160.         REG_SQE_ERRORS          = 0x1
  161.         REG_CARRIER_LOST        = 0x0
  162.  
  163. ; Register window 5
  164.         REG_INDICATION_ENABLE   = 0xc
  165.         REG_INTERRUPT_ENABLE    = 0xa
  166.         REG_TX_RECLAIM_THRESH   = 0x9
  167.         REG_RX_FILTER           = 0x8
  168.         REG_RX_EARLY_THRESH     = 0x6
  169.         REG_TX_START_THRESH     = 0x0
  170.  
  171. ; Register window 4
  172.         REG_UPPER_BYTES_OK      = 0xe
  173.         REG_BAD_SSD             = 0xc
  174.         REG_MEDIA_STATUS        = 0xa
  175.         REG_PHYSICAL_MGMT       = 0x8
  176.         REG_NETWORK_DIAGNOSTIC  = 0x6
  177.         REG_FIFO_DIAGNOSTIC     = 0x4
  178.         REG_VCO_DIAGNOSTIC      = 0x2   ; may not supported
  179.  
  180. ; Bits in register window 4
  181.         BIT_AUTOSELECT          = 24
  182.  
  183. ; Register window 3
  184.         REG_TX_FREE             = 0xc
  185.         REG_RX_FREE             = 0xa
  186.         REG_MEDIA_OPTIONS       = 0x8
  187.         REG_MAC_CONTROL         = 0x6
  188.         REG_MAX_PKT_SIZE        = 0x4
  189.         REG_INTERNAL_CONFIG     = 0x0
  190.  
  191. ; Register window 2
  192.         REG_RESET_OPTIONS       = 0xc
  193.         REG_STATION_MASK_HI     = 0xa
  194.         REG_STATION_MASK_MID    = 0x8
  195.         REG_STATION_MASK_LO     = 0x6
  196.         REG_STATION_ADDRESS_HI  = 0x4
  197.         REG_STATION_ADDRESS_MID = 0x2
  198.         REG_STATION_ADDRESS_LO  = 0x0
  199.  
  200. ; Register window 1
  201.         REG_TRIGGER_BITS        = 0xc
  202.         REG_SOS_BITS            = 0xa
  203.         REG_WAKE_ON_TIMER       = 0x8
  204.         REG_SMB_RXBYTES         = 0x7
  205.         REG_SMB_DIAG            = 0x5
  206.         REG_SMB_ARB             = 0x4
  207.         REG_SMB_STATUS          = 0x2
  208.         REG_SMB_ADDRESS         = 0x1
  209.         REG_SMB_FIFO_DATA       = 0x0
  210.  
  211. ; Register window 0
  212.         REG_EEPROM_DATA         = 0xc
  213.         REG_EEPROM_COMMAND      = 0xa
  214.         REG_BIOS_ROM_DATA       = 0x8
  215.         REG_BIOS_ROM_ADDR       = 0x4
  216.  
  217. ; Physical management bits
  218.         BIT_MGMT_DIR            = 2     ; drive with the data written in mgmtData
  219.         BIT_MGMT_DATA           = 1     ; MII management data bit
  220.         BIT_MGMT_CLK            = 0     ; MII management clock
  221.  
  222. ; MII commands
  223.         MII_CMD_MASK            = (1111b shl 10)
  224.         MII_CMD_READ            = (0110b shl 10)
  225.         MII_CMD_WRITE           = (0101b shl 10)
  226.  
  227. ; eeprom bits and commands
  228.         EEPROM_CMD_READ         = 0x80
  229.         EEPROM_BIT_BUSY         = 15
  230.  
  231. ; eeprom registers
  232.         EEPROM_REG_OEM_NODE_ADDR= 0xa
  233.         EEPROM_REG_CAPABILITIES = 0x10
  234.  
  235. ; Commands for command register
  236.         SELECT_REGISTER_WINDOW  = (1 shl 11)
  237.  
  238. ; Hw capabilities bitflags
  239.         IS_VORTEX               = 0x0001
  240.         IS_BOOMERANG            = 0x0002
  241.         IS_CYCLONE              = 0x0004
  242.         IS_TORNADO              = 0x0008
  243.         EEPROM_8BIT             = 0x0010
  244.         HAS_PWR_CTRL            = 0x0020
  245.         HAS_MII                 = 0x0040
  246.         HAS_NWAY                = 0x0080
  247.         HAS_CB_FNS              = 0x0100
  248.         INVERT_MII_PWR          = 0x0200
  249.         INVERT_LED_PWR          = 0x0400
  250.         MAX_COLLISION_RESET     = 0x0800
  251.         EEPROM_OFFSET           = 0x1000
  252.         HAS_HWCKSM              = 0x2000
  253.         EXTRA_PREAMBLE          = 0x4000
  254.  
  255. ; Status
  256.         IntLatch                = 0x0001
  257.         HostError               = 0x0002
  258.         TxComplete              = 0x0004
  259.         TxAvailable             = 0x0008
  260.         RxComplete              = 0x0010
  261.         RxEarly                 = 0x0020
  262.         IntReq                  = 0x0040
  263.         StatsFull               = 0x0080
  264.         DMADone                 = 0x0100
  265.         DownComplete            = 0x0200
  266.         UpComplete              = 0x0400
  267.         DMAInProgress           = 0x0800        ; 1 shl 11  (DMA controller is still busy)
  268.         CmdInProgress           = 0x1000        ; 1 shl 12  (EL3_CMD is still busy)
  269.  
  270.         S_5_INTS                = HostError + RxEarly + UpComplete + DownComplete + StatsFull ;+ TxComplete + RxComplete  + TxAvailable
  271.  
  272. ; Commands
  273.         TotalReset              = 0 shl 11
  274.         SelectWindow            = 1 shl 11
  275.         StartCoax               = 2 shl 11
  276.         RxDisable               = 3 shl 11
  277.         RxEnable                = 4 shl 11
  278.         RxReset                 = 5 shl 11
  279.         UpStall                 = 6 shl 11
  280.         UpUnstall               = (6 shl 11)+1
  281.         DownStall               = (6 shl 11)+2
  282.         DownUnstall             = (6 shl 11)+3
  283.         RxDiscard               = 8 shl 11
  284.         TxEnable                = 9 shl 11
  285.         TxDisable               = 10 shl 11
  286.         TxReset                 = 11 shl 11
  287.         FakeIntr                = 12 shl 11
  288.         AckIntr                 = 13 shl 11
  289.         SetIntrEnb              = 14 shl 11
  290.         SetStatusEnb            = 15 shl 11
  291.         SetRxFilter             = 16 shl 11
  292.         SetRxThreshold          = 17 shl 11
  293.         SetTxThreshold          = 18 shl 11
  294.         SetTxStart              = 19 shl 11
  295.         StartDMAUp              = 20 shl 11
  296.         StartDMADown            = (20 shl 11)+1
  297.         StatsEnable             = 21 shl 11
  298.         StatsDisable            = 22 shl 11
  299.         StopCoax                = 23 shl 11
  300.         SetFilterBit            = 25 shl 11
  301.  
  302. ; Rx mode bits
  303.         RxStation               = 1
  304.         RxMulticast             = 2
  305.         RxBroadcast             = 4
  306.         RxProm                  = 8
  307.  
  308.         MAX_ETH_FRAME_SIZE      = 1514
  309.  
  310.  
  311. struct  tx_desc
  312.  
  313.         next_ptr                dd ?
  314.         frame_start_hdr         dd ?
  315.         frag_addr               dd ?    ; for packet data
  316.         frag_len                dd ?    ; for packet data
  317.         realaddr                dd ?
  318.                                 rd 3    ; align 32
  319. ends
  320.  
  321.  
  322. struct  rx_desc
  323.  
  324.         next_ptr                dd ?
  325.         pkt_status              dd ?
  326.         frag_addr               dd ?
  327.         frag_len                dd ?    ; for packet data
  328.         realaddr                dd ?
  329.                                 rd 3    ; align 32
  330. ends
  331.  
  332.  
  333. struct  device                  ETH_DEVICE
  334.  
  335.         io_addr                 dd ?
  336.         pci_bus                 dd ?
  337.         pci_dev                 dd ?
  338.         irq_line                db ?
  339.                                 rb 3    ; alignment
  340.  
  341.         curr_tx                 dd ?
  342.         curr_rx                 dd ?
  343.         prev_tx_frame           dd ?
  344.         ver_id                  db ?
  345.         full_bus_master         db ?
  346.         has_hwcksm              db ?
  347.         preamble                db ?
  348.         dn_list_ptr_cleared     db ?
  349.         internal_link           dd ?    ; link state (to be used only internally by driver)
  350.  
  351.         rb 0x100 - ($ and 0xff) ; align 256
  352.         tx_desc_buffer          rd (sizeof.tx_desc*NUM_TX_DESC)/4
  353.         rx_desc_buffer          rd (sizeof.rx_desc*NUM_RX_DESC)/4
  354.  
  355. ends
  356.  
  357.  
  358. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  359. ;;                        ;;
  360. ;; proc START             ;;
  361. ;;                        ;;
  362. ;; (standard driver proc) ;;
  363. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  364.  
  365. proc START c, reason:dword, cmdline:dword
  366.  
  367.         cmp     [reason], DRV_ENTRY
  368.         jne     .fail
  369.  
  370.         DEBUGF  2,"Loading driver\n"
  371.         invoke  RegService, my_service, service_proc
  372.         ret
  373.  
  374.   .fail:
  375.         xor     eax, eax
  376.         ret
  377.  
  378. endp
  379.  
  380.  
  381. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  382. ;;                        ;;
  383. ;; proc SERVICE_PROC      ;;
  384. ;;                        ;;
  385. ;; (standard driver proc) ;;
  386. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  387.  
  388. align 4
  389. proc service_proc stdcall, ioctl:dword
  390.  
  391.         mov     edx, [ioctl]
  392.         mov     eax, [edx + IOCTL.io_code]
  393.  
  394. ;------------------------------------------------------
  395.  
  396.         cmp     eax, 0 ;SRV_GETVERSION
  397.         jne     @F
  398.  
  399.         cmp     [edx + IOCTL.out_size], 4
  400.         jb      .fail
  401.         mov     eax, [edx + IOCTL.output]
  402.         mov     [eax], dword API_VERSION
  403.  
  404.         xor     eax, eax
  405.         ret
  406.  
  407. ;------------------------------------------------------
  408.   @@:
  409.         cmp     eax, 1 ;SRV_HOOK
  410.         jne     .fail
  411.  
  412.         cmp     [edx + IOCTL.inp_size], 3               ; Data input must be at least 3 bytes
  413.         jb      .fail
  414.  
  415.         mov     eax, [edx + IOCTL.input]
  416.         cmp     byte [eax], 1                           ; 1 means device number and bus number (pci) are given
  417.         jne     .fail                                   ; other types of this hardware dont exist
  418.  
  419. ; check if the device is already listed
  420.  
  421.         mov     ecx, [devices]
  422.         test    ecx, ecx
  423.         jz      .firstdevice
  424.  
  425.         mov     esi, device_list
  426.         mov     eax, [edx + IOCTL.input]                ; get the pci bus and device numbers
  427.         mov     ax , [eax+1]                            ;
  428.   .nextdevice:
  429.         mov     ebx, [esi]
  430.         cmp     al, byte[ebx + device.pci_bus]
  431.         jne     @f
  432.         cmp     ah, byte[ebx + device.pci_dev]
  433.         je      .find_devicenum                         ; Device is already loaded, let's find it's device number
  434.        @@:
  435.         add     esi, 4
  436.         loop    .nextdevice
  437.  
  438. ; This device doesnt have its own eth_device structure yet, lets create one
  439.   .firstdevice:
  440.         cmp     [devices], MAX_DEVICES                  ; First check if the driver can handle one more card
  441.         jae     .fail
  442.  
  443.         allocate_and_clear ebx, sizeof.device, .fail    ; Allocate the buffer for device structure
  444.  
  445. ; Fill in the direct call addresses into the struct
  446.  
  447.         mov     [ebx + device.reset], reset
  448.         mov     [ebx + device.transmit], null_op
  449.         mov     [ebx + device.unload], null_op
  450.         mov     [ebx + device.name], my_service
  451.  
  452. ; save the pci bus and device numbers
  453.  
  454.         mov     eax, [edx + IOCTL.input]
  455.         movzx   ecx, byte[eax+1]
  456.         mov     [ebx + device.pci_bus], ecx
  457.         movzx   ecx, byte[eax+2]
  458.         mov     [ebx + device.pci_dev], ecx
  459.  
  460. ; Now, it's time to find the base io addres of the PCI device
  461.  
  462.         stdcall PCI_find_io, [ebx + device.pci_bus], [ebx + device.pci_dev]
  463.         mov     [ebx + device.io_addr], eax
  464.  
  465. ; We've found the io address, find IRQ now
  466.  
  467.         invoke  PciRead8, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.interrupt_line
  468.         mov     [ebx + device.irq_line], al
  469.  
  470.         DEBUGF  1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\
  471.         [ebx + device.pci_dev]:1,[ebx + device.pci_bus]:1,[ebx + device.irq_line]:1,[ebx + device.io_addr]:4
  472.  
  473. ; Ok, the eth_device structure is ready, let's probe the device
  474.         call    probe                                                   ; this function will output in eax
  475.         test    eax, eax
  476.         jnz     .err                                                    ; If an error occured, exit
  477.  
  478.         mov     eax, [devices]                                          ; Add the device structure to our device list
  479.         mov     [device_list+4*eax], ebx                                ;
  480.         inc     [devices]                                               ;
  481.  
  482.   .register:
  483.         mov     [ebx + device.type], NET_TYPE_ETH
  484.         invoke  NetRegDev
  485.  
  486.         cmp     eax, -1
  487.         je      .destroy
  488.  
  489.         call    start_device
  490.         ret
  491.  
  492. ; If the device was already loaded, find the device number and return it in eax
  493.  
  494.   .find_devicenum:
  495.         DEBUGF  2,"Trying to find device number of already registered device\n"
  496.         invoke  NetPtrToNum                                             ; This kernel procedure converts a pointer to device struct in ebx
  497.                                                                         ; into a device number in edi
  498.         mov     eax, edi                                                ; Application wants it in eax instead
  499.         DEBUGF  2,"Kernel says: %u\n", eax
  500.         ret
  501.  
  502. ; If an error occured, remove all allocated data and exit (returning -1 in eax)
  503.  
  504.   .destroy:
  505.         ; todo: reset device into virgin state
  506.  
  507.   .err:
  508.         invoke  KernelFree, ebx
  509.   .fail:
  510.         DEBUGF  2, "Failed to load\n"
  511.         or      eax, -1
  512.         ret
  513.  
  514. ;------------------------------------------------------
  515. endp
  516.  
  517.  
  518. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
  519. ;;                                                                        ;;
  520. ;;        Actual Hardware dependent code starts here                      ;;
  521. ;;                                                                        ;;
  522. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
  523.  
  524.  
  525. align 4
  526. null_op:
  527.  
  528.         ret
  529.  
  530.  
  531.  
  532. ;***************************************************************************
  533. ;   Function
  534. ;      probe
  535. ;   Description
  536. ;      Searches for an ethernet card, enables it and clears the rx buffer
  537. ;   Destroyed registers
  538. ;      eax, ebx, ecx, edx, edi, esi
  539. ;
  540. ;***************************************************************************
  541.  
  542. align 4
  543. probe:
  544.  
  545.         DEBUGF  1,"Probing 3com card\n"
  546.  
  547. ; Make the device a bus master
  548.         invoke  PciRead32, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.command
  549.         or      al, PCI_CMD_MASTER
  550.         invoke  PciWrite32, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.command, eax
  551.  
  552. ; wake up the card
  553.         DEBUGF 1,"Checking if the device is awake\n"
  554.  
  555. ; wake up - we directly do it by programming PCI
  556. ; check if the device is power management capable
  557.         invoke  PciRead16, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.status
  558.         test    al, PCI_STATUS_CAPA     ; is there "new capabilities" linked list?
  559.         jz      .device_awake
  560.  
  561. ; search for power management register
  562.         invoke  PciRead8, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.cap_ptr
  563.         and     al, not 3
  564.         cmp     al, 0x3f
  565.         jbe     .device_awake           ; invalid pointer if less then PCI header size
  566.  
  567. ; traverse the list
  568.         movzx   esi, al
  569.   .pm_loop:
  570.         invoke  PciRead16, [ebx + device.pci_bus], [ebx + device.pci_dev], esi
  571.         cmp     al, 1
  572.         je      .set_pm_state
  573.         movzx   esi, ah                 ; load address of next capability
  574.         test    ah, ah                  ; 0 if none left
  575.         jnz     .pm_loop
  576.         jmp     .device_awake
  577.  
  578. ; wake up the device if necessary
  579.   .set_pm_state:
  580.         DEBUGF 1,"Waking up the device\n"
  581.         add     esi, 4                  ; offset for power management
  582.         invoke  PciRead32, [ebx + device.pci_bus], [ebx + device.pci_dev], esi
  583.         test    al, 11b
  584.         jz      .device_awake
  585.         and     al, not 11b             ; set state to D0
  586.         invoke  PciWrite32, [ebx + device.pci_bus], [ebx + device.pci_dev], esi, eax
  587.  
  588.   .device_awake:
  589.         DEBUGF 1,"Device is awake\n"
  590.  
  591. ; Check device/vendor ID
  592.         invoke  PciRead32, [ebx + device.pci_bus], [ebx + device.pci_dev], 0
  593.  
  594.         DEBUGF  1,"Vendor id: 0x%x\n", ax
  595.  
  596.         cmp     ax, 0x10B7
  597.         jne     .notfound
  598.         shr     eax, 16
  599.  
  600.         DEBUGF  1,"Vendor ok!, device id: 0x%x\n", ax
  601.  
  602. ; get chip version
  603.         mov     ecx, HW_VERSIONS_SIZE/4-1
  604.   .loop:
  605.         cmp     ax, [hw_versions+ecx*4]
  606.         jz      .found
  607.         loop    .loop
  608.   .notfound:
  609.         DEBUGF  2,"Device id not found in list!\n"
  610.         or      eax, -1
  611.         ret
  612.   .found:
  613.         mov     esi, [hw_str+ecx*4]
  614.         DEBUGF  1,"Hardware type: %s\n", esi
  615.         mov     [ebx + device.name], esi
  616.  
  617.         mov     [ebx + device.ver_id], cl
  618.         test    word [hw_versions+2+ecx*4], HAS_HWCKSM
  619.         setnz   [ebx + device.has_hwcksm]
  620. ; set pci latency for vortex cards
  621.         test    word [hw_versions+2+ecx*4], IS_VORTEX
  622.         jz      .not_vortex
  623.  
  624.         mov     al, 11111000b ; 248 = max latency
  625.         invoke  PciWrite8, [ebx + device.pci_bus], [ebx + device.pci_dev], PCI_header00.max_latency, eax
  626.  
  627.   .not_vortex:
  628. ; set RX/TX functions
  629.         mov     ax, EEPROM_REG_CAPABILITIES
  630.         call    read_eeprom
  631.         test    al, 100000b ; full bus master?
  632.         setnz   [ebx + device.full_bus_master]
  633.         jnz     .boomerang_func
  634.         mov     [ebx + device.transmit], vortex_transmit
  635.         DEBUGF  2,"Device is a vortex type\n"
  636.         DEBUGF  2,"I'm sorry but vortex code hasnt been tested yet\n"
  637.         DEBUGF  2,"Please contact me on hidnplayr@kolibrios.org\n"
  638.         DEBUGF  2,"If you can help me finish it!\n"
  639.         or      eax, -1
  640.         ret
  641.         jmp     @f
  642.   .boomerang_func: ; full bus master, so use boomerang functions
  643.         mov     [ebx + device.transmit], boomerang_transmit
  644.         DEBUGF  1,"Device is a boomerang type\n"
  645.        @@:
  646.         call    read_mac_eeprom
  647.  
  648.         test    byte [ebx + device.full_bus_master], 0xff
  649.         jz      .set_preamble
  650. ; switch to register window 2
  651.         set_io  [ebx + device.io_addr], 0
  652.         set_io  [ebx + device.io_addr], REG_COMMAND
  653.         mov     ax, SELECT_REGISTER_WINDOW+2
  654.         out     dx, ax
  655. ; activate xcvr by setting some magic bits
  656.         set_io  [ebx + device.io_addr], REG_RESET_OPTIONS
  657.         in      ax, dx
  658.         and     ax, not 0x4010
  659.         movzx   ecx, [ebx + device.ver_id]
  660.         test    word [ecx*4+hw_versions+2], INVERT_LED_PWR
  661.         jz      @f
  662.         or      al, 0x10
  663.        @@:
  664.         test    word [ecx*4+hw_versions+2], INVERT_MII_PWR
  665.         jz      @f
  666.         or      ah, 0x40
  667.        @@:
  668.         out     dx, ax
  669.   .set_preamble:
  670. ; use preamble as default
  671.         mov     byte [ebx + device.preamble], 1 ; enable preamble
  672.  
  673.         DEBUGF 1,"Global reset..\n"
  674.  
  675. ; GlobalReset
  676.         set_io  [ebx + device.io_addr], 0
  677.         set_io  [ebx + device.io_addr], REG_COMMAND
  678.         xor     eax, eax
  679. ;       or      al, 0x14
  680.         out     dx, ax
  681. ; wait for GlobalReset to complete
  682.         mov     ecx, 2000
  683.   .rsloop:
  684.         in      ax, dx
  685.         test    ah, 10000b             ; CmdInProgress
  686.  
  687.         pusha
  688.         mov     esi, 1
  689.         invoke  Sleep
  690.         popa
  691.  
  692.         loopz   .rsloop
  693.  
  694.         DEBUGF 1,"Waiting for NIC to boot..\n"
  695. ; wait for 2 seconds for NIC to boot
  696.         mov     esi, 2000               ; WTF? FIXME
  697.         invoke  Sleep ; 2 seconds
  698.  
  699.         DEBUGF 1,"Ok!\n"
  700.  
  701.  
  702. ;--------------------------
  703. ;
  704. ; RESET
  705. ;
  706. ;--------------------------
  707.  
  708. reset:
  709.  
  710.         movzx   eax, [ebx + device.irq_line]
  711.         DEBUGF  1,"Attaching int handler to irq %x\n", eax:1
  712.  
  713.         movzx   ecx, [ebx + device.ver_id]
  714.         test    word [hw_versions+2+ecx*4], IS_VORTEX
  715.         jz      .not_vortex
  716.         mov     esi, int_vortex
  717.         jmp     .reg_int
  718.   .not_vortex:
  719.         mov     esi, int_boomerang
  720.   .reg_int:
  721.         invoke  AttachIntHandler, eax, esi, ebx
  722.         test    eax, eax
  723.         jnz     @f
  724.         DEBUGF  2,"Could not attach int handler!\n"
  725.         or      eax, -1
  726.         ret
  727.   @@:
  728.  
  729.         set_io  [ebx + device.io_addr], 0
  730.         set_io  [ebx + device.io_addr], REG_COMMAND
  731.         mov     ax, SELECT_REGISTER_WINDOW + 0
  732.         out     dx, ax
  733.  
  734.         mov     ax, StopCoax
  735.         out     dx, ax                        ; stop transceiver
  736.  
  737.         mov     ax, SELECT_REGISTER_WINDOW + 4
  738.         out     dx, ax                        ; disable UTP
  739.  
  740.         set_io  [ebx + device.io_addr], REG_MEDIA_STATUS
  741.         mov     ax, 0x0
  742.  
  743.         set_io  [ebx + device.io_addr], REG_COMMAND
  744.         mov     ax, SELECT_REGISTER_WINDOW + 0
  745.         out     dx, ax
  746.  
  747.         set_io  [ebx + device.io_addr], REG_FIFO_DIAGNOSTIC
  748.         mov     ax, 0
  749.         out     dx, ax                        ; disable card
  750.  
  751.         mov     ax, 1
  752.         out     dx, ax                        ; enable card
  753.  
  754.         call    write_mac
  755.  
  756.         set_io  [ebx + device.io_addr], 0
  757.         set_io  [ebx + device.io_addr], REG_COMMAND
  758.         mov     ax, SELECT_REGISTER_WINDOW + 1
  759.         out     dx, ax
  760.  
  761.         mov     ecx, 32
  762.         set_io  [ebx + device.io_addr], 0x0b
  763.   .loop:
  764.         in      al, dx
  765.         loop    .loop
  766.  
  767. ; Get rid of stray ints
  768.         set_io  [ebx + device.io_addr], REG_COMMAND
  769.         mov     ax, AckIntr + 0xff
  770.         out     dx, ax
  771.  
  772.         mov     ax, SetStatusEnb + S_5_INTS
  773.         out     dx, ax
  774.  
  775.         mov     ax, SetIntrEnb + S_5_INTS
  776.         out     dx, ax
  777.  
  778.         DEBUGF  1,"Setting RX mode\n"
  779.  
  780.         set_io  [ebx + device.io_addr], 0
  781.         set_io  [ebx + device.io_addr], REG_COMMAND
  782.  
  783. if      defined PROMISCIOUS
  784.         mov     ax, SetRxFilter + RxStation + RxMulticast + RxBroadcast + RxProm
  785. else if  defined ALLMULTI
  786.         mov     ax, SetRxFilter + RxStation + RxMulticast + RxBroadcast
  787. else
  788.         mov     ax, SetRxFilter + RxStation + RxBroadcast
  789. end if
  790.         out     dx, ax
  791.  
  792.         call    set_active_port
  793.  
  794.         call    create_rx_ring
  795.         test    eax, eax
  796.         jnz     .err
  797.  
  798.         call    rx_reset
  799.         call    tx_reset
  800.  
  801.         xor     eax, eax
  802. ; clear packet/byte counters
  803.  
  804.         lea     edi, [ebx + device.bytes_tx]
  805.         mov     ecx, 6
  806.         rep     stosd
  807.  
  808.         xor     eax, eax
  809.         ret
  810.  
  811.   .err:
  812.         DEBUGF  2,"reset failed\n"
  813.         or      eax, -1
  814.         ret
  815.  
  816.  
  817. align 4
  818. start_device:
  819.         DEBUGF  1,"Starting the device\n"
  820.  
  821.         set_io  [ebx + device.io_addr], 0
  822.         set_io  [ebx + device.io_addr], REG_COMMAND
  823.         mov     ax, SetTxThreshold + 60 ;2047 ; recommended by the manual :)
  824.         out     dx, ax
  825.  
  826.         call    check_tx_status
  827.  
  828.         set_io  [ebx + device.io_addr], 0
  829.         set_io  [ebx + device.io_addr], REG_COMMAND
  830. ; switch to register window 4
  831.         mov     ax, SELECT_REGISTER_WINDOW+4
  832.         out     dx, ax
  833.  
  834. ; wait for linkDetect
  835.         set_io  [ebx + device.io_addr], REG_MEDIA_STATUS
  836.         mov     ecx, 20         ; wait for max 2s
  837.   .link_detect_loop:
  838.         mov     esi, 100
  839.         invoke  Sleep           ; 100 ms
  840.         in      ax, dx
  841.         test    ah, 1000b       ; linkDetect
  842.         jnz     @f
  843.         loop    .link_detect_loop
  844.         DEBUGF  2,"Link detect timed-out!\n"
  845.        @@:
  846.  
  847. ; print link type
  848.         xor     eax, eax
  849.         bsr     ax, word[ebx + device.internal_link]
  850.         jz      @f
  851.         sub     ax, 5
  852.        @@:
  853.  
  854.         mov     esi, [link_str+eax*4]
  855.         DEBUGF  1,"Established Link type: %s\n", esi
  856.  
  857. ; enable interrupts
  858.         set_io  [ebx + device.io_addr], REG_COMMAND
  859.         mov     ax, SELECT_REGISTER_WINDOW + 1
  860.         out     dx, ax
  861.  
  862.         mov     ax, AckIntr + 0xff
  863.         out     dx, ax
  864.  
  865.         mov     ax, SetStatusEnb + S_5_INTS
  866.         out     dx, ax
  867.  
  868.         mov     ax, SetIntrEnb + S_5_INTS
  869.         out     dx, ax
  870.  
  871. ; Start RX/TX
  872.  
  873.         set_io  [ebx + device.io_addr], 0
  874.         set_io  [ebx + device.io_addr], REG_COMMAND
  875.         mov     ax, RxEnable
  876.         out     dx, ax
  877.  
  878.         mov     ax, TxEnable
  879.         out     dx, ax
  880.  
  881.         set_io  [ebx + device.io_addr], REG_COMMAND
  882.         mov     ax, SetRxThreshold + 208
  883.         out     dx, ax
  884.  
  885.         mov     ax, SetTxThreshold + 60 ;16 ; recommended by the manual :)
  886.         out     dx, ax
  887.  
  888.         mov     ax, SELECT_REGISTER_WINDOW + 1
  889.         out     dx, ax
  890.  
  891. ; Set the mtu, kernel will be able to send now
  892.         mov     [ebx + device.mtu], 1514
  893.  
  894. ; Set link state to unknown
  895.         mov     [ebx + device.state], ETH_LINK_UNKNOWN
  896.         xor     eax, eax
  897.  
  898.         ret
  899.  
  900.  
  901.  
  902. ;***************************************************************************
  903. ;   Function
  904. ;      tx_reset
  905. ;   Description
  906. ;      resets and enables transmitter engine
  907. ;
  908. ;***************************************************************************
  909.  
  910. align 4
  911. tx_reset:
  912.         DEBUGF 1,"tx reset\n"
  913.  
  914. ; TxReset
  915.         set_io  [ebx + device.io_addr], 0
  916.         set_io  [ebx + device.io_addr], REG_COMMAND
  917.         mov     ax, TxReset
  918.         out     dx, ax
  919. ; Wait for TxReset to complete
  920.         mov     ecx, 200000
  921.   .tx_reset_loop:
  922.         in      ax, dx
  923.         test    ah, 10000b ; check CmdInProgress
  924.         jz      .tx_set_prev
  925.         dec     ecx
  926.         jnz     .tx_reset_loop
  927.   .tx_set_prev:
  928. ; init last TX descriptor
  929.         lea     eax, [ebx + device.tx_desc_buffer + (NUM_TX_DESC-1)*sizeof.tx_desc]
  930.         mov     [ebx + device.curr_tx], eax
  931.  
  932.   .tx_enable:
  933.         ret
  934.  
  935.  
  936.  
  937. ;***************************************************************************
  938. ;   Function
  939. ;      rx_reset
  940. ;   Description
  941. ;      resets and enables receiver engine
  942. ;
  943. ;***************************************************************************
  944.  
  945. align 4
  946. rx_reset:
  947.  
  948.         DEBUGF 1,"rx reset\n"
  949.  
  950.         set_io  [ebx + device.io_addr], 0
  951.         set_io  [ebx + device.io_addr], REG_COMMAND
  952.         mov     ax, RxReset or 0x4
  953.         out     dx, ax
  954.  
  955. ; wait for RxReset to complete
  956.         mov     ecx, 200000
  957.   .loop:
  958.         in      ax, dx
  959.         test    ah, 10000b ; check CmdInProgress
  960.         jz      .done
  961.         dec     ecx
  962.         jnz     .loop
  963.   .done:
  964.  
  965.         lea     eax, [ebx + device.rx_desc_buffer]
  966.         mov     [ebx + device.curr_rx], eax
  967.         invoke  GetPhysAddr
  968.         set_io  [ebx + device.io_addr], 0
  969.         set_io  [ebx + device.io_addr], REG_UP_LIST_PTR
  970.         out     dx, eax
  971.  
  972.   .rx_enable:
  973.         ret
  974.  
  975.  
  976.  
  977. align 4
  978. create_rx_ring:
  979. ; create rx descriptor ring
  980.         lea     eax, [ebx + device.rx_desc_buffer]
  981.         invoke  GetPhysAddr
  982.         mov     edi, eax                                                ; real addr of first descr
  983.  
  984.         lea     esi, [ebx + device.rx_desc_buffer]                          ; ptr to first descr
  985.         lea     edx, [ebx + device.rx_desc_buffer + (NUM_RX_DESC-1)*sizeof.rx_desc]     ; ptr to last descr
  986.  
  987.         mov     ecx, NUM_RX_DESC
  988.   .loop:
  989.         mov     [edx + rx_desc.next_ptr], edi
  990.  
  991.         push    ecx edx
  992.         invoke  NetAlloc, MAX_ETH_FRAME_SIZE+NET_BUFF.data
  993.         pop     edx ecx
  994.         test    eax, eax
  995.         jz      .out_of_mem
  996.         mov     [esi + rx_desc.realaddr], eax
  997.         invoke  GetPhysAddr
  998.         add     eax, NET_BUFF.data
  999.         mov     [esi + rx_desc.frag_addr], eax
  1000.         and     [esi + rx_desc.pkt_status], 0
  1001.         mov     [esi + rx_desc.frag_len], MAX_ETH_FRAME_SIZE or (1 shl 31)
  1002.  
  1003.         DEBUGF  1,"rx_desc: lin=%x phys=%x len=%x next ptr=%x\n", [esi+rx_desc.realaddr]:8, [esi+rx_desc.frag_addr]:8, [esi+rx_desc.frag_len]:8, edi
  1004.         DEBUGF  1,"rx_desc: cur=%x prev=%x\n", esi, edx
  1005.  
  1006.         mov     edx, esi
  1007.         add     esi, sizeof.rx_desc
  1008.         add     edi, sizeof.rx_desc
  1009.         dec     ecx
  1010.         jnz     .loop
  1011.  
  1012.         xor     eax, eax
  1013.         ret
  1014.  
  1015.   .out_of_mem:
  1016.         or      eax, -1
  1017.         ret
  1018.  
  1019.  
  1020.  
  1021. ;---------------------------------------------------------------------------
  1022. ;   Function
  1023. ;      try_link_detect
  1024. ;   Description
  1025. ;      try_link_detect checks if link exists
  1026. ;   Parameters
  1027. ;      ebx = device structure
  1028. ;   Return value
  1029. ;      al - 0 ; no link detected
  1030. ;      al - 1 ; link detected
  1031. ;   Destroyed registers
  1032. ;      eax, ebx, ecx, edx, edi, esi
  1033. ;
  1034. ;---------------------------------------------------------------------------
  1035.  
  1036. align 4
  1037. try_link_detect:
  1038.  
  1039.         DEBUGF  1,"Trying to detect link\n"
  1040.  
  1041. ; create self-directed packet
  1042.         invoke  NetAlloc, 20+NET_BUFF.data     ; create a buffer for the self-directed packet
  1043.         test    eax, eax
  1044.         jz      .fail
  1045.  
  1046.         push    eax
  1047.         mov     [eax + NET_BUFF.length], 20
  1048.  
  1049.         lea     edi, [eax + NET_BUFF.data]
  1050.         lea     esi, [ebx + device.mac]
  1051.         movsw
  1052.         movsd
  1053.         sub     esi, 6
  1054.         movsw
  1055.         movsd
  1056.         mov     ax , 0x0608
  1057.         stosw
  1058.  
  1059. ; download self-directed packet
  1060.         call    [ebx + device.transmit]
  1061.  
  1062. ; switch to register window 4
  1063.         set_io  [ebx + device.io_addr], 0
  1064.         set_io  [ebx + device.io_addr], REG_COMMAND
  1065.         mov     ax, SELECT_REGISTER_WINDOW+4
  1066.         out     dx, ax
  1067.  
  1068. ; See if we have received the packet by now..
  1069.         cmp     [ebx + device.packets_rx], 0
  1070.         jnz     .link_detected
  1071.  
  1072. ; switch to register window 4
  1073.         set_io  [ebx + device.io_addr], REG_COMMAND
  1074.         mov     ax, SELECT_REGISTER_WINDOW+4
  1075.         out     dx, ax
  1076.  
  1077. ; read linkbeatdetect
  1078.         set_io  [ebx + device.io_addr], REG_MEDIA_STATUS
  1079.         in      ax, dx
  1080.         test    ah, 1000b ; test linkBeatDetect
  1081.         jnz     .link_detected
  1082.         xor     al, al
  1083.         jmp     .finish
  1084.  
  1085.   .link_detected:
  1086.         DEBUGF  1,"Link detected!\n"
  1087.         setb    al
  1088.  
  1089.   .finish:
  1090.         test    al, al
  1091.         jz      @f
  1092.         or      byte [ebx + device.internal_link+1], 100b
  1093.        @@:
  1094.         xor     eax, eax
  1095.         ret
  1096.  
  1097.   .fail:
  1098.         DEBUGF  1,"No link detected!\n"
  1099.         or      eax, -1
  1100.         ret
  1101.  
  1102.  
  1103.  
  1104. ;***************************************************************************
  1105. ;   Function
  1106. ;      try_phy
  1107. ;   Description
  1108. ;      try_phy checks the auto-negotiation function
  1109. ;      in the PHY at PHY index. It can also be extended to
  1110. ;      include link detection for non-IEEE 802.3u
  1111. ;      auto-negotiation devices, for instance the BCM5000.              ; TODO: BCM5000
  1112. ;   Parameters
  1113. ;       ah - PHY index
  1114. ;       ebx - device stucture
  1115. ;   Return value
  1116. ;      al - 0 link is auto-negotiated
  1117. ;      al - 1 no link is auto-negotiated
  1118. ;   Destroyed registers
  1119. ;       eax, ebx, ecx, edx, esi
  1120. ;
  1121. ;***************************************************************************
  1122.  
  1123. align 4
  1124. try_phy:
  1125.  
  1126.         DEBUGF 1,"PHY=%u\n", ah
  1127.         DEBUGF 1,"Detecting if device is auto-negotiation capable\n"
  1128.  
  1129.         mov     al, MII_BMCR
  1130.         push    eax
  1131.         call    mdio_read
  1132.         or      ax, BMCR_RESET
  1133.         mov     esi, eax
  1134.         mov     eax, [esp]
  1135.         call    mdio_write
  1136.  
  1137. ; wait for reset to complete
  1138.         mov     esi, 2000
  1139.         invoke  Sleep           ; 2s FIXME
  1140.  
  1141.         mov     eax, [esp]
  1142.         mov     al, MII_BMCR
  1143.         call    mdio_read
  1144.         test    ax, BMCR_RESET
  1145.         jnz     .fail1
  1146.  
  1147. ; wait for a while after reset
  1148.         mov     esi, 20
  1149.         invoke  Sleep           ; 20ms
  1150.  
  1151.         mov     eax, [esp]
  1152.         mov     al, MII_BMSR
  1153.         call    mdio_read
  1154.         test    al, BMSR_ERCAP
  1155.         jz      .fail2
  1156.         DEBUGF  1,"Extended capability supported\n"
  1157.         test    al, BMSR_ANEGCAPABLE
  1158.         jz      .fail2
  1159.         DEBUGF  1,"Auto-negotiation capable\n"
  1160.         test    al, BMSR_ANEGCOMPLETE
  1161.         jnz     .auto_neg_ok
  1162.         DEBUGF  1,"Restarting auto-negotiation\n"
  1163.  
  1164. ; restart auto-negotiation
  1165.         mov     eax, [esp]
  1166.         mov     al, MII_ADVERTISE
  1167.         push    eax
  1168.         call    mdio_read       ; returns with window #4
  1169.         or      ax, ADVERTISE_10HALF or ADVERTISE_10FULL or ADVERTISE_100HALF or ADVERTISE_100FULL
  1170.         mov     esi, eax
  1171.         pop     eax
  1172.         call    mdio_write      ; returns with window #4
  1173.         mov     eax, [esp]
  1174.         call    mdio_read       ; returns with window #4
  1175.         mov     esi, eax
  1176.         or      bx, BMCR_ANENABLE or BMCR_ANRESTART
  1177.         mov     eax, [esp]
  1178.         call    mdio_write      ; returns with window #4
  1179.         mov     esi, 4000
  1180.         invoke  Sleep  ; 4 seconds
  1181.         mov     eax, [esp]
  1182.  
  1183.         mov     al, MII_BMSR
  1184.         call    mdio_read ; returns with window #4
  1185.         test    al, BMSR_ANEGCOMPLETE
  1186.         jnz     .auto_neg_ok
  1187.  
  1188.         jmp     .fail3
  1189.   .auto_neg_ok:
  1190.         DEBUGF  1,"Auto-negotiation complete\n"
  1191.  
  1192. ; compare advertisement and link partner ability registers
  1193.         mov     eax, [esp]
  1194.         mov     al, MII_ADVERTISE
  1195.         call    mdio_read               ; returns with window #4
  1196.         xchg    eax, [esp]
  1197.         mov     al, MII_LPA
  1198.         call    mdio_read               ; returns with window #4
  1199.         pop     esi
  1200.         and     eax, esi
  1201.         and     eax, 11111100000b       ; Mask off
  1202.         push    eax
  1203.         mov     word[ebx + device.internal_link+2], ax
  1204.  
  1205. ; switch to register window 3
  1206.         set_io  [ebx + device.io_addr], 0
  1207.         set_io  [ebx + device.io_addr], REG_COMMAND
  1208.         mov     ax, SELECT_REGISTER_WINDOW+3
  1209.         out     dx, ax
  1210.  
  1211. ; set full-duplex mode
  1212.         set_io  [ebx + device.io_addr], REG_MAC_CONTROL
  1213.         in      ax, dx
  1214.         and     ax, not 0x120           ; clear full duplex and flow control
  1215.         pop     esi
  1216.         test    esi, 1010b shl 5        ; check for full-duplex
  1217.         jz      .half_duplex
  1218.         or      ax, 0x120               ; set full duplex and flow control
  1219.   .half_duplex:
  1220.         DEBUGF 1,"Using half-duplex\n"
  1221.         out     dx, ax
  1222.         mov     al, 1
  1223.         ret
  1224.  
  1225.   .fail1:
  1226.         DEBUGF  2,"reset failed!\n"
  1227.         pop     eax
  1228.         xor     al, al
  1229.         ret
  1230.  
  1231.   .fail2:
  1232.         DEBUGF  2,"This device is not auto-negotiation capable!\n"
  1233.         pop     eax
  1234.         xor     al, al
  1235.         ret
  1236.  
  1237.   .fail3:
  1238.         DEBUGF  2,"Auto-negotiation reset failed!\n"
  1239.         pop     eax
  1240.         xor     al, al
  1241.         ret
  1242.  
  1243.  
  1244.  
  1245. ;***************************************************************************
  1246. ;   Function
  1247. ;      try_mii
  1248. ;   Description
  1249. ;      try_MII checks the on-chip auto-negotiation logic
  1250. ;      or an off-chip MII PHY, depending upon what is set in
  1251. ;      xcvrSelect by the caller.
  1252. ;      It exits when it finds the first device with a good link.
  1253. ;   Parameters
  1254. ;
  1255. ;   Return value
  1256. ;      al - 0
  1257. ;      al - 1
  1258. ;   Destroyed registers
  1259. ;      eax, ebx, ecx, edx, esi
  1260. ;
  1261. ;***************************************************************************
  1262.  
  1263. align 4
  1264. try_mii:
  1265.  
  1266.         DEBUGF  1,"Trying to find MII PHY\n"
  1267.  
  1268. ; switch to register window 3
  1269.         set_io  [ebx + device.io_addr], 0
  1270.         set_io  [ebx + device.io_addr], REG_COMMAND
  1271.         mov     ax, SELECT_REGISTER_WINDOW+3
  1272.         out     dx, ax
  1273.         set_io  [ebx + device.io_addr], REG_INTERNAL_CONFIG
  1274.         in      eax, dx
  1275.         and     eax, (1111b shl 20)
  1276.         cmp     eax, (1000b shl 20) ; is auto-negotiation set?
  1277.         jne     .mii_device
  1278.  
  1279.         DEBUGF  1,"Auto-negotiation is set\n"
  1280. ; switch to register window 4
  1281.         set_io  [ebx + device.io_addr], REG_COMMAND
  1282.         mov     ax, SELECT_REGISTER_WINDOW+4
  1283.         out     dx, ax
  1284.  
  1285. ; PHY==24 is the on-chip auto-negotiation logic
  1286. ; it supports only 10base-T and 100base-TX
  1287.         mov     ah, 24
  1288.         call    try_phy
  1289.         test    al, al
  1290.         jz      .fail
  1291.  
  1292.         mov     cl, 24
  1293.         jmp     .check_preamble
  1294.  
  1295.   .mii_device:
  1296.         cmp     eax, (0110b shl 20)
  1297.         jne     .fail
  1298.  
  1299.         set_io  [ebx + device.io_addr], 0
  1300.         set_io  [ebx + device.io_addr], REG_COMMAND
  1301.         mov     ax , SELECT_REGISTER_WINDOW+4
  1302.         out     dx , ax
  1303.  
  1304.         set_io  [ebx + device.io_addr], REG_PHYSICAL_MGMT
  1305.         in      ax , dx
  1306.         and     al , (1 shl BIT_MGMT_DIR) or (1 shl BIT_MGMT_DATA)
  1307.         cmp     al , (1 shl BIT_MGMT_DATA)
  1308.         je      .search_for_phy
  1309.  
  1310.         xor     al, al
  1311.         ret
  1312.  
  1313.   .search_for_phy:
  1314. ; search for PHY
  1315.         mov     cx, 31
  1316.   .search_phy_loop:
  1317.         DEBUGF  1,"Searching for the PHY\n"
  1318.         cmp     cx, 24
  1319.         je      .next_phy
  1320.         mov     ah, cl                  ; ah = phy
  1321.         mov     al, MII_BMSR            ; al = Basic Mode Status Register       ; BUGFIX HERE! :):)
  1322.         push    cx
  1323.         call    mdio_read
  1324.         pop     cx
  1325.         test    ax, ax
  1326.         jz      .next_phy
  1327.         cmp     ax, 0xffff
  1328.         je      .next_phy
  1329.         mov     ah, cl                  ; ah = phy
  1330.         push    cx
  1331.         call    try_phy
  1332.         pop     cx
  1333.         test    al, al
  1334.         jnz     .check_preamble
  1335.   .next_phy:
  1336.         loopw   .search_phy_loop
  1337.  
  1338.   .fail:
  1339.         DEBUGF  1,"PHY not found\n"
  1340.         xor     al, al
  1341.         ret
  1342.  
  1343. ; epilog
  1344.   .check_preamble:
  1345.         DEBUGF  1,"Using PHY: %u\nChecking PreAmble\n", cl
  1346.         push    eax ; eax contains the return value of try_phy
  1347. ; check hard coded preamble forcing
  1348.         movzx   eax, [ebx + device.ver_id]
  1349.         test    word [eax*4+hw_versions+2], EXTRA_PREAMBLE
  1350.         setnz   [ebx + device.preamble] ; force preamble
  1351.         jnz     .finish
  1352.  
  1353. ; check mii for preamble suppression
  1354.         mov     ah, cl
  1355.         mov     al, MII_BMSR
  1356.         call    mdio_read
  1357.         test    al, 1000000b ; preamble suppression?
  1358.         setz    [ebx + device.preamble] ; no
  1359.  
  1360.   .finish:
  1361.         pop     eax
  1362.         ret
  1363.  
  1364.  
  1365.  
  1366. ;***************************************************************************
  1367. ;   Function
  1368. ;      test_packet
  1369. ;   Description
  1370. ;      try_loopback try a loopback packet for 10BASE2 or AUI port
  1371. ;   Parameters
  1372. ;      ebx = device structure
  1373. ;
  1374. ;***************************************************************************
  1375.  
  1376. align 4
  1377. test_packet:
  1378.  
  1379.         DEBUGF 1,"Sending test packet\n"
  1380.  
  1381. ; switch to register window 3
  1382.         set_io  [ebx + device.io_addr], 0
  1383.         set_io  [ebx + device.io_addr], REG_COMMAND
  1384.         mov     ax, SELECT_REGISTER_WINDOW+3
  1385.         out     dx, ax
  1386.  
  1387. ; set fullDuplexEnable in MacControl register
  1388.         set_io  [ebx + device.io_addr], REG_MAC_CONTROL
  1389.         in      ax, dx
  1390.         or      ax, 0x120
  1391.         out     dx, ax
  1392.  
  1393. ; switch to register window 5
  1394.         set_io  [ebx + device.io_addr], REG_COMMAND
  1395.         mov     ax, SELECT_REGISTER_WINDOW+5
  1396.         out     dx, ax
  1397.  
  1398. ; set RxFilter to enable individual address matches
  1399.         mov     ax, (10000b shl 11)
  1400.         set_io  [ebx + device.io_addr], REG_RX_FILTER
  1401.         in      al, dx
  1402.         or      al, 1
  1403.         set_io  [ebx + device.io_addr], REG_COMMAND
  1404.         out     dx, ax
  1405.  
  1406. ; issue RxEnable and TxEnable
  1407.         call    rx_reset
  1408.         call    tx_reset
  1409.  
  1410. ; create self-directed packet
  1411.         invoke  NetAlloc, 20 + NET_BUFF.data   ; create a buffer for the self-directed packet
  1412.         test    eax, eax
  1413.         jz      .fail
  1414.  
  1415.         push    eax
  1416.         mov     [eax + NET_BUFF.length], 20
  1417. ;        mov     [eax + NET_BUFF.device], ebx
  1418.  
  1419.         lea     edi, [eax + NET_BUFF.data]
  1420.         lea     esi, [ebx + device.mac]
  1421.         movsw
  1422.         movsd
  1423.         sub     esi, 6
  1424.         movsw
  1425.         movsd
  1426.         mov     ax, 0x0608
  1427.         stosw
  1428.  
  1429. ; download self-directed packet
  1430.         call    [ebx + device.transmit]
  1431.  
  1432. ; wait for 2s
  1433.         mov     esi, 2000       ; FIXME
  1434.         invoke  Sleep
  1435.  
  1436. ; check if self-directed packet is received
  1437.         mov     eax, [ebx + device.packets_rx]
  1438.         test    eax, eax
  1439.         jnz     .finish
  1440.  
  1441. ; switch to register window 3
  1442.         set_io  [ebx + device.io_addr], 0
  1443.         set_io  [ebx + device.io_addr], REG_COMMAND
  1444.         mov     ax, SELECT_REGISTER_WINDOW+3
  1445.         out     dx, ax
  1446.  
  1447. ; clear fullDuplexEnable in MacControl register
  1448.         set_io  [ebx + device.io_addr], REG_MAC_CONTROL
  1449.         in      ax, dx
  1450.         and     ax, not 0x120
  1451.         out     dx, ax
  1452.   .fail:
  1453.         xor     eax, eax
  1454.  
  1455.   .finish:
  1456.         ret
  1457.  
  1458.  
  1459.  
  1460. ;***************************************************************************
  1461. ;   Function
  1462. ;      try_loopback
  1463. ;   Description
  1464. ;      tries a loopback packet for 10BASE2 or AUI port
  1465. ;   Parameters
  1466. ;      al -  0: 10Mbps AUI connector
  1467. ;            1: 10BASE-2
  1468. ;
  1469. ;   Return value
  1470. ;      al - 0
  1471. ;      al - 1
  1472. ;   Destroyed registers
  1473. ;      eax, ebx, ecx, edx, edi, esi
  1474. ;
  1475. ;***************************************************************************
  1476.  
  1477. align 4
  1478. try_loopback:
  1479.  
  1480.         DEBUGF 1,"trying loopback\n"
  1481.  
  1482.         push    eax
  1483. ; switch to register window 3
  1484.         set_io  [ebx + device.io_addr], 0
  1485.         set_io  [ebx + device.io_addr], REG_COMMAND
  1486.         mov     ax, SELECT_REGISTER_WINDOW+3
  1487.         out     dx, ax
  1488.         mov     eax, [esp]
  1489.  
  1490.         mov     cl, al
  1491.         inc     cl
  1492.         shl     cl, 3
  1493.         or      byte [ebx + device.internal_link+1], cl
  1494.  
  1495.         test    al, al ; aui or coax?
  1496.         jz      .complete_loopback
  1497. ; enable 100BASE-2 DC-DC converter
  1498.         mov     ax, (10b shl 11) ; EnableDcConverter
  1499.         out     dx, ax
  1500.   .complete_loopback:
  1501.  
  1502.         mov     cx, 2 ; give a port 3 chances to complete a loopback
  1503.   .next_try:
  1504.         push    ecx
  1505.         call    test_packet
  1506.         pop     ecx
  1507.         test    eax, eax
  1508.         loopzw  .next_try
  1509.  
  1510.   .finish:
  1511.         xchg    eax, [esp]
  1512.         test    al, al
  1513.         jz      .aui_finish
  1514.  
  1515. ; issue DisableDcConverter command
  1516.         set_io  [ebx + device.io_addr], 0
  1517.         set_io  [ebx + device.io_addr], REG_COMMAND
  1518.         mov     ax, (10111b shl 11)
  1519.         out     dx, ax
  1520.   .aui_finish:
  1521.         pop     eax ; al contains the result of operation
  1522.  
  1523.         test    al, al
  1524.         jnz     @f
  1525.         and     byte [ebx + device.internal_link+1], not 11000b
  1526.        @@:
  1527.  
  1528.         ret
  1529.  
  1530.  
  1531. ;***************************************************************************
  1532. ;   Function
  1533. ;      set_active_port
  1534. ;   Description
  1535. ;      It selects the media port (transceiver) to be used
  1536. ;   Return value:
  1537. ;   Destroyed registers
  1538. ;      eax, ebx, ecx, edx, edi, esi
  1539. ;
  1540. ;***************************************************************************
  1541.  
  1542. align 4
  1543. set_active_port:
  1544.  
  1545.         DEBUGF 1,"Trying to find the active port\n"
  1546.  
  1547. ; switch to register window 3
  1548.         set_io  [ebx + device.io_addr], 0
  1549.         set_io  [ebx + device.io_addr], REG_COMMAND
  1550.         mov     ax, SELECT_REGISTER_WINDOW + 3
  1551.         out     dx, ax
  1552.  
  1553.         set_io  [ebx + device.io_addr], REG_INTERNAL_CONFIG
  1554.         in      eax, dx
  1555.         test    eax, (1 shl 24) ; check if autoselect enable
  1556.         jz      .set_first_available_media
  1557.  
  1558. ; check 100BASE-TX and 10BASE-T
  1559.         set_io  [ebx + device.io_addr], REG_MEDIA_OPTIONS
  1560.         in      ax, dx
  1561.         test    al, 1010b       ; check whether 100BASE-TX or 10BASE-T available
  1562.         jz      .mii_device     ; they are not available
  1563.  
  1564. ; set auto-negotiation
  1565.         set_io  [ebx + device.io_addr], REG_INTERNAL_CONFIG
  1566.         in      eax, dx
  1567.         and     eax, not (1111b shl 20)
  1568.         or      eax, (1000b shl 20)
  1569.         out     dx, eax
  1570.         call    try_mii
  1571.         test    al, al
  1572.         jz      .mii_device
  1573.         DEBUGF 1,"Using auto negotiation\n"
  1574.         ret
  1575.  
  1576.   .mii_device:
  1577. ; switch to register window 3
  1578.         set_io  [ebx + device.io_addr], 0
  1579. ; check for off-chip mii device
  1580.         set_io  [ebx + device.io_addr], REG_MEDIA_OPTIONS
  1581.         in      ax, dx
  1582.         test    al, 1000000b ; check miiDevice
  1583.         jz      .base_fx
  1584.         set_io  [ebx + device.io_addr], REG_INTERNAL_CONFIG
  1585.         in      eax, dx
  1586.         and     eax, not (1111b shl 20)
  1587.         or      eax, (0110b shl 20) ; set MIIDevice
  1588.         out     dx, eax
  1589.         call    try_mii
  1590.         test    al, al
  1591.         jz      .base_fx
  1592.         DEBUGF 1,"Using off-chip mii device\n"
  1593.         ret
  1594.  
  1595.   .base_fx:
  1596. ; switch to register window 3
  1597.         set_io  [ebx + device.io_addr], 0
  1598. ; check for 100BASE-FX
  1599.         set_io  [ebx + device.io_addr], REG_MEDIA_OPTIONS
  1600.         in      ax, dx ; read media option register
  1601.         test    al, 100b ; check 100BASE-FX
  1602.         jz      .aui_enable
  1603.         set_io  [ebx + device.io_addr], REG_INTERNAL_CONFIG
  1604.         in      eax, dx
  1605.         and     eax, not (1111b shl 20)
  1606.         or      eax, (0101b shl 20) ; set 100base-FX
  1607.         out     dx, eax
  1608.         call    try_link_detect
  1609.         test    al, al
  1610.         jz      .aui_enable
  1611.         DEBUGF 1,"Using 100Base-FX\n"
  1612.         ret
  1613.  
  1614.   .aui_enable:
  1615. ; switch to register window 3
  1616.         set_io  [ebx + device.io_addr], 0
  1617. ; check for 10Mbps AUI connector
  1618.         set_io  [ebx + device.io_addr], REG_MEDIA_OPTIONS
  1619.         in      ax, dx ; read media option register
  1620.         test    al, 100000b ; check 10Mbps AUI connector
  1621.         jz      .coax_available
  1622.         set_io  [ebx + device.io_addr], REG_INTERNAL_CONFIG
  1623.         in      eax, dx
  1624.         and     eax, not (1111b shl 20)
  1625.         or      eax, (0001b shl 20) ; set 10Mbps AUI connector
  1626.         out     dx, eax
  1627.         xor     al, al ; try 10Mbps AUI connector
  1628.         call    try_loopback
  1629.         test    al, al
  1630.         jz      .coax_available
  1631.         DEBUGF 1,"Using 10Mbps aui\n"
  1632.         ret
  1633.  
  1634.   .coax_available:
  1635. ; switch to register window 3
  1636.         set_io  [ebx + device.io_addr], 0
  1637. ; check for coaxial 10BASE-2 port
  1638.         set_io  [ebx + device.io_addr], REG_MEDIA_OPTIONS
  1639.         in      ax, dx ; read media option register
  1640.         test    al, 10000b ; check 10BASE-2
  1641.         jz      .set_first_available_media
  1642.  
  1643.         set_io  [ebx + device.io_addr], REG_INTERNAL_CONFIG
  1644.         in      eax, dx
  1645.         and     eax, not (1111b shl 20)
  1646.         or      eax, (0011b shl 20) ; set 10BASE-2
  1647.         out     dx, eax
  1648.         mov     al, 1
  1649.         call    try_loopback
  1650.         test    al, al
  1651.         jz      .set_first_available_media
  1652.         DEBUGF 1,"Using 10BASE-2 port\n"
  1653.         ret
  1654.  
  1655.   .set_first_available_media:
  1656.         DEBUGF  1,"Using the first available media\n"
  1657.  
  1658. ;***************************************************************************
  1659. ;   Function
  1660. ;      set_available_media
  1661. ;   Description
  1662. ;      sets the first available media
  1663. ;   Parameters
  1664. ;      ebx - ptr to device struct
  1665. ;   Return value
  1666. ;      al - 0
  1667. ;      al - 1
  1668. ;   Destroyed registers
  1669. ;      eax, edx
  1670. ;
  1671. ;***************************************************************************
  1672.  
  1673. align 4
  1674. set_available_media:
  1675.  
  1676.         DEBUGF  1,"Setting the available media\n"
  1677. ; switch to register window 3
  1678.         set_io  [ebx + device.io_addr], 0
  1679.         set_io  [ebx + device.io_addr], REG_COMMAND
  1680.         mov     ax, SELECT_REGISTER_WINDOW+3
  1681.         out     dx, ax
  1682.  
  1683.         set_io  [ebx + device.io_addr], REG_MEDIA_OPTIONS
  1684.         in      ax, dx
  1685.         DEBUGF  1,"available media:%x\n", al
  1686.         mov     cl, al
  1687.  
  1688.         set_io  [ebx + device.io_addr], REG_INTERNAL_CONFIG
  1689.         in      eax, dx
  1690.         and     eax, not (1111b shl 20) ; these bits hold the 'transceiver select' value
  1691.  
  1692.         test    cl, 10b         ; baseTXAvailable
  1693.         jz      @f
  1694.  
  1695.         DEBUGF  1,"base TX is available\n"
  1696.         or      eax, (100b shl 20)
  1697. if FORCE_FD
  1698.         mov     word [ebx + device.internal_link], (1 shl 8)
  1699. else
  1700.         mov     word [ebx + device.internal_link], (1 shl 7)
  1701. end if
  1702.         jmp     .set_media
  1703.        @@:
  1704.  
  1705.         test    cl, 100b        ; baseFXAvailable
  1706.         jz      @f
  1707.  
  1708.         DEBUGF  1,"base FX is available\n"
  1709.         or      eax, (101b shl 20)
  1710.         mov     word [ebx + device.internal_link], (1 shl 10)
  1711.         jmp     .set_media
  1712.        @@:
  1713.  
  1714.         test    cl, 1000000b    ; miiDevice
  1715.         jz      @f
  1716.  
  1717.         DEBUGF  1,"mii-device is available\n"
  1718.         or      eax, (0110b shl 20)
  1719.         mov     word [ebx + device.internal_link], (1 shl 13)
  1720.         jmp     .set_media
  1721.        @@:
  1722.  
  1723.         test    cl, 1000b       ; 10bTAvailable
  1724.         jz      @f
  1725.  
  1726.         DEBUGF  1,"10base-T is available\n"
  1727.   .set_default:
  1728. if FORCE_FD
  1729.         mov     word [ebx + device.internal_link], (1 shl 6)
  1730. else
  1731.         mov     word [ebx + device.internal_link], (1 shl 5)
  1732. end if
  1733.         jmp     .set_media
  1734.        @@:
  1735.  
  1736.         test    cl, 10000b      ; coaxAvailable
  1737.         jz      @f
  1738.  
  1739.         DEBUGF  1,"coax is available\n"
  1740.         push    eax
  1741.         set_io  [ebx + device.io_addr], REG_COMMAND
  1742.         mov     ax, (10b shl 11) ; EnableDcConverter
  1743.         out     dx, ax
  1744.         pop     eax
  1745.  
  1746.         or      eax, (11b shl 20)
  1747.         mov     word [ebx + device.internal_link], (1 shl 12)
  1748.         jmp     .set_media
  1749.        @@:
  1750.  
  1751.         test    cl, 10000b      ; auiAvailable
  1752.         jz      .set_default
  1753.  
  1754.         DEBUGF  1,"AUI is available\n"
  1755.         or      eax, (1 shl 20)
  1756.         mov     word [ebx + device.internal_link], (1 shl 11)
  1757.  
  1758.   .set_media:
  1759.         set_io  [ebx + device.io_addr], 0
  1760.         set_io  [ebx + device.io_addr], REG_INTERNAL_CONFIG
  1761.         out     dx, eax
  1762.  
  1763. if FORCE_FD
  1764.         DEBUGF  1,"Forcing full duplex\n"
  1765.         set_io  [ebx + device.io_addr], REG_MAC_CONTROL
  1766.         in      ax, dx
  1767.         or      ax, 0x120
  1768.         out     dx, ax
  1769. end if
  1770.  
  1771.         mov     al, 1
  1772.         ret
  1773.  
  1774. ;***************************************************************************
  1775. ;   Function
  1776. ;      write_eeprom
  1777. ;   Description
  1778. ;      reads eeprom
  1779. ;      Note : the caller must switch to the register window 0
  1780. ;             before calling this function
  1781. ;   Parameters:
  1782. ;      ax - register to be read (only the first 63 words can be read)
  1783. ;      cx - value to be read into the register
  1784. ;   Return value:
  1785. ;      ax - word read
  1786. ;   Destroyed registers
  1787. ;      ax, ebx, edx
  1788. ;
  1789. ;***************************************************************************
  1790. ;       align 4
  1791. ;write_eeprom:
  1792. ;       mov     edx, [io_addr]
  1793. ;       add     edx, REG_EEPROM_COMMAND
  1794. ;       cmp     ah, 11b
  1795. ;       ja      .finish ; address may have a value of maximal 1023
  1796. ;       shl     ax, 2
  1797. ;       shr     al, 2
  1798. ;       push    eax
  1799. ;; wait for busy
  1800. ;       mov     ebx, 0xffff
  1801. ;@@:
  1802. ;       in      ax, dx
  1803. ;       test    ah, 0x80
  1804. ;       jz      .write_enable
  1805. ;       dec     ebx
  1806. ;       jns     @r
  1807. ;; write enable
  1808. ;.write_enable:
  1809. ;       xor     eax, eax
  1810. ;       mov     eax, (11b shl 4)
  1811. ;       out     dx, ax
  1812. ;; wait for busy
  1813. ;       mov     ebx, 0xffff
  1814. ;@@:
  1815. ;       in      ax, dx
  1816. ;       test    ah, 0x80
  1817. ;       jz      .erase_loop
  1818. ;       dec     ebx
  1819. ;       jns     @r
  1820. ;.erase_loop:
  1821. ;       pop     eax
  1822. ;       push    eax
  1823. ;       or      ax, (11b shl 6) ; erase register
  1824. ;       out     dx, ax
  1825. ;       mov     ebx, 0xffff
  1826. ;@@:
  1827. ;       in      ax, dx
  1828. ;       test    ah, 0x80
  1829. ;       jz      .write_reg
  1830. ;       dec     ebx
  1831. ;       jns     @r
  1832. ;.write_reg:
  1833. ;       add     edx, REG_EEPROM_DATA-REG_EEPROM_COMMAND
  1834. ;       mov     eax, ecx
  1835. ;       out     dx, ax
  1836. ;; write enable
  1837. ;       add     edx, REG_EEPROM_COMMAND-REG_EEPROM_DATA
  1838. ;       xor     eax, eax
  1839. ;       mov     eax, (11b shl 4)
  1840. ;       out     dx, ax
  1841. ; wait for busy
  1842. ;       mov     ebx, 0xffff
  1843. ;@@:
  1844. ;       in      ax, dx
  1845. ;       test    ah, 0x80
  1846. ;       jz      .issue_write_reg
  1847. ;       dec     ebx
  1848. ;       jns     @r
  1849. ;.issue_write_reg:
  1850. ;       pop     eax
  1851. ;       or      ax, 01b shl 6
  1852. ;       out     dx, ax
  1853. ;.finish:
  1854. ;       ret
  1855.  
  1856.  
  1857. ;***************************************************************************
  1858. ;   Function
  1859. ;      read_eeprom
  1860. ;   Description
  1861. ;      reads eeprom
  1862. ;   Parameters:
  1863. ;       ax - register to be read (only the first 63 words can be read)
  1864. ;      ebx = driver structure
  1865. ;   Return value:
  1866. ;      ax - word read
  1867. ;   Destroyed registers
  1868. ;      ax, ebx, edx
  1869. ;
  1870. ;***************************************************************************
  1871.  
  1872. align 4
  1873. read_eeprom:
  1874.  
  1875.         DEBUGF 1,"Reading from eeprom.. "
  1876.  
  1877.         push    eax
  1878. ; switch to register window 0
  1879.         set_io  [ebx + device.io_addr], 0
  1880.         set_io  [ebx + device.io_addr], REG_COMMAND
  1881.         mov     ax, SELECT_REGISTER_WINDOW+0
  1882.         out     dx, ax
  1883.         pop     eax
  1884.         and     ax, 111111b ; take only the first 6 bits into account
  1885.         movzx   esi, [ebx + device.ver_id]
  1886.  
  1887.         test    word [esi*4+hw_versions+2], EEPROM_8BIT
  1888.         jz      @f
  1889.         add     ax, 0x230 ; hardware constant
  1890.         jmp     .read
  1891. @@:
  1892.  
  1893.         add     ax, EEPROM_CMD_READ
  1894.         test    word [esi*4+hw_versions+2], EEPROM_OFFSET
  1895.         jz      .read
  1896.         add     ax, 0x30
  1897. .read:
  1898.  
  1899.         set_io  [ebx + device.io_addr], REG_EEPROM_COMMAND
  1900.         out     dx, ax
  1901.         mov     ecx, 0xffff ; duration of about 162 us ;-)
  1902. .wait_for_reading:
  1903.         in      ax, dx
  1904.         test    ah, 0x80 ; check bit eepromBusy
  1905.         jz      .read_data
  1906.         loop    .wait_for_reading
  1907. .read_data:
  1908.         set_io  [ebx + device.io_addr], REG_EEPROM_DATA
  1909.         in      ax, dx
  1910.  
  1911.         DEBUGF 1,"ok!\n"
  1912.  
  1913.         ret
  1914.  
  1915. ;***************************************************************************
  1916. ;   Function
  1917. ;      mdio_sync
  1918. ;   Description
  1919. ;      initial synchronization
  1920. ;   Parameters
  1921. ;
  1922. ;   Return value
  1923. ;   Destroyed registers
  1924. ;      ax, edx, cl
  1925. ;
  1926. ;***************************************************************************
  1927.  
  1928. align 4
  1929. mdio_sync:
  1930.  
  1931.         DEBUGF 1,"syncing mdio\n"
  1932.  
  1933. ; switch to register window 4
  1934.         set_io  [ebx + device.io_addr], 0
  1935.         set_io  [ebx + device.io_addr], REG_COMMAND
  1936.         mov     ax, SELECT_REGISTER_WINDOW+4
  1937.         out     dx, ax
  1938.         cmp     [ebx + device.preamble], 0
  1939.         je      .no_preamble
  1940. ; send 32 logic ones
  1941.         set_io  [ebx + device.io_addr], REG_PHYSICAL_MGMT
  1942.         mov     ecx, 31
  1943.   .loop:
  1944.         mov     ax, (1 shl BIT_MGMT_DATA) or (1 shl BIT_MGMT_DIR)
  1945.         out     dx, ax
  1946.         in      ax, dx ; delay
  1947.         mov     ax, (1 shl BIT_MGMT_DATA) or (1 shl BIT_MGMT_DIR) or (1 shl BIT_MGMT_CLK)
  1948.         out     dx, ax
  1949.         in      ax, dx ; delay
  1950.         loop    .loop
  1951.   .no_preamble:
  1952.  
  1953.         ret
  1954.  
  1955. ;***************************************************************************
  1956. ;   Function
  1957. ;      mdio_read
  1958. ;   Description
  1959. ;      read MII register
  1960. ;      see page 16 in D83840A.pdf
  1961. ;   Parameters
  1962. ;       ah - PHY addr
  1963. ;       al - register addr
  1964. ;      ebx = device structure
  1965. ;   Return value
  1966. ;      ax - register read
  1967. ;
  1968. ;***************************************************************************
  1969.  
  1970. align 4
  1971. mdio_read:
  1972.  
  1973.         DEBUGF 1,"Reading MII registers\n"
  1974.  
  1975.         push    eax
  1976.         call    mdio_sync ; returns with window #4
  1977.         pop     eax
  1978.         set_io  [ebx + device.io_addr], 0
  1979.         set_io  [ebx + device.io_addr], REG_PHYSICAL_MGMT
  1980.         shl     al, 3
  1981.         shr     ax, 3
  1982.         and     ax, not MII_CMD_MASK
  1983.         or      ax, MII_CMD_READ
  1984.  
  1985.         mov     esi, eax
  1986.         mov     ecx, 13
  1987.   .cmd_loop:
  1988.         mov     ax, (1 shl BIT_MGMT_DIR) ; write mii
  1989.         bt      esi, ecx
  1990.         jnc     .zero_bit
  1991.         or      al, (1 shl BIT_MGMT_DATA)
  1992.  
  1993.   .zero_bit:
  1994.         out     dx, ax
  1995.         push    ax
  1996.         in      ax, dx ; delay
  1997.         pop     ax
  1998.         or      al, (1 shl BIT_MGMT_CLK) ; write
  1999.         out     dx, ax
  2000.         in      ax, dx ; delay
  2001.         loop    .cmd_loop
  2002.  
  2003. ; read data (18 bits with the two transition bits)
  2004.         mov     ecx, 17
  2005.         xor     esi, esi
  2006.   .read_loop:
  2007.         shl     esi, 1
  2008.         xor     eax, eax ; read comand
  2009.         out     dx, ax
  2010.         in      ax, dx ; delay
  2011.         in      ax, dx
  2012.         test    al, (1 shl BIT_MGMT_DATA)
  2013.         jz      .dont_set
  2014.         inc     esi
  2015.   .dont_set:
  2016.         mov     ax, (1 shl BIT_MGMT_CLK)
  2017.         out     dx, ax
  2018.         in      ax, dx ; delay
  2019.         loop    .read_loop
  2020.         mov     eax, esi
  2021.  
  2022.         ret
  2023.  
  2024.  
  2025.  
  2026. ;***************************************************************************
  2027. ;   Function
  2028. ;      mdio_write
  2029. ;   Description
  2030. ;      write MII register
  2031. ;      see page 16 in D83840A.pdf
  2032. ;   Parameters
  2033. ;       ah - PHY addr
  2034. ;       al - register addr
  2035. ;       si - word to be written
  2036. ;   Return value
  2037. ;      ax - register read
  2038. ;
  2039. ;***************************************************************************
  2040.  
  2041. align 4
  2042. mdio_write:
  2043.  
  2044.         DEBUGF 1,"Writing MII registers\n"
  2045.  
  2046.         push    eax
  2047.         call    mdio_sync
  2048.         pop     eax
  2049.         set_io  [ebx + device.io_addr], 0
  2050.         set_io  [ebx + device.io_addr], REG_PHYSICAL_MGMT
  2051.         shl     al, 3
  2052.         shr     ax, 3
  2053.         and     ax, not MII_CMD_MASK
  2054.         or      ax, MII_CMD_WRITE
  2055.         shl     eax, 2
  2056.         or      eax, 10b ; transition bits
  2057.         shl     eax, 16
  2058.         mov     ax, si
  2059.         mov     esi, eax
  2060.         mov     ecx, 31
  2061.  
  2062.   .cmd_loop:
  2063.         mov     ax, (1 shl BIT_MGMT_DIR) ; write mii
  2064.         bt      esi, ecx
  2065.         jnc     @f
  2066.         or      al, (1 shl BIT_MGMT_DATA)
  2067.        @@:
  2068.         out     dx, ax
  2069.         push    eax
  2070.         in      ax, dx ; delay
  2071.         pop     eax
  2072.         or      al, (1 shl BIT_MGMT_CLK) ; write
  2073.         out     dx, ax
  2074.         in      ax, dx ; delay
  2075.         loop    .cmd_loop
  2076.  
  2077.         ret
  2078.  
  2079.  
  2080. ;***************************************************************************
  2081. ;   Function
  2082. ;      check_tx_status
  2083. ;   Description
  2084. ;      Checks TxStatus queue.
  2085. ;   Return value
  2086. ;      al - 0 no error was found
  2087. ;      al - 1 error was found TxReset was needed
  2088. ;   Destroyed registers
  2089. ;      eax, ecx, edx
  2090. ;
  2091. ;***************************************************************************
  2092.  
  2093. align 4
  2094. check_tx_status:
  2095.  
  2096.         DEBUGF 1,"Checking TX status\n"
  2097.  
  2098. ; clear TxStatus queue
  2099.         set_io  [ebx + device.io_addr], 0
  2100.         set_io  [ebx + device.io_addr], REG_TX_STATUS
  2101.         mov     ecx, 31 ; max number of queue entries
  2102.  
  2103.   .tx_status_loop:
  2104.         in      al, dx
  2105.         test    al, al
  2106.         jz      .finish ; no error
  2107.         test    al, 0x3f
  2108.         jnz     .error
  2109.   .no_error_found:
  2110. ; clear current TxStatus entry which advances the next one
  2111.         xor     al, al
  2112.         out     dx, al
  2113.         loop    .tx_status_loop
  2114.  
  2115.   .finish:
  2116.         ret
  2117.  
  2118.   .error:
  2119.         call    tx_reset
  2120.         ret
  2121.  
  2122.  
  2123.  
  2124. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2125. ;;                                         ;;
  2126. ;; Transmit (vortex)                       ;;
  2127. ;;                                         ;;
  2128. ;; In: pointer to device structure in ebx  ;;
  2129. ;; Out: eax = 0 on success                 ;;
  2130. ;;                                         ;;
  2131. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2132. align 16
  2133. proc vortex_transmit stdcall bufferptr
  2134.  
  2135.         spin_lock_irqsave
  2136.  
  2137.         mov     esi, [bufferptr]
  2138.         DEBUGF  1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [esi + NET_BUFF.length]
  2139.         lea     eax, [esi + NET_BUFF.data]
  2140.         DEBUGF  1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
  2141.         [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
  2142.         [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
  2143.         [eax+13]:2,[eax+12]:2
  2144.  
  2145.         cmp     [esi + NET_BUFF.length], 1514
  2146.         ja      .error
  2147.         cmp     [esi + NET_BUFF.length], 60
  2148.         jb      .error
  2149.  
  2150.         call    check_tx_status
  2151.  
  2152. ; switch to register window 7
  2153.         set_io  [ebx + device.io_addr], 0
  2154.         set_io  [ebx + device.io_addr], REG_COMMAND
  2155.         mov     ax, SELECT_REGISTER_WINDOW + 7
  2156.         out     dx, ax
  2157.  
  2158. ; check for master operation in progress
  2159.         set_io  [ebx + device.io_addr], REG_MASTER_STATUS
  2160.         in      ax, dx
  2161.         test    ah, 0x80
  2162.         jnz     .overrun ; no DMA for sending
  2163.  
  2164. ; program frame address to be sent
  2165.         set_io  [ebx + device.io_addr], REG_MASTER_ADDRESS
  2166.         mov     eax, esi
  2167.         add     eax, [eax + NET_BUFF.offset]
  2168.         invoke  GetPhysAddr
  2169.         out     dx, eax
  2170.  
  2171. ; program frame length
  2172.         set_io  [ebx + device.io_addr], REG_MASTER_LEN
  2173.         mov     eax, [esi + NET_BUFF.length]
  2174.         out     dx, ax
  2175.  
  2176. ; start DMA Down
  2177.         set_io  [ebx + device.io_addr], REG_COMMAND
  2178.         mov     ax, (10100b shl 11) + 1 ; StartDMADown
  2179.         out     dx, ax
  2180.  
  2181. ; Update stats
  2182.         inc     [ebx + device.packets_tx]
  2183.         mov     eax, [esi + NET_BUFF.length]
  2184.         add     dword[ebx + device.bytes_tx], eax
  2185.         adc     dword[ebx + device.bytes_tx + 4], 0
  2186.  
  2187.         spin_unlock_irqrestore
  2188.         xor     eax, eax
  2189.         ret
  2190.  
  2191.   .error:
  2192.         DEBUGF  2, "TX packet error\n"
  2193.         inc     [ebx + device.packets_tx_err]
  2194.         invoke  NetFree, [bufferptr]
  2195.  
  2196.         spin_unlock_irqrestore
  2197.         or      eax, -1
  2198.         ret
  2199.  
  2200.   .overrun:
  2201.         DEBUGF  2, "TX overrun\n"
  2202.         inc     [ebx + device.packets_tx_ovr]
  2203.         invoke  NetFree, [bufferptr]
  2204.  
  2205.         spin_unlock_irqrestore
  2206.         or      eax, -1
  2207.         ret
  2208.  
  2209. endp
  2210.  
  2211. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2212. ;;                                         ;;
  2213. ;; Transmit (boomerang)                    ;;
  2214. ;;                                         ;;
  2215. ;; In: pointer to device structure in ebx  ;;
  2216. ;; Out: eax = 0 on success                 ;;
  2217. ;;                                         ;;
  2218. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2219. align 16
  2220. proc boomerang_transmit stdcall bufferptr
  2221.  
  2222.         spin_lock_irqsave
  2223.  
  2224.         mov     esi, [bufferptr]
  2225.         DEBUGF  1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr], [esi + NET_BUFF.length]
  2226.         lea     eax, [esi + NET_BUFF.data]
  2227.         DEBUGF  1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
  2228.         [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
  2229.         [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
  2230.         [eax+13]:2,[eax+12]:2
  2231.  
  2232.         cmp     [esi + NET_BUFF.length], 1514
  2233.         ja      .error
  2234.         cmp     [esi + NET_BUFF.length], 60
  2235.         jb      .error
  2236.  
  2237.         call    check_tx_status                         ; Reset TX engine if needed
  2238.  
  2239. ; calculate descriptor address
  2240.         mov     edi, [ebx + device.curr_tx]
  2241.         DEBUGF  1,"Previous TX desc: %x\n", edi
  2242.         add     edi, sizeof.tx_desc
  2243.         lea     ecx, [ebx + device.tx_desc_buffer + (NUM_TX_DESC)*sizeof.tx_desc]
  2244.         cmp     edi, ecx
  2245.         jb      @f
  2246.         lea     edi, [ebx + device.tx_desc_buffer]      ; Wrap if needed
  2247.        @@:
  2248.         DEBUGF  1,"Using TX desc: %x\n", esi
  2249.  
  2250. ; check DnListPtr
  2251.         set_io  [ebx + device.io_addr], 0
  2252.         set_io  [ebx + device.io_addr], REG_DN_LIST_PTR
  2253.         in      eax, dx
  2254. ; mark if Dn_List_Ptr is cleared
  2255.         test    eax, eax
  2256.         setz    [ebx + device.dn_list_ptr_cleared]
  2257.  
  2258. ; finish if no more free descriptor is available - FIXME!
  2259. ;        cmp     eax, esi
  2260. ;        jz      .finish
  2261.  
  2262. ; update statistics
  2263.         inc     [ebx + device.packets_tx]
  2264.         mov     ecx, [esi + NET_BUFF.length]
  2265.         add     dword [ebx + device.bytes_tx], ecx
  2266.         adc     dword [ebx + device.bytes_tx + 4], 0
  2267.  
  2268. ; program DPD
  2269.         and     [edi + tx_desc.next_ptr], 0
  2270.         mov     eax, [bufferptr]
  2271.         mov     [edi + tx_desc.realaddr], eax
  2272.         add     eax, [eax + NET_BUFF.offset]
  2273.         invoke  GetPhysAddr
  2274.         mov     [edi + tx_desc.frag_addr], eax
  2275. ;;;        mov     ecx, [buffersize]
  2276.         or      ecx, 0x80000000         ; last fragment flag
  2277.         mov     [edi + tx_desc.frag_len], ecx
  2278.  
  2279. ;;;        mov     ecx, [buffersize]       ; packet size
  2280.         or      ecx, 0x80008000         ; set OWN bit + transmission complete notification flag
  2281. ;        test    byte [ebx + device.has_hwcksm], 0xff
  2282. ;        jz      @f
  2283. ;        or      ecx, (1 shl 26)         ; set AddTcpChecksum
  2284. ;@@:
  2285.         mov     [edi + tx_desc.frame_start_hdr], ecx
  2286.         DEBUGF  1,"TX desc: lin=%x phys=%x len=%x start hdr=%x\n", [edi+tx_desc.realaddr]:8, [edi+tx_desc.frag_addr]:8, [edi+tx_desc.frag_len]:8, [edi+tx_desc.frame_start_hdr]:8
  2287.  
  2288. ; calculate physical address of tx descriptor
  2289.         mov     eax, edi
  2290.         invoke  GetPhysAddr
  2291.         cmp     [ebx + device.dn_list_ptr_cleared], 0
  2292.         je      .add_to_list
  2293.  
  2294. ; write Dn_List_Ptr
  2295.         DEBUGF  1,"TX desc phys addr=%x\n", eax
  2296.         set_io  [ebx + device.io_addr], 0
  2297.         set_io  [ebx + device.io_addr], REG_DN_LIST_PTR
  2298.         out     dx, eax
  2299.         jmp     .finish
  2300.  
  2301.   .add_to_list:
  2302.         DEBUGF  1,"Adding To list\n"
  2303.         push    eax
  2304. ; DnStall
  2305.         set_io  [ebx + device.io_addr], 0
  2306.         set_io  [ebx + device.io_addr], REG_COMMAND
  2307.         mov     ax, ((110b shl 11)+2)
  2308.         out     dx, ax
  2309.  
  2310. ; wait for DnStall to complete
  2311.         DEBUGF  1,"Waiting for DnStall\n"
  2312.         mov     ecx, 6000
  2313.   .wait_for_stall:
  2314.         in      ax, dx                  ; read REG_INT_STATUS
  2315.         test    ah, 10000b
  2316.         jz      .dnstall_ok
  2317.         dec     ecx
  2318.         jnz     .wait_for_stall
  2319.  
  2320.   .dnstall_ok:
  2321.         DEBUGF  1,"DnStall ok!\n"
  2322.         mov     ecx, [ebx + device.curr_tx]
  2323.         mov     [ecx + tx_desc.next_ptr], eax
  2324.  
  2325.         set_io  [ebx + device.io_addr], 0
  2326.         set_io  [ebx + device.io_addr], REG_DN_LIST_PTR
  2327.         in      eax, dx
  2328.         test    eax, eax
  2329.         pop     eax
  2330.         jnz     .dnunstall
  2331.  
  2332. ; if Dn_List_Ptr has been cleared fill it up
  2333.         DEBUGF  1,"DnList Ptr has been cleared\n"
  2334.         out     dx, eax
  2335.  
  2336.   .dnunstall:
  2337. ; DnUnStall
  2338.         set_io  [ebx + device.io_addr], 0
  2339.         set_io  [ebx + device.io_addr], REG_COMMAND
  2340.         mov     ax, ((110b shl 11)+3)
  2341.         out     dx, ax
  2342.  
  2343.   .finish:
  2344.         mov     [ebx + device.curr_tx], edi
  2345.  
  2346. ; Update stats
  2347.         inc     [ebx + device.packets_tx]
  2348.         mov     eax, [esi + NET_BUFF.length]
  2349.         add     dword[ebx + device.bytes_tx], eax
  2350.         adc     dword[ebx + device.bytes_tx + 4], 0
  2351.  
  2352.         spin_unlock_irqrestore
  2353.         xor     eax, eax
  2354.         ret
  2355.  
  2356.   .error:
  2357.         DEBUGF  2, "TX packet error\n"
  2358.         inc     [ebx + device.packets_tx_err]
  2359.         invoke  NetFree, [bufferptr]
  2360.  
  2361.         spin_unlock_irqrestore
  2362.         or      eax, -1
  2363.         ret
  2364.  
  2365.   .overrun:
  2366.         DEBUGF  2, "TX overrun\n"
  2367.         inc     [ebx + device.packets_tx_ovr]
  2368.         invoke  NetFree, [bufferptr]
  2369.  
  2370.         spin_unlock_irqrestore
  2371.         or      eax, -1
  2372.         ret
  2373.  
  2374. endp
  2375.  
  2376.  
  2377.  
  2378. ;---------------------------------
  2379. ; Write MAC
  2380.  
  2381. align 4
  2382. write_mac:
  2383.  
  2384.         DEBUGF 1,"Writing mac\n"
  2385.  
  2386.         set_io  [ebx + device.io_addr], 0
  2387.         set_io  [ebx + device.io_addr], REG_COMMAND
  2388.  
  2389. ; switch to register window 2
  2390.         mov     ax, SELECT_REGISTER_WINDOW+2
  2391.         out     dx, ax
  2392.  
  2393. ; write MAC addres back into the station address registers
  2394.         set_io  [ebx + device.io_addr], REG_STATION_ADDRESS_LO
  2395.         lea     esi, [ebx + device.mac]
  2396.         outsw
  2397.         inc     dx
  2398.         inc     dx
  2399.         outsw
  2400.         inc     dx
  2401.         inc     dx
  2402.         outsw
  2403.  
  2404.  
  2405. ;----------------------------
  2406. ; Read MAC
  2407.  
  2408. align 4
  2409. read_mac:
  2410.  
  2411.         DEBUGF 1,"Reading MAC\n"
  2412.  
  2413.         set_io  [ebx + device.io_addr], 0
  2414.         set_io  [ebx + device.io_addr], REG_COMMAND
  2415.  
  2416. ; switch to register window 2
  2417.         mov     ax, SELECT_REGISTER_WINDOW+2
  2418.         out     dx, ax
  2419.  
  2420. ; Read the MAC and write it to device.mac
  2421.         set_io  [ebx + device.io_addr], REG_STATION_ADDRESS_LO
  2422.         lea     edi, [ebx + device.mac]
  2423.         insw
  2424.         inc     dx
  2425.         inc     dx
  2426.         insw
  2427.         inc     dx
  2428.         inc     dx
  2429.         insw
  2430.  
  2431.         DEBUGF 1,"%x-%x-%x-%x-%x-%x\n", \
  2432.         [ebx + device.mac+0]:2,[ebx + device.mac+1]:2,[ebx + device.mac+2]:2,\
  2433.         [ebx + device.mac+3]:2,[ebx + device.mac+4]:2,[ebx + device.mac+5]:2
  2434.  
  2435.         ret
  2436.  
  2437.  
  2438. ;------------------------------------
  2439. ; Read MAC from eeprom
  2440.  
  2441. align 4
  2442. read_mac_eeprom:
  2443.  
  2444.         DEBUGF 1,"Reading MAC from eeprom\n"
  2445.  
  2446. ; read MAC from eeprom and write it to device.mac
  2447.         mov     ecx, 3
  2448.   .mac_loop:
  2449.         lea     ax, [EEPROM_REG_OEM_NODE_ADDR+ecx-1]
  2450.         push    ecx
  2451.         call    read_eeprom
  2452.         pop     ecx
  2453.         xchg    ah, al
  2454.         mov     word [ebx + device.mac+ecx*2-2], ax
  2455.         loop    .mac_loop
  2456.  
  2457.         DEBUGF 1,"%x-%x-%x-%x-%x-%x\n",\
  2458.         [ebx + device.mac+0]:2,[ebx + device.mac+1]:2,[ebx + device.mac+2]:2,\
  2459.         [ebx + device.mac+3]:2,[ebx + device.mac+4]:2,[ebx + device.mac+5]:2
  2460.  
  2461.         ret
  2462.  
  2463.  
  2464.  
  2465.  
  2466.  
  2467. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2468. ;;                          ;;
  2469. ;; Vortex Interrupt handler ;;
  2470. ;;                          ;;
  2471. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2472. align 16
  2473. int_vortex:
  2474.  
  2475.         push    ebx esi edi
  2476.  
  2477.         mov     ebx, [esp+4*4]
  2478.         DEBUGF  1,"INT for 0x%x\n", ebx
  2479.  
  2480. ; TODO? if we are paranoid, we can check that the value from ebx is present in the current device_list
  2481.  
  2482.         set_io  [ebx + device.io_addr], 0
  2483.         set_io  [ebx + device.io_addr], REG_INT_STATUS
  2484.         in      ax, dx
  2485.         and     ax, S_5_INTS
  2486.         jnz     .nothing
  2487.  
  2488.         DEBUGF  1,"Status: %x\n", eax:4
  2489.  
  2490.         test    ax, RxComplete
  2491.         jz      .noRX
  2492.  
  2493.         set_io  [ebx + device.io_addr], 0
  2494.   .rx_status_loop:
  2495. ; examine RxStatus
  2496.         set_io  [ebx + device.io_addr], REG_RX_STATUS
  2497.         in      ax, dx
  2498.         test    ax, ax
  2499.         jz      .finish
  2500.  
  2501.         test    ah, 0x80 ; rxIncomplete
  2502.         jnz     .finish
  2503.  
  2504.         test    ah, 0x40
  2505.         jz      .check_length
  2506.  
  2507. ; discard the top frame received advancing the next one
  2508.         set_io  [ebx + device.io_addr], REG_COMMAND
  2509.         mov     ax, (01000b shl 11)
  2510.         out     dx, ax
  2511.         jmp     .rx_status_loop
  2512.  
  2513.   .check_length:
  2514.         and     eax, 0x1fff
  2515.         cmp     eax, MAX_ETH_FRAME_SIZE
  2516.         ja      .discard_frame ; frame is too long discard it
  2517.  
  2518.   .check_dma:
  2519.         mov     ecx, eax
  2520. ; switch to register window 7
  2521.         set_io  [ebx + device.io_addr], 0
  2522.         set_io  [ebx + device.io_addr], REG_COMMAND
  2523.         mov     ax, SELECT_REGISTER_WINDOW+7
  2524.         out     dx, ax
  2525. ; check for master operation in progress
  2526.         set_io  [ebx + device.io_addr], REG_MASTER_STATUS
  2527.         in      ax, dx
  2528.  
  2529.         test    ah, 0x80
  2530.         jnz     .finish
  2531.  
  2532.   .read_frame:
  2533. ; program buffer address to read in
  2534.         push    ecx
  2535.         invoke  NetAlloc, MAX_ETH_FRAME_SIZE + NET_BUFF.data
  2536.         pop     ecx
  2537.         test    eax, eax
  2538.         jz      .finish
  2539.  
  2540.         push    .discard_frame
  2541.         push    eax
  2542.         mov     [eax + NET_BUFF.length], ecx
  2543.         mov     [eax + NET_BUFF.device], ebx
  2544.         mov     [eax + NET_BUFF.offset], NET_BUFF.data
  2545.         invoke  GetPhysAddr
  2546.         add     eax, NET_BUFF.data
  2547.         set_io  [ebx + device.io_addr], REG_MASTER_ADDRESS
  2548.         out     dx, eax
  2549.  
  2550. ; program frame length
  2551.         set_io  [ebx + device.io_addr], REG_MASTER_LEN
  2552.         mov     ax, 1560
  2553.         out     dx, ax
  2554.  
  2555. ; start DMA Up
  2556.         set_io  [ebx + device.io_addr], REG_COMMAND
  2557.         mov     ax, (10100b shl 11) ; StartDMAUp
  2558.         out     dx, ax
  2559.  
  2560. ; check for master operation in progress
  2561.         set_io  [ebx + device.io_addr], REG_MASTER_STATUS   ; TODO: use timeout and reset after timeout expired
  2562.   .dma_loop:
  2563.         in      ax, dx
  2564.         test    ah, 0x80
  2565.         jnz     .dma_loop
  2566.  
  2567. ; registrate the received packet to kernel
  2568.         jmp     [EthInput]
  2569.  
  2570. ; discard the top frame received
  2571.   .discard_frame:
  2572.         set_io  [ebx + device.io_addr], 0
  2573.         set_io  [ebx + device.io_addr], REG_COMMAND
  2574.         mov     ax, (01000b shl 11)
  2575.         out     dx, ax
  2576.  
  2577.   .finish:
  2578.   .noRX:
  2579.         test    ax, DMADone
  2580.         jz      .noDMA
  2581.  
  2582.         push    ax
  2583.  
  2584.         set_io  [ebx + device.io_addr], 0
  2585.         set_io  [ebx + device.io_addr], 12
  2586.         in      ax, dx
  2587.         test    ax, 0x1000
  2588.         jz      .nodmaclear
  2589.  
  2590.         mov     ax, 0x1000
  2591.         out     dx, ax
  2592.  
  2593.   .nodmaclear:
  2594.         pop     ax
  2595.  
  2596.         DEBUGF  1, "DMA Done!\n", cx
  2597.  
  2598.   .noDMA:
  2599.   .ACK:
  2600.         set_io  [ebx + device.io_addr], 0
  2601.         set_io  [ebx + device.io_addr], REG_COMMAND
  2602.         mov     ax, AckIntr + IntReq + IntLatch
  2603.         out     dx, ax
  2604.  
  2605.         pop     edi esi ebx
  2606.         xor     eax, eax
  2607.         inc     eax
  2608.  
  2609.         ret
  2610.  
  2611.   .nothing:
  2612.         pop     edi esi ebx
  2613.         xor     eax, eax
  2614.  
  2615.         ret
  2616.  
  2617.  
  2618.  
  2619.  
  2620. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2621. ;;                             ;;
  2622. ;; Boomerang Interrupt handler ;;
  2623. ;;                             ;;
  2624. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2625. align 16
  2626. int_boomerang:
  2627.  
  2628.         push    ebx esi edi
  2629.  
  2630.         mov     ebx, [esp+4*4]
  2631.         DEBUGF  1,"INT for 0x%x\n", ebx
  2632.  
  2633. ; TODO? if we are paranoid, we can check that the value from ebx is present in the current device_list
  2634.  
  2635.         set_io  [ebx + device.io_addr], 0
  2636.         set_io  [ebx + device.io_addr], REG_INT_STATUS
  2637.         in      ax, dx
  2638.         test    ax, S_5_INTS
  2639.         jz      .nothing
  2640.   .got_it:
  2641.         DEBUGF  1,"Status: %x\n", ax
  2642.  
  2643.         push    ax
  2644.  
  2645. ; disable all INTS
  2646.  
  2647.         set_io  [ebx + device.io_addr], REG_COMMAND
  2648.         mov     ax, SetIntrEnb
  2649.         out     dx, ax
  2650.  
  2651. ;--------------------------------------------------------------------------
  2652.         test    word[esp], UpComplete
  2653.         jz      .noRX
  2654.  
  2655.         push    ebx
  2656.  
  2657.   .receive:
  2658.         DEBUGF  1,"UpComplete\n"
  2659.  
  2660. ; check if packet is uploaded
  2661.         mov     esi, [ebx + device.curr_rx]
  2662.         test    byte [esi+rx_desc.pkt_status+1], 0x80 ; upPktComplete
  2663.         jz      .finish
  2664.         DEBUGF  1, "Current RX desc: %x\n", esi
  2665. ; packet is uploaded check for any error
  2666.   .check_error:
  2667.         test    byte [esi + rx_desc.pkt_status+1], 0x40 ; upError
  2668.         jz      .copy_packet_length
  2669.         DEBUGF  1,"Error in packet\n"
  2670.         and     [esi + rx_desc.pkt_status], 0           ; mark packet as read
  2671.         jmp     .finish
  2672.   .copy_packet_length:
  2673.         mov     ecx, [esi + rx_desc.pkt_status]
  2674.         and     ecx, 0x1fff
  2675.  
  2676. ;        cmp     ecx, MAX_ETH_PKT_SIZE
  2677. ;        jbe     .copy_packet
  2678. ;        and     [esi+rx_desc.pkt_status], 0
  2679. ;        jmp     .finish
  2680. ;  .copy_packet:
  2681.  
  2682.         DEBUGF  1, "Received %u bytes in buffer %x\n", ecx, [esi + rx_desc.realaddr]:8
  2683.  
  2684.         push    dword .loop ;.finish
  2685.         mov     eax, [esi + rx_desc.realaddr]
  2686.         push    eax
  2687.         mov     [eax + NET_BUFF.length], ecx
  2688.         mov     [eax + NET_BUFF.device], ebx
  2689.         mov     [eax + NET_BUFF.offset], NET_BUFF.data
  2690.  
  2691. ; update statistics
  2692.         inc     [ebx + device.packets_rx]
  2693.         add     dword [ebx + device.bytes_rx], ecx
  2694.         adc     dword [ebx + device.bytes_rx + 4], 0
  2695.  
  2696. ; update rx descriptor (Alloc new buffer for next packet)
  2697.         invoke  NetAlloc, MAX_ETH_FRAME_SIZE + NET_BUFF.data
  2698.         mov     [esi + rx_desc.realaddr], eax
  2699.         invoke  GetPhysAddr
  2700.         add     eax, NET_BUFF.data
  2701.         mov     [esi + rx_desc.frag_addr], eax
  2702.         and     [esi + rx_desc.pkt_status], 0
  2703.         mov     [esi + rx_desc.frag_len], MAX_ETH_FRAME_SIZE or (1 shl 31)
  2704.  
  2705. ; Update rx descriptor pointer
  2706.         add     esi, sizeof.rx_desc
  2707.         lea     ecx, [ebx + device.rx_desc_buffer+(NUM_RX_DESC)*sizeof.rx_desc]
  2708.         cmp     esi, ecx
  2709.         jb      @f
  2710.         lea     esi, [ebx + device.rx_desc_buffer]
  2711.        @@:
  2712.         mov     [ebx + device.curr_rx], esi
  2713.         DEBUGF  1, "Next RX desc: %x\n", esi
  2714.  
  2715.         jmp     [EthInput]
  2716.   .loop:
  2717.  
  2718.         mov     ebx, [esp]
  2719.         jmp     .receive
  2720.  
  2721.   .finish:
  2722.         pop     ebx
  2723.  
  2724. ; check if the NIC is in the upStall state
  2725.         set_io  [ebx + device.io_addr], 0
  2726.         set_io  [ebx + device.io_addr], REG_UP_PKT_STATUS
  2727.         in      eax, dx
  2728.         test    ah, 0x20             ; UpStalled
  2729.         jz      .noUpUnStall
  2730.  
  2731.         DEBUGF  1, "upUnStalling\n"
  2732. ; issue upUnStall command
  2733.         set_io  [ebx + device.io_addr], REG_COMMAND
  2734.         mov     ax, ((11b shl 12)+1) ; upUnStall
  2735.         out     dx, ax
  2736.  
  2737.         ;;;; FIXME: make upunstall work
  2738.  
  2739.   .noUpUnStall:
  2740.   .noRX:
  2741.         test    word[esp], DownComplete
  2742.         jz      .noTX
  2743.         DEBUGF  1, "Downcomplete!\n"
  2744.  
  2745.         mov     ecx, NUM_TX_DESC
  2746.         lea     esi, [ebx + device.tx_desc_buffer]
  2747.   .txloop:
  2748.         test    [esi+tx_desc.frame_start_hdr], 1 shl 31
  2749.         jz      .maybenext
  2750.  
  2751.         and     [esi+tx_desc.frame_start_hdr], 0
  2752.         push    ecx
  2753.         invoke  NetFree, [esi+tx_desc.realaddr]
  2754.         pop     ecx
  2755.  
  2756.   .maybenext:
  2757.         add     esi, sizeof.tx_desc
  2758.         dec     ecx
  2759.         jnz     .txloop
  2760.  
  2761.   .noTX:
  2762.         pop     ax
  2763.  
  2764.         set_io  [ebx + device.io_addr], 0
  2765.         set_io  [ebx + device.io_addr], REG_COMMAND
  2766.         or      ax, AckIntr
  2767.         out     dx, ax
  2768.  
  2769.         set_io  [ebx + device.io_addr], REG_INT_STATUS
  2770.         in      ax, dx
  2771.         test    ax, S_5_INTS
  2772.         jnz     .got_it
  2773.  
  2774. ;re-enable ints
  2775.         set_io  [ebx + device.io_addr], REG_COMMAND
  2776.         mov     ax, SetIntrEnb + S_5_INTS
  2777.         out     dx, ax
  2778.  
  2779.         pop     edi esi ebx
  2780.         xor     eax, eax
  2781.         inc     eax
  2782.  
  2783.         ret
  2784.  
  2785.   .nothing:
  2786.         pop     edi esi ebx
  2787.         xor     eax, eax
  2788.  
  2789.         ret
  2790.  
  2791.  
  2792.  
  2793.  
  2794. ; End of code
  2795.  
  2796. data fixups
  2797. end data
  2798.  
  2799. include '../peimport.inc'
  2800.  
  2801. my_service           db '3C59X',0                    ; max 16 chars include zero
  2802.  
  2803. macro strtbl name, [string]
  2804. {
  2805. common
  2806.         label name dword
  2807. forward
  2808.         local label
  2809.         dd label
  2810. forward
  2811.         label db string, 0
  2812. }
  2813.  
  2814. strtbl link_str, \
  2815.         "No valid link type detected", \
  2816.         "10BASE-T half duplex", \
  2817.         "10BASE-T full-duplex", \
  2818.         "100BASE-TX half duplex", \
  2819.         "100BASE-TX full duplex", \
  2820.         "100BASE-T4", \
  2821.         "100BASE-FX", \
  2822.         "10Mbps AUI", \
  2823.         "10Mbps COAX (BNC)", \
  2824.         "miiDevice - not supported"
  2825.  
  2826. strtbl hw_str, \
  2827.         "3c590 Vortex 10Mbps", \
  2828.         "3c592 EISA 10Mbps Demon/Vortex", \
  2829.         "3c597 EISA Fast Demon/Vortex", \
  2830.         "3c595 Vortex 100baseTx", \
  2831.         "3c595 Vortex 100baseT4", \
  2832.         "3c595 Vortex 100base-MII", \
  2833.         "3c900 Boomerang 10baseT", \
  2834.         "3c900 Boomerang 10Mbps Combo", \
  2835.         "3c900 Cyclone 10Mbps TPO", \
  2836.         "3c900 Cyclone 10Mbps Combo", \
  2837.         "3c900 Cyclone 10Mbps TPC", \
  2838.         "3c900B-FL Cyclone 10base-FL", \
  2839.         "3c905 Boomerang 100baseTx", \
  2840.         "3c905 Boomerang 100baseT4", \
  2841.         "3c905B Cyclone 100baseTx", \
  2842.         "3c905B Cyclone 10/100/BNC", \
  2843.         "3c905B-FX Cyclone 100baseFx", \
  2844.         "3c905C Tornado", \
  2845.         "3c980 Cyclone", \
  2846.         "3c982 Dual Port Server Cyclone", \
  2847.         "3cSOHO100-TX Hurricane", \
  2848.         "3c555 Laptop Hurricane", \
  2849.         "3c556 Laptop Tornado", \
  2850.         "3c556B Laptop Hurricane", \
  2851.         "3c575 [Megahertz] 10/100 LAN CardBus", \
  2852.         "3c575 Boomerang CardBus", \
  2853.         "3CCFE575BT Cyclone CardBus", \
  2854.         "3CCFE575CT Tornado CardBus", \
  2855.         "3CCFE656 Cyclone CardBus", \
  2856.         "3CCFEM656B Cyclone+Winmodem CardBus", \
  2857.         "3CXFEM656C Tornado+Winmodem CardBus", \
  2858.         "3c450 HomePNA Tornado", \
  2859.         "3c920 Tornado", \
  2860.         "3c982 Hydra Dual Port A", \
  2861.         "3c982 Hydra Dual Port B", \
  2862.         "3c905B-T4", \
  2863.         "3c920B-EMB-WNM Tornado"
  2864.  
  2865.  
  2866.  
  2867. align 4
  2868. hw_versions:
  2869. dw 0x5900, IS_VORTEX                                                                                                            ; 3c590 Vortex 10Mbps
  2870. dw 0x5920, IS_VORTEX                                                                                                            ; 3c592 EISA 10Mbps Demon/Vortex
  2871. dw 0x5970, IS_VORTEX                                                                                                            ; 3c597 EISA Fast Demon/Vortex
  2872. dw 0x5950, IS_VORTEX                                                                                                            ; 3c595 Vortex 100baseTx
  2873. dw 0x5951, IS_VORTEX                                                                                                            ; 3c595 Vortex 100baseT4
  2874. dw 0x5952, IS_VORTEX                                                                                                            ; 3c595 Vortex 100base-MII
  2875. dw 0x9000, IS_BOOMERANG                                                                                                         ; 3c900 Boomerang 10baseT
  2876. dw 0x9001, IS_BOOMERANG                                                                                                         ; 3c900 Boomerang 10Mbps Combo
  2877. dw 0x9004, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM                                                                                 ; 3c900 Cyclone 10Mbps TPO
  2878. dw 0x9005, IS_CYCLONE or HAS_HWCKSM                                                                                             ; 3c900 Cyclone 10Mbps Combo
  2879. dw 0x9006, IS_CYCLONE or HAS_HWCKSM                                                                                             ; 3c900 Cyclone 10Mbps TPC
  2880. dw 0x900A, IS_CYCLONE or HAS_HWCKSM                                                                                             ; 3c900B-FL Cyclone 10base-FL
  2881. dw 0x9050, IS_BOOMERANG or HAS_MII                                                                                              ; 3c905 Boomerang 100baseTx
  2882. dw 0x9051, IS_BOOMERANG or HAS_MII                                                                                              ; 3c905 Boomerang 100baseT4
  2883. dw 0x9055, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE                                                               ; 3c905B Cyclone 100baseTx
  2884. dw 0x9058, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM                                                                                 ; 3c905B Cyclone 10/100/BNC
  2885. dw 0x905A, IS_CYCLONE or HAS_HWCKSM                                                                                             ; 3c905B-FX Cyclone 100baseFx
  2886. dw 0x9200, IS_TORNADO or HAS_NWAY or HAS_HWCKSM                                                                                 ; 3c905C Tornado
  2887. dw 0x9800, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM                                                                                 ; 3c980 Cyclone
  2888. dw 0x9805, IS_TORNADO or HAS_NWAY or HAS_HWCKSM                                                                                 ; 3c982 Dual Port Server Cyclone
  2889. dw 0x7646, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM                                                                                 ; 3cSOHO100-TX Hurricane
  2890. dw 0x5055, IS_CYCLONE or EEPROM_8BIT or HAS_HWCKSM                                                                              ; 3c555 Laptop Hurricane
  2891. dw 0x6055, IS_TORNADO or HAS_NWAY or EEPROM_8BIT or HAS_CB_FNS or INVERT_MII_PWR or HAS_HWCKSM                                  ; 3c556 Laptop Tornado
  2892. dw 0x6056, IS_TORNADO or HAS_NWAY or EEPROM_OFFSET or HAS_CB_FNS or INVERT_MII_PWR or HAS_HWCKSM                                ; 3c556B Laptop Hurricane
  2893. dw 0x5b57, IS_BOOMERANG or HAS_MII or EEPROM_8BIT                                                                               ; 3c575 [Megahertz] 10/100 LAN CardBus
  2894. dw 0x5057, IS_BOOMERANG or HAS_MII or EEPROM_8BIT                                                                               ; 3c575 Boomerang CardBus
  2895. dw 0x5157, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_LED_PWR or HAS_HWCKSM                                  ; 3CCFE575BT Cyclone CardBus
  2896. dw 0x5257, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or MAX_COLLISION_RESET or HAS_HWCKSM           ; 3CCFE575CT Tornado CardBus
  2897. dw 0x6560, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or INVERT_LED_PWR or HAS_HWCKSM                ; 3CCFE656 Cyclone CardBus
  2898. dw 0x6562, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or INVERT_LED_PWR or HAS_HWCKSM                ; 3CCFEM656B Cyclone+Winmodem CardBus
  2899. dw 0x6564, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR or MAX_COLLISION_RESET or HAS_HWCKSM           ; 3CXFEM656C Tornado+Winmodem CardBus
  2900. dw 0x4500, IS_TORNADO or HAS_NWAY or HAS_HWCKSM                                                                                 ; 3c450 HomePNA Tornado
  2901. dw 0x9201, IS_TORNADO or HAS_NWAY or HAS_HWCKSM                                                                                 ; 3c920 Tornado
  2902. dw 0x1201, IS_TORNADO or HAS_HWCKSM or HAS_NWAY                                                                                 ; 3c982 Hydra Dual Port A
  2903. dw 0x1202, IS_TORNADO or HAS_HWCKSM or HAS_NWAY                                                                                 ; 3c982 Hydra Dual Port B
  2904. dw 0x9056, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE                                                               ; 3c905B-T4
  2905. dw 0x9210, IS_TORNADO or HAS_NWAY or HAS_HWCKSM                                                                                 ; 3c920B-EMB-WNM Tornado
  2906. HW_VERSIONS_SIZE = $ - hw_versions
  2907.  
  2908. include_debug_strings                           ; All data wich FDO uses will be included here
  2909.  
  2910. align 4
  2911. devices         dd 0
  2912. device_list     rd MAX_DEVICES                  ; This list contains all pointers to device structures the driver is handling
  2913.  
  2914.  
  2915.  
  2916.  
  2917.