Removed REG*() macros and replaced them with read*() write*() macros.
Added chipset configuration, phy access, tx and rx interrupt handling, read and write hooks. Nearly working git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7382 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
/* Realtek RTL8169 Family Driver
|
||||||
|
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
|
||||||
|
*/
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
#include <Errors.h>
|
#include <Errors.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -5,6 +8,8 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
//#define DEBUG
|
||||||
|
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
@@ -13,34 +18,120 @@
|
|||||||
|
|
||||||
static int32 gOpenMask = 0;
|
static int32 gOpenMask = 0;
|
||||||
|
|
||||||
|
void
|
||||||
|
write_phy_reg(rtl8169_device *device, int reg, uint16 value)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
write32(REG_PHYAR, 0x80000000 | (reg & 0x1f) << 16 | value);
|
||||||
|
snooze(1000);
|
||||||
|
for (i = 0; i < 2000; i++) {
|
||||||
|
if ((read32(REG_PHYAR) & 0x80000000) == 0)
|
||||||
|
break;
|
||||||
|
snooze(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16
|
||||||
|
read_phy_reg(rtl8169_device *device, int reg)
|
||||||
|
{
|
||||||
|
uint32 v;
|
||||||
|
int i;
|
||||||
|
write32(REG_PHYAR, (reg & 0x1f) << 16);
|
||||||
|
snooze(1000);
|
||||||
|
for (i = 0; i < 2000; i++) {
|
||||||
|
v = read32(REG_PHYAR);
|
||||||
|
if (v & 0x80000000)
|
||||||
|
return v & 0xffff;
|
||||||
|
snooze(100);
|
||||||
|
}
|
||||||
|
return 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
write_phy_reg_bit(rtl8169_device *device, int reg, int bitnum, int bitval)
|
||||||
|
{
|
||||||
|
uint16 val = read_phy_reg(device, reg);
|
||||||
|
if (bitval == 1)
|
||||||
|
val |= (1 << bitnum);
|
||||||
|
else
|
||||||
|
val &= ~(1 << bitnum);
|
||||||
|
write_phy_reg(device, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
phy_config(rtl8169_device *device)
|
||||||
|
{
|
||||||
|
TRACE("phy_config()\n");
|
||||||
|
|
||||||
|
if (device->phy_version == 0 || device->phy_version == 1) {
|
||||||
|
uint16 val;
|
||||||
|
TRACE("performing phy init\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
write_phy_reg(device, 0x04, 0x01e1); // 10/100 capability
|
||||||
|
write_phy_reg(device, 0x09, 0x0200); // 1000 capability
|
||||||
|
write_phy_reg(device, 0x00, 0x1200); // enable and rstart NWAY
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
dump_phy_stat(rtl8169_device *device)
|
||||||
|
{
|
||||||
|
uint32 v = read8(REG_PHY_STAT);
|
||||||
|
if (v & PHY_STAT_EnTBI) {
|
||||||
|
uint32 tbi = read32(REG_TBICSR);
|
||||||
|
TRACE("TBI mode active\n");
|
||||||
|
if (tbi & TBICSR_ResetTBI)
|
||||||
|
TRACE("TBICSR_ResetTBI\n");
|
||||||
|
if (tbi & TBICSR_TBILoopBack)
|
||||||
|
TRACE("TBICSR_TBILoopBack\n");
|
||||||
|
if (tbi & TBICSR_TBINWEn)
|
||||||
|
TRACE("TBICSR_TBINWEn\n");
|
||||||
|
if (tbi & TBICSR_TBIReNW)
|
||||||
|
TRACE("TBICSR_TBIReNW\n");
|
||||||
|
if (tbi & TBICSR_TBILinkOk)
|
||||||
|
TRACE("TBICSR_TBILinkOk\n");
|
||||||
|
if (tbi & TBICSR_NWComplete)
|
||||||
|
TRACE("TBICSR_NWComplete\n");
|
||||||
|
} else {
|
||||||
|
TRACE("TBI mode NOT active\n");
|
||||||
|
if (v & PHY_STAT_1000MF)
|
||||||
|
TRACE("PHY_STAT_1000MF\n");
|
||||||
|
if (v & PHY_STAT_100M)
|
||||||
|
TRACE("PHY_STAT_100M\n");
|
||||||
|
if (v & PHY_STAT_10M)
|
||||||
|
TRACE("PHY_STAT_10M\n");
|
||||||
|
}
|
||||||
|
if (v & PHY_STAT_TxFlow)
|
||||||
|
TRACE("PHY_STAT_TxFlow\n");
|
||||||
|
if (v & PHY_STAT_RxFlow)
|
||||||
|
TRACE("PHY_STAT_RxFlow\n");
|
||||||
|
if (v & PHY_STAT_LinkSts)
|
||||||
|
TRACE("PHY_STAT_LinkSts\n");
|
||||||
|
if (v & PHY_STAT_FullDup)
|
||||||
|
TRACE("PHY_STAT_FullDup\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
init_buf_desc(rtl8169_device *device)
|
init_buf_desc(rtl8169_device *device)
|
||||||
{
|
{
|
||||||
void *rx_buf_desc_virt, *rx_buf_desc_phy;
|
void *rx_buf_desc_virt, *rx_buf_desc_phy;
|
||||||
void *tx_buf_desc_virt, *tx_buf_desc_phy;
|
void *tx_buf_desc_virt, *tx_buf_desc_phy;
|
||||||
void *tx_prio_buf_desc_virt, *tx_prio_buf_desc_phy;
|
|
||||||
void *tx_buf_virt, *tx_buf_phy;
|
void *tx_buf_virt, *tx_buf_phy;
|
||||||
void *rx_buf_virt, *rx_buf_phy;
|
void *rx_buf_virt, *rx_buf_phy;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
device->txBufArea = alloc_mem(&tx_buf_virt, &tx_buf_phy, TX_DESC_COUNT * FRAME_SIZE, 0, "rtl8169 tx buf");
|
device->txBufArea = alloc_mem(&tx_buf_virt, &tx_buf_phy, TX_DESC_COUNT * FRAME_SIZE, 0, "rtl8169 tx buf");
|
||||||
device->rxBufArea = alloc_mem(&rx_buf_virt, &rx_buf_phy, RX_DESC_COUNT * FRAME_SIZE, 0, "rtl8169 rx buf");
|
device->rxBufArea = alloc_mem(&rx_buf_virt, &rx_buf_phy, RX_DESC_COUNT * FRAME_SIZE, 0, "rtl8169 rx buf");
|
||||||
device->txDescArea = alloc_mem(&tx_buf_desc_virt, &tx_buf_desc_phy, TX_DESC_COUNT * sizeof(tx_desc), 0, "rtl8169 tx desc");
|
device->txDescArea = alloc_mem(&tx_buf_desc_virt, &tx_buf_desc_phy, TX_DESC_COUNT * sizeof(buf_desc), 0, "rtl8169 tx desc");
|
||||||
device->txPrioDescArea = alloc_mem(&tx_prio_buf_desc_virt, &tx_prio_buf_desc_phy, sizeof(tx_desc), 0, "rtl8169 prio tx desc");
|
device->rxDescArea = alloc_mem(&rx_buf_desc_virt, &rx_buf_desc_phy, RX_DESC_COUNT * sizeof(buf_desc), 0, "rtl8169 rx desc");
|
||||||
device->rxDescArea = alloc_mem(&rx_buf_desc_virt, &rx_buf_desc_phy, RX_DESC_COUNT * sizeof(rx_desc), 0, "rtl8169 rx desc");
|
if (device->txBufArea < B_OK || device->rxBufArea < B_OK || device->txDescArea < B_OK || device->rxDescArea < B_OK)
|
||||||
if (device->txBufArea < B_OK || device->rxBufArea < B_OK || device->txDescArea < B_OK || device->txPrioDescArea < B_OK || device->rxDescArea < B_OK)
|
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
device->txDesc = (tx_desc *) tx_buf_desc_virt;
|
device->txDesc = (buf_desc *) tx_buf_desc_virt;
|
||||||
device->txPrioDesc = (tx_desc *) tx_prio_buf_desc_virt;
|
device->rxDesc = (buf_desc *) rx_buf_desc_virt;
|
||||||
device->rxDesc = (rx_desc *) rx_buf_desc_virt;
|
|
||||||
|
|
||||||
// setup unused priority transmit descriptor
|
|
||||||
device->txPrioDesc->stat_len = TX_DESC_FS | TX_DESC_LS | TX_DESC_EOR;
|
|
||||||
device->txPrioDesc->vlan = 0;
|
|
||||||
device->txPrioDesc->buf_low = 0;
|
|
||||||
device->txPrioDesc->buf_high = 0;
|
|
||||||
|
|
||||||
// setup transmit descriptors
|
// setup transmit descriptors
|
||||||
for (i = 0; i < TX_DESC_COUNT; i++) {
|
for (i = 0; i < TX_DESC_COUNT; i++) {
|
||||||
device->txBuf[i] = (char *)tx_buf_virt + (i * FRAME_SIZE);
|
device->txBuf[i] = (char *)tx_buf_virt + (i * FRAME_SIZE);
|
||||||
@@ -53,25 +144,111 @@ init_buf_desc(rtl8169_device *device)
|
|||||||
// setup receive descriptors
|
// setup receive descriptors
|
||||||
for (i = 0; i < RX_DESC_COUNT; i++) {
|
for (i = 0; i < RX_DESC_COUNT; i++) {
|
||||||
device->rxBuf[i] = (char *)rx_buf_virt + (i * FRAME_SIZE);
|
device->rxBuf[i] = (char *)rx_buf_virt + (i * FRAME_SIZE);
|
||||||
device->rxDesc[i].stat_len = RX_DESC_FS | RX_DESC_LS | RX_DESC_OWN;
|
device->rxDesc[i].stat_len = RX_DESC_OWN | FRAME_SIZE;
|
||||||
device->rxDesc[i].buf_low = (uint32)((char *)rx_buf_phy + (i * FRAME_SIZE));
|
device->rxDesc[i].buf_low = (uint32)((char *)rx_buf_phy + (i * FRAME_SIZE));
|
||||||
device->rxDesc[i].buf_high = 0;
|
device->rxDesc[i].buf_high = 0;
|
||||||
}
|
}
|
||||||
device->rxDesc[i - 1].stat_len |= RX_DESC_EOR;
|
device->rxDesc[i - 1].stat_len |= RX_DESC_EOR;
|
||||||
|
|
||||||
LOG("tx_buf_desc_phy = %p\n", tx_buf_desc_phy);
|
write32(REG_RDSAR_LOW, (uint32)rx_buf_desc_phy);
|
||||||
*REG32(REG_TNPDS_LOW) = (uint32)tx_buf_desc_phy;
|
write32(REG_RDSAR_HIGH, 0);
|
||||||
LOG("REG_TNPDS_LOW = %p\n", (void *) *REG32(REG_TNPDS_LOW));
|
write32(REG_TNPDS_LOW, (uint32)tx_buf_desc_phy);
|
||||||
|
write32(REG_TNPDS_HIGH, 0);
|
||||||
*REG32(REG_TNPDS_HIGH) = 0;
|
write32(REG_THPDS_LOW, 0); // high priority tx is unused
|
||||||
*REG32(REG_THPDS_LOW) = (uint32)tx_prio_buf_desc_phy;
|
write32(REG_THPDS_HIGH, 0);
|
||||||
*REG32(REG_THPDS_HIGH) = 0;
|
|
||||||
*REG32(REG_RDSAR_LOW) = (uint32)rx_buf_desc_phy;
|
|
||||||
*REG32(REG_RDSAR_HIGH) = 0;
|
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void
|
||||||
|
rtl8169_tx_int(rtl8169_device *device)
|
||||||
|
{
|
||||||
|
int32 limit;
|
||||||
|
int32 count;
|
||||||
|
|
||||||
|
acquire_spinlock(&device->txSpinlock);
|
||||||
|
|
||||||
|
for (count = 0, limit = device->txUsed; limit > 0; limit--) {
|
||||||
|
if (device->txDesc[device->txIntIndex].stat_len & TX_DESC_OWN)
|
||||||
|
break;
|
||||||
|
device->txIntIndex = (device->txIntIndex + 1) % TX_DESC_COUNT;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dprintf("tx int, txUsed %d, count %d\n", device->txUsed, count);
|
||||||
|
|
||||||
|
device->txUsed -= count;
|
||||||
|
|
||||||
|
release_spinlock(&device->txSpinlock);
|
||||||
|
|
||||||
|
if (count)
|
||||||
|
release_sem_etc(device->txFreeSem, count, B_DO_NOT_RESCHEDULE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline void
|
||||||
|
rtl8169_rx_int(rtl8169_device *device)
|
||||||
|
{
|
||||||
|
int32 limit;
|
||||||
|
int32 count;
|
||||||
|
|
||||||
|
acquire_spinlock(&device->rxSpinlock);
|
||||||
|
|
||||||
|
for (count = 0, limit = device->rxFree; limit > 0; limit--) {
|
||||||
|
if (device->rxDesc[device->rxIntIndex].stat_len & RX_DESC_OWN)
|
||||||
|
break;
|
||||||
|
device->rxIntIndex = (device->rxIntIndex + 1) % RX_DESC_COUNT;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// dprintf("rx int, rxFree %d, count %d\n", device->rxFree, count);
|
||||||
|
|
||||||
|
device->rxFree -= count;
|
||||||
|
|
||||||
|
release_spinlock(&device->rxSpinlock);
|
||||||
|
|
||||||
|
if (count)
|
||||||
|
release_sem_etc(device->rxReadySem, count, B_DO_NOT_RESCHEDULE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32
|
||||||
|
rtl8169_int(void *data)
|
||||||
|
{
|
||||||
|
rtl8169_device *device = (rtl8169_device *)data;
|
||||||
|
uint16 stat;
|
||||||
|
int32 ret;
|
||||||
|
|
||||||
|
stat = read16(REG_INT_STAT);
|
||||||
|
if (stat == 0 || stat == 0xffff)
|
||||||
|
return B_UNHANDLED_INTERRUPT;
|
||||||
|
|
||||||
|
write16(REG_INT_STAT, stat);
|
||||||
|
ret = B_HANDLED_INTERRUPT;
|
||||||
|
|
||||||
|
if (stat & INT_FOVW) {
|
||||||
|
TRACE("INT_FOVW\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat & INT_PUN) {
|
||||||
|
TRACE("INT_PUN\n");
|
||||||
|
dump_phy_stat(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat & (INT_TOK | INT_TER)) {
|
||||||
|
rtl8169_tx_int(device);
|
||||||
|
ret = B_INVOKE_SCHEDULER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stat & (INT_ROK | INT_RER)) {
|
||||||
|
rtl8169_rx_int(device);
|
||||||
|
ret = B_INVOKE_SCHEDULER;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
rtl8169_open(const char *name, uint32 flags, void** cookie)
|
rtl8169_open(const char *name, uint32 flags, void** cookie)
|
||||||
{
|
{
|
||||||
@@ -82,14 +259,14 @@ rtl8169_open(const char *name, uint32 flags, void** cookie)
|
|||||||
int mask;
|
int mask;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
LOG("rtl8169_open()\n");
|
TRACE("rtl8169_open()\n");
|
||||||
|
|
||||||
for (dev_id = 0; (deviceName = gDevNameList[dev_id]) != NULL; dev_id++) {
|
for (dev_id = 0; (deviceName = gDevNameList[dev_id]) != NULL; dev_id++) {
|
||||||
if (!strcmp(name, deviceName))
|
if (!strcmp(name, deviceName))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (deviceName == NULL) {
|
if (deviceName == NULL) {
|
||||||
LOG("invalid device name");
|
ERROR("invalid device name");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,74 +285,160 @@ rtl8169_open(const char *name, uint32 flags, void** cookie)
|
|||||||
|
|
||||||
device->devId = dev_id;
|
device->devId = dev_id;
|
||||||
device->pciInfo = gDevList[dev_id];
|
device->pciInfo = gDevList[dev_id];
|
||||||
device->blockFlag = (flags & O_NONBLOCK) ? B_TIMEOUT : 0;
|
device->nonblocking = (flags & O_NONBLOCK) ? true : false;
|
||||||
device->closed = false;
|
device->closed = false;
|
||||||
|
|
||||||
|
device->rxSpinlock = 0;
|
||||||
device->rxReadySem = create_sem(0, "rtl8169 rx ready");
|
device->rxReadySem = create_sem(0, "rtl8169 rx ready");
|
||||||
|
device->rxNextIndex = 0;
|
||||||
|
device->rxIntIndex = 0;
|
||||||
|
device->rxFree = RX_DESC_COUNT;
|
||||||
|
|
||||||
|
device->txSpinlock = 0;
|
||||||
device->txFreeSem = create_sem(TX_DESC_COUNT, "rtl8169 tx free");
|
device->txFreeSem = create_sem(TX_DESC_COUNT, "rtl8169 tx free");
|
||||||
device->txIndex = 0;
|
device->txNextIndex = 0;
|
||||||
device->rxIndex = 0;
|
device->txIntIndex = 0;
|
||||||
|
device->txUsed = 0;
|
||||||
|
|
||||||
// enable busmaster and memory mapped access, disable io port access
|
// enable busmaster and memory mapped access, disable io port access
|
||||||
val = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, PCI_command, 2);
|
val = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, PCI_command, 2);
|
||||||
val = PCI_PCICMD_BME | PCI_PCICMD_MSE | (val & ~PCI_PCICMD_IOS);
|
val = PCI_PCICMD_BME | PCI_PCICMD_MSE | (val & ~PCI_PCICMD_IOS);
|
||||||
gPci->write_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, PCI_command, 2, val);
|
gPci->write_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, PCI_command, 2, val);
|
||||||
|
|
||||||
|
// adjust PCI latency timer
|
||||||
|
TRACE("changing PCI latency to 0x40\n");
|
||||||
|
gPci->write_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, PCI_latency, 1, 0x40);
|
||||||
|
|
||||||
|
// get IRQ
|
||||||
|
device->irq = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, PCI_interrupt_line, 1);
|
||||||
|
if (device->irq == 0 || device->irq == 0xff) {
|
||||||
|
ERROR("no IRQ assigned\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("IRQ %d\n", device->irq);
|
||||||
|
|
||||||
// map registers into memory
|
// map registers into memory
|
||||||
val = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, 0x14, 4);
|
val = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, 0x14, 4);
|
||||||
val &= PCI_address_memory_32_mask;
|
val &= PCI_address_memory_32_mask;
|
||||||
LOG("hardware register address %p\n", (void *) val);
|
TRACE("hardware register address %p\n", (void *) val);
|
||||||
device->refArea = map_mem(&device->regAddr, (void *)val, 256, 0, "rtl8169 register");
|
device->refArea = map_mem(&device->regAddr, (void *)val, 256, 0, "rtl8169 register");
|
||||||
if (device->refArea < B_OK)
|
if (device->refArea < B_OK) {
|
||||||
|
ERROR("can't map hardware registers\n");
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
LOG("mapped %p to %p\n", (void *)val, device->regAddr);
|
|
||||||
|
|
||||||
// get IRQ
|
|
||||||
device->irq = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, PCI_interrupt_line, 1);
|
|
||||||
if (device->irq == 0 || device->irq == 0xff)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
LOG("IRQ %d\n", device->irq);
|
|
||||||
|
|
||||||
// disable receiver & transmitter
|
|
||||||
*REG8(REG_CR) &= ~REG_CR_RE | REG_CR_TE;
|
|
||||||
|
|
||||||
// setup buffer descriptors and buffers
|
|
||||||
if (init_buf_desc(device) != B_OK)
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
// soft reset
|
|
||||||
*REG8(REG_CR) |= REG_CR_RST;
|
|
||||||
for (i = 0; ((*REG8(REG_CR)) & REG_CR_RST) && i < 100; i++)
|
|
||||||
snooze(10000);
|
|
||||||
if (i == 100) {
|
|
||||||
LOG("reset failed\n");
|
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
LOG("reset done, i %d\n", i);
|
|
||||||
|
|
||||||
for (i = 0; i < 6; i++)
|
|
||||||
device->macaddr[i] = *REG8(i);
|
|
||||||
|
|
||||||
dprintf("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
|
TRACE("mapped registers to %p\n", device->regAddr);
|
||||||
|
|
||||||
|
// disable receiver & transmitter
|
||||||
|
write8(REG_CR, read8(REG_CR) & ~(CR_RE | CR_TE));
|
||||||
|
|
||||||
|
// do a soft reset, does also initialize chip with buffer descriptors
|
||||||
|
write8(REG_CR, read8(REG_CR) | CR_RST);
|
||||||
|
for (i = 0; (read8(REG_CR) & CR_RST) && i < 1000; i++)
|
||||||
|
snooze(10);
|
||||||
|
if (i == 1000) {
|
||||||
|
ERROR("hardware reset failed\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE("reset done\n");
|
||||||
|
|
||||||
|
// get MAC hardware version
|
||||||
|
device->mac_version = ((read32(REG_TX_CONFIG) & 0x7c000000) >> 25) | ((read32(REG_TX_CONFIG) & 0x00800000) >> 23);
|
||||||
|
TRACE("8169 Mac Version %d\n", device->mac_version);
|
||||||
|
if (device->mac_version > 0) { // this is a RTL8169s single chip
|
||||||
|
// get PHY hardware version
|
||||||
|
device->phy_version = read_phy_reg(device, 0x03) & 0x0f;
|
||||||
|
TRACE("8169 Phy Version %d\n", device->phy_version);
|
||||||
|
} else {
|
||||||
|
device->phy_version = 0;
|
||||||
|
TRACE("8169 Phy Version unknown\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device->mac_version == 1) {
|
||||||
|
TRACE("Setting MAC Reg C+CR 0x82h = 0x01h\n");
|
||||||
|
write8(0x82, 0x01);
|
||||||
|
TRACE("Setting PHY Reg 0x0bh = 0x00h\n");
|
||||||
|
write_phy_reg(device, 0x0b, 0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// configure PHY
|
||||||
|
phy_config(device);
|
||||||
|
|
||||||
|
// initialize MAC address
|
||||||
|
for (i = 0; i < 6; i++)
|
||||||
|
device->macaddr[i] = read8(i);
|
||||||
|
|
||||||
|
TRACE("MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||||
device->macaddr[0], device->macaddr[1], device->macaddr[2],
|
device->macaddr[0], device->macaddr[1], device->macaddr[2],
|
||||||
device->macaddr[3], device->macaddr[4], device->macaddr[5]);
|
device->macaddr[3], device->macaddr[4], device->macaddr[5]);
|
||||||
|
|
||||||
|
// setup interrupt handler
|
||||||
|
if (install_io_interrupt_handler(device->irq, rtl8169_int, device, 0) < B_OK) {
|
||||||
|
ERROR("can't install interrupt handler\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
write16(0xe0, read16(0xe0)); // write CR+ command
|
||||||
|
|
||||||
|
write16(0xe0, read16(0xe0) | 0x0003); // don't know what this does, BSD says "enable C+ Tx/Rx"
|
||||||
|
|
||||||
|
if (device->mac_version == 1) {
|
||||||
|
TRACE("Setting Reg C+CR bit 3 and bit 14 to 1\n");
|
||||||
|
write16(0xe0, read16(0xe0) | 0x4008);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup buffer descriptors and buffers
|
||||||
|
if (init_buf_desc(device) != B_OK) {
|
||||||
|
ERROR("setting up buffer descriptors failed\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
LOG("tx base = %p\n", (void *) *REG32(REG_TNPDS_LOW));
|
|
||||||
|
|
||||||
// enable receiver & transmitter
|
// enable receiver & transmitter
|
||||||
// *REG8(REG_CR) |= REG_CR_RE | REG_CR_TE;
|
write8(REG_CR, read8(REG_CR) | CR_RE | CR_TE);
|
||||||
|
|
||||||
|
write8(REG_9346CR, 0xc0); // enable config access
|
||||||
|
write8(REG_CONFIG1, read8(REG_CONFIG1) & ~1); // disable power management
|
||||||
|
write8(REG_9346CR, 0x00); // disable config access
|
||||||
|
|
||||||
|
write8(0xec, 0x3f); // disable early transmit treshold
|
||||||
|
write16(0xda, FRAME_SIZE); // receive packet maximum size
|
||||||
|
|
||||||
|
write16(0x5c, read16(0x5c) & 0xf000); // disable early receive interrupts
|
||||||
|
|
||||||
|
write32(0x4c, 0); // RxMissed ???
|
||||||
|
|
||||||
|
// setup receive config, can only be done when receiver is enabled!
|
||||||
|
// 1024 byte FIFO treshold, 1024 DMA burst
|
||||||
|
write32(REG_RX_CONFIG, (read32(REG_RX_CONFIG) & RX_CONFIG_MASK)
|
||||||
|
| (0x6 << RC_CONFIG_RXFTH_Shift) | (0x6 << RC_CONFIG_MAXDMA_Shift)
|
||||||
|
| RX_CONFIG_AcceptBroad | RX_CONFIG_AcceptMulti | RX_CONFIG_AcceptMyPhys);
|
||||||
|
|
||||||
|
write32(0x8, 0); // multicast filter
|
||||||
|
write32(0xc, 0); // multicast filter
|
||||||
|
|
||||||
|
// setup transmit config, can only be done when transmitter is enabled!
|
||||||
|
// append CRC, 1024 DMA burst
|
||||||
|
write32(REG_TX_CONFIG, (read32(REG_TX_CONFIG) & ~(0x10000 | (1 << 8))) | (0x6 << 8));
|
||||||
|
|
||||||
|
// clear pending interrupt status
|
||||||
|
write16(REG_INT_STAT, 0xffff);
|
||||||
|
|
||||||
|
// enable used interrupts
|
||||||
|
write16(REG_INT_MASK, INT_FOVW | INT_PUN | INT_TER | INT_TOK | INT_RER | INT_ROK);
|
||||||
|
|
||||||
|
dump_phy_stat(device);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
LOG("error!\n");
|
|
||||||
delete_sem(device->rxReadySem);
|
delete_sem(device->rxReadySem);
|
||||||
delete_sem(device->txFreeSem);
|
delete_sem(device->txFreeSem);
|
||||||
delete_area(device->refArea);
|
delete_area(device->refArea);
|
||||||
delete_area(device->txBufArea);
|
delete_area(device->txBufArea);
|
||||||
delete_area(device->rxBufArea);
|
delete_area(device->rxBufArea);
|
||||||
delete_area(device->txDescArea);
|
delete_area(device->txDescArea);
|
||||||
delete_area(device->txPrioDescArea);
|
|
||||||
delete_area(device->rxDescArea);
|
delete_area(device->rxDescArea);
|
||||||
free(device);
|
free(device);
|
||||||
atomic_and(&gOpenMask, ~(1 << dev_id));
|
atomic_and(&gOpenMask, ~(1 << dev_id));
|
||||||
@@ -187,7 +450,7 @@ status_t
|
|||||||
rtl8169_close(void* cookie)
|
rtl8169_close(void* cookie)
|
||||||
{
|
{
|
||||||
rtl8169_device *device = (rtl8169_device *)cookie;
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
LOG("rtl8169_close()\n");
|
TRACE("rtl8169_close()\n");
|
||||||
|
|
||||||
device->closed = true;
|
device->closed = true;
|
||||||
release_sem(device->rxReadySem);
|
release_sem(device->rxReadySem);
|
||||||
@@ -201,10 +464,16 @@ status_t
|
|||||||
rtl8169_free(void* cookie)
|
rtl8169_free(void* cookie)
|
||||||
{
|
{
|
||||||
rtl8169_device *device = (rtl8169_device *)cookie;
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
LOG("rtl8169_free()\n");
|
TRACE("rtl8169_free()\n");
|
||||||
|
|
||||||
// disable receiver & transmitter
|
// disable receiver & transmitter
|
||||||
*REG8(REG_CR) &= ~REG_CR_RE | REG_CR_TE;
|
write8(REG_CR, read8(REG_CR) & ~(CR_RE | CR_TE));
|
||||||
|
|
||||||
|
// disable interrupts
|
||||||
|
write16(REG_INT_MASK, 0);
|
||||||
|
|
||||||
|
// well...
|
||||||
|
remove_io_interrupt_handler (device->irq, rtl8169_int, device);
|
||||||
|
|
||||||
delete_sem(device->rxReadySem);
|
delete_sem(device->rxReadySem);
|
||||||
delete_sem(device->txFreeSem);
|
delete_sem(device->txFreeSem);
|
||||||
@@ -212,7 +481,6 @@ rtl8169_free(void* cookie)
|
|||||||
delete_area(device->txBufArea);
|
delete_area(device->txBufArea);
|
||||||
delete_area(device->rxBufArea);
|
delete_area(device->rxBufArea);
|
||||||
delete_area(device->txDescArea);
|
delete_area(device->txDescArea);
|
||||||
delete_area(device->txPrioDescArea);
|
|
||||||
delete_area(device->rxDescArea);
|
delete_area(device->rxDescArea);
|
||||||
free(device);
|
free(device);
|
||||||
atomic_and(&gOpenMask, ~(1 << device->devId));
|
atomic_and(&gOpenMask, ~(1 << device->devId));
|
||||||
@@ -224,24 +492,58 @@ status_t
|
|||||||
rtl8169_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
|
rtl8169_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
|
||||||
{
|
{
|
||||||
rtl8169_device *device = (rtl8169_device *)cookie;
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
|
cpu_status cpu;
|
||||||
status_t stat;
|
status_t stat;
|
||||||
LOG("rtl8169_read()\n");
|
int len;
|
||||||
|
TRACE("rtl8169_read() enter\n");
|
||||||
|
|
||||||
if (device->closed)
|
if (device->closed) {
|
||||||
|
TRACE("rtl8169_read() interrupted 1\n");
|
||||||
return B_INTERRUPTED;
|
return B_INTERRUPTED;
|
||||||
|
}
|
||||||
retry:
|
retry:
|
||||||
stat = acquire_sem_etc(device->rxReadySem, 1, B_CAN_INTERRUPT | device->blockFlag, 0);
|
stat = acquire_sem_etc(device->rxReadySem, 1, B_CAN_INTERRUPT | (device->nonblocking ? B_TIMEOUT : 0), 0);
|
||||||
if (device->closed)
|
if (device->closed) {
|
||||||
|
// TRACE("rtl8169_read() interrupted 2\n"); // net_server will crash if we print this (race condition in net_server?)
|
||||||
return B_INTERRUPTED;
|
return B_INTERRUPTED;
|
||||||
|
}
|
||||||
if (stat == B_WOULD_BLOCK) {
|
if (stat == B_WOULD_BLOCK) {
|
||||||
|
TRACE("rtl8169_read() would block (OK 0 bytes)\n");
|
||||||
*num_bytes = 0;
|
*num_bytes = 0;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
if (stat != B_OK)
|
if (stat != B_OK) {
|
||||||
|
TRACE("rtl8169_read() error\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device->rxDesc[device->rxNextIndex].stat_len & RX_DESC_OWN) {
|
||||||
|
ERROR("rtl8169_read() buffer still in use\n");
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = (device->rxDesc[device->rxNextIndex].stat_len & RX_DESC_LEN_MASK);
|
||||||
|
len -= 4; // remove CRC that Realtek always appends
|
||||||
|
if (len < 0)
|
||||||
|
len = 0;
|
||||||
|
if (len > *num_bytes)
|
||||||
|
len = *num_bytes;
|
||||||
|
|
||||||
|
memcpy(buf, device->rxBuf[device->rxNextIndex], len);
|
||||||
|
*num_bytes = len;
|
||||||
|
|
||||||
|
cpu = disable_interrupts();
|
||||||
|
acquire_spinlock(&device->rxSpinlock);
|
||||||
|
|
||||||
|
device->rxDesc[device->rxNextIndex].stat_len = RX_DESC_OWN | FRAME_SIZE | (device->rxDesc[device->rxNextIndex].stat_len & RX_DESC_EOR);
|
||||||
|
device->rxFree++;
|
||||||
|
|
||||||
|
release_spinlock(&device->rxSpinlock);
|
||||||
|
restore_interrupts(cpu);
|
||||||
|
|
||||||
|
device->rxNextIndex = (device->rxNextIndex + 1) % RX_DESC_COUNT;
|
||||||
|
|
||||||
|
TRACE("rtl8169_read() leave\n");
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,72 +552,126 @@ status_t
|
|||||||
rtl8169_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
|
rtl8169_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
|
||||||
{
|
{
|
||||||
rtl8169_device *device = (rtl8169_device *)cookie;
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
|
cpu_status cpu;
|
||||||
status_t stat;
|
status_t stat;
|
||||||
|
int len;
|
||||||
|
|
||||||
LOG("rtl8169_write()\n");
|
TRACE("rtl8169_write() enter\n");
|
||||||
|
|
||||||
if (device->closed)
|
len = *num_bytes;
|
||||||
return B_INTERRUPTED;
|
if (len > FRAME_SIZE) {
|
||||||
|
TRACE("rtl8169_write() buffer too large\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
stat = acquire_sem_etc(device->txFreeSem, 1, B_CAN_INTERRUPT | B_TIMEOUT, TX_TIMEOUT);
|
if (device->closed) {
|
||||||
if (device->closed)
|
TRACE("rtl8169_write() interrupted 1\n");
|
||||||
return B_INTERRUPTED;
|
return B_INTERRUPTED;
|
||||||
if (device->blockFlag && stat == B_WOULD_BLOCK) {
|
}
|
||||||
|
retry:
|
||||||
|
stat = acquire_sem_etc(device->txFreeSem, 1, B_CAN_INTERRUPT | B_TIMEOUT, device->nonblocking ? 0 : TX_TIMEOUT);
|
||||||
|
if (device->closed) {
|
||||||
|
TRACE("rtl8169_write() interrupted 2\n");
|
||||||
|
return B_INTERRUPTED;
|
||||||
|
}
|
||||||
|
if (stat == B_WOULD_BLOCK) {
|
||||||
|
TRACE("rtl8169_write() would block (OK 0 bytes)\n");
|
||||||
*num_bytes = 0;
|
*num_bytes = 0;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
if (stat != B_OK)
|
if (stat == B_TIMED_OUT) {
|
||||||
|
TRACE("rtl8169_write() timeout\n");
|
||||||
|
return B_BUSY;
|
||||||
|
}
|
||||||
|
if (stat != B_OK) {
|
||||||
|
TRACE("rtl8169_write() error\n");
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device->txDesc[device->txNextIndex].stat_len & TX_DESC_OWN) {
|
||||||
|
ERROR("rtl8169_write() buffer still in use\n");
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(device->txBuf[device->txNextIndex], buffer, len);
|
||||||
|
|
||||||
|
cpu = disable_interrupts();
|
||||||
|
acquire_spinlock(&device->txSpinlock);
|
||||||
|
|
||||||
|
device->txUsed++;
|
||||||
|
device->txDesc[device->txNextIndex].stat_len = (device->txDesc[device->txNextIndex].stat_len & RX_DESC_EOR) | TX_DESC_OWN | TX_DESC_FS | TX_DESC_LS | len;
|
||||||
|
|
||||||
|
release_spinlock(&device->txSpinlock);
|
||||||
|
restore_interrupts(cpu);
|
||||||
|
|
||||||
|
device->txNextIndex = (device->txNextIndex + 1) % TX_DESC_COUNT;
|
||||||
|
|
||||||
|
write8(REG_TPPOLL, read8(REG_TPPOLL) | TPPOLL_NPQ); // set queue polling bit
|
||||||
|
|
||||||
|
TRACE("rtl8169_write() leave\n");
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
rtl8169_control(void *cookie, uint32 op, void *arg, size_t len)
|
rtl8169_control(void *cookie, uint32 op, void *arg, size_t len)
|
||||||
{
|
{
|
||||||
rtl8169_device *device = (rtl8169_device *)cookie;
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
|
|
||||||
LOG("rtl8169_control()\n");
|
|
||||||
|
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case ETHER_INIT:
|
case ETHER_INIT:
|
||||||
LOG("ETHER_INIT\n");
|
TRACE("rtl8169_control() ETHER_INIT\n");
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
case ETHER_GETADDR:
|
case ETHER_GETADDR:
|
||||||
LOG("ETHER_GETADDR\n");
|
TRACE("rtl8169_control() ETHER_GETADDR\n");
|
||||||
memcpy(arg, &device->macaddr, sizeof(device->macaddr));
|
memcpy(arg, &device->macaddr, sizeof(device->macaddr));
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
case ETHER_NONBLOCK:
|
case ETHER_NONBLOCK:
|
||||||
LOG("ETHER_NON_BLOCK\n");
|
if (*(int32 *)arg) {
|
||||||
device->blockFlag = *(int32 *)arg ? B_TIMEOUT : 0;
|
TRACE("non blocking mode on\n");
|
||||||
|
device->nonblocking = true;
|
||||||
|
/* could be used to unblock pending read and write calls,
|
||||||
|
* but this doesn't seem to be required
|
||||||
|
release_sem_etc(device->txFreeSem, 1, B_DO_NOT_RESCHEDULE);
|
||||||
|
release_sem_etc(device->rxReadySem, 1, B_DO_NOT_RESCHEDULE);
|
||||||
|
*/
|
||||||
|
} else {
|
||||||
|
TRACE("non blocking mode off\n");
|
||||||
|
device->nonblocking = false;
|
||||||
|
}
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
case ETHER_ADDMULTI:
|
case ETHER_ADDMULTI:
|
||||||
LOG("ETHER_ADDMULTI\n");
|
TRACE("rtl8169_control() ETHER_ADDMULTI\n");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ETHER_REMMULTI:
|
case ETHER_REMMULTI:
|
||||||
LOG("ETHER_REMMULTI\n");
|
TRACE("rtl8169_control() ETHER_REMMULTI\n");
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
case ETHER_SETPROMISC:
|
case ETHER_SETPROMISC:
|
||||||
LOG("ETHER_SETPROMISC\n");
|
if (*(int32 *)arg) {
|
||||||
|
TRACE("promiscuous mode on\n");
|
||||||
|
write32(REG_RX_CONFIG, read32(REG_RX_CONFIG) | RX_CONFIG_AcceptAllPhys);
|
||||||
|
write32(0x8, 0xffffffff); // multicast filter
|
||||||
|
write32(0xc, 0xffffffff); // multicast filter
|
||||||
|
} else {
|
||||||
|
TRACE("promiscuous mode off\n");
|
||||||
|
write32(REG_RX_CONFIG, read32(REG_RX_CONFIG) & ~RX_CONFIG_AcceptAllPhys);
|
||||||
|
write32(0x8, 0); // multicast filter
|
||||||
|
write32(0xc, 0); // multicast filter
|
||||||
|
}
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
case ETHER_GETFRAMESIZE:
|
case ETHER_GETFRAMESIZE:
|
||||||
LOG("ETHER_GETFRAMESIZE\n");
|
TRACE("rtl8169_control() ETHER_GETFRAMESIZE\n");
|
||||||
*(uint32*)arg = FRAME_SIZE;
|
*(uint32*)arg = FRAME_SIZE;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG("Invalid command\n");
|
TRACE("rtl8169_control() Invalid command\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,16 @@
|
|||||||
|
/* Realtek RTL8169 Family Driver
|
||||||
|
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
|
||||||
|
*/
|
||||||
#ifndef __DEVICE_H
|
#ifndef __DEVICE_H
|
||||||
#define __DEVICE_H
|
#define __DEVICE_H
|
||||||
|
|
||||||
#include <PCI.h>
|
#include <PCI.h>
|
||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
|
|
||||||
#define TX_TIMEOUT 250000
|
#define TX_TIMEOUT 6000000 // 6 seconds
|
||||||
#define FRAME_SIZE 1536 // must be multiple of 8
|
#define FRAME_SIZE 1536 // must be multiple of 8
|
||||||
#define TX_DESC_COUNT 42 // must be <= 1024
|
#define TX_DESC_COUNT 256 // must be <= 1024
|
||||||
#define RX_DESC_COUNT 42 // must be <= 1024
|
#define RX_DESC_COUNT 256 // must be <= 1024
|
||||||
|
|
||||||
extern pci_module_info *gPci;
|
extern pci_module_info *gPci;
|
||||||
|
|
||||||
@@ -22,21 +25,26 @@ typedef struct {
|
|||||||
int devId;
|
int devId;
|
||||||
pci_info * pciInfo;
|
pci_info * pciInfo;
|
||||||
|
|
||||||
volatile uint32 blockFlag;
|
volatile bool nonblocking;
|
||||||
volatile bool closed;
|
volatile bool closed;
|
||||||
|
|
||||||
sem_id rxReadySem;
|
spinlock txSpinlock;
|
||||||
sem_id txFreeSem;
|
sem_id txFreeSem;
|
||||||
|
volatile int32 txNextIndex; // next descriptor that will be used for writing
|
||||||
|
volatile int32 txIntIndex; // current descriptor that needs be checked
|
||||||
|
volatile int32 txUsed;
|
||||||
|
|
||||||
|
spinlock rxSpinlock;
|
||||||
|
sem_id rxReadySem;
|
||||||
|
volatile int32 rxNextIndex; // next descriptor that will be used for reading
|
||||||
|
volatile int32 rxIntIndex; // current descriptor that needs be checked
|
||||||
|
volatile int32 rxFree;
|
||||||
|
|
||||||
volatile int32 txIndex;
|
|
||||||
volatile int32 rxIndex;
|
|
||||||
|
|
||||||
volatile tx_desc * txDesc;
|
volatile buf_desc * txDesc;
|
||||||
volatile tx_desc * txPrioDesc;
|
volatile buf_desc * rxDesc;
|
||||||
volatile rx_desc * rxDesc;
|
|
||||||
|
|
||||||
area_id txDescArea;
|
area_id txDescArea;
|
||||||
area_id txPrioDescArea;
|
|
||||||
area_id rxDescArea;
|
area_id rxDescArea;
|
||||||
area_id txBufArea;
|
area_id txBufArea;
|
||||||
area_id rxBufArea;
|
area_id rxBufArea;
|
||||||
@@ -46,13 +54,18 @@ typedef struct {
|
|||||||
|
|
||||||
void * regAddr;
|
void * regAddr;
|
||||||
area_id refArea;
|
area_id refArea;
|
||||||
uint8 irq;
|
|
||||||
|
|
||||||
|
uint8 irq;
|
||||||
uint8 macaddr[6];
|
uint8 macaddr[6];
|
||||||
|
int mac_version;
|
||||||
|
int phy_version;
|
||||||
} rtl8169_device;
|
} rtl8169_device;
|
||||||
|
|
||||||
#define REG8(offset) ((volatile uint8 *)((char *)(device->regAddr) + (offset)))
|
#define read8(offset) (*(volatile uint8 *) ((char *)(device->regAddr) + (offset)))
|
||||||
#define REG16(offset) ((volatile uint16 *)((char *)(device->regAddr) + (offset)))
|
#define read16(offset) (*(volatile uint16 *)((char *)(device->regAddr) + (offset)))
|
||||||
#define REG32(offset) ((volatile uint32 *)((char *)(device->regAddr) + (offset)))
|
#define read32(offset) (*(volatile uint32 *)((char *)(device->regAddr) + (offset)))
|
||||||
|
#define write8(offset, value) (*(volatile uint8 *) ((char *)(device->regAddr) + (offset)) = value)
|
||||||
|
#define write16(offset, value) (*(volatile uint16 *)((char *)(device->regAddr) + (offset)) = value)
|
||||||
|
#define write32(offset, value) (*(volatile uint32 *)((char *)(device->regAddr) + (offset)) = value)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user