1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
4 ;; Distributed under terms of the GNU General Public License ;;
6 ;; AMD PCnet driver for KolibriOS ;;
8 ;; By hidnplayr & clevermouse ;;
10 ;; Based on the PCnet32 driver for MenuetOS, by Jarek Pelczar ;;
12 ;; GNU GENERAL PUBLIC LICENSE ;;
13 ;; Version 2, June 1991 ;;
15 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
21 COMPATIBLE_API
= 0x0100
22 API_VERSION
= (COMPATIBLE_API
shl 16) + CURRENT_API
26 MAX_DEVICES
= 16 ; Maximum number of devices this driver may handle
28 __DEBUG__
= 1 ; 1 = on, 0 = off
29 __DEBUG_LEVEL__
= 2 ; 1 = verbose, 2 = errors only
31 TX_RING_SIZE
= 32 ; Number of packets in send ring buffer
32 RX_RING_SIZE
= 32 ; Number of packets in receive ring buffer
34 ; end configureable area
36 section '.flat' readable writable executable
38 include '../struct.inc'
39 include '../macros.inc'
40 include '../proc32.inc'
42 include '../netdrv.inc'
44 if
(bsr TX_RING_SIZE
)>(bsf TX_RING_SIZE
)
45 display
'TX_RING_SIZE must be a power of two'
49 if
(bsr RX_RING_SIZE
)>(bsf RX_RING_SIZE
)
50 display
'RX_RING_SIZE must be a power of two'
65 TX_RING_LEN_BITS
= ((bsf TX_RING_SIZE
) shl 12)
66 RX_RING_LEN_BITS
= ((bsf RX_RING_SIZE
) shl 4)
108 CSR_MEMERRTIMEO
= 0x64
115 ; Control and Status Register (CSR0)
117 CSR_INIT
= 0x0001 ;1 shl 0
118 CSR_START
= 0x0002 ;1 shl 1
119 CSR_STOP
= 0x0004 ;1 shl 2
120 CSR_TX
= 0x0008 ;1 shl 3
121 CSR_TXON
= 0x0010 ;1 shl 4
122 CSR_RXON
= 0x0020 ;1 shl 5
123 CSR_INTEN
= 0x0040 ;1 shl 6
124 CSR_INTR
= 0x0080 ;1 shl 7
125 CSR_IDONE
= 0x0100 ;1 shl 8
126 CSR_TINT
= 0x0200 ;1 shl 9
127 CSR_RINT
= 0x0400 ;1 shl 10
128 CSR_MERR
= 0x0800 ;1 shl 11
129 CSR_MISS
= 0x1000 ;1 shl 12
130 CSR_CERR
= 0x2000 ;1 shl 13
132 ; Interrupt masks and deferral control (CSR3)
135 IMR_ENMBA
= 0x0008 ; enable modified backoff alg
137 IMR_LAPPEN
= 0x0020 ; lookahead packet processing enb
138 IMR_DXSUFLO
= 0x0040 ; disable TX stop on underflow
145 ; Masked interrupts will be disabled.
146 IMR
= 0 ;IMR_IDONE ;or IMR_TINT or IMR_RINT or IMR_MERR or IMR_MISS
148 ; Test and features control (CSR4)
150 TFEAT_TXSTRTMASK
= 0x0004
151 TFEAT_TXSTRT
= 0x0008
152 TFEAT_RXCCOFLOWM
= 0x0010 ; Rx collision counter oflow
153 TFEAT_RXCCOFLOW
= 0x0020
155 TFEAT_UINTREQ
= 0x0080
156 TFEAT_MISSOFLOWM
= 0x0100
157 TFEAT_MISSOFLOW
= 0x0200
158 TFEAT_STRIP_FCS
= 0x0400
159 TFEAT_PAD_TX
= 0x0800
160 TFEAT_TXDPOLL
= 0x1000
161 TFEAT_DMAPLUS
= 0x4000
163 ; Extended control and interrupt 1 (CSR5)
165 EXTCTL1_SPND
= 0x0001 ; suspend
166 EXTCTL1_MPMODE
= 0x0002 ; magic packet mode
167 EXTCTL1_MPENB
= 0x0004 ; magic packet enable
168 EXTCTL1_MPINTEN
= 0x0008 ; magic packet interrupt enable
169 EXTCTL1_MPINT
= 0x0010 ; magic packet interrupt
170 EXTCTL1_MPPLBA
= 0x0020 ; magic packet phys. logical bcast
171 EXTCTL1_EXDEFEN
= 0x0040 ; excessive deferral interrupt enb.
172 EXTCTL1_EXDEF
= 0x0080 ; excessive deferral interrupt
173 EXTCTL1_SINTEN
= 0x0400 ; system interrupt enable
174 EXTCTL1_SINT
= 0x0800 ; system interrupt
175 EXTCTL1_LTINTEN
= 0x4000 ; last TX interrupt enb
176 EXTCTL1_TXOKINTD
= 0x8000 ; TX OK interrupt disable
178 ; RX/TX descriptor len (CSR6)
180 DTBLLEN_RLEN
= 0x0F00
181 DTBLLEN_TLEN
= 0xF000
183 ; Extended control and interrupt 2 (CSR7)
185 EXTCTL2_MIIPDTINTE
= 0x0001
186 EXTCTL2_MIIPDTINT
= 0x0002
187 EXTCTL2_MCCIINTE
= 0x0004
188 EXTCTL2_MCCIINT
= 0x0008
189 EXTCTL2_MCCINTE
= 0x0010
190 EXTCTL2_MCCINT
= 0x0020
191 EXTCTL2_MAPINTE
= 0x0040
192 EXTCTL2_MAPINT
= 0x0080
193 EXTCTL2_MREINTE
= 0x0100
194 EXTCTL2_MREINT
= 0x0200
195 EXTCTL2_STINTE
= 0x0400
196 EXTCTL2_STINT
= 0x0800
197 EXTCTL2_RXDPOLL
= 0x1000
198 EXTCTL2_RDMD
= 0x2000
199 EXTCTL2_RXFRTG
= 0x4000
200 EXTCTL2_FASTSPNDE
= 0x8000
204 MODE_RXD
= 0x0001 ; RX disable
205 MODE_TXD
= 0x0002 ; TX disable
206 MODE_LOOP
= 0x0004 ; loopback enable
208 MODE_FORCECOLL
= 0x0010
210 MODE_INTLOOP
= 0x0040
211 MODE_PORTSEL
= 0x0180
213 MODE_RXNOBROAD
= 0x4000
214 MODE_PROMISC
= 0x8000
216 ; BCR (Bus Control Registers)
218 BCR_MMRA
= 0x00 ; Master Mode Read Active
219 BCR_MMW
= 0x01 ; Master Mode Write Active
230 BCR_PCISUBVENID
= 0x17
231 BCR_PCISUBSYSID
= 0x18
255 RXSTAT_BPE
= 0x0080 ; bus parity error
256 RXSTAT_ENP
= 0x0100 ; end of packet
257 RXSTAT_STP
= 0x0200 ; start of packet
258 RXSTAT_BUFF
= 0x0400 ; buffer error
259 RXSTAT_CRC
= 0x0800 ; CRC error
260 RXSTAT_OFLOW
= 0x1000 ; rx overrun
261 RXSTAT_FRAM
= 0x2000 ; framing error
262 RXSTAT_ERR
= 0x4000 ; error summary
267 TXSTAT_TRC
= 0x0000000F ; transmit retries
268 TXSTAT_RTRY
= 0x04000000 ; retry
269 TXSTAT_LCAR
= 0x08000000 ; lost carrier
270 TXSTAT_LCOL
= 0x10000000 ; late collision
271 TXSTAT_EXDEF
= 0x20000000 ; excessive deferrals
272 TXSTAT_UFLOW
= 0x40000000 ; transmit underrun
273 TXSTAT_BUFF
= 0x80000000 ; buffer error
276 TXCTL_ERR
= 0x4000 ; error summary
277 TXCTL_ADD_FCS
= 0x2000 ; add FCS to pkt
278 TXCTL_MORE_LTINT
= 0x1000
285 TXCTL_MBO
= 0x0000F000
286 TXCTL_BUFSZ
= 0x00000FFF
291 ; Pcnet configuration structure
292 struct pcnet_init_block
304 struct device ETH_DEVICE
306 rb
0x100-($
and 0xff) ; align 256
307 init_block pcnet_init_block
309 rb
0x100-($
and 0xff) ; align 256
310 rx_ring rb RX_RING_SIZE
* sizeof.descriptor
312 rb
0x100-($
and 0xff) ; align 256
313 tx_ring rb TX_RING_SIZE
* sizeof.descriptor
337 rb
0x100-($
and 0xff) ; align 256
361 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
365 ;; (standard driver proc) ;;
366 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
368 proc START c
, reason:dword, cmdline:dword
370 cmp [reason
], DRV_ENTRY
373 DEBUGF
2,"Loading driver\n"
374 invoke RegService
, my_service
, service_proc
384 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
386 ;; proc SERVICE_PROC ;;
388 ;; (standard driver proc) ;;
389 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
392 proc service_proc stdcall
, ioctl:dword
395 mov eax, [edx + IOCTL.io_code
]
397 ;------------------------------------------------------
399 cmp eax, 0 ;SRV_GETVERSION
402 cmp [edx + IOCTL.out_size
], 4
404 mov eax, [edx + IOCTL.output
]
405 mov [eax], dword API_VERSION
410 ;------------------------------------------------------
415 cmp [edx + IOCTL.inp_size
], 3 ; Data input must be at least 3 bytes
418 mov eax, [edx + IOCTL.input
]
419 cmp byte[eax], 1 ; 1 means device number and bus number (pci) are given
420 jne .fail
; other types arent supported for this card yet
422 ; check if the device is already listed
429 ; mov eax, [edx + IOCTL.input] ; get the pci bus and device numbers
433 cmp al, byte[ebx + device.pci_bus
]
435 cmp ah, byte[ebx + device.pci_dev
]
436 je .find_devicenum
; Device is already loaded, let's find it's device number
441 ; This device doesnt have its own eth_device structure yet, lets create one
444 cmp [devices
], MAX_DEVICES
; First check if the driver can handle one more card
447 allocate_and_clear
ebx, sizeof.device
, .fail
449 ; Fill in the direct call addresses into the struct
451 mov [ebx + device.reset
], reset
452 mov [ebx + device.transmit
], transmit
453 mov [ebx + device.unload
], unload
454 mov [ebx + device.
name], my_service
456 ; save the pci bus and device numbers
458 mov eax, [edx + IOCTL.input
]
459 movzx ecx, byte[eax+1]
460 mov [ebx + device.pci_bus
], ecx
461 movzx ecx, byte[eax+2]
462 mov [ebx + device.pci_dev
], ecx
464 ; Now, it's time to find the base io addres of the PCI device
466 stdcall PCI_find_io
, [ebx + device.pci_bus
], [ebx + device.pci_dev
]
467 mov [ebx + device.io_addr
], eax
469 ; We've found the io address, find IRQ now
471 invoke PciRead8
, [ebx + device.pci_bus
], [ebx + device.pci_dev
], PCI_header00.interrupt_line
472 mov [ebx + device.irq_line
], al
474 DEBUGF
1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\
475 [ebx + device.pci_dev
]:1,[ebx + device.pci_bus
]:1,[ebx + device.irq_line
]:1,[ebx + device.io_addr
]:4
477 ; Ok, the eth_device structure is ready, let's probe the device
478 ; Because initialization fires IRQ, IRQ handler must be aware of this device
479 mov eax, [devices
] ; Add the device structure to our device list
480 mov [device_list
+4*eax], ebx ; (IRQ handler uses this list to find device)
483 call probe
; this function will output in eax
485 jnz .destroy
; If an error occured, exit
487 mov [ebx + device.
type], NET_TYPE_ETH
494 ; If the device was already loaded, find the device number and return it in eax
497 DEBUGF
1,"Trying to find device number of already registered device\n"
498 invoke NetPtrToNum
; This kernel procedure converts a pointer to device struct in ebx
499 ; into a device number in edi
500 mov eax, edi ; Application wants it in eax instead
501 DEBUGF
1,"Kernel says: %u\n", eax
504 ; If an error occured, remove all allocated data and exit (returning -1 in eax)
507 ; todo: reset device into virgin state
508 add eax, NET_BUFF.data
511 DEBUGF
2,"Error, removing all data !\n"
512 invoke KernelFree
, ebx
518 ;------------------------------------------------------
522 ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
524 ;; Actual Hardware dependent code starts here ;;
526 ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
531 cmp [ebx + device.link_timer
], 0
533 invoke CancelTimerHS
, [ebx + device.link_timer
]
536 ; TODO: (in this particular order)
539 ; - Detach int handler
540 ; - Remove device from local list (device_list)
541 ; - call unregister function in kernel
542 ; - Remove all allocated structures and buffers the card used
548 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
550 ;; probe: enables the device (if it really is a PCnet device)
552 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
557 mov edx, [ebx + device.io_addr
]
606 DEBUGF
2,"device not found!\n"
612 call [ebx + device.read_csr
]
622 call [ebx + device.read_csr
]
625 mov [ebx + device.chip_version
], ax
627 mov [ebx + device.fdx
], 0
628 mov [ebx + device.mii
], 0
629 mov [ebx + device.fset
], 0
630 mov [ebx + device.dxsuflo
], 0
631 mov [ebx + device.ltint
], 0
638 mov [ebx + device.fdx
], 1
653 DEBUGF
2,"Invalid chip rev\n"
656 mov [ebx + device.
name], device_l2
659 mov [ebx + device.
name], device_l4
660 ; mov [ebx + device.fdx], 1
663 mov [ebx + device.
name], device_l5
664 ; mov [ebx + device.fdx], 1
665 mov [ebx + device.mii
], 1
666 mov [ebx + device.fset
], 1
667 mov [ebx + device.ltint
], 1
670 mov [ebx + device.
name], device_l6
671 ; mov [ebx + device.fdx], 1
672 mov [ebx + device.mii
], 1
673 mov [ebx + device.fset
], 1
676 mov [ebx + device.
name], device_l7
677 ; mov [ebx + device.fdx], 1
678 mov [ebx + device.mii
], 1
681 mov [ebx + device.
name], device_l8
682 ; mov [ebx + device.fdx], 1
684 call dword [ebx + device.read_bcr
]
685 call dword [ebx + device.write_bcr
]
688 mov [ebx + device.
name], device_l9
689 ; mov [ebx + device.fdx], 1
690 mov [ebx + device.mii
], 1
692 DEBUGF
1,"device name: %s\n", [ebx + device.
name]
694 cmp [ebx + device.fset
], 1
697 call [ebx + device.read_bcr
]
699 call [ebx + device.write_bcr
]
702 ; call [ebx + device.read_csr]
704 call [ebx + device.write_csr
]
706 mov [ebx + device.dxsuflo
],1
707 mov [ebx + device.ltint
],1
710 ; Make the device a bus master
711 invoke PciRead32
, [ebx + device.pci_bus
], [ebx + device.pci_dev
], PCI_header00.command
712 or al, PCI_CMD_MASTER
713 invoke PciWrite32
, [ebx + device.pci_bus
], [ebx + device.pci_dev
], PCI_header00.command
, eax
715 mov [ebx + device.options
], PORT_ASEL
716 mov [ebx + device.init_block.mode
], MODE_RXD
+ MODE_TXD
; disable receive and transmit
717 mov [ebx + device.init_block.tlen_rlen
], (TX_RING_LEN_BITS
or RX_RING_LEN_BITS
)
719 mov dword[ebx + device.init_block.filter
], 0
720 mov dword[ebx + device.init_block.filter
+4], 0
725 ; Stop link check timer if it was already running
726 cmp [ebx + device.link_timer
], 0
728 invoke CancelTimerHS
, [ebx + device.link_timer
]
733 movzx eax, [ebx + device.irq_line
]
734 DEBUGF
1,"Attaching int handler to irq %x\n", eax:1
735 invoke AttachIntHandler
, eax, int_handler
, ebx
738 DEBUGF
2,"Could not attach int handler!\n"
743 mov edx, [ebx + device.io_addr
]
744 call [ebx + device.sw_reset
]
746 ; Switch pcnet32 to 32bit mode
749 call [ebx + device.write_bcr
]
751 ; set/reset autoselect bit
753 call [ebx + device.read_bcr
]
755 test [ebx + device.options
], PORT_ASEL
759 call [ebx + device.write_bcr
]
761 ; Handle full duplex setting
762 cmp byte [ebx + device.full_duplex
], 0
765 call [ebx + device.read_bcr
]
767 test [ebx + device.options
], PORT_FD
770 cmp [ebx + device.options
], PORT_FD
or PORT_AUI
775 test [ebx + device.options
], PORT_ASEL
777 cmp [ebx + device.chip_version
], 0x2627
782 call [ebx + device.write_bcr
]
785 ; set/reset GPSI bit in test register
787 call [ebx + device.read_csr
]
788 mov ecx, [ebx + device.options
]
789 and ecx, PORT_PORTSEL
794 call [ebx + device.write_csr
]
795 cmp [ebx + device.mii
], 0
797 test [ebx + device.options
], PORT_ASEL
800 call [ebx + device.read_bcr
]
802 test [ebx + device.options
], PORT_FD
806 test [ebx + device.options
], PORT_100
810 call [ebx + device.write_bcr
]
813 test [ebx + device.options
], PORT_ASEL
816 DEBUGF
1,"ASEL, enable auto-negotiation\n"
817 call [ebx + device.read_bcr
]
820 call [ebx + device.write_bcr
]
822 cmp [ebx + device.ltint
], 0
825 call [ebx + device.read_csr
]
827 call [ebx + device.write_csr
]
829 mov eax, [ebx + device.options
]
830 and eax, PORT_PORTSEL
832 mov [ebx + device.init_block.mode
], ax
833 mov dword [ebx + device.init_block.filter
], -1
834 mov dword [ebx + device.init_block.filter
+4], -1
838 ;-----------------------------
840 test [ebx + device.mii
], 1
843 mov [ebx + device.phy
], 0
851 DEBUGF
1, "PHY ID1: 0x%x\n", ax
858 DEBUGF
1, "PHY ID2: 0x%x\n", ax
862 cmp [ebx + device.phy
], 31
864 mov ax, [ebx + device.chip_version
]
867 cmp ax, 0x2624 ; 79c971 & 79c972 have phantom phy at id 31
871 inc [ebx + device.phy
]
872 cmp [ebx + device.phy
], MAX_PHYS
875 DEBUGF
2, "No PHY found!\n"
880 DEBUGF
1, "Found PHY at 0x%x\n", [ebx + device.phy
]:4
884 ;-----------------------------------------------
888 lea esi, [ebx + device.mac
]
889 lea edi, [ebx + device.init_block.phys_addr
]
897 mov edx, [ebx + device.io_addr
] ; init ring destroys edx
899 lea eax, [ebx + device.init_block
]
904 call [ebx + device.write_csr
]
908 call [ebx + device.write_csr
]
911 mov eax, 0x0915 ; Auto TX PAD ?
912 call [ebx + device.write_csr
]
914 ; Set the interrupt mask
917 call [ebx + device.write_csr
]
919 ; Initialise the device
922 call [ebx + device.write_csr
]
927 call [ebx + device.read_csr
]
933 DEBUGF
2,"Initialize timeout!\n"
936 ; Start the device and enable interrupts
938 mov eax, CSR_START
+ CSR_INTEN
939 call [ebx + device.write_csr
]
942 mov [ebx + device.mtu
], 1514
944 mov [ebx + device.state
], ETH_LINK_UNKNOWN
945 ; Start media check timer
946 cmp [ebx + device.mii
], 0
948 mov [ebx + device.state
], ETH_LINK_DOWN
949 invoke TimerHS
, 0, 50, check_media_mii
, ebx
950 mov [ebx + device.link_timer
], eax
953 DEBUGF
1,"reset complete\n"
962 DEBUGF
1,"init ring\n"
964 lea edi, [ebx + device.rx_ring
]
967 mov [ebx + device.init_block.rx_ring_phys
], eax
968 mov ecx, RX_RING_SIZE
971 invoke NetAlloc
, PKT_BUF_SZ
+NET_BUFF.data
975 mov [edi + descriptor.virtual
], eax
977 add eax, NET_BUFF.data
978 mov [edi + descriptor.base
], eax
979 mov [edi + descriptor.
length], - PKT_BUF_SZ
980 mov dword[edi + descriptor.msg_length
], 0 ; also clears misc field
981 mov [edi + descriptor.status
], RXSTAT_OWN
982 add edi, sizeof.descriptor
986 lea edi, [ebx + device.tx_ring
]
989 mov [ebx + device.init_block.tx_ring_phys
], eax
990 mov ecx, TX_RING_SIZE
992 mov [edi + descriptor.status
], 0
993 add edi, sizeof.descriptor
997 mov [ebx + device.init_block.tlen_rlen
], (TX_RING_LEN_BITS
or RX_RING_LEN_BITS
)
999 mov [ebx + device.cur_tx
], 0
1000 mov [ebx + device.last_tx
], 0
1001 mov [ebx + device.cur_rx
], 0
1007 DEBUGF
2,"Out of memory!\n"
1015 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1019 ;; In: pointer to device structure in ebx ;;
1021 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1023 proc transmit stdcall bufferptr
1027 mov esi, [bufferptr
]
1028 DEBUGF
1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr
], [esi + NET_BUFF.
length]
1029 lea eax, [esi + NET_BUFF.data
]
1030 DEBUGF
1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
1031 [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
1032 [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
1033 [eax+13]:2,[eax+12]:2
1035 cmp [esi + NET_BUFF.
length], 1514
1037 cmp [esi + NET_BUFF.
length], 60
1041 lea edi, [ebx + device.tx_ring
]
1042 mov ecx, [ebx + device.cur_tx
]
1046 test [edi + descriptor.status
], TXCTL_OWN
1048 ; descriptor is free, use it
1049 mov [edi + descriptor.virtual
], esi
1051 add eax, [eax + NET_BUFF.
offset]
1053 mov [edi + descriptor.base
], eax
1055 mov eax, [esi + NET_BUFF.
length]
1057 mov [edi + descriptor.
length], ax
1058 ; put to transfer queue
1059 mov [edi + descriptor.status
], TXCTL_OWN
+ TXCTL_STP
+ TXCTL_ENP
1061 ; trigger an immediate send
1062 mov edx, [ebx + device.io_addr
]
1064 call [ebx + device.read_csr
]
1066 call [ebx + device.write_csr
]
1068 ; get next descriptor
1069 inc [ebx + device.cur_tx
]
1070 and [ebx + device.cur_tx
], TX_RING_SIZE
- 1
1073 inc [ebx + device.packets_tx
]
1074 mov eax, [esi + NET_BUFF.
length]
1075 add dword[ebx + device.bytes_tx
], eax
1076 adc dword[ebx + device.bytes_tx
+ 4], 0
1078 spin_unlock_irqrestore
1083 DEBUGF
2, "TX packet error\n"
1084 inc [ebx + device.packets_tx_err
]
1085 invoke NetFree
, [bufferptr
]
1087 spin_unlock_irqrestore
1092 DEBUGF
2, "TX overrun\n"
1093 inc [ebx + device.packets_tx_ovr
]
1094 invoke NetFree
, [bufferptr
]
1096 spin_unlock_irqrestore
1103 ;;;;;;;;;;;;;;;;;;;;;;;
1105 ;; Interrupt handler ;;
1107 ;;;;;;;;;;;;;;;;;;;;;;;
1116 ; find pointer of device wich made IRQ occur
1121 mov esi, device_list
1124 mov edx, [ebx + device.io_addr
]
1127 call [ebx + device.read_csr
] ; get IRQ reason
1128 call [ebx + device.write_csr
] ; write it back to ACK
1130 test ax, CSR_RINT
or CSR_TINT
1143 DEBUGF
1,"Device: %x status: %x\n", ebx, eax:4
1153 mov eax, [ebx + device.cur_rx
]
1155 lea edi, [ebx + device.rx_ring
]
1156 add edi, eax ; edi now points to current rx ring entry
1158 mov ax, [edi + descriptor.status
]
1159 DEBUGF
1,"RX packet status: %x\n", eax:4
1161 test ax, RXSTAT_OWN
; If this bit is set, the controller OWN's the packet, if not, we do
1163 ; Both Start of packet and End of packet bits should be set, we dont support multi frame packets
1169 movzx ecx, [edi + descriptor.msg_length
] ; get packet length in ecx
1170 sub ecx, 4 ; We dont need the CRC
1171 DEBUGF
1,"Got %u bytes\n", ecx
1173 ; Set pointers for ETH_input
1174 push .rx_loop
; return address
1175 mov eax, [edi + descriptor.virtual
]
1176 push eax ; packet address
1177 mov [eax + NET_BUFF.
length], ecx
1178 mov [eax + NET_BUFF.device
], ebx
1179 mov [eax + NET_BUFF.
offset], NET_BUFF.data
1182 add dword[ebx + device.bytes_rx
], ecx
1183 adc dword[ebx + device.bytes_rx
+ 4], 0
1184 inc [ebx + device.packets_rx
]
1186 ; now allocate a new buffer
1187 invoke NetAlloc
, PKT_BUF_SZ
+NET_BUFF.data
; Allocate a buffer for the next packet
1190 mov [edi + descriptor.virtual
], eax ; set virtual address
1192 add eax, NET_BUFF.data
1193 mov [edi + descriptor.base
], eax ; and physical address
1194 mov [edi + descriptor.status
], RXSTAT_OWN
; give it back to PCnet controller
1196 inc [ebx + device.cur_rx
] ; set next receive descriptor
1197 and [ebx + device.cur_rx
], RX_RING_SIZE
- 1
1203 DEBUGF
2,"RX FIFO overrun\n"
1204 inc [ebx + device.packets_rx_ovr
]
1208 DEBUGF
2,"Dropping incoming packet\n"
1209 inc [ebx + device.packets_rx_drop
]
1212 mov [edi + descriptor.status
], RXSTAT_OWN
; give it back to PCnet controller
1214 inc [ebx + device.cur_rx
] ; set next receive descriptor
1215 and [ebx + device.cur_rx
], RX_RING_SIZE
- 1
1228 lea edi, [ebx + device.tx_ring
]
1229 mov eax, [ebx + device.last_tx
]
1233 test [edi + descriptor.status
], TXCTL_OWN
1236 mov eax, [edi + descriptor.virtual
]
1240 mov [edi + descriptor.virtual
], 0
1242 DEBUGF
1,"Removing packet %x from memory\n", eax
1246 inc [ebx + device.last_tx
]
1247 and [ebx + device.last_tx
], TX_RING_SIZE
- 1
1260 ;;;;;;;;;;;;;;;;;;;;;;;
1262 ;; Write MAC address ;;
1264 ;;;;;;;;;;;;;;;;;;;;;;;
1267 write_mac: ; in: mac pushed onto stack (as 3 words)
1269 DEBUGF
1,"Writing MAC: %x-%x-%x-%x-%x-%x\n",\
1270 [esp+0]:2,[esp+1]:2,[esp+2]:2,[esp+3]:2,[esp+4]:2,[esp+5]:2
1272 mov edx, [ebx + device.io_addr
]
1279 call [ebx + device.write_csr
]
1284 ; Notice this procedure does not ret, but continues to read_mac instead.
1286 ;;;;;;;;;;;;;;;;;;;;;;
1288 ;; Read MAC address ;;
1290 ;;;;;;;;;;;;;;;;;;;;;;
1293 DEBUGF
1,"Reading MAC\n"
1295 mov edx, [ebx + device.io_addr
]
1296 lea edi, [ebx + device.mac
]
1310 DEBUGF
1,"MAC = %x-%x-%x-%x-%x-%x\n",\
1311 [ebx + device.mac
+0]:2,[ebx + device.mac
+1]:2,[ebx + device.mac
+2]:2,\
1312 [ebx + device.mac
+3]:2,[ebx + device.mac
+4]:2,[ebx + device.mac
+5]:2
1319 DEBUGF
1,"Switching to 16-bit mode\n"
1321 mov [ebx + device.read_csr
], wio_read_csr
1322 mov [ebx + device.write_csr
], wio_write_csr
1323 mov [ebx + device.read_bcr
], wio_read_bcr
1324 mov [ebx + device.write_bcr
], wio_write_bcr
1325 mov [ebx + device.read_rap
], wio_read_rap
1326 mov [ebx + device.write_rap
], wio_write_rap
1327 mov [ebx + device.sw_reset
], wio_reset
1334 DEBUGF
1,"Switching to 32-bit mode\n"
1336 mov [ebx + device.read_csr
], dwio_read_csr
1337 mov [ebx + device.write_csr
], dwio_write_csr
1338 mov [ebx + device.read_bcr
], dwio_read_bcr
1339 mov [ebx + device.write_bcr
], dwio_write_bcr
1340 mov [ebx + device.read_rap
], dwio_read_rap
1341 mov [ebx + device.write_rap
], dwio_write_rap
1342 mov [ebx + device.sw_reset
], dwio_reset
1356 add edx, WIO_RDP
- WIO_RAP
1373 add edx, WIO_RDP
- WIO_RAP
1389 add edx, WIO_BDP
- WIO_RAP
1406 add edx, WIO_BDP
- WIO_RAP
1454 add edx, DWIO_RDP
- DWIO_RAP
1470 add edx, DWIO_RDP
- DWIO_RAP
1486 add edx, DWIO_BDP
- DWIO_RAP
1502 add edx, DWIO_BDP
- DWIO_RAP
1546 mov ax, [ebx + device.phy
]
1551 mov ecx, BCR_MIIADDR
1552 call [ebx + device.write_bcr
]
1554 mov ecx, BCR_MIIDATA
1555 call [ebx + device.read_bcr
]
1565 mov ax, [ebx + device.phy
]
1570 mov ecx, BCR_MIIADDR
1571 call [ebx + device.write_bcr
]
1574 mov ecx, BCR_MIIDATA
1575 call [ebx + device.write_bcr
]
1582 proc check_media_mii stdcall
dev:dword
1587 mov edx, [ebx + device.io_addr
]
1596 and eax, BMSR_LSTATUS
1598 cmp eax, [ebx + device.state
]
1601 spin_unlock_irqrestore
1608 test ecx, BMSR_ANEGCOMPLETE
1611 mov ecx, MII_ADVERTISE
1619 test eax, LPA_100FULL
1621 mov eax, ETH_LINK_SPEED_100M
or ETH_LINK_FULL_DUPLEX
1625 test eax, LPA_100HALF
1627 mov eax, ETH_LINK_SPEED_100M
1631 test eax, LPA_10FULL
1633 mov eax, ETH_LINK_SPEED_10M
or ETH_LINK_FULL_DUPLEX
1637 test eax, LPA_10HALF
1639 mov eax, ETH_LINK_SPEED_10M
1643 mov eax, ETH_LINK_UNKNOWN
1646 mov [ebx + device.state
], eax
1647 invoke NetLinkChanged
1650 spin_unlock_irqrestore
1663 include '../peimport.inc'
1665 my_service
db 'PCNET32',0 ; max 16 chars include zero
1667 device_l2
db "PCnet/PCI 79C970",0
1668 device_l4
db "PCnet/PCI II 79C970A",0
1669 device_l5
db "PCnet/FAST 79C971",0
1670 device_l6
db "PCnet/FAST+ 79C972",0
1671 device_l7
db "PCnet/FAST III 79C973",0
1672 device_l8
db "PCnet/Home 79C978",0
1673 device_l9
db "PCnet/FAST III 79C975",0
1676 dd PORT_ASEL
; 0 Auto-select
1677 dd PORT_AUI
; 1 BNC/AUI
1678 dd PORT_AUI
; 2 AUI/BNC
1679 dd PORT_ASEL
; 3 not supported
1680 dd PORT_10BT
or PORT_FD
; 4 10baseT-FD
1681 dd PORT_ASEL
; 5 not supported
1682 dd PORT_ASEL
; 6 not supported
1683 dd PORT_ASEL
; 7 not supported
1684 dd PORT_ASEL
; 8 not supported
1685 dd PORT_MII
; 9 MII 10baseT
1686 dd PORT_MII
or PORT_FD
; 10 MII 10baseT-FD
1687 dd PORT_MII
; 11 MII (autosel)
1688 dd PORT_10BT
; 12 10BaseT
1689 dd PORT_MII
or PORT_100
; 13 MII 100BaseTx
1690 dd PORT_MII
or PORT_100
or PORT_FD
; 14 MII 100BaseTx-FD
1691 dd PORT_ASEL
; 15 not supported
1693 include_debug_strings
; All data wich FDO uses will be included here
1698 device_list rd MAX_DEVICES
; This list contains all pointers to device structures the driver is handling