Subversion Repositories Kolibri OS

Rev

Rev 3156 | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                  ;;
  3. ;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.     ;;
  4. ;; Distributed under terms of the GNU General Public License        ;;
  5. ;;                                                                  ;;
  6. ;;  PCnet driver for KolibriOS                                      ;;
  7. ;;                                                                  ;;
  8. ;;  By hidnplayr & clevermouse                                      ;;
  9. ;;                                                                  ;;
  10. ;;  Based on the PCnet32 driver for MenuetOS, by Jarek Pelczar      ;;
  11. ;;                                                                  ;;
  12. ;;          GNU GENERAL PUBLIC LICENSE                              ;;
  13. ;;             Version 2, June 1991                                 ;;
  14. ;;                                                                  ;;
  15. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  16.  
  17. format MS COFF
  18.  
  19.         API_VERSION             =   0x01000100
  20.  
  21.         DEBUG                   =   1
  22.         __DEBUG__               =   1
  23.         __DEBUG_LEVEL__         =   1
  24.  
  25.         MAX_DEVICES =   4
  26.         MAX_ETH_FRAME_SIZE =   1514
  27.  
  28. include 'proc32.inc'
  29. include 'imports.inc'
  30. include 'fdo.inc'
  31. include 'netdrv.inc'
  32.  
  33.  
  34. public START
  35. public service_proc
  36. public version
  37.  
  38.  
  39. virtual at ebx
  40.  
  41.         device:
  42.  
  43.         ETH_DEVICE
  44.  
  45. ; device specific
  46.  
  47.       .private:
  48.       .mode_            dw ?
  49.       .tlen_rlen        dw ?
  50.       .phys_addr        dp ?
  51.       .reserved         dw ?
  52.       .filter           dq ?
  53.       .rx_ring_phys     dd ?
  54.       .tx_ring_phys     dd ?
  55.  
  56.       .cur_rx           db ?
  57.       .cur_tx           db ?
  58.       .dirty_rx         dd ?
  59.       .dirty_tx         dd ?
  60.       .tx_full          db ?
  61.       .options          dd ?
  62.       .full_duplex      db ?
  63.       .chip_version     dd ?
  64.       .mii              db ?
  65.       .ltint            db ?
  66.       .dxsuflo          db ?
  67.       .fset             db ?
  68.       .fdx              db ?
  69.  
  70.       .rx_buffer        dd ?
  71.       .tx_buffer        dd ?
  72.  
  73.       .io_addr          dd ?
  74.       .irq_line         db ?
  75.       .pci_bus          db ?
  76.       .pci_dev          db ?
  77.  
  78.  
  79.       .access_read_csr          dd ?
  80.       .access_write_csr         dd ?
  81.       .access_read_bcr          dd ?
  82.       .access_write_bcr         dd ?
  83.       .access_read_rap          dd ?
  84.       .access_write_rap         dd ?
  85.       .access_reset             dd ?
  86.  
  87.       device_size       = $ - device
  88.  
  89. end virtual
  90.  
  91. struc buf_head {
  92.         .base           dd ?
  93.         .length         dw ?
  94.         .status         dw ?
  95.         .msg_length     dw ?
  96.         .misc           dw ?
  97.         .reserved       dd ?
  98.  
  99.         .size:
  100. }
  101.  
  102. virtual at 0
  103.  buf_head buf_head
  104. end virtual
  105.  
  106.         PCNET_PORT_AUI                =   0x00
  107.         PCNET_PORT_10BT               =   0x01
  108.         PCNET_PORT_GPSI               =   0x02
  109.         PCNET_PORT_MII                =   0x03
  110.         PCNET_PORT_PORTSEL            =   0x03
  111.         PCNET_PORT_ASEL               =   0x04
  112.         PCNET_PORT_100                =   0x40
  113.         PCNET_PORT_FD                 =   0x80
  114.  
  115.         PCNET_DMA_MASK                =   0xffffffff
  116.  
  117.         PCNET_LOG_TX_BUFFERS          =   2
  118.         PCNET_LOG_RX_BUFFERS          =   2
  119.  
  120.         PCNET_TX_RING_SIZE            =   4
  121.         PCNET_TX_RING_MOD_MASK        =   (PCNET_TX_RING_SIZE-1)
  122.         PCNET_TX_RING_LEN_BITS        =   (PCNET_LOG_TX_BUFFERS shl 12)
  123.  
  124.         PCNET_RX_RING_SIZE            =   4
  125.         PCNET_RX_RING_MOD_MASK        =   (PCNET_RX_RING_SIZE-1)
  126.         PCNET_RX_RING_LEN_BITS        =   (PCNET_LOG_RX_BUFFERS shl 4)
  127.  
  128.         PCNET_PKT_BUF_SZ              =   1544
  129.         PCNET_PKT_BUF_SZ_NEG          =   0xf9f8
  130.  
  131.         PCNET_WIO_RDP                 =   0x10
  132.         PCNET_WIO_RAP                 =   0x12
  133.         PCNET_WIO_RESET               =   0x14
  134.         PCNET_WIO_BDP                 =   0x16
  135.         PCNET_DWIO_RDP                =   0x10
  136.         PCNET_DWIO_RAP                =   0x14
  137.         PCNET_DWIO_RESET              =   0x18
  138.         PCNET_DWIO_BDP                =   0x1C
  139.         PCNET_TOTAL_SIZE              =   0x20
  140.  
  141. ; CSR registers
  142.  
  143.         PCNET_CSR_CSR                 =   0x00
  144.         PCNET_CSR_IAB0                =   0x01
  145.         PCNET_CSR_IAB1                =   0x02
  146.         PCNET_CSR_IMR                 =   0x03
  147.         PCNET_CSR_TFEAT               =   0x04
  148.         PCNET_CSR_EXTCTL1             =   0x05
  149.         PCNET_CSR_DTBLLEN             =   0x06
  150.         PCNET_CSR_EXTCTL2             =   0x07
  151.         PCNET_CSR_MAR0                =   0x08
  152.         PCNET_CSR_MAR1                =   0x09
  153.         PCNET_CSR_MAR2                =   0x0A
  154.         PCNET_CSR_MAR3                =   0x0B
  155.         PCNET_CSR_PAR0                =   0x0C
  156.         PCNET_CSR_PAR1                =   0x0D
  157.         PCNET_CSR_PAR2                =   0x0E
  158.         PCNET_CSR_MODE                =   0x0F
  159.         PCNET_CSR_RXADDR0             =   0x18
  160.         PCNET_CSR_RXADDR1             =   0x19
  161.         PCNET_CSR_TXADDR0             =   0x1E
  162.         PCNET_CSR_TXADDR1             =   0x1F
  163.         PCNET_CSR_TXPOLL              =   0x2F
  164.         PCNET_CSR_RXPOLL              =   0x31
  165.         PCNET_CSR_RXRINGLEN           =   0x4C
  166.         PCNET_CSR_TXRINGLEN           =   0x4E
  167.         PCNET_CSR_DMACTL              =   0x50
  168.         PCNET_CSR_BUSTIMER            =   0x52
  169.         PCNET_CSR_MEMERRTIMEO         =   0x64
  170.         PCNET_CSR_ONNOWMISC           =   0x74
  171.         PCNET_CSR_ADVFEAT             =   0x7A
  172.         PCNET_CSR_MACCFG              =   0x7D
  173.         PCNET_CSR_CHIPID0             =   0x58
  174.         PCNET_CSR_CHIPID1             =   0x59
  175.  
  176. ; Control and Status Register (CSR0)
  177.  
  178.         PCNET_CSR_INIT                =   1 shl 0
  179.         PCNET_CSR_START               =   1 shl 1
  180.         PCNET_CSR_STOP                =   1 shl 2
  181.         PCNET_CSR_TX                  =   1 shl 3
  182.         PCNET_CSR_TXON                =   1 shl 4
  183.         PCNET_CSR_RXON                =   1 shl 5
  184.         PCNET_CSR_INTEN               =   1 shl 6
  185.         PCNET_CSR_INTR                =   1 shl 7
  186.         PCNET_CSR_IDONE               =   1 shl 8
  187.         PCNET_CSR_TINT                =   1 shl 9
  188.         PCNET_CSR_RINT                =   1 shl 10
  189.         PCNET_CSR_MERR                =   1 shl 11
  190.         PCNET_CSR_MISS                =   1 shl 12
  191.         PCNET_CSR_CERR                =   1 shl 13
  192.  
  193. ; Interrupt masks and deferral control (CSR3)
  194.  
  195.         PCNET_IMR_BSWAP               =   0x0004
  196.         PCNET_IMR_ENMBA               =   0x0008  ; enable modified backoff alg
  197.         PCNET_IMR_DXMT2PD             =   0x0010
  198.         PCNET_IMR_LAPPEN              =   0x0020  ; lookahead packet processing enb
  199.         PCNET_IMR_DXSUFLO             =   0x0040  ; disable TX stop on underflow
  200.         PCNET_IMR_IDONE               =   0x0100
  201.         PCNET_IMR_TINT                =   0x0200
  202.         PCNET_IMR_RINT                =   0x0400
  203.         PCNET_IMR_MERR                =   0x0800
  204.         PCNET_IMR_MISS                =   0x1000
  205.  
  206.         PCNET_IMR                     =   PCNET_IMR_TINT+PCNET_IMR_RINT+PCNET_IMR_IDONE+PCNET_IMR_MERR+PCNET_IMR_MISS
  207.  
  208. ; Test and features control (CSR4)
  209.  
  210.         PCNET_TFEAT_TXSTRTMASK        =   0x0004
  211.         PCNET_TFEAT_TXSTRT            =   0x0008
  212.         PCNET_TFEAT_RXCCOFLOWM        =   0x0010  ; Rx collision counter oflow
  213.         PCNET_TFEAT_RXCCOFLOW         =   0x0020
  214.         PCNET_TFEAT_UINT              =   0x0040
  215.         PCNET_TFEAT_UINTREQ           =   0x0080
  216.         PCNET_TFEAT_MISSOFLOWM        =   0x0100
  217.         PCNET_TFEAT_MISSOFLOW         =   0x0200
  218.         PCNET_TFEAT_STRIP_FCS         =   0x0400
  219.         PCNET_TFEAT_PAD_TX            =   0x0800
  220.         PCNET_TFEAT_TXDPOLL           =   0x1000
  221.         PCNET_TFEAT_DMAPLUS           =   0x4000
  222.  
  223. ; Extended control and interrupt 1 (CSR5)
  224.  
  225.         PCNET_EXTCTL1_SPND            =   0x0001  ; suspend
  226.         PCNET_EXTCTL1_MPMODE          =   0x0002  ; magic packet mode
  227.         PCNET_EXTCTL1_MPENB           =   0x0004  ; magic packet enable
  228.         PCNET_EXTCTL1_MPINTEN         =   0x0008  ; magic packet interrupt enable
  229.         PCNET_EXTCTL1_MPINT           =   0x0010  ; magic packet interrupt
  230.         PCNET_EXTCTL1_MPPLBA          =   0x0020  ; magic packet phys. logical bcast
  231.         PCNET_EXTCTL1_EXDEFEN         =   0x0040  ; excessive deferral interrupt enb.
  232.         PCNET_EXTCTL1_EXDEF           =   0x0080  ; excessive deferral interrupt
  233.         PCNET_EXTCTL1_SINTEN          =   0x0400  ; system interrupt enable
  234.         PCNET_EXTCTL1_SINT            =   0x0800  ; system interrupt
  235.         PCNET_EXTCTL1_LTINTEN         =   0x4000  ; last TX interrupt enb
  236.         PCNET_EXTCTL1_TXOKINTD        =   0x8000  ; TX OK interrupt disable
  237.  
  238. ; RX/TX descriptor len (CSR6)
  239.  
  240.         PCNET_DTBLLEN_RLEN            =   0x0F00
  241.         PCNET_DTBLLEN_TLEN            =   0xF000
  242.  
  243. ; Extended control and interrupt 2 (CSR7)
  244.  
  245.         PCNET_EXTCTL2_MIIPDTINTE      =   0x0001
  246.         PCNET_EXTCTL2_MIIPDTINT       =   0x0002
  247.         PCNET_EXTCTL2_MCCIINTE        =   0x0004
  248.         PCNET_EXTCTL2_MCCIINT         =   0x0008
  249.         PCNET_EXTCTL2_MCCINTE         =   0x0010
  250.         PCNET_EXTCTL2_MCCINT          =   0x0020
  251.         PCNET_EXTCTL2_MAPINTE         =   0x0040
  252.         PCNET_EXTCTL2_MAPINT          =   0x0080
  253.         PCNET_EXTCTL2_MREINTE         =   0x0100
  254.         PCNET_EXTCTL2_MREINT          =   0x0200
  255.         PCNET_EXTCTL2_STINTE          =   0x0400
  256.         PCNET_EXTCTL2_STINT           =   0x0800
  257.         PCNET_EXTCTL2_RXDPOLL         =   0x1000
  258.         PCNET_EXTCTL2_RDMD            =   0x2000
  259.         PCNET_EXTCTL2_RXFRTG          =   0x4000
  260.         PCNET_EXTCTL2_FASTSPNDE       =   0x8000
  261.  
  262. ; Mode (CSR15)
  263.  
  264.         PCNET_MODE_RXD                =   0x0001  ; RX disable
  265.         PCNET_MODE_TXD                =   0x0002  ; TX disable
  266.         PCNET_MODE_LOOP               =   0x0004  ; loopback enable
  267.         PCNET_MODE_TXCRCD             =   0x0008
  268.         PCNET_MODE_FORCECOLL          =   0x0010
  269.         PCNET_MODE_RETRYD             =   0x0020
  270.         PCNET_MODE_INTLOOP            =   0x0040
  271.         PCNET_MODE_PORTSEL            =   0x0180
  272.         PCNET_MODE_RXVPAD             =   0x2000
  273.         PCNET_MODE_RXNOBROAD          =   0x4000
  274.         PCNET_MODE_PROMISC            =   0x8000
  275.  
  276. ; BCR (Bus Control Registers)
  277.  
  278.         PCNET_BCR_MMRA                =   0x00    ; Master Mode Read Active
  279.         PCNET_BCR_MMW                 =   0x01    ; Master Mode Write Active
  280.         PCNET_BCR_MISCCFG             =   0x02
  281.         PCNET_BCR_LED0                =   0x04
  282.         PCNET_BCR_LED1                =   0x05
  283.         PCNET_BCR_LED2                =   0x06
  284.         PCNET_BCR_LED3                =   0x07
  285.         PCNET_BCR_DUPLEX              =   0x09
  286.         PCNET_BCR_BUSCTL              =   0x12
  287.         PCNET_BCR_EECTL               =   0x13
  288.         PCNET_BCR_SSTYLE              =   0x14
  289.         PCNET_BCR_PCILAT              =   0x16
  290.         PCNET_BCR_PCISUBVENID         =   0x17
  291.         PCNET_BCR_PCISUBSYSID         =   0x18
  292.         PCNET_BCR_SRAMSIZE            =   0x19
  293.         PCNET_BCR_SRAMBOUND           =   0x1A
  294.         PCNET_BCR_SRAMCTL             =   0x1B
  295.         PCNET_BCR_MIICTL              =   0x20
  296.         PCNET_BCR_MIIADDR             =   0x21
  297.         PCNET_BCR_MIIDATA             =   0x22
  298.         PCNET_BCR_PCIVENID            =   0x23
  299.         PCNET_BCR_PCIPCAP             =   0x24
  300.         PCNET_BCR_DATA0               =   0x25
  301.         PCNET_BCR_DATA1               =   0x26
  302.         PCNET_BCR_DATA2               =   0x27
  303.         PCNET_BCR_DATA3               =   0x28
  304.         PCNET_BCR_DATA4               =   0x29
  305.         PCNET_BCR_DATA5               =   0x2A
  306.         PCNET_BCR_DATA6               =   0x2B
  307.         PCNET_BCR_DATA7               =   0x2C
  308.         PCNET_BCR_ONNOWPAT0           =   0x2D
  309.         PCNET_BCR_ONNOWPAT1           =   0x2E
  310.         PCNET_BCR_ONNOWPAT2           =   0x2F
  311.         PCNET_BCR_PHYSEL              =   0x31
  312.  
  313. ; RX status register
  314.  
  315.         PCNET_RXSTAT_BPE              =   0x0080  ; bus parity error
  316.         PCNET_RXSTAT_ENP              =   0x0100  ; end of packet
  317.         PCNET_RXSTAT_STP              =   0x0200  ; start of packet
  318.         PCNET_RXSTAT_BUFF             =   0x0400  ; buffer error
  319.         PCNET_RXSTAT_CRC              =   0x0800  ; CRC error
  320.         PCNET_RXSTAT_OFLOW            =   0x1000  ; rx overrun
  321.         PCNET_RXSTAT_FRAM             =   0x2000  ; framing error
  322.         PCNET_RXSTAT_ERR              =   0x4000  ; error summary
  323.         PCNET_RXSTAT_OWN              =   0x8000
  324.  
  325. ; TX status register
  326.  
  327.         PCNET_TXSTAT_TRC              =   0x0000000F      ; transmit retries
  328.         PCNET_TXSTAT_RTRY             =   0x04000000      ; retry
  329.         PCNET_TXSTAT_LCAR             =   0x08000000      ; lost carrier
  330.         PCNET_TXSTAT_LCOL             =   0x10000000      ; late collision
  331.         PCNET_TXSTAT_EXDEF            =   0x20000000      ; excessive deferrals
  332.         PCNET_TXSTAT_UFLOW            =   0x40000000      ; transmit underrun
  333.         PCNET_TXSTAT_BUFF             =   0x80000000      ; buffer error
  334.  
  335.         PCNET_TXCTL_OWN               =   0x80000000
  336.         PCNET_TXCTL_ERR               =   0x40000000      ; error summary
  337.         PCNET_TXCTL_ADD_FCS           =   0x20000000      ; add FCS to pkt
  338.         PCNET_TXCTL_MORE_LTINT        =   0x10000000
  339.         PCNET_TXCTL_ONE               =   0x08000000
  340.         PCNET_TXCTL_DEF               =   0x04000000
  341.         PCNET_TXCTL_STP               =   0x02000000
  342.         PCNET_TXCTL_ENP               =   0x01000000
  343.         PCNET_TXCTL_BPE               =   0x00800000
  344.         PCNET_TXCTL_MBO               =   0x0000F000
  345.         PCNET_TXCTL_BUFSZ             =   0x00000FFF
  346.  
  347.  
  348.  
  349.  
  350. section '.flat' code readable align 16
  351.  
  352. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  353. ;;                        ;;
  354. ;; proc START             ;;
  355. ;;                        ;;
  356. ;; (standard driver proc) ;;
  357. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  358.  
  359. proc START stdcall, state:dword
  360.  
  361.         cmp [state], 1
  362.         jne .exit
  363.  
  364.   .entry:
  365.  
  366.         DEBUGF 1,"Loading %s driver\n", my_service
  367.         stdcall RegService, my_service, service_proc
  368.         ret
  369.  
  370.   .fail:
  371.   .exit:
  372.         xor eax, eax
  373.         ret
  374.  
  375. endp
  376.  
  377.  
  378. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  379. ;;                        ;;
  380. ;; proc SERVICE_PROC      ;;
  381. ;;                        ;;
  382. ;; (standard driver proc) ;;
  383. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  384.  
  385. align 4
  386. proc service_proc stdcall, ioctl:dword
  387.  
  388.         mov     edx, [ioctl]
  389.         mov     eax, [IOCTL.io_code]
  390.  
  391. ;------------------------------------------------------
  392.  
  393.         cmp     eax, 0 ;SRV_GETVERSION
  394.         jne     @F
  395.  
  396.         cmp     [IOCTL.out_size], 4
  397.         jb      .fail
  398.         mov     eax, [IOCTL.output]
  399.         mov     [eax], dword API_VERSION
  400.  
  401.         xor     eax, eax
  402.         ret
  403.  
  404. ;------------------------------------------------------
  405.   @@:
  406.         cmp     eax, 1 ;SRV_HOOK
  407.         jne     .fail
  408.  
  409.         cmp     [IOCTL.inp_size], 3               ; Data input must be at least 3 bytes
  410.         jb      .fail
  411.  
  412.         mov     eax, [IOCTL.input]
  413.         cmp     byte [eax], 1                           ; 1 means device number and bus number (pci) are given
  414.         jne     .fail                                   ; other types arent supported for this card yet
  415.  
  416. ; check if the device is already listed
  417.  
  418.         mov     ecx, [devices]
  419.         test    ecx, ecx
  420.         jz      .firstdevice
  421.  
  422.         mov     esi, device_list
  423. ;        mov     eax, [IOCTL.input]                      ; get the pci bus and device numbers
  424.         mov     ax , [eax+1]                            ;
  425.   .nextdevice:
  426.         mov     ebx, [esi]
  427.         cmp     ax , word [device.pci_bus]              ; compare with pci and device num in device list (notice the usage of word instead of byte)
  428.         je      .find_devicenum                         ; Device is already loaded, let's find it's device number
  429.         add     esi, 4
  430.         loop    .nextdevice
  431.  
  432. ; This device doesnt have its own eth_device structure yet, lets create one
  433.  
  434.   .firstdevice:
  435.         cmp     [devices], MAX_DEVICES                  ; First check if the driver can handle one more card
  436.         jae     .fail
  437.  
  438.         allocate_and_clear ebx, device_size, .fail
  439.  
  440. ; Fill in the direct call addresses into the struct
  441.  
  442.         mov     [device.reset], reset
  443.         mov     [device.transmit], transmit
  444.         mov     [device.get_MAC], read_mac
  445.         mov     [device.set_MAC], write_mac
  446.         mov     [device.unload], unload
  447.         mov     [device.name], my_service
  448.  
  449. ; save the pci bus and device numbers
  450.  
  451.         mov     eax, [IOCTL.input]
  452.         mov     cl , [eax+1]
  453.         mov     [device.pci_bus], cl
  454.         mov     cl , [eax+2]
  455.         mov     [device.pci_dev], cl
  456.  
  457. ; Now, it's time to find the base io addres of the PCI device
  458.  
  459.         find_io [device.pci_bus], [device.pci_dev], [device.io_addr]
  460.  
  461. ; We've found the io address, find IRQ now
  462.  
  463.         find_irq [device.pci_bus], [device.pci_dev], [device.irq_line]
  464.  
  465.         DEBUGF  1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\
  466.         [device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:4
  467.  
  468.         allocate_and_clear [device.tx_buffer], PCNET_RX_RING_SIZE * (PCNET_PKT_BUF_SZ + buf_head.size), .err
  469.         allocate_and_clear [device.rx_buffer], PCNET_TX_RING_SIZE * (PCNET_PKT_BUF_SZ + buf_head.size), .err
  470.  
  471. ; Ok, the eth_device structure is ready, let's probe the device
  472. ; Because initialization fires IRQ, IRQ handler must be aware of this device
  473.         mov     eax, [devices]                                        ; Add the device structure to our device list
  474.         mov     [device_list+4*eax], ebx                                 ; (IRQ handler uses this list to find device)
  475.         inc     [devices]                                             ;
  476.  
  477.         call    probe                                                   ; this function will output in eax
  478.         test    eax, eax
  479.         jnz     .destroy                                                        ; If an error occured, exit
  480.  
  481.         mov     [device.type], NET_TYPE_ETH
  482.         call    NetRegDev
  483.         cmp     eax, -1
  484.         je      .destroy
  485.  
  486.         ret
  487.  
  488. ; If the device was already loaded, find the device number and return it in eax
  489.  
  490.   .find_devicenum:
  491.         DEBUGF  1,"Trying to find device number of already registered device\n"
  492.         call    NetPtrToNum                                             ; This kernel procedure converts a pointer to device struct in ebx
  493.                                                                         ; into a device number in edi
  494.         mov     eax, edi                                                ; Application wants it in eax instead
  495.         DEBUGF  1,"Kernel says: %u\n", eax
  496.         ret
  497.  
  498. ; If an error occured, remove all allocated data and exit (returning -1 in eax)
  499.  
  500.   .destroy:
  501.         ; todo: reset device into virgin state
  502.  
  503.         dec     [devices]
  504.   .err:
  505.         DEBUGF  1,"Error, removing all data !\n"
  506.         stdcall KernelFree, [device.rx_buffer]
  507.         stdcall KernelFree, [device.tx_buffer]
  508.         stdcall KernelFree, ebx
  509.  
  510.   .fail:
  511.         or      eax, -1
  512.         ret
  513.  
  514. ;------------------------------------------------------
  515. endp
  516.  
  517.  
  518. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
  519. ;;                                                                        ;;
  520. ;;        Actual Hardware dependent code starts here                      ;;
  521. ;;                                                                        ;;
  522. ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
  523.  
  524. align 4
  525. unload:
  526.         ; TODO: (in this particular order)
  527.         ;
  528.         ; - Stop the device
  529.         ; - Detach int handler
  530.         ; - Remove device from local list (RTL8139_LIST)
  531.         ; - call unregister function in kernel
  532.         ; - Remove all allocated structures and buffers the card used
  533.  
  534.         or      eax,-1
  535.  
  536. ret
  537.  
  538.  
  539. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  540. ;;
  541. ;;  probe: enables the device (if it really is a PCnet device)
  542. ;;
  543. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  544.  
  545. align 4
  546. probe:
  547.         mov     edx, [device.io_addr]
  548.  
  549.         call    wio_reset
  550.  
  551.         xor     ecx, ecx
  552.         call    wio_read_csr
  553.         cmp     eax, 4
  554.         jne     .try_dwio
  555.  
  556.         ; Try Word I/O
  557.         mov     ax , 88
  558.         add     edx, PCNET_WIO_RAP
  559.         out     dx , ax
  560.         nop
  561.         nop
  562.         in      ax , dx
  563.         sub     edx, PCNET_WIO_RAP
  564.         cmp     ax , 88
  565.         jne     .try_dwio
  566.  
  567.         call    switch_to_wio
  568.  
  569.         jmp     .L1
  570.  
  571.   .try_dwio:
  572.         call    dwio_reset
  573.  
  574.         xor     ecx, ecx
  575.         call    dwio_read_csr
  576.         cmp     eax, 4
  577.         jne     .no_dev
  578.  
  579.         ; Try Dword I/O
  580.         add     edx, PCNET_DWIO_RAP
  581.         mov     eax, 88
  582.         out     dx , eax
  583.         nop
  584.         nop
  585.         in      eax, dx
  586.         sub     edx, PCNET_DWIO_RAP
  587.         and     eax, 0xffff
  588.         cmp     eax, 88
  589.         jne     .no_dev
  590.  
  591.         call    switch_to_dwio
  592.  
  593.         jmp     .L1
  594.  
  595.   .no_dev:
  596.         DEBUGF 1,"PCnet device not found!\n"
  597.         mov     eax, 1
  598.         ret
  599.   .L1:
  600.  
  601.         mov     ecx, PCNET_CSR_CHIPID0
  602.         call    [device.access_read_csr]
  603.         mov     esi, eax
  604.  
  605.         mov     ecx, PCNET_CSR_CHIPID1
  606.         call    [device.access_read_csr]
  607.         shl     eax, 16
  608.         or      eax, esi
  609.  
  610.         mov     ecx, eax
  611.         and     ecx, 0xfff
  612.         cmp     ecx, 3
  613.         jne     .no_dev
  614.  
  615.         shr     eax, 12
  616.         and     eax, 0xffff
  617.         mov     [device.chip_version], eax
  618.  
  619.         DEBUGF 1,"chip version ok\n"
  620.         mov     [device.fdx], 0
  621.         mov     [device.mii], 0
  622.         mov     [device.fset], 0
  623.         mov     [device.dxsuflo], 0
  624.         mov     [device.ltint], 0
  625.  
  626.         cmp     eax, 0x2420
  627.         je      .L2
  628.         cmp     eax, 0x2430
  629.         je      .L2
  630.  
  631.         mov     [device.fdx], 1
  632.  
  633.         cmp     eax, 0x2621
  634.         je      .L4
  635.         cmp     eax, 0x2623
  636.         je      .L5
  637.         cmp     eax, 0x2624
  638.         je      .L6
  639.         cmp     eax, 0x2625
  640.         je      .L7
  641.         cmp     eax, 0x2626
  642.         je      .L8
  643.         cmp     eax, 0x2627
  644.         je      .L9
  645.  
  646.         DEBUGF 1,"Invalid chip rev\n"
  647.         jmp     .no_dev
  648.   .L2:
  649.         mov     [device.name], device_l2
  650.         jmp     .L10
  651.   .L4:
  652.         mov     [device.name], device_l4
  653. ;        mov     [device.fdx], 1
  654.         jmp     .L10
  655.   .L5:
  656.         mov     [device.name], device_l5
  657. ;        mov     [device.fdx], 1
  658.         mov     [device.mii], 1
  659.         mov     [device.fset], 1
  660.         mov     [device.ltint], 1
  661.         jmp     .L10
  662.   .L6:
  663.         mov     [device.name], device_l6
  664. ;        mov     [device.fdx], 1
  665.         mov     [device.mii], 1
  666.         mov     [device.fset], 1
  667.         jmp     .L10
  668.   .L7:
  669.         mov     [device.name], device_l7
  670. ;        mov     [device.fdx], 1
  671.         mov     [device.mii], 1
  672.         jmp     .L10
  673.   .L8:
  674.         mov     [device.name], device_l8
  675. ;        mov     [device.fdx], 1
  676.         mov     ecx, PCNET_CSR_RXPOLL
  677.         call    dword [device.access_read_bcr]
  678.         call    dword [device.access_write_bcr]
  679.         jmp     .L10
  680.   .L9:
  681.         mov     [device.name], device_l9
  682. ;        mov     [device.fdx], 1
  683.         mov     [device.mii], 1
  684.   .L10:
  685.         DEBUGF 1,"device name: %s\n",[device.name]
  686.  
  687.         cmp     [device.fset], 1
  688.         jne     .L11
  689.         mov     ecx, PCNET_BCR_BUSCTL
  690.         call    [device.access_read_bcr]
  691.         or      eax, 0x800
  692.         call    [device.access_write_bcr]
  693.  
  694.         mov     ecx, PCNET_CSR_DMACTL
  695.         call    [device.access_read_csr]
  696. ;        and     eax, 0xc00
  697. ;        or      eax, 0xc00
  698.         mov     eax, 0xc00
  699.         call    [device.access_write_csr]
  700.  
  701.         mov     [device.dxsuflo],1
  702.         mov     [device.ltint],1
  703.   .L11:
  704.  
  705.         make_bus_master [device.pci_bus], [device.pci_dev]
  706.  
  707.         mov     eax, PCNET_PORT_ASEL
  708.         mov     [device.options], eax
  709.         mov     [device.mode_], word 0x0003
  710.         mov     [device.tlen_rlen], word (PCNET_TX_RING_LEN_BITS or PCNET_RX_RING_LEN_BITS)
  711.  
  712.         mov     dword [device.filter], 0
  713.         mov     dword [device.filter+4], 0
  714.  
  715.         mov     eax, PCNET_IMR
  716.         mov     ecx, PCNET_CSR_IMR                      ; Write interrupt mask
  717.         call    [device.access_write_csr]
  718.  
  719. align 4
  720. reset:
  721.  
  722. ; attach int handler
  723.  
  724.         movzx   eax, [device.irq_line]
  725.         DEBUGF  1,"Attaching int handler to irq %x\n",eax:1
  726.         stdcall AttachIntHandler, eax, int_handler, dword 0
  727.         test    eax, eax
  728.         jnz     @f
  729.         DEBUGF  1,"\nCould not attach int handler!\n"
  730. ;        or      eax, -1
  731. ;        ret
  732.   @@:
  733.  
  734.         mov     edx, [device.io_addr]
  735.         call    [device.access_reset]
  736.  
  737.         ; Switch pcnet32 to 32bit mode
  738.         mov     ecx, PCNET_BCR_SSTYLE
  739.         mov     eax, 2
  740.         call    [device.access_write_bcr]
  741.  
  742.         ; set/reset autoselect bit
  743.         mov     ecx, PCNET_BCR_MISCCFG
  744.         call    [device.access_read_bcr]
  745.         and     eax,not 2
  746.         test    [device.options], PCNET_PORT_ASEL
  747.         jz      .L1
  748.         or      eax, 2
  749.   .L1:
  750.         call    [device.access_write_bcr]
  751.  
  752.  
  753.         ; Handle full duplex setting
  754.         cmp     byte [device.full_duplex], 0
  755.         je      .L2
  756.         mov     ecx, PCNET_BCR_DUPLEX
  757.         call    [device.access_read_bcr]
  758.         and     eax, not 3
  759.         test    [device.options], PCNET_PORT_FD
  760.         jz      .L3
  761.         or      eax, 1
  762.         cmp     [device.options], PCNET_PORT_FD or PCNET_PORT_AUI
  763.         jne     .L4
  764.         or      eax, 2
  765.         jmp     .L4
  766.   .L3:
  767.         test    [device.options], PCNET_PORT_ASEL
  768.         jz      .L4
  769.         cmp     [device.chip_version], 0x2627
  770.         jne     .L4
  771.         or      eax, 3
  772.   .L4:
  773.         mov     ecx, PCNET_BCR_DUPLEX
  774.         call    [device.access_write_bcr]
  775.   .L2:
  776.  
  777.  
  778.         ; set/reset GPSI bit in test register
  779.         mov     ecx, 124
  780.         call    [device.access_read_csr]
  781.         mov     ecx, [device.options]
  782.         and     ecx, PCNET_PORT_PORTSEL
  783.         cmp     ecx, PCNET_PORT_GPSI
  784.         jne     .L5
  785.         or      eax, 0x10
  786.   .L5:
  787.         call    [device.access_write_csr]
  788.         cmp     [device.mii], 0
  789.         je      .L6
  790.         test    [device.options], PCNET_PORT_ASEL
  791.         jnz     .L6
  792.         mov     ecx, PCNET_BCR_MIICTL
  793.         call    [device.access_read_bcr]
  794.         and     eax,not 0x38
  795.         test    [device.options], PCNET_PORT_FD
  796.         jz      .L7
  797.         or      eax, 0x10
  798.   .L7:
  799.         test    [device.options], PCNET_PORT_100
  800.         jz      .L8
  801.         or      eax, 0x08
  802.   .L8:
  803.         call    [device.access_write_bcr]
  804.         jmp     .L9
  805. .L6:
  806.         test    [device.options], PCNET_PORT_ASEL
  807.         jz      .L9
  808.         mov     ecx, PCNET_BCR_MIICTL
  809.         DEBUGF 1,"ASEL, enable auto-negotiation\n"
  810.         call    [device.access_read_bcr]
  811.         and     eax, not 0x98
  812.         or      eax, 0x20
  813.         call    [device.access_write_bcr]
  814. .L9:
  815.         cmp     [device.ltint],0
  816.         je      .L10
  817.         mov     ecx,5
  818.         call    [device.access_read_csr]
  819.         or      eax,(1 shl 14)
  820.         call    [device.access_write_csr]
  821. .L10:
  822.         mov     eax,[device.options]
  823.         and     eax,PCNET_PORT_PORTSEL
  824.         shl     eax,7
  825.         mov     [device.mode_],ax
  826.         mov     dword [device.filter], -1
  827.         mov     dword [device.filter+4], -1
  828.  
  829.         call    read_mac
  830.  
  831.         lea     esi, [device.mac]
  832.         lea     edi, [device.phys_addr]
  833.         movsd
  834.         movsw
  835.  
  836.         call    init_ring
  837.  
  838.         lea     eax, [device.private]
  839.         GetRealAddr
  840.  
  841.         push    eax
  842.         and     eax, 0xffff
  843.         mov     ecx, 1
  844.         call    [device.access_write_csr]
  845.         pop     eax
  846.         shr     eax,16
  847.         mov     ecx,2
  848.         call    [device.access_write_csr]
  849.  
  850.         mov     ecx,4
  851.         mov     eax,0x0915
  852.         call    [device.access_write_csr]
  853.  
  854.         mov     ecx,0
  855.         mov     eax,1
  856.         call    [device.access_write_csr]
  857.  
  858.         mov     [device.tx_full],0
  859.         mov     [device.cur_rx],0
  860.         mov     [device.cur_tx],0
  861.         mov     [device.dirty_rx],0
  862.         mov     [device.dirty_tx],0
  863.  
  864.         mov     ecx,100
  865. .L11:
  866.         push    ecx
  867.         xor     ecx,ecx
  868.         call    [device.access_read_csr]
  869.         pop     ecx
  870.         test    ax,0x100
  871.         jnz     .L12
  872.         loop    .L11
  873. .L12:
  874.  
  875.         DEBUGF 1,"hardware reset\n"
  876.         xor     ecx, ecx
  877.         mov     eax, 0x0002
  878.         call    [device.access_write_csr]
  879.  
  880.         xor     ecx, ecx
  881.         call    [device.access_read_csr]
  882.  
  883.         xor     ecx, ecx
  884.         mov     eax, PCNET_CSR_INTEN or PCNET_CSR_START
  885.         call    [device.access_write_csr]
  886.  
  887. ; Set the mtu, kernel will be able to send now
  888.         mov     [device.mtu], 1514
  889.  
  890.         DEBUGF 1,"PCNET reset complete\n"
  891.         xor     eax, eax
  892.         ret
  893.  
  894.  
  895. align 4
  896. init_ring:
  897.  
  898.         mov     ecx, PCNET_RX_RING_SIZE
  899.         mov     edi, [device.rx_buffer]
  900.         mov     eax, edi
  901.         GetRealAddr
  902.         mov     [device.rx_ring_phys], eax
  903.         add     eax, PCNET_RX_RING_SIZE * buf_head.size
  904.   .rx_init:
  905.         mov     [edi + buf_head.base], eax
  906.         mov     [edi + buf_head.length], PCNET_PKT_BUF_SZ_NEG
  907.         mov     [edi + buf_head.status], 0x8000
  908.         and     dword [edi + buf_head.msg_length], 0
  909.         and     dword [edi + buf_head.reserved], 0
  910.         add     eax, PCNET_PKT_BUF_SZ
  911.         add     edi, buf_head.size
  912.         loop    .rx_init
  913.  
  914.         mov     ecx, PCNET_TX_RING_SIZE
  915.         mov     edi, [device.tx_buffer]
  916.         mov     eax, edi
  917.         GetRealAddr
  918.         mov     [device.tx_ring_phys], eax
  919.         add     eax, PCNET_TX_RING_SIZE * buf_head.size
  920.   .tx_init:
  921.         mov     [edi + buf_head.base], eax
  922.         and     dword [edi + buf_head.length], 0
  923.         and     dword [edi + buf_head.msg_length], 0
  924.         and     dword [edi + buf_head.reserved], 0
  925.         add     eax, PCNET_PKT_BUF_SZ
  926.         add     edi, buf_head.size
  927.         loop    .tx_init
  928.  
  929.         mov     [device.tlen_rlen], (PCNET_TX_RING_LEN_BITS or PCNET_RX_RING_LEN_BITS)
  930.  
  931.         ret
  932.  
  933.  
  934.  
  935.  
  936. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  937. ;;                                         ;;
  938. ;; Transmit                                ;;
  939. ;;                                         ;;
  940. ;; In: buffer pointer in [esp+4]           ;;
  941. ;;     size of buffer in [esp+8]           ;;
  942. ;;     pointer to device structure in ebx  ;;
  943. ;;                                         ;;
  944. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  945.  
  946. align 4
  947. transmit:
  948.         DEBUGF  1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8]
  949.         mov     eax, [esp+4]
  950.         DEBUGF  1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
  951.         [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
  952.         [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
  953.         [eax+13]:2,[eax+12]:2
  954.  
  955.         cmp     dword [esp+8], 1514
  956.         ja      .nospace                        ; packet is too long
  957.         cmp     dword [esp+8], 60
  958.         jb      .nospace                        ; packet is too short
  959.  
  960. ; check descriptor
  961.         movzx   eax, [device.cur_tx]
  962.         imul    edi, eax, PCNET_PKT_BUF_SZ
  963.         shl     eax, 4
  964.         add     eax, [device.tx_buffer]
  965.         add     edi, [device.tx_buffer]
  966.         add     edi, PCNET_TX_RING_SIZE * buf_head.size
  967.  
  968.         test    byte [eax + buf_head.status + 1], 80h
  969.         jnz     .nospace
  970. ; descriptor is free, copy data
  971.         mov     esi, [esp+4]
  972.         mov     ecx, [esp+8]
  973.         mov     edx, ecx
  974.         shr     ecx, 2
  975.         and     edx, 3
  976.         rep     movsd
  977.         mov     ecx, edx
  978.         rep     movsb
  979. ; set length
  980.         mov     ecx, [esp+8]
  981.         neg     ecx
  982.         mov     [eax + buf_head.length], cx
  983. ; put to transfer queue
  984.         mov     [eax + buf_head.status], 0x8300
  985.  
  986. ; trigger an immediate send
  987.         mov     edx, [device.io_addr]
  988.         xor     ecx, ecx         ; CSR0
  989.         call    [device.access_read_csr]
  990.         or      eax, PCNET_CSR_TX
  991.         call    [device.access_write_csr]
  992.  
  993. ; get next descriptor 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, ...
  994.         inc     [device.cur_tx]
  995.         and     [device.cur_tx], 3
  996.         DEBUGF  2," - Packet Sent! "
  997.  
  998. ; Update stats
  999.         inc     [device.packets_tx]
  1000.         mov     eax, [esp+8]
  1001.         add     dword [device.bytes_tx], eax
  1002.         adc     dword [device.bytes_tx + 4], 0
  1003.  
  1004. .finish:
  1005.         DEBUGF  2," - Done!\n"
  1006.         stdcall KernelFree, [esp+4]
  1007.         xor     eax, eax
  1008.         ret     8
  1009.  
  1010. .nospace:
  1011.         DEBUGF  1, 'ERROR: no free transmit descriptors\n'
  1012.         stdcall KernelFree, [esp+4]
  1013.         or      eax, -1
  1014.         ret     8
  1015.  
  1016.  
  1017.  
  1018. ;;;;;;;;;;;;;;;;;;;;;;;
  1019. ;;                   ;;
  1020. ;; Interrupt handler ;;
  1021. ;;                   ;;
  1022. ;;;;;;;;;;;;;;;;;;;;;;;
  1023.  
  1024. align 4
  1025. int_handler:
  1026.  
  1027.         DEBUGF  1,"\n%s int\n", my_service
  1028.  
  1029. ; find pointer of device wich made IRQ occur
  1030.  
  1031.         mov     ecx, [devices]
  1032.         test    ecx, ecx
  1033.         jz      .nothing
  1034.         mov     esi, device_list
  1035.   .nextdevice:
  1036.         mov     ebx, [esi]
  1037.  
  1038.         mov     edx, [device.io_addr]     ; get IRQ reason
  1039.         push    ecx
  1040.         xor     ecx, ecx ; CSR0
  1041.         call    [device.access_read_csr]
  1042.         pop     ecx
  1043.         test    al, al
  1044.         js      .got_it
  1045.   .continue:
  1046.         add     esi, 4
  1047.         dec     ecx
  1048.         jnz     .nextdevice
  1049.   .nothing:
  1050.         ret                                         ; If no device was found, abort (The irq was probably for a device, not registered to this driver
  1051.  
  1052.   .got_it:
  1053.  
  1054.         DEBUGF  1,"Device: %x Status: %x ", ebx, eax:2
  1055.  
  1056. ;-------------------------------------------------------
  1057. ; Possible reasons:
  1058. ; initialization done - ignore
  1059. ; transmit done - ignore
  1060. ; packet received - handle
  1061. ; Clear ALL IRQ reasons.
  1062. ; N.B. One who wants to handle more than one reason must be ready
  1063. ; to two or more reasons in one IRQ.
  1064.         xor     ecx, ecx
  1065.         call    [device.access_write_csr]
  1066. ; Received packet ok?
  1067.  
  1068.         test    ax, PCNET_CSR_RINT
  1069.         jz      @f
  1070.  
  1071.         push    ebx
  1072. .receiver_test_loop:
  1073.         pop     ebx
  1074.         movzx   eax, [device.cur_rx]
  1075. ;        and     eax, PCNET_RX_RING_MOD_MASK
  1076.         mov     edi, eax
  1077.  
  1078.         imul    esi, eax, PCNET_PKT_BUF_SZ      ;
  1079.         add     esi, [device.rx_buffer]         ; esi now points to rx buffer
  1080.         add     esi, PCNET_RX_RING_SIZE * buf_head.size
  1081.  
  1082.         shl     edi, 4                          ; desc * 16 (16 is size of one ring entry)
  1083.         add     edi, [device.rx_buffer]     ; edi now points to current rx ring entry
  1084.  
  1085.         mov     cx , [edi + buf_head.status]
  1086.  
  1087.         test    cx , PCNET_RXSTAT_OWN           ; If this bit is set, the controller OWN's the packet, if not, we do
  1088.         jnz     .abort
  1089.  
  1090.         test    cx , PCNET_RXSTAT_ENP
  1091.         jz      .abort
  1092.  
  1093.         test    cx , PCNET_RXSTAT_STP
  1094.         jz      .abort
  1095.  
  1096.         movzx   ecx, [edi + buf_head.msg_length]        ; get packet length in ecx
  1097.         sub     ecx, 4                          ;
  1098.  
  1099.         push    ecx
  1100.         stdcall KernelAlloc, ecx                ; Allocate a buffer to put packet into
  1101.         pop     ecx
  1102.         test    eax, eax                        ; Test if we allocated succesfully
  1103.         jz      .abort                          ;
  1104.  
  1105. ; Update stats
  1106.         add     dword [device.bytes_rx], ecx
  1107.         adc     dword [device.bytes_rx + 4], 0
  1108.         inc     dword [device.packets_rx]
  1109.  
  1110.         push    ebx
  1111.         push    .receiver_test_loop             ;
  1112.         push    ecx                             ; for eth_receiver
  1113.         push    eax                             ;
  1114.  
  1115.         xchg    edi, eax
  1116.         push    ecx
  1117.         shr     ecx, 2
  1118.         cld
  1119.         rep     movsd
  1120.         pop     ecx
  1121.         and     ecx, 3
  1122.         rep     movsb
  1123.  
  1124. ;       mov     word [eax + buf_head.length], PCNET_PKT_BUF_SZ_NEG
  1125.         mov     word [eax + buf_head.status], PCNET_RXSTAT_OWN      ; Set OWN bit back to 1 (controller may write to tx-buffer again now)
  1126.  
  1127.         inc     [device.cur_rx]           ; update descriptor
  1128.         and     [device.cur_rx], 3        ;
  1129.  
  1130.         jmp     Eth_input
  1131.  
  1132.   .abort:
  1133.  
  1134.   @@:
  1135.  
  1136.         ret
  1137.  
  1138.  
  1139.  
  1140.  
  1141. ;;;;;;;;;;;;;;;;;;;;;;;
  1142. ;;                   ;;
  1143. ;; Write MAC address ;;
  1144. ;;                   ;;
  1145. ;;;;;;;;;;;;;;;;;;;;;;;
  1146.  
  1147. align 4
  1148. write_mac:      ; in: mac pushed onto stack (as 3 words)
  1149.  
  1150.         DEBUGF  1,"Writing MAC: %x-%x-%x-%x-%x-%x",[esp+0]:2,[esp+1]:2,[esp+2]:2,[esp+3]:2,[esp+4]:2,[esp+5]:2
  1151.  
  1152.         mov     edx, [device.io_addr]
  1153.         add     dx, 2
  1154.         xor     eax, eax
  1155.  
  1156.         mov     ecx, PCNET_CSR_PAR0
  1157.        @@:
  1158.         pop     ax
  1159.         call    [device.access_write_csr]
  1160.         DEBUGF  1,"."
  1161.         inc     ecx
  1162.         cmp     ecx, PCNET_CSR_PAR2
  1163.         jb      @r
  1164.  
  1165.         DEBUGF  1,"\n"
  1166.  
  1167. ; Notice this procedure does not ret, but continues to read_mac instead.
  1168.  
  1169. ;;;;;;;;;;;;;;;;;;;;;;
  1170. ;;                  ;;
  1171. ;; Read MAC address ;;
  1172. ;;                  ;;
  1173. ;;;;;;;;;;;;;;;;;;;;;;
  1174. align 4
  1175. read_mac:
  1176.         DEBUGF  1,"Reading MAC"
  1177.  
  1178.         mov     edx, [device.io_addr]
  1179.         add     dx, 6
  1180.        @@:
  1181.         dec     dx
  1182.         dec     dx
  1183.         in      ax, dx
  1184.         push    ax
  1185.         DEBUGF  1,"."
  1186.         cmp     edx, [device.io_addr]
  1187.         ja      @r
  1188.  
  1189.         DEBUGF  1," %x-%x-%x-%x-%x-%x\n",[esp+0]:2,[esp+1]:2,[esp+2]:2,[esp+3]:2,[esp+4]:2,[esp+5]:2
  1190.  
  1191.         lea     edi, [device.mac]
  1192.         pop     ax
  1193.         stosw
  1194.         pop     ax
  1195.         stosw
  1196.         pop     ax
  1197.         stosw
  1198.  
  1199.         ret
  1200.  
  1201. align 4
  1202. switch_to_wio:
  1203.  
  1204.         DEBUGF  1,"Switching to 16-bit mode\n"
  1205.  
  1206.         mov     [device.access_read_csr], wio_read_csr
  1207.         mov     [device.access_write_csr], wio_write_csr
  1208.         mov     [device.access_read_bcr], wio_read_bcr
  1209.         mov     [device.access_write_bcr], wio_write_bcr
  1210.         mov     [device.access_read_rap], wio_read_rap
  1211.         mov     [device.access_write_rap], wio_write_rap
  1212.         mov     [device.access_reset], wio_reset
  1213.  
  1214.         ret
  1215.  
  1216. align 4
  1217. switch_to_dwio:
  1218.  
  1219.         DEBUGF  1,"Switching to 32-bit mode\n"
  1220.  
  1221.         mov     [device.access_read_csr], dwio_read_csr
  1222.         mov     [device.access_write_csr], dwio_write_csr
  1223.         mov     [device.access_read_bcr], dwio_read_bcr
  1224.         mov     [device.access_write_bcr], dwio_write_bcr
  1225.         mov     [device.access_read_rap], dwio_read_rap
  1226.         mov     [device.access_write_rap], dwio_write_rap
  1227.         mov     [device.access_reset], dwio_reset
  1228.  
  1229.         ret
  1230.  
  1231.  
  1232. ; ecx - index
  1233. ; return:
  1234. ; eax - data
  1235. align 4
  1236. wio_read_csr:
  1237.  
  1238.         add     edx, PCNET_WIO_RAP
  1239.         mov     ax , cx
  1240.         out     dx , ax
  1241.         add     edx, PCNET_WIO_RDP - PCNET_WIO_RAP
  1242.         in      ax , dx
  1243.         and     eax, 0xffff
  1244.         sub     edx, PCNET_WIO_RDP
  1245.  
  1246.         ret
  1247.  
  1248.  
  1249. ; eax - data
  1250. ; ecx - index
  1251. align 4
  1252. wio_write_csr:
  1253.  
  1254.         add     edx, PCNET_WIO_RAP
  1255.         xchg    eax, ecx
  1256.         out     dx , ax
  1257.         xchg    eax, ecx
  1258.         add     edx, PCNET_WIO_RDP - PCNET_WIO_RAP
  1259.         out     dx , ax
  1260.         sub     edx, PCNET_WIO_RDP
  1261.  
  1262.         ret
  1263.  
  1264.  
  1265. ; ecx - index
  1266. ; return:
  1267. ; eax - data
  1268. align 4
  1269. wio_read_bcr:
  1270.  
  1271.         add     edx, PCNET_WIO_RAP
  1272.         mov     ax , cx
  1273.         out     dx , ax
  1274.         add     edx, PCNET_WIO_BDP - PCNET_WIO_RAP
  1275.         in      ax , dx
  1276.         and     eax, 0xffff
  1277.         sub     edx, PCNET_WIO_BDP
  1278.  
  1279.         ret
  1280.  
  1281.  
  1282. ; eax - data
  1283. ; ecx - index
  1284. align 4
  1285. wio_write_bcr:
  1286.  
  1287.         add     edx, PCNET_WIO_RAP
  1288.         xchg    eax, ecx
  1289.         out     dx , ax
  1290.         xchg    eax, ecx
  1291.         add     edx, PCNET_WIO_BDP - PCNET_WIO_RAP
  1292.         out     dx , ax
  1293.         sub     edx, PCNET_WIO_BDP
  1294.  
  1295.         ret
  1296.  
  1297. align 4
  1298. wio_read_rap:
  1299.  
  1300.         add     edx, PCNET_WIO_RAP
  1301.         in      ax , dx
  1302.         and     eax, 0xffff
  1303.         sub     edx, PCNET_WIO_RAP
  1304.  
  1305.         ret
  1306.  
  1307. ; eax - val
  1308. align 4
  1309. wio_write_rap:
  1310.  
  1311.         add     edx, PCNET_WIO_RAP
  1312.         out     dx , ax
  1313.         sub     edx, PCNET_WIO_RAP
  1314.  
  1315.         ret
  1316.  
  1317. align 4
  1318. wio_reset:
  1319.  
  1320.         push    eax
  1321.         add     edx, PCNET_WIO_RESET
  1322.         in      ax , dx
  1323.         pop     eax
  1324.         sub     edx, PCNET_WIO_RESET
  1325.  
  1326.         ret
  1327.  
  1328.  
  1329.  
  1330. ; ecx - index
  1331. ; return:
  1332. ; eax - data
  1333. align 4
  1334. dwio_read_csr:
  1335.  
  1336.         add     edx, PCNET_DWIO_RAP
  1337.         mov     eax, ecx
  1338.         out     dx , eax
  1339.         add     edx, PCNET_DWIO_RDP - PCNET_DWIO_RAP
  1340.         in      eax, dx
  1341.         and     eax, 0xffff
  1342.         sub     edx, PCNET_DWIO_RDP
  1343.  
  1344.         ret
  1345.  
  1346.  
  1347. ; ecx - index
  1348. ; eax - data
  1349. align 4
  1350. dwio_write_csr:
  1351.  
  1352.         add     edx, PCNET_DWIO_RAP
  1353.         xchg    eax, ecx
  1354.         out     dx , eax
  1355.         add     edx, PCNET_DWIO_RDP - PCNET_DWIO_RAP
  1356.         xchg    eax, ecx
  1357.         out     dx , eax
  1358.         sub     edx, PCNET_DWIO_RDP
  1359.  
  1360.         ret
  1361.  
  1362. ; ecx - index
  1363. ; return:
  1364. ; eax - data
  1365. align 4
  1366. dwio_read_bcr:
  1367.  
  1368.         add     edx, PCNET_DWIO_RAP
  1369.         mov     eax, ecx
  1370.         out     dx , eax
  1371.         add     edx, PCNET_DWIO_BDP - PCNET_DWIO_RAP
  1372.         in      eax, dx
  1373.         and     eax, 0xffff
  1374.         sub     edx, PCNET_DWIO_BDP
  1375.  
  1376.         ret
  1377.  
  1378.  
  1379. ; ecx - index
  1380. ; eax - data
  1381. align 4
  1382. dwio_write_bcr:
  1383.  
  1384.         add     edx, PCNET_DWIO_RAP
  1385.         xchg    eax, ecx
  1386.         out     dx , eax
  1387.         add     edx, PCNET_DWIO_BDP - PCNET_DWIO_RAP
  1388.         xchg    eax, ecx
  1389.         out     dx , eax
  1390.         sub     edx, PCNET_DWIO_BDP
  1391.  
  1392.         ret
  1393.  
  1394. align 4
  1395. dwio_read_rap:
  1396.  
  1397.         add     edx, PCNET_DWIO_RAP
  1398.         in      eax, dx
  1399.         and     eax, 0xffff
  1400.         sub     edx, PCNET_DWIO_RAP
  1401.  
  1402.         ret
  1403.  
  1404.  
  1405. ; eax - val
  1406. align 4
  1407. dwio_write_rap:
  1408.  
  1409.         add     edx, PCNET_DWIO_RAP
  1410.         out     dx , eax
  1411.         sub     edx, PCNET_DWIO_RAP
  1412.  
  1413.         ret
  1414.  
  1415. align 4
  1416. dwio_reset:
  1417.  
  1418.         push    eax
  1419.         add     edx, PCNET_DWIO_RESET
  1420.         in      eax, dx
  1421.         pop     eax
  1422.         sub     edx, PCNET_DWIO_RESET
  1423.  
  1424.         ret
  1425.  
  1426.  
  1427.  
  1428. ; End of code
  1429.  
  1430. align 4                                       ; Place all initialised data here
  1431.  
  1432. devices     dd 0
  1433. version       dd (5 shl 16) or (API_VERSION and 0xFFFF)
  1434. my_service    db 'PCnet',0                    ; max 16 chars include zero
  1435.  
  1436. device_l2     db "PCnet/PCI 79C970",0
  1437. device_l4     db "PCnet/PCI II 79C970A",0
  1438. device_l5     db "PCnet/FAST 79C971",0
  1439. device_l6     db "PCnet/FAST+ 79C972",0
  1440. device_l7     db "PCnet/FAST III 79C973",0
  1441. device_l8     db "PCnet/Home 79C978",0
  1442. device_l9     db "PCnet/FAST III 79C975",0
  1443.  
  1444. options_mapping:
  1445. dd PCNET_PORT_ASEL                                      ;  0 Auto-select
  1446. dd PCNET_PORT_AUI                                       ;  1 BNC/AUI
  1447. dd PCNET_PORT_AUI                                       ;  2 AUI/BNC
  1448. dd PCNET_PORT_ASEL                                      ;  3 not supported
  1449. dd PCNET_PORT_10BT or PCNET_PORT_FD                     ;  4 10baseT-FD
  1450. dd PCNET_PORT_ASEL                                      ;  5 not supported
  1451. dd PCNET_PORT_ASEL                                      ;  6 not supported
  1452. dd PCNET_PORT_ASEL                                      ;  7 not supported
  1453. dd PCNET_PORT_ASEL                                      ;  8 not supported
  1454. dd PCNET_PORT_MII                                       ;  9 MII 10baseT
  1455. dd PCNET_PORT_MII or PCNET_PORT_FD                      ; 10 MII 10baseT-FD
  1456. dd PCNET_PORT_MII                                       ; 11 MII (autosel)
  1457. dd PCNET_PORT_10BT                                      ; 12 10BaseT
  1458. dd PCNET_PORT_MII or PCNET_PORT_100                     ; 13 MII 100BaseTx
  1459. dd PCNET_PORT_MII or PCNET_PORT_100 or PCNET_PORT_FD    ; 14 MII 100BaseTx-FD
  1460. dd PCNET_PORT_ASEL                                      ; 15 not supported
  1461.  
  1462. include_debug_strings                                   ; All data wich FDO uses will be included here
  1463.  
  1464. section '.data' data readable writable align 16         ; place all uninitialized data place here
  1465.  
  1466. device_list rd MAX_DEVICES                                 ; This list contains all pointers to device structures the driver is handling
  1467.