0,0 → 1,1259 |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Copyright (C) KolibriOS team 2004-2010. All rights reserved. ;; |
;; Distributed under terms of the GNU General Public License ;; |
;; ;; |
;; MTD80x driver for KolibriOS ;; |
;; ;; |
;; Based on mtd80x.c from the etherboot project ;; |
;; ;; |
;; Written by hidnplayr@kolibrios.org ;; |
;; ;; |
;; GNU GENERAL PUBLIC LICENSE ;; |
;; Version 2, June 1991 ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
format MS COFF |
|
API_VERSION equ 0x01000100 |
DRIVER_VERSION equ 5 |
|
MAX_DEVICES equ 16 |
|
DEBUG equ 1 |
__DEBUG__ equ 1 |
__DEBUG_LEVEL__ equ 1 |
|
NUM_TX_DESC equ 4 |
NUM_RX_DESC equ 4 |
|
include 'proc32.inc' |
include 'imports.inc' |
include 'fdo.inc' |
include 'netdrv.inc' |
|
public START |
public service_proc |
public version |
|
|
; for different PHY |
|
MysonPHY equ 1 |
AhdocPHY equ 2 |
SeeqPHY equ 3 |
MarvellPHY equ 4 |
Myson981 equ 5 |
LevelOnePHY equ 6 |
OtherPHY equ 10 |
|
; Offsets to the Command and Status Registers. |
|
PAR0 equ 0x0 ; physical address 0-3 |
PAR1 equ 0x04 ; physical address 4-5 |
MAR0 equ 0x08 ; multicast address 0-3 |
MAR1 equ 0x0C ; multicast address 4-7 |
FAR0 equ 0x10 ; flow-control address 0-3 |
FAR1 equ 0x14 ; flow-control address 4-5 |
TCRRCR equ 0x18 ; receive & transmit configuration |
BCR equ 0x1C ; bus command |
TXPDR equ 0x20 ; transmit polling demand |
RXPDR equ 0x24 ; receive polling demand |
RXCWP equ 0x28 ; receive current word pointer |
TXLBA equ 0x2C ; transmit list base address |
RXLBA equ 0x30 ; receive list base address |
ISR equ 0x34 ; interrupt status |
IMR equ 0x38 ; interrupt mask |
FTH equ 0x3C ; flow control high/low threshold |
MANAGEMENT equ 0x40 ; bootrom/eeprom and mii management |
TALLY equ 0x44 ; tally counters for crc and mpa |
TSR equ 0x48 ; tally counter for transmit status |
BMCRSR equ 0x4c ; basic mode control and status |
PHYIDENTIFIER equ 0x50 ; phy identifier |
ANARANLPAR equ 0x54 ; auto-negotiation advertisement and link partner ability |
ANEROCR equ 0x58 ; auto-negotiation expansion and pci conf. |
BPREMRPSR equ 0x5c ; bypass & receive error mask and phy status |
|
; Bits in the interrupt status/enable registers. |
|
RFCON equ 0x00020000 ; receive flow control xon packet |
RFCOFF equ 0x00010000 ; receive flow control xoff packet |
LSCStatus equ 0x00008000 ; link status change |
ANCStatus equ 0x00004000 ; autonegotiation completed |
FBE equ 0x00002000 ; fatal bus error |
FBEMask equ 0x00001800 ; mask bit12-11 |
ParityErr equ 0x00000000 ; parity error |
TargetErr equ 0x00001000 ; target abort |
MasterErr equ 0x00000800 ; master error |
TUNF equ 0x00000400 ; transmit underflow |
ROVF equ 0x00000200 ; receive overflow |
ETI equ 0x00000100 ; transmit early int |
ERI equ 0x00000080 ; receive early int |
CNTOVF equ 0x00000040 ; counter overflow |
RBU equ 0x00000020 ; receive buffer unavailable |
TBU equ 0x00000010 ; transmit buffer unavilable |
TI equ 0x00000008 ; transmit interrupt |
RI equ 0x00000004 ; receive interrupt |
RxErr equ 0x00000002 ; receive error |
|
; Bits in the NetworkConfig register. |
|
RxModeMask equ 0xe0 |
AcceptAllPhys equ 0x80 ; promiscuous mode |
AcceptBroadcast equ 0x40 ; accept broadcast |
AcceptMulticast equ 0x20 ; accept mutlicast |
AcceptRunt equ 0x08 ; receive runt pkt |
ALP equ 0x04 ; receive long pkt |
AcceptErr equ 0x02 ; receive error pkt |
|
AcceptMyPhys equ 0x00000000 |
RxEnable equ 0x00000001 |
RxFlowCtrl equ 0x00002000 |
TxEnable equ 0x00040000 |
TxModeFDX equ 0x00100000 |
TxThreshold equ 0x00e00000 |
|
PS1000 equ 0x00010000 |
PS10 equ 0x00080000 |
FD equ 0x00100000 |
|
|
; Bits in network_desc.status |
|
RXOWN equ 0x80000000 ; own bit |
FLNGMASK equ 0x0fff0000 ; frame length |
FLNGShift equ 16 |
MARSTATUS equ 0x00004000 ; multicast address received |
BARSTATUS equ 0x00002000 ; broadcast address received |
PHYSTATUS equ 0x00001000 ; physical address received |
RXFSD equ 0x00000800 ; first descriptor |
RXLSD equ 0x00000400 ; last descriptor |
ErrorSummary equ 0x80 ; error summary |
RUNT equ 0x40 ; runt packet received |
LONG equ 0x20 ; long packet received |
FAE equ 0x10 ; frame align error |
CRC equ 0x08 ; crc error |
RXER equ 0x04 ; receive error |
|
; rx_desc_control_bits |
|
RXIC equ 0x00800000 ; interrupt control |
RBSShift equ 0 |
|
; tx_desc_status_bits |
|
TXOWN equ 0x80000000 ; own bit |
JABTO equ 0x00004000 ; jabber timeout |
CSL equ 0x00002000 ; carrier sense lost |
LC equ 0x00001000 ; late collision |
EC equ 0x00000800 ; excessive collision |
UDF equ 0x00000400 ; fifo underflow |
DFR equ 0x00000200 ; deferred |
HF equ 0x00000100 ; heartbeat fail |
NCRMask equ 0x000000ff ; collision retry count |
NCRShift equ 0 |
|
; tx_desc_control_bits |
|
TXIC equ 0x80000000 ; interrupt control |
ETIControl equ 0x40000000 ; early transmit interrupt |
TXLD equ 0x20000000 ; last descriptor |
TXFD equ 0x10000000 ; first descriptor |
CRCEnable equ 0x08000000 ; crc control |
PADEnable equ 0x04000000 ; padding control |
RetryTxLC equ 0x02000000 ; retry late collision |
PKTSMask equ 0x3ff800 ; packet size bit21-11 |
PKTSShift equ 11 |
TBSMask equ 0x000007ff ; transmit buffer bit 10-0 |
TBSShift equ 0 |
|
; BootROM/EEPROM/MII Management Register |
|
MASK_MIIR_MII_READ equ 0x00000000 |
MASK_MIIR_MII_WRITE equ 0x00000008 |
MASK_MIIR_MII_MDO equ 0x00000004 |
MASK_MIIR_MII_MDI equ 0x00000002 |
MASK_MIIR_MII_MDC equ 0x00000001 |
|
; ST+OP+PHYAD+REGAD+TA |
|
OP_READ equ 0x6000 ; ST:01+OP:10+PHYAD+REGAD+TA:Z0 |
OP_WRITE equ 0x5002 ; ST:01+OP:01+PHYAD+REGAD+TA:10 |
|
; ------------------------------------------------------------------------- |
; Constants for Myson PHY |
; ------------------------------------------------------------------------- |
|
MysonPHYID equ 0xd0000302 |
MysonPHYID0 equ 0x0302 |
StatusRegister equ 18 |
SPEED100 equ 0x0400 ; bit10 |
FULLMODE equ 0x0800 ; bit11 |
|
; ------------------------------------------------------------------------- |
; Constants for Seeq 80225 PHY |
; ------------------------------------------------------------------------- |
|
SeeqPHYID0 equ 0x0016 |
MIIRegister18 equ 18 |
SPD_DET_100 equ 0x80 |
DPLX_DET_FULL equ 0x40 |
|
; ------------------------------------------------------------------------- |
; Constants for Ahdoc 101 PHY |
; ------------------------------------------------------------------------- |
|
AhdocPHYID0 equ 0x0022 |
DiagnosticReg equ 18 |
DPLX_FULL equ 0x0800 |
Speed_100 equ 0x0400 |
|
; -------------------------------------------------------------------------- |
; Constants |
; -------------------------------------------------------------------------- |
|
MarvellPHYID0 equ 0x0141 |
LevelOnePHYID0 equ 0x0013 |
|
MII1000BaseTControlReg equ 9 |
MII1000BaseTStatusReg equ 10 |
SpecificReg equ 17 |
|
; for 1000BaseT Control Register |
|
PHYAbletoPerform1000FullDuplex equ 0x0200 |
PHYAbletoPerform1000HalfDuplex equ 0x0100 |
PHY1000AbilityMask equ 0x300 |
|
; for phy specific status register, marvell phy. |
|
SpeedMask equ 0x0c000 |
Speed_1000M equ 0x08000 |
Speed_100M equ 0x4000 |
Speed_10M equ 0 |
Full_Duplex equ 0x2000 |
|
; for phy specific status register, levelone phy |
|
LXT1000_100M equ 0x08000 |
LXT1000_1000M equ 0x0c000 |
LXT1000_Full equ 0x200 |
|
; for PHY |
|
LinkIsUp equ 0x0004 |
LinkIsUp2 equ 0x00040000 |
|
|
|
virtual at 0 |
|
mtd_desc: |
.status dd ? |
.control dd ? |
.buffer dd ? |
.next_desc dd ? |
|
.next_desc_logical dd ? |
.skbuff dd ? |
|
.reserved1 dd ? |
.reserved2 dd ? |
|
.size = $ |
|
end virtual |
|
|
virtual at ebx |
|
device: |
|
ETH_DEVICE |
|
.tx_desc rb NUM_TX_DESC*mtd_desc.size |
.rx_desc rb NUM_RX_DESC*mtd_desc.size |
|
.io_addr dd ? |
.pci_bus db ? |
.pci_dev db ? |
.irq_line db ? |
.dev_id dw ? |
|
.flags dd ? |
|
.crvalue dd ? |
.bcrvalue dd ? |
|
.cur_rx dd ? |
.cur_tx dd ? |
|
; These values are keep track of the transceiver/media in use. |
|
.linkok dd ? |
.line_speed dd ? |
.duplexmode dd ? |
.default_port dd ? |
.PHYType dd ? |
|
; MII transceiver section. |
|
.mii_cnt dd ? ; MII device addresses. |
.phys db ? ; MII device addresses. |
|
device_size = $ - device |
|
end virtual |
|
|
|
section '.flat' code readable align 16 |
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc START ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
align 4 |
proc START stdcall, state:dword |
|
cmp [state], 1 |
jne .exit |
|
.entry: |
|
DEBUGF 2,"Loading mtd80x driver\n" |
stdcall RegService, my_service, service_proc |
ret |
|
.fail: |
.exit: |
xor eax, eax |
ret |
|
endp |
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; proc SERVICE_PROC ;; |
;; ;; |
;; (standard driver proc) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
align 4 |
proc service_proc stdcall, ioctl:dword |
|
mov edx, [ioctl] |
mov eax, [IOCTL.io_code] |
|
;------------------------------------------------------ |
|
cmp eax, 0 ;SRV_GETVERSION |
jne @F |
|
cmp [IOCTL.out_size], 4 |
jl .fail |
mov eax, [IOCTL.output] |
mov [eax], dword API_VERSION |
|
xor eax, eax |
ret |
|
;------------------------------------------------------ |
@@: |
cmp eax, 1 ;SRV_HOOK |
jne .fail |
|
cmp [IOCTL.inp_size], 3 ; Data input must be at least 3 bytes |
jl .fail |
|
mov eax, [IOCTL.input] |
cmp byte [eax], 1 ; 1 means device number and bus number (pci) are given |
jne .fail ; other types arent supported for this card yet |
|
; check if the device is already listed |
|
mov esi, device_list |
mov ecx, [devices] |
test ecx, ecx |
jz .firstdevice |
|
; mov eax, [IOCTL.input] ; get the pci bus and device numbers |
mov ax , [eax+1] ; |
.nextdevice: |
mov ebx, [esi] |
cmp ax , word [device.pci_bus] ; compare with pci and device num in device list (notice the usage of word instead of byte) |
je .find_devicenum ; Device is already loaded, let's find it's device number |
add esi, 4 |
loop .nextdevice |
|
|
; This device doesnt have its own eth_device structure yet, lets create one |
.firstdevice: |
cmp [devices], MAX_DEVICES ; First check if the driver can handle one more card |
jge .fail |
|
allocate_and_clear ebx, device_size, .fail |
|
; Fill in the direct call addresses into the struct |
|
mov [device.reset], reset |
mov [device.transmit], transmit |
mov [device.get_MAC], read_mac |
mov [device.set_MAC], write_mac |
mov [device.unload], unload |
mov [device.name], my_service |
|
; save the pci bus and device numbers |
|
mov eax, [IOCTL.input] |
mov cl , [eax+1] |
mov [device.pci_bus], cl |
mov cl , [eax+2] |
mov [device.pci_dev], cl |
|
; Now, it's time to find the base io addres of the PCI device |
|
find_io [device.pci_bus], [device.pci_dev], [device.io_addr] |
|
; We've found the io address, find IRQ now |
|
find_irq [device.pci_bus], [device.pci_dev], [device.irq_line] |
|
DEBUGF 2,"Hooking into device, dev:%x, bus:%x, irq:%x, addr:%x\n",\ |
[device.pci_dev]:1,[device.pci_bus]:1,[device.irq_line]:1,[device.io_addr]:8 |
|
; Ok, the eth_device structure is ready, let's probe the device |
; Because initialization fires IRQ, IRQ handler must be aware of this device |
mov eax, [devices] ; Add the device structure to our device list |
mov [device_list+4*eax], ebx ; (IRQ handler uses this list to find device) |
inc [devices] ; |
|
call probe ; this function will output in eax |
test eax, eax |
jnz .err2 ; If an error occured, exit |
|
mov [device.type], NET_TYPE_ETH |
call NetRegDev |
|
cmp eax, -1 |
je .destroy |
|
ret |
|
; If the device was already loaded, find the device number and return it in eax |
|
.find_devicenum: |
DEBUGF 2,"Trying to find device number of already registered device\n" |
mov ebx, eax |
call NetPtrToNum ; This kernel procedure converts a pointer to device struct in ebx |
; into a device number in edi |
mov eax, edi ; Application wants it in eax instead |
DEBUGF 2,"Kernel says: %u\n", eax |
ret |
|
; If an error occured, remove all allocated data and exit (returning -1 in eax) |
|
.destroy: |
; todo: reset device into virgin state |
|
.err2: |
dec [devices] |
.err: |
DEBUGF 2,"removing device structure\n" |
stdcall KernelFree, ebx |
.fail: |
or eax, -1 |
ret |
|
;------------------------------------------------------ |
endp |
|
|
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
;; ;; |
;; Actual Hardware dependent code starts here ;; |
;; ;; |
;;/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\;; |
|
|
|
align 4 |
unload: |
; TODO: (in this particular order) |
; |
; - Stop the device |
|
; /* Disable Tx Rx*/ |
; outl( mtdx.crvalue & (~TxEnable) & (~RxEnable), mtdx.ioaddr + TCRRCR ); |
; |
; /* Reset the chip to erase previous misconfiguration. */ |
; mtd_reset(nic); |
|
; - Detach int handler |
; - Remove device from local list (device_list) |
; - call unregister function in kernel |
; - Remove all allocated structures and buffers the card used |
|
or eax,-1 |
|
ret |
|
|
;------- |
; |
; PROBE |
; |
;------- |
align 4 |
probe: |
|
DEBUGF 2,"Probing mtd80x device\n" |
|
make_bus_master [device.pci_bus], [device.pci_dev] |
|
movzx eax, [device.pci_bus] |
movzx ecx, [device.pci_dev] |
stdcall PciRead32, eax ,ecx ,0 |
|
cmp ax , 0x1516 |
jne .notfound |
shr eax, 16 |
mov [device.dev_id], ax |
|
cmp ax, 0x0800 |
je .has_mii_xcvr |
|
cmp ax, 0x0803 |
je .has_chip_xcvr |
|
cmp ax, 0x0891 |
je .has_mii_xcvr |
|
.notfound: |
DEBUGF 1,"Device not supported!\n" |
xor eax, eax |
dec eax |
ret |
|
.has_chip_xcvr: |
DEBUGF 1,"Device has chip xcvr\n" |
|
jmp .xcvr_set |
|
.has_mii_xcvr: |
DEBUGF 1,"Device has mii xcvr\n" |
|
.xcvr_set: |
|
call read_mac |
|
; Reset the chip to erase previous misconfiguration. |
|
set_io 0 |
set_io BCR |
xor eax, eax |
inc eax |
out dx, eax |
|
; find the connected MII xcvrs |
|
cmp [device.dev_id], 0x0803 |
je .is_803 |
|
; int phy, phy_idx equ 0; |
; |
; for (phy equ 1; phy < 32 && phy_idx < 1; phy++) { |
; int mii_status equ mdio_read(nic, phy, 1); |
; |
; if (mii_status !equ 0xffff && mii_status !equ 0x0000) { |
; mtdx.phys[phy_idx] equ phy; |
; |
; DBG ( "%s: MII PHY found at address %d, status " |
; "0x%4.4x.\n", mtdx.nic_name, phy, mii_status ); |
; /* get phy type */ |
; { |
; unsigned int data; |
; |
; data equ mdio_read(nic, mtdx.phys[phy_idx], 2); |
; if (data equequ SeeqPHYID0) |
; mtdx.PHYType equ SeeqPHY; |
; else if (data equequ AhdocPHYID0) |
; mtdx.PHYType equ AhdocPHY; |
; else if (data equequ MarvellPHYID0) |
; mtdx.PHYType equ MarvellPHY; |
; else if (data equequ MysonPHYID0) |
; mtdx.PHYType equ Myson981; |
; else if (data equequ LevelOnePHYID0) |
; mtdx.PHYType equ LevelOnePHY; |
; else |
; mtdx.PHYType equ OtherPHY; |
; } |
; phy_idx++; |
; } |
; } |
; |
; mtdx.mii_cnt equ phy_idx; |
; if (phy_idx equequ 0) { |
; printf("%s: MII PHY not found -- this device may " |
; "not operate correctly.\n", mtdx.nic_name); |
; } |
|
jmp .no_803 |
|
.is_803: |
|
mov [device.phys], 32 |
|
; get phy type |
set_io 0 |
set_io PHYIDENTIFIER |
in eax, dx |
|
cmp eax, MysonPHYID |
jne @f |
|
mov [device.PHYType], MysonPHY |
DEBUGF 1,"MysonPHY\n" |
jmp .no_803 |
|
@@: |
mov [device.PHYType], OtherPHY |
DEBUGF 1,"OtherPHY\n" |
|
.no_803: |
|
;------- |
; |
; RESET |
; |
;------- |
align 4 |
reset: |
|
DEBUGF 1,"Resetting mtd80x\n" |
|
;-------------------------------- |
; insert irq handler on given irq |
|
movzx eax, [device.irq_line] |
DEBUGF 1,"Attaching int handler to irq %x\n", eax:1 |
stdcall AttachIntHandler, eax, int_handler, dword 0 |
test eax, eax |
jnz @f |
DEBUGF 1,"\nCould not attach int handler!\n" |
; or eax, -1 |
; ret |
@@: |
|
; Reset the chip to erase previous misconfiguration. |
|
set_io 0 |
set_io BCR |
xor eax, eax |
inc eax |
out dx, eax |
|
call init_ring |
|
; Initialize other registers. |
; Configure the PCI bus bursts and FIFO thresholds. |
|
mov [device.bcrvalue], 0x10 ; little-endian, 8 burst length |
mov [device.crvalue], 0xa00 ; 128 burst length |
|
cmp [device.dev_id], 0x891 |
jne @f |
or [device.bcrvalue], 0x200 ; set PROG bit |
or [device.crvalue], 0x02000000 ; set enhanced bit |
@@: |
|
or [device.crvalue], RxEnable + TxThreshold + TxEnable |
|
call set_rx_mode |
|
set_io 0 |
set_io BCR |
mov eax, [device.bcrvalue] |
out dx, eax |
|
set_io TCRRCR |
mov eax, [device.crvalue] |
out dx, eax |
|
call getlinkstatus |
call getlinktype |
|
; Restart Rx engine if stopped. |
|
set_io 0 |
set_io RXPDR |
xor eax, eax |
out dx, eax |
|
; Enable interrupts |
|
set_io 0 |
set_io ISR |
mov eax, (FBE or TUNF or CNTOVF or RBU or TI or RI) |
out dx, eax |
|
set_io IMR |
; mov eax, (FBE or TUNF or CNTOVF or RBU or TI or RI) |
out dx, eax |
|
; clear packet/byte counters |
|
xor eax, eax |
lea edi, [device.bytes_tx] |
mov ecx, 6 |
rep stosd |
|
mov [device.mtu], 1514 |
xor eax, eax |
|
ret |
|
|
|
|
align 4 |
init_ring: |
|
DEBUGF 1,"initializing rx and tx ring\n" |
|
; Initialize all Rx descriptors |
|
lea esi, [device.rx_desc] |
mov [device.cur_rx], esi |
mov ecx, NUM_RX_DESC |
.rx_desc_loop: |
mov [esi + mtd_desc.status], RXOWN |
mov [esi + mtd_desc.control], 1536 shl RBSShift |
|
lea eax, [esi + mtd_desc.size] |
mov [esi + mtd_desc.next_desc_logical], eax |
push ecx esi |
GetRealAddr |
mov [esi + mtd_desc.next_desc], eax |
|
stdcall KernelAlloc, 1536 |
pop esi |
push esi |
mov [esi + mtd_desc.skbuff], eax |
call GetPgAddr |
pop esi ecx |
mov [esi + mtd_desc.buffer], eax |
|
add esi, mtd_desc.size |
loop .rx_desc_loop |
|
; Mark the last entry as wrapping the ring. |
|
lea eax, [device.rx_desc] |
mov [esi - mtd_desc.size + mtd_desc.next_desc_logical], eax |
push esi |
GetRealAddr |
pop esi |
mov [esi - mtd_desc.size + mtd_desc.next_desc], eax |
|
set_io 0 |
set_io RXLBA |
out dx, eax |
|
; Initialize all Tx descriptors |
|
lea esi, [device.tx_desc] |
mov [device.cur_tx], esi |
mov ecx, NUM_TX_DESC |
.tx_desc_loop: |
mov [esi + mtd_desc.status], 0 |
|
lea eax, [esi + mtd_desc.size] |
mov [esi + mtd_desc.next_desc_logical], eax |
push ecx esi |
GetRealAddr |
pop esi ecx |
mov [esi + mtd_desc.next_desc], eax |
|
add esi, mtd_desc.size |
loop .tx_desc_loop |
|
; Mark the last entry as wrapping the ring. |
|
lea eax, [device.tx_desc] |
mov [esi - mtd_desc.size + mtd_desc.next_desc_logical], eax |
push esi |
GetRealAddr |
pop esi |
mov [esi - mtd_desc.size + mtd_desc.next_desc], eax |
|
set_io 0 |
set_io TXLBA |
out dx, eax |
|
ret |
|
|
align 4 |
set_rx_mode: |
|
DEBUGF 1,"Setting RX mode\n" |
|
; Too many to match, or accept all multicasts. |
|
set_io 0 |
set_io MAR0 |
xor eax, eax |
not eax |
out dx, eax |
set_io MAR1 |
out dx, eax |
|
and [device.crvalue], not (RxModeMask) |
or [device.crvalue], AcceptBroadcast + AcceptMulticast + AcceptMyPhys |
|
ret |
|
|
align 4 |
getlinkstatus: |
|
DEBUGF 1,"Getting link status\n" |
|
mov [device.linkok], 0 |
|
cmp [device.PHYType], MysonPHY |
jne .no_myson_phy |
|
set_io 0 |
set_io BMCRSR |
mov ecx, 1000 |
.loop1: |
in eax, dx |
test eax, LinkIsUp2 |
jnz .link_ok |
|
push ecx edx ebx |
mov esi, 10 |
call Sleep |
pop ebx edx ecx |
loop .loop1 |
|
ret |
|
.no_myson_phy: |
|
; for (i equ 0; i < DelayTime; ++i) { |
; if (mdio_read(nic, mtdx.phys[0], MII_BMSR) & BMSR_LSTATUS) { |
; mtdx.linkok equ 1; |
; return; |
; } |
; m80x_delay(100); |
|
ret |
|
.link_ok: |
DEBUGF 1,"Link is up\n" |
inc [device.linkok] |
ret |
|
|
|
|
align 4 |
getlinktype: |
|
DEBUGF 1,"Getting link type\n" |
|
cmp [device.PHYType], MysonPHY |
jne .no_myson_phy |
|
DEBUGF 1,"myson PHY\n" |
|
set_io 0 |
set_io TCRRCR |
in eax, dx |
|
mov [device.duplexmode], 1 ; 1 equ half duplex |
test eax, FD |
jne @f |
DEBUGF 1,"full duplex\n" |
inc [device.duplexmode] ; 2 equ full duplex |
@@: |
|
mov [device.line_speed], 1 ; 1 equ 10M |
test eax, PS10 |
jne @f |
DEBUGF 1,"100mbit\n" |
inc [device.line_speed] ; 2 equ 100M |
@@: |
|
ret |
|
.no_myson_phy: |
|
DEBUGF 1,"no myson phy\n" |
|
; if (mtdx.PHYType equequ SeeqPHY) { /* this PHY is SEEQ 80225 */ |
; unsigned int data; |
; |
; data equ mdio_read(dev, mtdx.phys[0], MIIRegister18); |
; if (data & SPD_DET_100) |
; mtdx.line_speed equ 2; /* 100M */ |
; else |
; mtdx.line_speed equ 1; /* 10M */ |
; if (data & DPLX_DET_FULL) |
; mtdx.duplexmode equ 2; /* full duplex mode */ |
; else |
; mtdx.duplexmode equ 1; /* half duplex mode */ |
; } else if (mtdx.PHYType equequ AhdocPHY) { |
; unsigned int data; |
; |
; data equ mdio_read(dev, mtdx.phys[0], DiagnosticReg); |
; if (data & Speed_100) |
; mtdx.line_speed equ 2; /* 100M */ |
; else |
; mtdx.line_speed equ 1; /* 10M */ |
; if (data & DPLX_FULL) |
; mtdx.duplexmode equ 2; /* full duplex mode */ |
; else |
; mtdx.duplexmode equ 1; /* half duplex mode */ |
; } |
; else if (mtdx.PHYType equequ MarvellPHY) { |
; unsigned int data; |
; |
; data equ mdio_read(dev, mtdx.phys[0], SpecificReg); |
; if (data & Full_Duplex) |
; mtdx.duplexmode equ 2; /* full duplex mode */ |
; else |
; mtdx.duplexmode equ 1; /* half duplex mode */ |
; data &equ SpeedMask; |
; if (data equequ Speed_1000M) |
; mtdx.line_speed equ 3; /* 1000M */ |
; else if (data equequ Speed_100M) |
; mtdx.line_speed equ 2; /* 100M */ |
; else |
; mtdx.line_speed equ 1; /* 10M */ |
; } |
; else if (mtdx.PHYType equequ Myson981) { |
; unsigned int data; |
; |
; data equ mdio_read(dev, mtdx.phys[0], StatusRegister); |
; |
; if (data & SPEED100) |
; mtdx.line_speed equ 2; |
; else |
; mtdx.line_speed equ 1; |
; |
; if (data & FULLMODE) |
; mtdx.duplexmode equ 2; |
; else |
; mtdx.duplexmode equ 1; |
; } |
; else if (mtdx.PHYType equequ LevelOnePHY) { |
; unsigned int data; |
; |
; data equ mdio_read(dev, mtdx.phys[0], SpecificReg); |
; if (data & LXT1000_Full) |
; mtdx.duplexmode equ 2; /* full duplex mode */ |
; else |
; mtdx.duplexmode equ 1; /* half duplex mode */ |
; data &equ SpeedMask; |
; if (data equequ LXT1000_1000M) |
; mtdx.line_speed equ 3; /* 1000M */ |
; else if (data equequ LXT1000_100M) |
; mtdx.line_speed equ 2; /* 100M */ |
; else |
; mtdx.line_speed equ 1; /* 10M */ |
; } |
|
; // chage crvalue |
; // mtdx.crvalue&equ(~PS10)&(~FD); |
; mtdx.crvalue &equ (~PS10) & (~FD) & (~PS1000); |
; if (mtdx.line_speed equequ 1) |
; mtdx.crvalue |equ PS10; |
; else if (mtdx.line_speed equequ 3) |
; mtdx.crvalue |equ PS1000; |
; if (mtdx.duplexmode equequ 2) |
; mtdx.crvalue |equ FD; |
; |
|
ret |
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Transmit ;; |
;; ;; |
;; In: buffer pointer in [esp+4] ;; |
;; size of buffer in [esp+8] ;; |
;; pointer to device structure in ebx ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
align 4 |
transmit: |
|
DEBUGF 1,"Transmitting packet, buffer:%x, size:%u\n",[esp+4],[esp+8] |
mov eax, [esp+4] |
DEBUGF 1,"To: %x-%x-%x-%x-%x-%x From: %x-%x-%x-%x-%x-%x Type:%x%x\n",\ |
[eax+00]:2,[eax+01]:2,[eax+02]:2,[eax+03]:2,[eax+04]:2,[eax+05]:2,\ |
[eax+06]:2,[eax+07]:2,[eax+08]:2,[eax+09]:2,[eax+10]:2,[eax+11]:2,\ |
[eax+13]:2,[eax+12]:2 |
|
cmp dword [esp+8], 1514 |
ja .fail |
|
mov esi, [device.cur_tx] |
push [esi + mtd_desc.next_desc_logical] |
pop [device.cur_tx] |
|
; todo: check if descriptor is not owned by the device! |
|
mov eax, [esp + 4] |
mov [esi + mtd_desc.skbuff], eax |
GetRealAddr |
mov [esi + mtd_desc.buffer], eax |
|
mov eax, [esp + 8] |
shl eax, PKTSShift ; packet size |
or eax, TXLD + TXFD + CRCEnable + PADEnable + TXIC + 1536 shl TBSShift ; buffer size |
mov [esi + mtd_desc.control], eax |
|
mov [esi + mtd_desc.status], TXOWN |
|
;------------- |
; Update stats |
|
inc [device.packets_tx] |
mov eax, [esp+8] |
add dword [device.bytes_tx], eax |
adc dword [device.bytes_tx + 4], 0 |
|
; Point to transmit descriptor |
|
set_io 0 |
set_io TXLBA |
mov eax, esi |
GetRealAddr |
out dx, eax |
|
; set_io TCRRCR |
; mov eax, [device.crvalue] |
; out dx, eax |
|
; Wake the potentially-idle transmit channel. |
|
set_io TXPDR ; TX Poll |
xor eax, eax |
out dx, eax |
|
DEBUGF 1,"transmit ok\n" |
xor eax, eax |
ret 8 |
|
.fail: |
DEBUGF 1,"transmit failed\n" |
or eax, -1 |
stdcall KernelFree, [esp + 4] |
ret 8 |
|
|
|
align 4 |
read_mac: |
|
set_io 0 |
set_io PAR0 |
lea edi, [device.mac] |
insd |
stosd |
set_io PAR1 |
insw |
stosw |
|
DEBUGF 1,"MAC = %x-%x-%x-%x-%x-%x\n",\ |
[device.mac+0]:2,[device.mac+1]:2,[device.mac+2]:2,[device.mac+3]:2,[device.mac+4]:2,[device.mac+5]:2 |
|
ret |
|
align 4 |
write_mac: |
|
ret |
|
|
|
;;;;;;;;;;;;;;;;;;;;;;; |
;; ;; |
;; Interrupt handler ;; |
;; ;; |
;;;;;;;;;;;;;;;;;;;;;;; |
|
align 4 |
int_handler: |
|
DEBUGF 1,"\nIRQ %x\n",eax:2 ; no, you cant replace 'eax:2' with 'al', this must be a bug in FDO |
|
; find pointer of device wich made IRQ occur |
|
mov ecx, [devices] |
test ecx, ecx |
jz .fail |
mov esi, device_list |
.nextdevice: |
mov ebx, dword [esi] |
|
set_io 0 |
set_io ISR |
in eax, dx |
out dx , eax ; send it back to ACK |
; and eax, ; int mask |
test eax, eax |
jnz .got_it |
|
.continue: |
add esi, 4 |
dec ecx |
jnz .nextdevice |
|
ret ; If no device was found, abort (The irq was probably for a device, not registered to this driver) |
|
.got_it: |
|
DEBUGF 1,"Status=%x\n", eax |
|
test ax, RI ; receive interrupt |
jz .no_rx |
|
DEBUGF 1,"Receive interrupt\n" |
.rx: |
push ax |
|
.rx_loop: |
mov esi, [device.cur_rx] |
|
test [esi + mtd_desc.status], RXOWN |
jnz .fail_rx |
|
push .rx_complete |
|
mov ecx, [esi + mtd_desc.status] |
shr ecx, FLNGShift |
sub ecx, 4 ; we dont need CRC |
push ecx |
|
;------------- |
; Update stats |
|
add dword [device.bytes_rx], ecx |
adc dword [device.bytes_rx + 4], 0 |
inc dword [device.packets_rx] |
|
|
push [esi + mtd_desc.skbuff] |
|
jmp EthReceiver |
|
.rx_complete: |
mov esi, [device.cur_rx] |
|
mov [esi + mtd_desc.control], 1536 shl RBSShift |
|
stdcall KernelAlloc, 1536 |
mov [esi + mtd_desc.skbuff], eax |
call GetPgAddr |
mov [esi + mtd_desc.buffer], eax |
|
mov [esi + mtd_desc.status], RXOWN |
|
mov eax, [esi + mtd_desc.next_desc_logical] |
mov [device.cur_rx], eax |
|
jmp .rx_loop |
; |
; while( ( mtdx.cur_rx->status & RXOWN ) == 0 ) |
; { |
; mtdx.cur_rx->status = RXOWN; |
; mtdx.cur_rx = mtdx.cur_rx->next_desc_logical; |
; } |
; |
; /* Restart Rx engine if stopped. */ |
; outl(0, mtdx.ioaddr + RXPDR); |
|
.fail_rx: |
DEBUGF 1,"RX failed\n" |
|
pop ax |
.no_rx: |
|
test ax, TI ; transmit interrupt |
jz .no_tx |
|
DEBUGF 1,"Transmit interrupt\n" |
push ax |
|
lea esi, [device.tx_desc] |
mov ecx, NUM_TX_DESC |
.tx_loop: |
|
test [esi + mtd_desc.status], TXOWN |
jnz .skip_this_one |
|
mov eax, [esi + mtd_desc.skbuff] |
test eax, eax |
je .skip_this_one |
|
mov [esi + mtd_desc.skbuff], 0 |
|
DEBUGF 1,"freeing buffer:%x\n", eax |
stdcall KernelFree, eax |
|
.skip_this_one: |
mov esi, [esi + mtd_desc.next_desc_logical] |
loop .tx_loop |
|
pop ax |
|
.no_tx: |
|
test ax, TBU |
jz .no_tbu |
|
DEBUGF 1,"Transmit buffer unavailable!\n" |
|
.no_tbu: |
|
.fail: |
|
ret |
|
|
; End of code |
|
align 4 ; Place all initialised data here |
|
devices dd 0 |
version dd (DRIVER_VERSION shl 16) or (API_VERSION and 0xFFFF) |
my_service db 'mtd80x',0 ; max 16 chars include zero |
|
|
; 0x1516, 0x0800, "MTD800", "Myson MTD800" |
; 0x1516, 0x0803, "MTD803", "Surecom EP-320X" |
; 0x1516, 0x0891, "MTD891", "Myson MTD891" |
|
|
include_debug_strings ; All data wich FDO uses will be included here |
|
section '.data' data readable writable align 16 ; place all uninitialized data place here |
|
device_list rd MAX_DEVICES ; This list contains all pointers to device structures the driver is handling |
|
|