mirror of
https://github.com/Zeal-Operating-System/ZealOS.git
synced 2025-06-07 08:14:48 +00:00
Add PCNet driver by TomAwezome
This commit is contained in:
parent
472bc164d8
commit
fa2e657452
Binary file not shown.
@ -221,7 +221,7 @@ I64 AsmMakeArgMask(CCompCtrl *cc, CAsmArg *arg)
|
||||
res = comp.size_arg_mask[arg->size];
|
||||
|
||||
if (aotc->seg_size == 64)
|
||||
res &= ~ARGG_MOFFS; //0xFF0FFFFFFF;
|
||||
res &= ~ARGG_MOFFS;
|
||||
|
||||
if (arg->reg1 != REG_NONE && arg->imm_or_off_present && !arg->num.i &&
|
||||
!arg->num.global_asm_undef_hash && !arg->num.local_asm_undef_hash)
|
||||
@ -229,53 +229,53 @@ I64 AsmMakeArgMask(CCompCtrl *cc, CAsmArg *arg)
|
||||
|
||||
if (arg->reg2 != REG_NONE || arg->scale != 1)
|
||||
{//if reg or scale
|
||||
res &= ARGG_M|ARGG_RM; //0x0000FF0000;
|
||||
res &= ARGG_M|ARGG_RM;
|
||||
goto mm_done;
|
||||
}
|
||||
|
||||
if (arg->indirect)
|
||||
{
|
||||
if (arg->imm_or_off_present)
|
||||
res &= ARGG_RM|ARGG_M|ARGG_MN|ARGG_MOFFS;//0x00FFFF0000;
|
||||
res &= ARGG_RM | ARGG_M | ARGG_MN | ARGG_MOFFS;
|
||||
else
|
||||
res &= ARGG_RM|ARGG_M|ARGG_MN;//0x000FFF0000;
|
||||
res &= ARGG_RM | ARGG_M | ARGG_MN;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arg->imm_or_off_present)
|
||||
res &= ARGG_MN|ARGG_IMM|ARGG_UIMM|ARGG_REL; //0x000F000FFE;
|
||||
res &= ARGG_MN | ARGG_IMM | ARGG_UIMM | ARGG_REL;
|
||||
else
|
||||
res &= ARGG_R|ARGG_RM|ARGG_M|ARGG_MN|ARGT_AL|ARGT_AX|ARGT_EAX|ARGT_RAX|ARGT_CL|ARGT_DX;//0x3F0FFFF000;
|
||||
res &= ARGG_R | ARGG_RM | ARGG_M | ARGG_MN | ARGT_AL | ARGT_AX | ARGT_EAX | ARGT_RAX | ARGT_CL | ARGT_DX;
|
||||
}
|
||||
|
||||
if (arg->seg != REG_NONE)
|
||||
res &= ARGG_RM|ARGG_M|ARGG_MN|ARGG_MOFFS;//0x00FFFF0000;
|
||||
res &= ARGG_RM | ARGG_M | ARGG_MN | ARGG_MOFFS;
|
||||
|
||||
if (arg->reg1 == REG_NONE)
|
||||
{
|
||||
if (arg->indirect)
|
||||
res &= ARGG_RM|ARGG_M|ARGG_MN|ARGG_MOFFS; //0x00FFFF0000;
|
||||
res &= ARGG_RM | ARGG_M | ARGG_MN | ARGG_MOFFS;
|
||||
else if (arg->num.i < 0)
|
||||
{
|
||||
if (arg->num.i >= I8_MIN)
|
||||
res &= 0x8FE;
|
||||
res &= ARGG_REL | ARGG_IMM;//|ARGT_UIMM64; //0x8FE;
|
||||
else if (arg->num.i >= I16_MIN)
|
||||
res &= 0x8EE;
|
||||
res &= ARGG_REL | ARGT_IMM64 | ARGT_IMM32 | ARGT_IMM16;///|ARGT_UIMM64;//0x8EE;
|
||||
else if (arg->num.i >= I32_MIN)
|
||||
res &= 0x8CE;
|
||||
res &= ARGG_REL | ARGT_IMM64 | ARGT_IMM32;//|ARGT_UIMM64;//0x8CE;
|
||||
else
|
||||
res &= 0x88E;
|
||||
res &= ARGG_REL | ARGT_IMM64;//|ARGT_UIMM64;//0x88E;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (arg->num.i <= I8_MAX)
|
||||
res &= 0xFFE;
|
||||
res &= ARGG_REL|ARGG_IMM|ARGG_UIMM;//0xFFE;
|
||||
else if (arg->num.i <= U8_MAX)
|
||||
res &= 0xFEE;
|
||||
res &= ARGG_REL | ARGT_IMM64 | ARGT_IMM32 | ARGT_IMM16 | ARGG_UIMM;//0xFEE;
|
||||
else if (arg->num.i <= I16_MAX)
|
||||
res &= 0xEEE;
|
||||
res &= ARGG_REL | ARGT_IMM64 | ARGT_IMM32 |ARGT_IMM16 | ARGT_UIMM64 | ARGT_UIMM32 | ARGT_UIMM16;//0xEEE;
|
||||
else if (arg->num.i <= U16_MAX)
|
||||
res &= 0xECE;
|
||||
res &= ARGG_REL | ARGT_IMM64 | ARGT_IMM32 | ARGT_UIMM64 | ARGT_UIMM32 | ARGT_UIMM16;//0xECE;
|
||||
else if (arg->num.i <= I32_MAX)
|
||||
res &= 0xCCE;
|
||||
else if (arg->num.i <= U32_MAX)
|
||||
@ -283,16 +283,20 @@ I64 AsmMakeArgMask(CCompCtrl *cc, CAsmArg *arg)
|
||||
else
|
||||
res &= 0x88E;
|
||||
}
|
||||
} else {
|
||||
res&= 0x3F00FFF000;
|
||||
if (!arg->indirect) //M8-M64
|
||||
res&=0xFFFF0FFFFF;
|
||||
}
|
||||
switch (arg->reg1) {
|
||||
else
|
||||
{
|
||||
res &= 0x3F00FFF000;
|
||||
if (!arg->indirect) //M8-M64
|
||||
res &= 0xFFFF0FFFFF;
|
||||
}
|
||||
|
||||
switch (arg->reg1)
|
||||
{
|
||||
case REG_RAX: res&=~0x3000000000; break;
|
||||
case REG_RCX: res&=~0x2F00000000; break;
|
||||
case REG_RDX: res&=~0x1F00000000; break;
|
||||
default: res&=~0x3F00000000;
|
||||
default: res&=~0x3F00000000;
|
||||
}
|
||||
mm_done:
|
||||
return res;
|
||||
|
543
src/Home/PCNet.CC
Executable file
543
src/Home/PCNet.CC
Executable file
@ -0,0 +1,543 @@
|
||||
/* AMD PCNetII Driver
|
||||
Author: TomAwezome
|
||||
|
||||
Driver is based on:
|
||||
- minexew's ShrineOS PCNet.CC implementation
|
||||
- OSDev AMD_PCNET documentation
|
||||
- AMD PCnet(TM)-PCI datasheet
|
||||
- any other useful sources.
|
||||
|
||||
Guidelines:
|
||||
- Magic numbers are bad. #defines are good.
|
||||
- Understandability over LOC.
|
||||
- Clear documentation.
|
||||
*/
|
||||
|
||||
#define PCNET_DEVICE_ID 0x2000
|
||||
#define PCNET_VENDOR_ID 0x1022
|
||||
|
||||
#define PCI_REG_COMMAND 0x04
|
||||
|
||||
#define PCNET_CMDf_IOEN 0
|
||||
#define PCNET_CMDf_BMEN 2
|
||||
|
||||
#define PCNET_CMDF_IOEN (1 << PCNET_CMDf_IOEN)
|
||||
#define PCNET_CMDF_BMEN (1 << PCNET_CMDf_BMEN)
|
||||
|
||||
#define PCNET_WD_RESET 0x14 // reset reg location when card is in 16-bit mode
|
||||
|
||||
#define PCNET_DW_RDP 0x10
|
||||
#define PCNET_DW_RAP 0x14
|
||||
#define PCNET_DW_RESET 0x18 // reset reg location when card is in 32-bit mode
|
||||
|
||||
#define PCNET_CSR_CTRLSTATUS 0
|
||||
#define PCNET_CSR_INTERRUPTS 3
|
||||
#define PCNET_CSR_FEATURECTRL 4
|
||||
#define PCNET_CSR_LADRF0 8
|
||||
#define PCNET_CSR_LADRF1 9
|
||||
#define PCNET_CSR_LADRF2 10
|
||||
#define PCNET_CSR_LADRF3 11
|
||||
#define PCNET_CSR_PADR0 12
|
||||
#define PCNET_CSR_PADR1 13
|
||||
#define PCNET_CSR_PADR2 14
|
||||
#define PCNET_CSR_MODE 15
|
||||
#define PCNET_CSR_BADRL 24
|
||||
#define PCNET_CSR_BADRU 25
|
||||
#define PCNET_CSR_BADTL 30
|
||||
#define PCNET_CSR_BADTU 31
|
||||
#define PCNET_CSR_POLLINT 47
|
||||
#define PCNET_CSR_SOFTWARESTYLE 58
|
||||
#define PCNET_CSR_RXRINGLEN 76
|
||||
#define PCNET_CSR_TXRINGLEN 78
|
||||
|
||||
#define PCNET_SWSTYLE_SELECTION 2 // AMD PCNet datasheet p. 1-968
|
||||
|
||||
// Refer to AMD PCNet datasheet p. 1-954, 1-956, 1-957 for Interrupt Mask details.
|
||||
#define PCNET_INT_BSWP 2 // Byte Swap (Big-Endian / Little-Endian)
|
||||
#define PCNET_INT_IDONM 8 // Initialization Done Mask
|
||||
#define PCNET_INT_TINTM 9 // Transmit Interrupt Mask
|
||||
#define PCNET_INT_RINTM 10 // Receive Interrupt Mask
|
||||
|
||||
#define PCNET_FEATURE_APADXMT 11
|
||||
|
||||
#define PCNET_CTRL_INIT 0
|
||||
#define PCNET_CTRL_STRT 1
|
||||
#define PCNET_CTRL_STOP 2
|
||||
#define PCNET_CTRL_RINT 10
|
||||
|
||||
#define PCNET_RX_BUFF_COUNT 32 // Linux & Shrine Driver use 32 and 8 for
|
||||
#define PCNET_TX_BUFF_COUNT 8 // these, we could allow more if wanted.
|
||||
|
||||
|
||||
#define PCNET_DESCRIPTORf_OWN 31 // AMD PCNet datasheet p.1-992, 1-994
|
||||
//#define PCNET_DESCRIPTORF_OWN (1 << PCNET_DESCRIPTORf_OWN)
|
||||
|
||||
/* Ethernet Frame Size. Linux uses 1544,
|
||||
OSDev and Shrine use 1548. Based on
|
||||
IEEE 802.3as, max frame size was agreed
|
||||
upon as 2000 bytes. */
|
||||
#define ETHERNET_FRAME_SIZE 2000
|
||||
|
||||
#define INT_DEST_CPU 0
|
||||
|
||||
class CPCNet
|
||||
{
|
||||
CPCIDev* pci;
|
||||
U8 mac_address[6]; //MAC address is first 6 bytes of PCNet EEPROM (page # ? )
|
||||
|
||||
I64 current_rx_de_index; // Current Receive DE being processed. Gets incremented, wrapped to 0 at max of PCNET_RX_BUFF_COUNT.
|
||||
I64 current_tx_de_index; // Current Transmit DE being processed. Gets incremented, wrapped to 0 at max of PCNET_TX_BUFF_COUNT.
|
||||
|
||||
U8* rx_de_buffer; // Uncached-alias of pointer to the buffer of RX Descriptor Entries.
|
||||
U8* tx_de_buffer; // Uncached-alias of pointer to the buffer of TX Descriptor Entries.
|
||||
U8* rx_de_buffer_phys; // Pointer to the buffer of RX Descriptor Entries. (Code Heap, lower 2Gb)
|
||||
U8* tx_de_buffer_phys; // Pointer to the buffer of TX Descriptor Entries. (Code Heap, lower 2Gb)
|
||||
|
||||
U32 rx_buffer_addr; // 'Physical address of actual receive buffers (< 4 Gb)'
|
||||
U32 tx_buffer_addr; // 'Physical address of actual transmit buffers (< 4 Gb)'
|
||||
|
||||
} pcnet; // pcnet is the global variable we store all of this into.
|
||||
|
||||
class CPCNetDescriptorEntry
|
||||
{/* AMD PCNet datasheet p.1-991 & p.1-994 NOTE: chart typo on 1-994, see ONES and BCNT on 1-995.
|
||||
TX and RX DE's are the same size (16-Bytes) and structure,
|
||||
but have different registers and functions.
|
||||
The RX and TX DE buffers of the CPCNet class
|
||||
are allocated to a certain amount of these DEs. */
|
||||
U32 buffer_addr;
|
||||
U32 status1;
|
||||
U32 status2;
|
||||
U32 reserved;
|
||||
};
|
||||
|
||||
|
||||
CPCIDev* PCNetPCIDevFind()
|
||||
{// Find and return PCNetII card as a CPCIDev pointer.
|
||||
return PCIDevFind(,,PCNET_VENDOR_ID,PCNET_DEVICE_ID);
|
||||
}
|
||||
|
||||
U32 PCNetGetIOBase()
|
||||
{/* Return memory IO base address
|
||||
of PCNet card. Bits 0-4 are not
|
||||
for the IO base, so an AND with
|
||||
~0x1F ignores those bits. */
|
||||
U32 io_base = pcnet.pci->base[0] & ~0x1F;
|
||||
return io_base;
|
||||
}
|
||||
|
||||
U0 PCNetReset()
|
||||
{/* Reads the 32- and 16-bit RESET registers,
|
||||
which, regardless of which mode the card is in,
|
||||
will reset it back to 16-bit mode. */
|
||||
InU32(PCNetGetIOBase() + PCNET_DW_RESET);
|
||||
InU16(PCNetGetIOBase() + PCNET_WD_RESET);
|
||||
Sleep(1); // OSDev says minimum 1 æS
|
||||
}
|
||||
|
||||
U0 PCNetEnter32BitMode()
|
||||
{/* AMD PCNet datasheet p. 1-930
|
||||
Summary: A 32-bit write (while in 16-bit mode)
|
||||
to RDP will cause 16-bit mode exit
|
||||
and immediate enter into 32-bit mode. */
|
||||
OutU32(PCNetGetIOBase() + PCNET_DW_RDP, 0);
|
||||
|
||||
}
|
||||
|
||||
U0 PCNetWriteRAP(U32 value)
|
||||
{/* AMD PCNet datasheet p. 1-952
|
||||
Summary: Register Address Pointer register
|
||||
value will indicate which CSR / BCR register
|
||||
we want to access in RDP / BDP. */
|
||||
OutU32(PCNetGetIOBase() + PCNET_DW_RAP, value);
|
||||
}
|
||||
|
||||
U0 PCNetWriteCSR(U32 csr, U32 value)
|
||||
{/* AMD PCNet datasheet p. 1-952
|
||||
Summary: Control and Status Registers are
|
||||
accessed via the RDP (Register Data Port).
|
||||
Which CSR is selected is based on the value
|
||||
in the RAP. */
|
||||
PCNetWriteRAP(csr);
|
||||
OutU32(PCNetGetIOBase() + PCNET_DW_RDP, value);
|
||||
}
|
||||
|
||||
U32 PCNetReadCSR(U32 csr)
|
||||
{/* AMD PCNet datasheet p. 1-952
|
||||
Summary: Control and Status Registers are
|
||||
accessed via the RDP (Register Data Port).
|
||||
Which CSR is selected is based on the value
|
||||
in the RAP. */
|
||||
PCNetWriteRAP(csr);
|
||||
return InU32(PCNetGetIOBase() + PCNET_DW_RDP);
|
||||
}
|
||||
|
||||
U0 PCNetSetSWStyle()
|
||||
{/* AMD PCNet datasheet p. 1-968
|
||||
In CSR58 (Software Style), the 8-bit
|
||||
SWSTYLE register dictates interpretation of certain
|
||||
bits in the CSR space, and widths of descriptors and
|
||||
initialization block. In PCINet-PCI mode, CSR4 bits
|
||||
function as defined in the datasheet , and TMD1[29]
|
||||
functions as ADD_FCS. */
|
||||
U32 csr = PCNetReadCSR(PCNET_CSR_SOFTWARESTYLE);
|
||||
|
||||
csr &= ~0xFF; // clears first 8 bits: SWSTYLE 8-bit register.
|
||||
csr |= PCNET_SWSTYLE_SELECTION; // set SWSTYLE to PCNet-PCI mode.
|
||||
|
||||
PCNetWriteCSR(PCNET_CSR_SOFTWARESTYLE, csr);
|
||||
}
|
||||
|
||||
U0 PCNetGetMAC()
|
||||
{/* AMD PCNet datasheet p. 1-887, 1-931, 1-937
|
||||
MAC address stored at first 6 bytes of PCNet EEPROM.
|
||||
EEPROM addresses shadow-copied to APROM at hardware init.
|
||||
APROM accessible at first 16 bytes of PCI IO space. */
|
||||
I64 i;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
pcnet.mac_address[i] = InU8(PCNetGetIOBase() + i);
|
||||
}
|
||||
}
|
||||
|
||||
U0 PCNetInitDescriptorEntry(CPCNetDescriptorEntry* entry, U32 buffer_address, I64 is_rx)
|
||||
{
|
||||
entry->buffer_addr = buffer_address;
|
||||
|
||||
/* AMD PCNet datasheet p.1-991.
|
||||
BCNT is the usable buffer length, expressed as first
|
||||
12 bits of 2s-complement of desired length.
|
||||
Bits 0-11 of a DE are for the buffer byte count (BCNT),
|
||||
and bits 12-15 of a DE must be written all ones (ONES) */
|
||||
U16 buffer_byte_count = -ETHERNET_FRAME_SIZE; // Sets up as 2s complement of the desired length.
|
||||
buffer_byte_count &= 0x0FFF; // Masks 0 over everything except bits 0-11.
|
||||
|
||||
entry->status1 |= buffer_byte_count; // Sets BCNT reg (first 12 bits) in DE TMD1/RMD1.
|
||||
entry->status1 |= 0xF000; // Sets bits 12-15 (ONES) in DE TMD1/RMD1 as all ones.
|
||||
|
||||
//if this is a Receive DE, give ownership to the card so the PCNet can fill them.
|
||||
if (is_rx)
|
||||
Bts(&entry->status1, PCNET_DESCRIPTORf_OWN);
|
||||
ClassRep(entry);
|
||||
|
||||
}
|
||||
|
||||
U0 PCNetAllocateBuffers()
|
||||
{
|
||||
I64 de_index; // used in for loops for TX and RX DE access.
|
||||
|
||||
/* AMD PCNet datasheet p.1-913, p.1-990
|
||||
When SSIZE32=1, Descriptor Ring Entry Base Address
|
||||
must be on 16-byte boundary. (TDRA[3:0]=0, RDRA[3:0]=0) */
|
||||
pcnet.rx_de_buffer_phys = CAllocAligned(sizeof(CPCNetDescriptorEntry) * PCNET_RX_BUFF_COUNT,
|
||||
16,
|
||||
Fs->code_heap);
|
||||
pcnet.tx_de_buffer_phys = CAllocAligned(sizeof(CPCNetDescriptorEntry) * PCNET_TX_BUFF_COUNT,
|
||||
16,
|
||||
Fs->code_heap);
|
||||
|
||||
//Shrine does a check and returns -1 here, if the end of either buffer exceeds 0x100000000
|
||||
|
||||
pcnet.rx_de_buffer = dev.uncached_alias + pcnet.rx_de_buffer_phys; // we want uncached
|
||||
pcnet.tx_de_buffer = dev.uncached_alias + pcnet.tx_de_buffer_phys; // access to these.
|
||||
|
||||
pcnet.rx_buffer_addr = CAlloc(ETHERNET_FRAME_SIZE * PCNET_RX_BUFF_COUNT, //Shrine has a TODO to figure out
|
||||
Fs->code_heap);
|
||||
pcnet.tx_buffer_addr = CAlloc(ETHERNET_FRAME_SIZE * PCNET_TX_BUFF_COUNT, //if these should be uncached too.
|
||||
Fs->code_heap); //note, p.1-991,1-994: RBADR is only 32 bits wide.
|
||||
|
||||
//Shrine does a check and returns -1 here, if the end of either buffer exceeds 0x100000000
|
||||
|
||||
|
||||
CPCNetDescriptorEntry* entry;
|
||||
|
||||
entry = pcnet.rx_de_buffer;
|
||||
for (de_index = 0; de_index < PCNET_RX_BUFF_COUNT; de_index++)
|
||||
{
|
||||
PCNetInitDescriptorEntry(&entry[de_index], pcnet.rx_buffer_addr, TRUE); // TRUE for is_rx.
|
||||
}
|
||||
|
||||
entry = pcnet.tx_de_buffer;
|
||||
for (de_index = 0; de_index < PCNET_TX_BUFF_COUNT; de_index++)
|
||||
{
|
||||
PCNetInitDescriptorEntry(&entry[de_index], pcnet.tx_buffer_addr, FALSE); // FALSE for is_rx.
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
U0 PCNetDirectInit()
|
||||
{/* AMD PCNet datasheet p. 1-1021
|
||||
Instead of setting up initialization block,
|
||||
direct writes to the necessary CSRs can be
|
||||
used to manually initialize the PCNet card. */
|
||||
|
||||
/* AMD PCNet datasheet p.1-991
|
||||
If Logical Address Filter is set as
|
||||
all 0, all incoming logical addresses
|
||||
are rejected. Disables multicast. */
|
||||
PCNetWriteCSR(PCNET_CSR_LADRF0, 0);
|
||||
PCNetWriteCSR(PCNET_CSR_LADRF1, 0);
|
||||
PCNetWriteCSR(PCNET_CSR_LADRF2, 0);
|
||||
PCNetWriteCSR(PCNET_CSR_LADRF3, 0);
|
||||
|
||||
/* The Physical Address is the MAC.
|
||||
AMD PCNet datasheet p.1-960, 1-961
|
||||
The first 16 bits of CSRs 12-14 are
|
||||
for the Physical Address, the upper bits
|
||||
are reserved, written 0 read undefined.
|
||||
|
||||
The OR and bit-shift of 8 allows writing
|
||||
separate U8 values in the correct locations
|
||||
of the CSR. */
|
||||
PCNetWriteCSR(PCNET_CSR_PADR0,
|
||||
pcnet.mac_address[0] | (pcnet.mac_address[1] << 8));
|
||||
PCNetWriteCSR(PCNET_CSR_PADR1,
|
||||
pcnet.mac_address[2] | (pcnet.mac_address[3] << 8));
|
||||
PCNetWriteCSR(PCNET_CSR_PADR2,
|
||||
pcnet.mac_address[4] | (pcnet.mac_address[5] << 8));
|
||||
|
||||
/* AMD PCNet datasheet p.1-961, 1-962, 1-963
|
||||
Refer to datasheet for specifics.
|
||||
Most relevant, when setting Mode to 0,
|
||||
promiscuous mode is is disabled, TX and
|
||||
RX enabled, enable RX broadcast and unicast. */
|
||||
PCNetWriteCSR(PCNET_CSR_MODE, 0);
|
||||
|
||||
/* AMD PCNet datasheet p.1-964
|
||||
CSR 24 and 25 need to be filled
|
||||
with the lower and upper 16 bits,
|
||||
respectively, of the address of
|
||||
the RX packet ring. Likewise for
|
||||
CSR 30 and 31 for the TX packet ring.
|
||||
|
||||
0xFFFF AND on address will leave
|
||||
only lower 16 bits remaining.
|
||||
|
||||
Bitshift right of 16 will replace
|
||||
first 16 bits with upper 16 bits,
|
||||
remaining bits cleared.*/
|
||||
PCNetWriteCSR(PCNET_CSR_BADRL,
|
||||
pcnet.rx_buffer_addr & 0xFFFF);
|
||||
PCNetWriteCSR(PCNET_CSR_BADRU,
|
||||
pcnet.rx_buffer_addr >> 16);
|
||||
|
||||
PCNetWriteCSR(PCNET_CSR_BADTL,
|
||||
pcnet.tx_buffer_addr & 0xFFFF);
|
||||
PCNetWriteCSR(PCNET_CSR_BADTU,
|
||||
pcnet.tx_buffer_addr >> 16);
|
||||
|
||||
/* AMD PCNet datasheet p. 1-967
|
||||
Default value at hardware init is
|
||||
all 0. Standard init block process
|
||||
sets this, but if doing directly
|
||||
it is imperative to manually set it 0. */
|
||||
PCNetWriteCSR(PCNET_CSR_POLLINT, 0);
|
||||
|
||||
/* AMD PCNet datasheet p. 1-970
|
||||
Receive and Transmit Ring Length CSRs
|
||||
bits 0-15 need to be set as the 2s complement
|
||||
of the ring length. The AND with 0xFFFF clears
|
||||
the upper Reserved bits, which are to be written
|
||||
as zeroes read undefined. */
|
||||
PCNetWriteCSR(PCNET_CSR_RXRINGLEN,
|
||||
-PCNET_RX_BUFF_COUNT & 0xFFFF);
|
||||
PCNetWriteCSR(PCNET_CSR_TXRINGLEN,
|
||||
-PCNET_TX_BUFF_COUNT & 0xFFFF);
|
||||
|
||||
|
||||
}
|
||||
|
||||
U0 PCNetSetInterruptCSR()
|
||||
{/* AMD PCNet datasheet p.1-952, 1-953, 1-954, 1-955, 1-956, 1-957
|
||||
Refer to datasheet for specifics on the Interrupt Masks.
|
||||
Most of these, when set 0, allow interrupts to be set in CSR0.
|
||||
We set Big-Endian disabled, RX interrupts
|
||||
enabled, Init Done interrupt disabled, and TX interrupt
|
||||
disabled. */
|
||||
U32 csr = PCNetReadCSR(PCNET_CSR_INTERRUPTS);
|
||||
|
||||
Btr(&csr, PCNET_INT_BSWP);
|
||||
Btr(&csr, PCNET_INT_RINTM);
|
||||
|
||||
Bts(&csr, PCNET_INT_IDONM);
|
||||
Bts(&csr, PCNET_INT_TINTM);
|
||||
|
||||
PCNetWriteCSR(PCNET_CSR_INTERRUPTS, csr);
|
||||
}
|
||||
|
||||
U0 PCNetEnableTXAutoPad()
|
||||
{/* AMD PCNet datasheet p.1-958
|
||||
Setting bit 11 (Auto Pad Transmit) allows
|
||||
shoft transmit frames to be automatically
|
||||
extended to 64 bytes. */
|
||||
U32 csr = PCNetReadCSR(PCNET_CSR_FEATURECTRL);
|
||||
|
||||
Bts(&csr, PCNET_FEATURE_APADXMT);
|
||||
|
||||
PCNetWriteCSR(PCNET_CSR_FEATURECTRL, csr);
|
||||
|
||||
}
|
||||
|
||||
U0 PCNetExitConfigMode()
|
||||
{/* AMD PCNet datasheet p.1-954
|
||||
PCNet controller can be started
|
||||
after configuring by ensuring INIT
|
||||
and STOP are cleared and START bit
|
||||
is set, in Status and Control Register
|
||||
(CSR0). */
|
||||
U32 csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS);
|
||||
|
||||
Btr(&csr, PCNET_CTRL_INIT);
|
||||
Btr(&csr, PCNET_CTRL_STOP);
|
||||
|
||||
Bts(&csr, PCNET_CTRL_STRT);
|
||||
|
||||
}
|
||||
|
||||
I64 PCNetDriverOwns(CPCNetDescriptorEntry* entry)
|
||||
{/* Returns whether the value of the OWN bit of the
|
||||
Descriptor Entry is zero. If 0, driver owns,
|
||||
if 1, PCNet card owns it. */
|
||||
return !Bt(&entry->status1, PCNET_DESCRIPTORf_OWN);
|
||||
|
||||
}
|
||||
|
||||
I64 PCNetReceivePacket(U8** packet_buffer_out, U16* packet_length_out)
|
||||
{/* Receives the packet at the current RX DE index. Parameters
|
||||
are both pointers, since we modify the value at the packet_buffer_out,
|
||||
and at the packet_length, ending with returning the index of the DE
|
||||
we just processed.
|
||||
The MCNT is stored at the first two bytes of the RMD2. We AND with
|
||||
0xFFFF to only take in those first two bytes: that is the packet_length.
|
||||
The increment of the current RX DE index is done by assigning it the
|
||||
value of incrementing it AND the max DE index-1. This will increment it
|
||||
as well as wrap back to 0 if we hit the max DE index. */
|
||||
I64 de_index = pcnet.current_rx_de_index;
|
||||
|
||||
CPCNetDescriptorEntry* entry = pcnet.rx_de_buffer;
|
||||
entry = &entry[de_index];
|
||||
|
||||
U16 packet_length = entry->status2 & 0xFFFF;
|
||||
|
||||
pcnet.current_rx_de_index = (pcnet.current_rx_de_index + 1)
|
||||
& (PCNET_RX_BUFF_COUNT - 1);
|
||||
|
||||
|
||||
*packet_buffer_out = pcnet.rx_buffer_addr + (de_index * ETHERNET_FRAME_SIZE);
|
||||
*packet_length_out = packet_length;
|
||||
return de_index;
|
||||
|
||||
|
||||
}
|
||||
|
||||
U0 PCNetReleaseReceivePacket(I64 de_index)
|
||||
{/* Release ownership of the packet to the PCNet card
|
||||
by setting the OWN bit to 1. */
|
||||
CPCNetDescriptorEntry* entry = pcnet.rx_de_buffer;
|
||||
entry = &entry[de_index];
|
||||
|
||||
Bts(&entry->status1, PCNET_DESCRIPTORf_OWN);
|
||||
}
|
||||
|
||||
interrupt U0 PCNetIRQ()
|
||||
{// todo: comments explaining proces...maybe reimplement interrupt handling altogether.
|
||||
U32 csr = PCNetReadCSR(PCNET_CSR_CTRLSTATUS);
|
||||
//"Interrupt Reason: %X , %b\n",csr,csr;
|
||||
|
||||
CPCNetDescriptorEntry* entry = pcnet.rx_de_buffer;
|
||||
|
||||
while (PCNetDriverOwns(&entry[pcnet.current_rx_de_index]))
|
||||
{
|
||||
U8* packet_buffer;
|
||||
U16 packet_length;
|
||||
I64 de_index = PCNetReceivePacket(packet_buffer, packet_length);
|
||||
|
||||
if (de_index >= 0) // necessary? check increment logic in PCNetReceivePacket.
|
||||
{
|
||||
//NetFIFOPushCopy(packet_buffer, packet_length);
|
||||
PCNetReleaseReceivePacket(de_index);
|
||||
}
|
||||
|
||||
Bts(&csr, PCNET_CTRL_RINT);
|
||||
|
||||
PCNetWriteCSR(PCNET_CSR_CTRLSTATUS, csr);
|
||||
}
|
||||
|
||||
*(dev.uncached_alias + LAPIC_EOI)(U32*) = 0;
|
||||
}
|
||||
|
||||
U0 PCIRerouteInterrupts(I64 base)
|
||||
{ // todo: comments explaining process, maybe better var names
|
||||
I64 i;
|
||||
U8* da = dev.uncached_alias + IOAPIC_REG;
|
||||
U32* _d = dev.uncached_alias + IOAPIC_DATA;
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
*da = IOREDTAB + i*2 + 1;
|
||||
*_d = dev.mp_apic_ids[INT_DEST_CPU] << 24;
|
||||
*da = IOREDTAB + i*2;
|
||||
*_d = 0x4000 + base + i;
|
||||
}
|
||||
}
|
||||
|
||||
U0 PCNetSetupInterrupts()
|
||||
{ // todo: comments explaining process
|
||||
IntEntrySet(I_USER+0, &PCNetIRQ, IDTET_IRQ);
|
||||
IntEntrySet(I_USER+1, &PCNetIRQ, IDTET_IRQ);
|
||||
IntEntrySet(I_USER+2, &PCNetIRQ, IDTET_IRQ);
|
||||
IntEntrySet(I_USER+3, &PCNetIRQ, IDTET_IRQ);
|
||||
PCIRerouteInterrupts(I_USER);
|
||||
}
|
||||
|
||||
U0 PCNetInit()
|
||||
{
|
||||
MemSet(&pcnet, 0, sizeof(CPCNet)); // pcnet global var will hold member data the driver uses often.
|
||||
|
||||
pcnet.pci = PCNetPCIDevFind();
|
||||
if (pcnet.pci == NULL)
|
||||
return; // if we don't find the card, quit.
|
||||
|
||||
/* Clear command register of PCNet
|
||||
PCI device, set IO Enable and Bus
|
||||
Master Enable bits of the register. */
|
||||
PCIWriteU16(pcnet.pci->bus,
|
||||
pcnet.pci->dev,
|
||||
pcnet.pci->fun,
|
||||
PCI_REG_COMMAND,
|
||||
PCNET_CMDF_IOEN | PCNET_CMDF_BMEN);
|
||||
|
||||
PCNetReset();
|
||||
|
||||
PCNetEnter32BitMode();
|
||||
|
||||
PCNetSetSWStyle();
|
||||
|
||||
PCNetGetMAC();
|
||||
// OSDev has code ensuring auto selected connection...
|
||||
|
||||
PCNetAllocateBuffers();
|
||||
|
||||
PCNetDirectInit();
|
||||
|
||||
PCNetSetInterruptCSR();
|
||||
|
||||
PCNetEnableTXAutoPad();
|
||||
|
||||
PCNetExitConfigMode();
|
||||
|
||||
PCNetSetupInterrupts();
|
||||
|
||||
|
||||
Sleep(100);//? necssary?
|
||||
ClassRep(&pcnet);
|
||||
|
||||
"pcnet->rx_de_buffer: %X\n",pcnet.rx_de_buffer;
|
||||
"pcnet->tx_de_buffer: %X\n",pcnet.tx_de_buffer;
|
||||
"pcnet->rx_de_buffer_phys: %X\n",pcnet.rx_de_buffer_phys;
|
||||
"pcnet->rx_de_buffer_phys: %X\n",pcnet.tx_de_buffer_phys;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
PCNetInit();
|
10
src/Home/Registry.CC
Executable file
10
src/Home/Registry.CC
Executable file
@ -0,0 +1,10 @@
|
||||
$TR,"Zenith"$
|
||||
$ID,2$$TR,"SysMessageFlags"$
|
||||
$ID,2$sys_message_flags[0]=0;
|
||||
$ID,-2$$TR,"SysRegVer"$
|
||||
$ID,2$registry_version=1.000;
|
||||
$ID,-2$$ID,-2$$TR,"Once"$
|
||||
$ID,2$$TR,"Zenith"$
|
||||
$ID,2$$ID,-2$$TR,"User"$
|
||||
$ID,2$$ID,-2$$ID,-2$$TR,"AutoComplete"$
|
||||
$ID,2$ac.col = TEXT_COLS-30;ac.row = TEXT_ROWS/5+4;$ID,-2$
|
@ -52,4 +52,4 @@ U0 Tmp()
|
||||
}
|
||||
}
|
||||
Tmp;
|
||||
PaletteSetSmooth;
|
||||
PaletteSetGruvboxLight;
|
Loading…
x
Reference in New Issue
Block a user