Subversion Repositories Kolibri OS

Rev

Rev 5074 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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