1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3 ;; Copyright (C) KolibriOS team 2004-2021. All rights reserved. ;;
4 ;; Distributed under terms of the GNU General Public License ;;
6 ;; i8254x driver for KolibriOS ;;
8 ;; based on i8254x.asm from baremetal os ;;
10 ;; Written by hidnplayr (hidnplayr@gmail.com) ;;
12 ;; GNU GENERAL PUBLIC LICENSE ;;
13 ;; Version 2, June 1991 ;;
15 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
21 COMPATIBLE_API
= 0x0100
22 API_VERSION
= (COMPATIBLE_API
shl 16) + CURRENT_API
27 __DEBUG_LEVEL__
= 2 ; 1 = verbose, 2 = errors only
29 MAX_PKT_SIZE
= 1514 ; Maximum packet size
31 RX_RING_SIZE
= 64 ; Must be a power of 2, and minimum 8
32 TX_RING_SIZE
= 64 ; Must be a power of 2, and minimum 8
34 section '.flat' readable writable executable
36 include '../proc32.inc'
37 include '../struct.inc'
38 include '../macros.inc'
40 include '../netdrv.inc'
43 REG_CTRL
= 0x0000 ; Control Register
44 REG_STATUS
= 0x0008 ; Device Status Register
45 REG_CTRLEXT
= 0x0018 ; Extended Control Register
46 REG_MDIC
= 0x0020 ; MDI Control Register
47 REG_FCAL
= 0x0028 ; Flow Control Address Low
48 REG_FCAH
= 0x002C ; Flow Control Address High
49 REG_FCT
= 0x0030 ; Flow Control Type
50 REG_VET
= 0x0038 ; VLAN Ether Type
51 REG_ICR
= 0x00C0 ; Interrupt Cause Read
52 REG_ITR
= 0x00C4 ; Interrupt Throttling Register
53 REG_ICS
= 0x00C8 ; Interrupt Cause Set Register
54 REG_IMS
= 0x00D0 ; Interrupt Mask Set/Read Register
55 REG_IMC
= 0x00D8 ; Interrupt Mask Clear Register
56 REG_RCTL
= 0x0100 ; Receive Control Register
57 REG_FCTTV
= 0x0170 ; Flow Control Transmit Timer Value
58 REG_TXCW
= 0x0178 ; Transmit Configuration Word
59 REG_RXCW
= 0x0180 ; Receive Configuration Word
60 REG_TCTL
= 0x0400 ; Transmit Control Register
61 REG_TIPG
= 0x0410 ; Transmit Inter Packet Gap
63 REG_LEDCTL
= 0x0E00 ; LED Control
64 REG_PBA
= 0x1000 ; Packet Buffer Allocation
66 REG_RDBAL
= 0x2800 ; RX Descriptor Base Address Low
67 REG_RDBAH
= 0x2804 ; RX Descriptor Base Address High
68 REG_RDLEN
= 0x2808 ; RX Descriptor Length
69 REG_RDH
= 0x2810 ; RX Descriptor Head
70 REG_RDT
= 0x2818 ; RX Descriptor Tail
71 REG_RDTR
= 0x2820 ; RX Delay Timer Register
72 REG_RXDCTL
= 0x3828 ; RX Descriptor Control
73 REG_RADV
= 0x282C ; RX Int. Absolute Delay Timer
74 REG_RSRPD
= 0x2C00 ; RX Small Packet Detect Interrupt
76 REG_TXDMAC
= 0x3000 ; TX DMA Control
77 REG_TDBAL
= 0x3800 ; TX Descriptor Base Address Low
78 REG_TDBAH
= 0x3804 ; TX Descriptor Base Address High
79 REG_TDLEN
= 0x3808 ; TX Descriptor Length
80 REG_TDH
= 0x3810 ; TX Descriptor Head
81 REG_TDT
= 0x3818 ; TX Descriptor Tail
82 REG_TIDV
= 0x3820 ; TX Interrupt Delay Value
83 REG_TXDCTL
= 0x3828 ; TX Descriptor Control
84 REG_TADV
= 0x382C ; TX Absolute Interrupt Delay Value
85 REG_TSPMT
= 0x3830 ; TCP Segmentation Pad & Min Threshold
87 REG_RXCSUM
= 0x5000 ; RX Checksum Control
89 ; Register list for i8254x
90 I82542_REG_RDTR
= 0x0108 ; RX Delay Timer Register
91 I82542_REG_RDBAL
= 0x0110 ; RX Descriptor Base Address Low
92 I82542_REG_RDBAH
= 0x0114 ; RX Descriptor Base Address High
93 I82542_REG_RDLEN
= 0x0118 ; RX Descriptor Length
94 I82542_REG_RDH
= 0x0120 ; RDH for i82542
95 I82542_REG_RDT
= 0x0128 ; RDT for i82542
96 I82542_REG_TDBAL
= 0x0420 ; TX Descriptor Base Address Low
97 I82542_REG_TDBAH
= 0x0424 ; TX Descriptor Base Address Low
98 I82542_REG_TDLEN
= 0x0428 ; TX Descriptor Length
99 I82542_REG_TDH
= 0x0430 ; TDH for i82542
100 I82542_REG_TDT
= 0x0438 ; TDT for i82542
102 ; CTRL - Control Register (0x0000)
103 CTRL_FD
= 0x00000001 ; Full Duplex
104 CTRL_LRST
= 0x00000008 ; Link Reset
105 CTRL_ASDE
= 0x00000020 ; Auto-speed detection
106 CTRL_SLU
= 0x00000040 ; Set Link Up
107 CTRL_ILOS
= 0x00000080 ; Invert Loss of Signal
108 CTRL_SPEED_MASK
= 0x00000300 ; Speed selection
110 CTRL_FRCSPD
= 0x00000800 ; Force Speed
111 CTRL_FRCDPLX
= 0x00001000 ; Force Duplex
112 CTRL_SDP0_DATA
= 0x00040000 ; SDP0 data
113 CTRL_SDP1_DATA
= 0x00080000 ; SDP1 data
114 CTRL_SDP0_IODIR
= 0x00400000 ; SDP0 direction
115 CTRL_SDP1_IODIR
= 0x00800000 ; SDP1 direction
116 CTRL_RST
= 0x04000000 ; Device Reset
117 CTRL_RFCE
= 0x08000000 ; RX Flow Ctrl Enable
118 CTRL_TFCE
= 0x10000000 ; TX Flow Ctrl Enable
119 CTRL_VME
= 0x40000000 ; VLAN Mode Enable
120 CTRL_PHY_RST
= 0x80000000 ; PHY reset
122 ; STATUS - Device Status Register (0x0008)
123 STATUS_FD
= 0x00000001 ; Full Duplex
124 STATUS_LU
= 0x00000002 ; Link Up
125 STATUS_TXOFF
= 0x00000010 ; Transmit paused
126 STATUS_TBIMODE
= 0x00000020 ; TBI Mode
127 STATUS_SPEED_MASK
= 0x000000C0 ; Link Speed setting
128 STATUS_SPEED_SHIFT
= 6
129 STATUS_ASDV_MASK
= 0x00000300 ; Auto Speed Detection
130 STATUS_ASDV_SHIFT
= 8
131 STATUS_PCI66
= 0x00000800 ; PCI bus speed
132 STATUS_BUS64
= 0x00001000 ; PCI bus width
133 STATUS_PCIX_MODE
= 0x00002000 ; PCI-X mode
134 STATUS_PCIXSPD_MASK
= 0x0000C000 ; PCI-X speed
135 STATUS_PCIXSPD_SHIFT
= 14
137 ; CTRL_EXT - Extended Device Control Register (0x0018)
138 CTRLEXT_PHY_INT
= 0x00000020 ; PHY interrupt
139 CTRLEXT_SDP6_DATA
= 0x00000040 ; SDP6 data
140 CTRLEXT_SDP7_DATA
= 0x00000080 ; SDP7 data
141 CTRLEXT_SDP6_IODIR
= 0x00000400 ; SDP6 direction
142 CTRLEXT_SDP7_IODIR
= 0x00000800 ; SDP7 direction
143 CTRLEXT_ASDCHK
= 0x00001000 ; Auto-Speed Detect Chk
144 CTRLEXT_EE_RST
= 0x00002000 ; EEPROM reset
145 CTRLEXT_SPD_BYPS
= 0x00008000 ; Speed Select Bypass
146 CTRLEXT_RO_DIS
= 0x00020000 ; Relaxed Ordering Dis.
147 CTRLEXT_LNKMOD_MASK
= 0x00C00000 ; Link Mode
148 CTRLEXT_LNKMOD_SHIFT
= 22
150 ; MDIC - MDI Control Register (0x0020)
151 MDIC_DATA_MASK
= 0x0000FFFF ; Data
152 MDIC_REG_MASK
= 0x001F0000 ; PHY Register
154 MDIC_PHY_MASK
= 0x03E00000 ; PHY Address
156 MDIC_OP_MASK
= 0x0C000000 ; Opcode
158 MDIC_R
= 0x10000000 ; Ready
159 MDIC_I
= 0x20000000 ; Interrupt Enable
160 MDIC_E
= 0x40000000 ; Error
162 ; ICR - Interrupt Cause Read (0x00c0)
163 ICR_TXDW
= 0x00000001 ; TX Desc Written back
164 ICR_TXQE
= 0x00000002 ; TX Queue Empty
165 ICR_LSC
= 0x00000004 ; Link Status Change
166 ICR_RXSEQ
= 0x00000008 ; RX Sence Error
167 ICR_RXDMT0
= 0x00000010 ; RX Desc min threshold reached
168 ICR_RXO
= 0x00000040 ; RX Overrun
169 ICR_RXT0
= 0x00000080 ; RX Timer Interrupt
170 ICR_MDAC
= 0x00000200 ; MDIO Access Complete
171 ICR_RXCFG
= 0x00000400
172 ICR_PHY_INT
= 0x00001000 ; PHY Interrupt
173 ICR_GPI_SDP6
= 0x00002000 ; GPI on SDP6
174 ICR_GPI_SDP7
= 0x00004000 ; GPI on SDP7
175 ICR_TXD_LOW
= 0x00008000 ; TX Desc low threshold hit
176 ICR_SRPD
= 0x00010000 ; Small RX packet detected
178 ; RCTL - Receive Control Register (0x0100)
179 RCTL_EN
= 0x00000002 ; Receiver Enable
180 RCTL_SBP
= 0x00000004 ; Store Bad Packets
181 RCTL_UPE
= 0x00000008 ; Unicast Promiscuous Enabled
182 RCTL_MPE
= 0x00000010 ; Xcast Promiscuous Enabled
183 RCTL_LPE
= 0x00000020 ; Long Packet Reception Enable
184 RCTL_LBM_MASK
= 0x000000C0 ; Loopback Mode
186 RCTL_RDMTS_MASK
= 0x00000300 ; RX Desc Min Threshold Size
188 RCTL_MO_MASK
= 0x00003000 ; Multicast Offset
190 RCTL_BAM
= 0x00008000 ; Broadcast Accept Mode
191 RCTL_BSIZE_MASK
= 0x00030000 ; RX Buffer Size
192 RCTL_BSIZE_SHIFT
= 16
193 RCTL_VFE
= 0x00040000 ; VLAN Filter Enable
194 RCTL_CFIEN
= 0x00080000 ; CFI Enable
195 RCTL_CFI
= 0x00100000 ; Canonical Form Indicator Bit
196 RCTL_DPF
= 0x00400000 ; Discard Pause Frames
197 RCTL_PMCF
= 0x00800000 ; Pass MAC Control Frames
198 RCTL_BSEX
= 0x02000000 ; Buffer Size Extension
199 RCTL_SECRC
= 0x04000000 ; Strip Ethernet CRC
201 ; TCTL - Transmit Control Register (0x0400)
202 TCTL_EN
= 0x00000002 ; Transmit Enable
203 TCTL_PSP
= 0x00000008 ; Pad short packets
204 TCTL_SWXOFF
= 0x00400000 ; Software XOFF Transmission
206 ; PBA - Packet Buffer Allocation (0x1000)
207 PBA_RXA_MASK
= 0x0000FFFF ; RX Packet Buffer
209 PBA_TXA_MASK
= 0xFFFF0000 ; TX Packet Buffer
213 FCT_TYPE_DEFAULT
= 0x8808
217 ; === TX Descriptor ===
222 length_cso_cmd
dd ? ; 16 bits length + 8 bits cso + 8 bits cmd
223 status
dd ? ; status, checksum start field, special
226 ; TX Packet Length (word 2)
227 TXDESC_LEN_MASK
= 0x0000ffff
229 ; TX Descriptor CMD field (word 2)
230 TXDESC_IDE
= 0x80000000 ; Interrupt Delay Enable
231 TXDESC_VLE
= 0x40000000 ; VLAN Packet Enable
232 TXDESC_DEXT
= 0x20000000 ; Extension
233 TXDESC_RPS
= 0x10000000 ; Report Packet Sent
234 TXDESC_RS
= 0x08000000 ; Report Status
235 TXDESC_IC
= 0x04000000 ; Insert Checksum
236 TXDESC_IFCS
= 0x02000000 ; Insert FCS
237 TXDESC_EOP
= 0x01000000 ; End Of Packet
239 ; TX Descriptor STA field (word 3)
240 TXDESC_TU
= 0x00000008 ; Transmit Underrun
241 TXDESC_LC
= 0x00000004 ; Late Collision
242 TXDESC_EC
= 0x00000002 ; Excess Collisions
243 TXDESC_DD
= 0x00000001 ; Descriptor Done
247 ; === RX Descriptor ===
256 ; RX Packet Length (word 2)
257 RXDESC_LEN_MASK
= 0x0000ffff
259 ; RX Descriptor STA field (word 3)
260 RXDESC_PIF
= 0x00000080 ; Passed In-exact Filter
261 RXDESC_IPCS
= 0x00000040 ; IP cksum calculated
262 RXDESC_TCPCS
= 0x00000020 ; TCP cksum calculated
263 RXDESC_VP
= 0x00000008 ; Packet is 802.1Q
264 RXDESC_IXSM
= 0x00000004 ; Ignore cksum indication
265 RXDESC_EOP
= 0x00000002 ; End Of Packet
266 RXDESC_DD
= 0x00000001 ; Descriptor Done
268 struct device ETH_DEVICE
279 rb
0x100 - ($
and 0xff) ; align 256
280 rx_desc rb RX_RING_SIZE
*sizeof.RDESC
*2
282 rb
0x100 - ($
and 0xff) ; align 256
283 tx_desc rb TX_RING_SIZE
*sizeof.TDESC
*2
287 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
291 ;; (standard driver proc) ;;
292 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
294 proc START c
, reason:dword, cmdline:dword
296 cmp [reason
], DRV_ENTRY
299 DEBUGF
1,"Loading driver\n"
300 invoke RegService
, my_service
, service_proc
310 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
312 ;; proc SERVICE_PROC ;;
314 ;; (standard driver proc) ;;
315 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
318 proc service_proc stdcall
, ioctl:dword
321 mov eax, [edx + IOCTL.io_code
]
323 ;------------------------------------------------------
325 cmp eax, 0 ;SRV_GETVERSION
328 cmp [edx + IOCTL.out_size
], 4
330 mov eax, [edx + IOCTL.output
]
331 mov dword[eax], API_VERSION
336 ;------------------------------------------------------
341 cmp [edx + IOCTL.inp_size
], 3 ; Data input must be at least 3 bytes
344 mov eax, [edx + IOCTL.input
]
345 cmp byte[eax], 1 ; 1 means device number and bus number (pci) are given
346 jne .fail
; other types arent supported for this card yet
348 ; check if the device is already listed
355 ; mov eax, [edx + IOCTL.input] ; get the pci bus and device numbers
359 cmp al, byte[ebx + device.pci_bus
]
361 cmp ah, byte[ebx + device.pci_dev
]
362 je .find_devicenum
; Device is already loaded, let's find it's device number
368 ; This device doesnt have its own eth_device structure yet, lets create one
370 cmp [devices
], MAX_DEVICES
; First check if the driver can handle one more card
373 allocate_and_clear
ebx, sizeof.device
, .fail
; Allocate the buffer for device structure
375 ; Fill in the direct call addresses into the struct
377 mov [ebx + device.reset
], reset
378 mov [ebx + device.transmit
], transmit
379 mov [ebx + device.unload
], unload
380 mov [ebx + device.
name], my_service
382 ; save the pci bus and device numbers
384 mov eax, [edx + IOCTL.input
]
385 movzx ecx, byte[eax+1]
386 mov [ebx + device.pci_bus
], ecx
387 movzx ecx, byte[eax+2]
388 mov [ebx + device.pci_dev
], ecx
390 ; Now, it's time to find the base mmio addres of the PCI device
392 stdcall PCI_find_mmio
, [ebx + device.pci_bus
], [ebx + device.pci_dev
] ; returns in eax
396 ; Create virtual mapping of the physical memory
398 invoke MapIoMem
, eax, 10000h, PG_SW
+PG_NOCACHE
399 mov [ebx + device.mmio_addr
], eax
401 ; We've found the mmio address, find IRQ now
403 invoke PciRead8
, [ebx + device.pci_bus
], [ebx + device.pci_dev
], PCI_header00.interrupt_line
404 mov [ebx + device.irq_line
], al
406 DEBUGF
1,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\
407 [ebx + device.pci_dev
]:1,[ebx + device.pci_bus
]:1,[ebx + device.irq_line
]:1,[ebx + device.mmio_addr
]:8
409 ; Ok, the eth_device structure is ready, let's probe the device
410 call probe
; this function will output in eax
412 jnz .err
; If an error occured, exit
414 mov eax, [devices
] ; Add the device structure to our device list
415 mov [device_list
+4*eax], ebx ; (IRQ handler uses this list to find device)
422 mov [ebx + device.
type], NET_TYPE_ETH
429 ; If the device was already loaded, find the device number and return it in eax
432 DEBUGF
1,"Trying to find device number of already registered device\n"
433 invoke NetPtrToNum
; This kernel procedure converts a pointer to device struct in ebx
434 ; into a device number in edi
435 mov eax, edi ; Application wants it in eax instead
436 DEBUGF
1,"Kernel says: %u\n", eax
439 ; If an error occured, remove all allocated data and exit (returning -1 in eax)
442 ; todo: reset device into virgin state
445 invoke KernelFree
, ebx
448 DEBUGF
2,"Loading driver failed\n"
452 ;------------------------------------------------------
456 ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
458 ;; Actual Hardware dependent code starts here ;;
460 ;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;;
468 ; TODO: (in this particular order)
471 ; - Detach int handler
472 ; - Remove device from local list (device_list)
473 ; - call unregister function in kernel
474 ; - Remove all allocated structures and buffers the card used
481 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
483 ;; probe: enables the device (if it really is I8254X)
485 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
491 ; Make the device a bus master
492 invoke PciRead32
, [ebx + device.pci_bus
], [ebx + device.pci_dev
], PCI_header00.command
493 or al, PCI_CMD_MASTER
494 invoke PciWrite32
, [ebx + device.pci_bus
], [ebx + device.pci_dev
], PCI_header00.command
, eax
496 ; TODO: validate the device
500 movzx eax, [ebx + device.irq_line
]
501 DEBUGF
1,"Attaching int handler to irq %x\n", eax:1
502 invoke AttachIntHandler
, eax, int_handler
, ebx
505 DEBUGF
2,"Could not attach int handler!\n"
514 mov esi, [ebx + device.mmio_addr
]
516 or dword[esi + REG_CTRL
], CTRL_RST
; reset device
523 test dword[esi + REG_CTRL
], CTRL_RST
526 mov dword[esi + REG_IMC
], 0xffffffff ; Disable all interrupt causes
527 mov eax, dword [esi + REG_ICR
] ; Clear any pending interrupts
528 mov dword[esi + REG_ITR
], 0 ; Disable interrupt throttling logic
530 mov dword[esi + REG_PBA
], 0x00000004 ; PBA: set the RX buffer size to 4KB (TX buffer is calculated as 64-RX buffer)
531 mov dword[esi + REG_RDTR
], 0 ; RDTR: set no delay
533 mov dword[esi + REG_TXCW
], 0x00008060 ; TXCW: TxConfigWord (Half/Full duplex, Next Page Reqest)
535 mov eax, [esi + REG_CTRL
]
536 or eax, 1 shl 6 + 1 shl 5
537 and eax, not (1 shl 3 + 1 shl 7 + 1 shl 30 + 1 shl 31)
538 mov dword [esi + REG_CTRL
], eax ; CTRL: clear LRST, set SLU and ASDE, clear RSTPHY, VME, and ILOS
540 lea edi, [esi + 0x5200] ; MTA: reset
561 lea edi, [ebx + device.rx_desc
]
562 mov ecx, RX_RING_SIZE
566 invoke NetAlloc
, MAX_PKT_SIZE
+NET_BUFF.data
569 DEBUGF
1,"RX buffer: 0x%x\n", eax
571 mov dword[edi + RX_RING_SIZE
*sizeof.RDESC
], eax
575 add eax, NET_BUFF.data
576 mov [edi + RDESC.addr_l
], eax
577 mov [edi + RDESC.addr_h
], 0
578 mov [edi + RDESC.status_l
], 0
579 mov [edi + RDESC.status_h
], 0
580 add edi, sizeof.RDESC
585 mov [ebx + device.cur_rx
], 0
587 lea eax, [ebx + device.rx_desc
]
589 mov dword[esi + REG_RDBAL
], eax ; Receive Descriptor Base Address Low
590 mov dword[esi + REG_RDBAH
], 0 ; Receive Descriptor Base Address High
591 mov dword[esi + REG_RDLEN
], RX_RING_SIZE
*sizeof.RDESC
; Receive Descriptor Length
592 mov dword[esi + REG_RDH
], 0 ; Receive Descriptor Head
593 mov dword[esi + REG_RDT
], RX_RING_SIZE
-1 ; Receive Descriptor Tail
594 mov dword[esi + REG_RCTL
], RCTL_SBP
or RCTL_BAM
or RCTL_SECRC
or RCTL_UPE
or RCTL_MPE
595 ; Store Bad Packets, Broadcast Accept Mode, Strip Ethernet CRC from incoming packet, Promiscuous mode
596 xor eax, eax ; success!
600 DEBUGF
2,"Out of memory!\n"
610 lea edi, [ebx + device.tx_desc
]
611 mov ecx, TX_RING_SIZE
613 mov [edi + TDESC.addr_l
], eax
614 mov [edi + TDESC.addr_h
], 0
615 mov [edi + TDESC.length_cso_cmd
], 0
616 mov [edi + TDESC.status
], 0
617 add edi, sizeof.TDESC
621 mov [ebx + device.cur_tx
], 0
622 mov [ebx + device.last_tx
], 0
624 lea eax, [ebx + device.tx_desc
]
626 mov dword[esi + REG_TDBAL
], eax ; Transmit Descriptor Base Address Low
627 mov dword[esi + REG_TDBAH
], 0 ; Transmit Descriptor Base Address High
628 mov dword[esi + REG_TDLEN
], RX_RING_SIZE
*sizeof.TDESC
; Transmit Descriptor Length
629 mov dword[esi + REG_TDH
], 0 ; Transmit Descriptor Head
630 mov dword[esi + REG_TDT
], 0 ; Transmit Descriptor Tail
631 mov dword[esi + REG_TCTL
], 0x010400fa ; Enabled, Pad Short Packets, 15 retrys, 64-byte COLD, Re-transmit on Late Collision
632 mov dword[esi + REG_TIPG
], 0x0060200A ; IPGT 10, IPGR1 8, IPGR2 6
648 mov esi, [ebx + device.mmio_addr
]
649 or dword[esi + REG_RCTL
], RCTL_EN
; Enable the receiver
652 mov [esi + REG_RDTR
], eax ; Clear the Receive Delay Timer Register
653 mov [esi + REG_RADV
], eax ; Clear the Receive Interrupt Absolute Delay Timer
654 mov [esi + REG_RSRPD
], eax ; Clear the Receive Small Packet Detect Interrupt
656 mov dword[esi + REG_IMS
], 0x1F6DC ; Enable interrupt types
657 mov eax, [esi + REG_ICR
] ; Clear pending interrupts
659 mov [ebx + device.mtu
], 1514
671 DEBUGF
1,"Read MAC\n"
673 mov esi, [ebx + device.mmio_addr
]
675 mov eax, [esi+0x5400] ; RAL
679 mov dword[ebx + device.mac
], eax
680 mov eax, [esi+0x5404] ; RAH
681 mov word[ebx + device.mac
+4], ax
686 mov dword[esi+0x14], 0x00000001
689 mov word[ebx + device.mac
], ax
691 mov dword[esi+0x14], 0x00000101
694 mov word[ebx + device.mac
+2], ax
696 mov dword[esi+0x14], 0x00000201
699 mov word[ebx + device.mac
+4], ax
702 DEBUGF
1,"MAC = %x-%x-%x-%x-%x-%x\n",\
703 [ebx + device.mac
+0]:2,[ebx + device.mac
+1]:2,[ebx + device.mac
+2]:2,\
704 [ebx + device.mac
+3]:2,[ebx + device.mac
+4]:2,[ebx + device.mac
+5]:2
711 DEBUGF
1,"Verifying link status\n"
713 xor ecx, ecx ; ETH_LINK_DOWN
714 mov esi, [ebx + device.mmio_addr
]
715 mov eax, [esi + REG_STATUS
]
721 or cl, ETH_LINK_FULL_DUPLEX
723 shr eax, STATUS_SPEED_SHIFT
727 or cl, ETH_LINK_SPEED_10M
732 or cl, ETH_LINK_SPEED_100M
735 or cl, ETH_LINK_SPEED_1G
739 mov [ebx + device.state
], ecx
740 invoke NetLinkChanged
744 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
748 ;; In: ebx = pointer to device structure ;;
749 ;; Out: eax = 0 on success ;;
751 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
753 proc transmit stdcall bufferptr
758 DEBUGF
1,"Transmitting packet, buffer:%x, size:%u\n", [bufferptr
], [esi + NET_BUFF.
length]
759 lea eax, [esi + NET_BUFF.data
]
760 DEBUGF
1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\
761 [eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\
762 [eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\
763 [eax+13]:2,[eax+12]:2
765 cmp [esi + NET_BUFF.
length], 1514
767 cmp [esi + NET_BUFF.
length], 60
770 ; Program the descriptor (use legacy mode)
771 mov edi, [ebx + device.cur_tx
]
772 DEBUGF
1, "Using TX desc: %u\n", edi
773 shl edi, 4 ; edi = edi * sizeof.TDESC
774 lea edi, [ebx + device.tx_desc
+ edi]
776 mov dword[edi + TX_RING_SIZE
*sizeof.TDESC
], eax ; Store the data location (for driver)
777 add eax, [eax + NET_BUFF.
offset]
779 mov [edi + TDESC.addr_l
], eax ; Data location (for hardware)
780 mov [edi + TDESC.addr_h
], 0
782 mov ecx, [esi + NET_BUFF.
length]
783 or ecx, TXDESC_EOP
+ TXDESC_IFCS
+ TXDESC_RS
784 mov [edi + TDESC.length_cso_cmd
], ecx
785 mov [edi + TDESC.status
], 0
787 ; Tell i8254x wich descriptor(s) we programmed, by moving the tail
788 mov edi, [ebx + device.mmio_addr
]
789 mov eax, [ebx + device.cur_tx
]
791 and eax, TX_RING_SIZE
-1
792 mov [ebx + device.cur_tx
], eax
793 mov dword[edi + REG_TDT
], eax ; TDT - Transmit Descriptor Tail
796 inc [ebx + device.packets_tx
]
797 mov eax, [esi + NET_BUFF.
length]
798 add dword[ebx + device.bytes_tx
], eax
799 adc dword[ebx + device.bytes_tx
+ 4], 0
803 spin_unlock_irqrestore
810 DEBUGF
2,"Send failed\n"
811 invoke NetFree
, [bufferptr
]
812 spin_unlock_irqrestore
819 ;;;;;;;;;;;;;;;;;;;;;;;
821 ;; Interrupt handler ;;
823 ;;;;;;;;;;;;;;;;;;;;;;;
830 DEBUGF
1,"INT for 0x%x\n", ebx
832 ; TODO? if we are paranoid, we can check that the value from ebx is present in the current device_list
834 mov edi, [ebx + device.mmio_addr
]
835 mov eax, [edi + REG_ICR
]
836 cmp eax, 0xffffffff ; if so, hardware is no longer present
841 DEBUGF
1,"Status: %x\n", eax
846 test eax, ICR_RXDMT0
+ ICR_RXT0
852 ; Get last descriptor addr
853 mov esi, [ebx + device.cur_rx
]
854 shl esi, 4 ; esi = esi * sizeof.RDESC
855 lea esi, [ebx + device.rx_desc
+ esi]
856 cmp byte[esi + RDESC.status_h
], 0 ; Check status field
861 movzx ecx, word[esi + 8] ; Get the packet length
862 DEBUGF
1,"got %u bytes\n", ecx
863 mov eax, [esi + RX_RING_SIZE
*sizeof.RDESC
] ; Get packet pointer
865 mov [eax + NET_BUFF.
length], ecx
866 mov [eax + NET_BUFF.device
], ebx
867 mov [eax + NET_BUFF.
offset], NET_BUFF.data
870 add dword[ebx + device.bytes_rx
], ecx
871 adc dword[ebx + device.bytes_rx
+ 4], 0
872 inc [ebx + device.packets_rx
]
874 ; Allocate new descriptor
876 invoke NetAlloc
, MAX_PKT_SIZE
+NET_BUFF.data
880 mov dword[esi + RX_RING_SIZE
*sizeof.RDESC
], eax
882 add eax, NET_BUFF.data
883 mov [esi + RDESC.addr_l
], eax
884 mov [esi + RDESC.status_l
], 0
885 mov [esi + RDESC.status_h
], 0
887 ; Move the receive descriptor tail
888 mov esi, [ebx + device.mmio_addr
]
889 mov eax, [ebx + device.cur_rx
]
890 mov [esi + REG_RDT
], eax
892 ; Move to next rx desc
893 inc [ebx + device.cur_rx
]
894 and [ebx + device.cur_rx
], RX_RING_SIZE
-1
899 DEBUGF
2,"Out of memory!\n"
901 ; Move to next rx desc
902 inc [ebx + device.cur_rx
]
903 and [ebx + device.cur_rx
], RX_RING_SIZE
-1
914 DEBUGF
2,"Link Changed\n"
926 DEBUGF
1,"Transmit done\n"
948 mov edi, [ebx + device.last_tx
]
949 shl edi, 4 ; edi = edi * sizeof.TDESC
950 lea edi, [ebx + device.tx_desc
+ edi]
951 test [edi + TDESC.status
], TXDESC_DD
; Descriptor done?
953 cmp dword[edi + TX_RING_SIZE
*sizeof.TDESC
], 0
956 DEBUGF
1,"Cleaning up TX desc: 0x%x\n", edi
959 push dword[edi + TX_RING_SIZE
*sizeof.TDESC
]
960 mov dword[edi + TX_RING_SIZE
*sizeof.TDESC
], 0
964 inc [ebx + device.last_tx
]
965 and [ebx + device.last_tx
], TX_RING_SIZE
-1
980 include '../peimport.inc'
982 include_debug_strings
983 my_service
db 'I8254X', 0 ; max 16 chars include zero
987 device_list rd MAX_DEVICES
; This list contains all pointers to device structures the driver is handling