First version of the:
Realtek RTL8169 Family Gigabit Ethernet Driver Very basic, does only detection of the card and sets up some buffer descriptors. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7380 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef __DEBUG_H
|
||||||
|
#define __DEBUG_H
|
||||||
|
|
||||||
|
#include <KernelExport.h>
|
||||||
|
|
||||||
|
#define DEBUG
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define LOG dprintf
|
||||||
|
#else
|
||||||
|
#define LOG(a...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
#include <KernelExport.h>
|
||||||
|
#include <Errors.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "driver.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static int32 gOpenMask = 0;
|
||||||
|
|
||||||
|
status_t
|
||||||
|
init_buf_desc(rtl8169_device *device)
|
||||||
|
{
|
||||||
|
void *rx_buf_desc_virt, *rx_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 *rx_buf_virt, *rx_buf_phy;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
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->txDescArea = alloc_mem(&tx_buf_desc_virt, &tx_buf_desc_phy, TX_DESC_COUNT * sizeof(tx_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(rx_desc), 0, "rtl8169 rx desc");
|
||||||
|
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;
|
||||||
|
|
||||||
|
device->txDesc = (tx_desc *) tx_buf_desc_virt;
|
||||||
|
device->txPrioDesc = (tx_desc *) tx_prio_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
|
||||||
|
for (i = 0; i < TX_DESC_COUNT; i++) {
|
||||||
|
device->txBuf[i] = (char *)tx_buf_virt + (i * FRAME_SIZE);
|
||||||
|
device->txDesc[i].stat_len = TX_DESC_FS | TX_DESC_LS;
|
||||||
|
device->txDesc[i].buf_low = (uint32)((char *)tx_buf_phy + (i * FRAME_SIZE));
|
||||||
|
device->txDesc[i].buf_high = 0;
|
||||||
|
}
|
||||||
|
device->txDesc[i - 1].stat_len |= TX_DESC_EOR;
|
||||||
|
|
||||||
|
// setup receive descriptors
|
||||||
|
for (i = 0; i < RX_DESC_COUNT; i++) {
|
||||||
|
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].buf_low = (uint32)((char *)rx_buf_phy + (i * FRAME_SIZE));
|
||||||
|
device->rxDesc[i].buf_high = 0;
|
||||||
|
}
|
||||||
|
device->rxDesc[i - 1].stat_len |= RX_DESC_EOR;
|
||||||
|
|
||||||
|
LOG("tx_buf_desc_phy = %p\n", tx_buf_desc_phy);
|
||||||
|
*REG32(REG_TNPDS_LOW) = (uint32)tx_buf_desc_phy;
|
||||||
|
LOG("REG_TNPDS_LOW = %p\n", (void *) *REG32(REG_TNPDS_LOW));
|
||||||
|
|
||||||
|
*REG32(REG_TNPDS_HIGH) = 0;
|
||||||
|
*REG32(REG_THPDS_LOW) = (uint32)tx_prio_buf_desc_phy;
|
||||||
|
*REG32(REG_THPDS_HIGH) = 0;
|
||||||
|
*REG32(REG_RDSAR_LOW) = (uint32)rx_buf_desc_phy;
|
||||||
|
*REG32(REG_RDSAR_HIGH) = 0;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t
|
||||||
|
rtl8169_open(const char *name, uint32 flags, void** cookie)
|
||||||
|
{
|
||||||
|
rtl8169_device *device;
|
||||||
|
char *deviceName;
|
||||||
|
uint32 val;
|
||||||
|
int dev_id;
|
||||||
|
int mask;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
LOG("rtl8169_open()\n");
|
||||||
|
|
||||||
|
for (dev_id = 0; (deviceName = gDevNameList[dev_id]) != NULL; dev_id++) {
|
||||||
|
if (!strcmp(name, deviceName))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (deviceName == NULL) {
|
||||||
|
LOG("invalid device name");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// allow only one concurrent access
|
||||||
|
mask = 1 << dev_id;
|
||||||
|
if (atomic_or(&gOpenMask, mask) & mask)
|
||||||
|
return B_BUSY;
|
||||||
|
|
||||||
|
*cookie = device = (rtl8169_device *)malloc(sizeof(rtl8169_device));
|
||||||
|
if (!device) {
|
||||||
|
atomic_and(&gOpenMask, ~(1 << dev_id));
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(device, 0, sizeof(*device));
|
||||||
|
|
||||||
|
device->devId = dev_id;
|
||||||
|
device->pciInfo = gDevList[dev_id];
|
||||||
|
device->blockFlag = (flags & O_NONBLOCK) ? B_TIMEOUT : 0;
|
||||||
|
device->closed = false;
|
||||||
|
device->rxReadySem = create_sem(0, "rtl8169 rx ready");
|
||||||
|
device->txFreeSem = create_sem(TX_DESC_COUNT, "rtl8169 tx free");
|
||||||
|
device->txIndex = 0;
|
||||||
|
device->rxIndex = 0;
|
||||||
|
|
||||||
|
// 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 = 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);
|
||||||
|
|
||||||
|
// map registers into memory
|
||||||
|
val = gPci->read_pci_config(device->pciInfo->bus, device->pciInfo->device, device->pciInfo->function, 0x14, 4);
|
||||||
|
val &= PCI_address_memory_32_mask;
|
||||||
|
LOG("hardware register address %p\n", (void *) val);
|
||||||
|
device->refArea = map_mem(&device->regAddr, (void *)val, 256, 0, "rtl8169 register");
|
||||||
|
if (device->refArea < B_OK)
|
||||||
|
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",
|
||||||
|
device->macaddr[0], device->macaddr[1], device->macaddr[2],
|
||||||
|
device->macaddr[3], device->macaddr[4], device->macaddr[5]);
|
||||||
|
|
||||||
|
LOG("tx base = %p\n", (void *) *REG32(REG_TNPDS_LOW));
|
||||||
|
|
||||||
|
// enable receiver & transmitter
|
||||||
|
// *REG8(REG_CR) |= REG_CR_RE | REG_CR_TE;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
err:
|
||||||
|
LOG("error!\n");
|
||||||
|
delete_sem(device->rxReadySem);
|
||||||
|
delete_sem(device->txFreeSem);
|
||||||
|
delete_area(device->refArea);
|
||||||
|
delete_area(device->txBufArea);
|
||||||
|
delete_area(device->rxBufArea);
|
||||||
|
delete_area(device->txDescArea);
|
||||||
|
delete_area(device->txPrioDescArea);
|
||||||
|
delete_area(device->rxDescArea);
|
||||||
|
free(device);
|
||||||
|
atomic_and(&gOpenMask, ~(1 << dev_id));
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
rtl8169_close(void* cookie)
|
||||||
|
{
|
||||||
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
|
LOG("rtl8169_close()\n");
|
||||||
|
|
||||||
|
device->closed = true;
|
||||||
|
release_sem(device->rxReadySem);
|
||||||
|
release_sem(device->txFreeSem);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
rtl8169_free(void* cookie)
|
||||||
|
{
|
||||||
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
|
LOG("rtl8169_free()\n");
|
||||||
|
|
||||||
|
// disable receiver & transmitter
|
||||||
|
*REG8(REG_CR) &= ~REG_CR_RE | REG_CR_TE;
|
||||||
|
|
||||||
|
delete_sem(device->rxReadySem);
|
||||||
|
delete_sem(device->txFreeSem);
|
||||||
|
delete_area(device->refArea);
|
||||||
|
delete_area(device->txBufArea);
|
||||||
|
delete_area(device->rxBufArea);
|
||||||
|
delete_area(device->txDescArea);
|
||||||
|
delete_area(device->txPrioDescArea);
|
||||||
|
delete_area(device->rxDescArea);
|
||||||
|
free(device);
|
||||||
|
atomic_and(&gOpenMask, ~(1 << device->devId));
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
rtl8169_read(void* cookie, off_t position, void *buf, size_t* num_bytes)
|
||||||
|
{
|
||||||
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
|
status_t stat;
|
||||||
|
LOG("rtl8169_read()\n");
|
||||||
|
|
||||||
|
if (device->closed)
|
||||||
|
return B_INTERRUPTED;
|
||||||
|
retry:
|
||||||
|
stat = acquire_sem_etc(device->rxReadySem, 1, B_CAN_INTERRUPT | device->blockFlag, 0);
|
||||||
|
if (device->closed)
|
||||||
|
return B_INTERRUPTED;
|
||||||
|
if (stat == B_WOULD_BLOCK) {
|
||||||
|
*num_bytes = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
if (stat != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
rtl8169_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes)
|
||||||
|
{
|
||||||
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
|
status_t stat;
|
||||||
|
|
||||||
|
LOG("rtl8169_write()\n");
|
||||||
|
|
||||||
|
if (device->closed)
|
||||||
|
return B_INTERRUPTED;
|
||||||
|
|
||||||
|
stat = acquire_sem_etc(device->txFreeSem, 1, B_CAN_INTERRUPT | B_TIMEOUT, TX_TIMEOUT);
|
||||||
|
if (device->closed)
|
||||||
|
return B_INTERRUPTED;
|
||||||
|
if (device->blockFlag && stat == B_WOULD_BLOCK) {
|
||||||
|
*num_bytes = 0;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
if (stat != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
rtl8169_control(void *cookie, uint32 op, void *arg, size_t len)
|
||||||
|
{
|
||||||
|
rtl8169_device *device = (rtl8169_device *)cookie;
|
||||||
|
|
||||||
|
LOG("rtl8169_control()\n");
|
||||||
|
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case ETHER_INIT:
|
||||||
|
LOG("ETHER_INIT\n");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case ETHER_GETADDR:
|
||||||
|
LOG("ETHER_GETADDR\n");
|
||||||
|
memcpy(arg, &device->macaddr, sizeof(device->macaddr));
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case ETHER_NONBLOCK:
|
||||||
|
LOG("ETHER_NON_BLOCK\n");
|
||||||
|
device->blockFlag = *(int32 *)arg ? B_TIMEOUT : 0;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case ETHER_ADDMULTI:
|
||||||
|
LOG("ETHER_ADDMULTI\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ETHER_REMMULTI:
|
||||||
|
LOG("ETHER_REMMULTI\n");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case ETHER_SETPROMISC:
|
||||||
|
LOG("ETHER_SETPROMISC\n");
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case ETHER_GETFRAMESIZE:
|
||||||
|
LOG("ETHER_GETFRAMESIZE\n");
|
||||||
|
*(uint32*)arg = FRAME_SIZE;
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
default:
|
||||||
|
LOG("Invalid command\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
#ifndef __DEVICE_H
|
||||||
|
#define __DEVICE_H
|
||||||
|
|
||||||
|
#include <PCI.h>
|
||||||
|
#include "hardware.h"
|
||||||
|
|
||||||
|
#define TX_TIMEOUT 250000
|
||||||
|
#define FRAME_SIZE 1536 // must be multiple of 8
|
||||||
|
#define TX_DESC_COUNT 42 // must be <= 1024
|
||||||
|
#define RX_DESC_COUNT 42 // must be <= 1024
|
||||||
|
|
||||||
|
extern pci_module_info *gPci;
|
||||||
|
|
||||||
|
status_t rtl8169_open(const char *name, uint32 flags, void** cookie);
|
||||||
|
status_t rtl8169_read(void* cookie, off_t position, void *buf, size_t* num_bytes);
|
||||||
|
status_t rtl8169_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes);
|
||||||
|
status_t rtl8169_control(void *cookie, uint32 op, void *arg, size_t len);
|
||||||
|
status_t rtl8169_close(void* cookie);
|
||||||
|
status_t rtl8169_free(void* cookie);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int devId;
|
||||||
|
pci_info * pciInfo;
|
||||||
|
|
||||||
|
volatile uint32 blockFlag;
|
||||||
|
volatile bool closed;
|
||||||
|
|
||||||
|
sem_id rxReadySem;
|
||||||
|
sem_id txFreeSem;
|
||||||
|
|
||||||
|
volatile int32 txIndex;
|
||||||
|
volatile int32 rxIndex;
|
||||||
|
|
||||||
|
volatile tx_desc * txDesc;
|
||||||
|
volatile tx_desc * txPrioDesc;
|
||||||
|
volatile rx_desc * rxDesc;
|
||||||
|
|
||||||
|
area_id txDescArea;
|
||||||
|
area_id txPrioDescArea;
|
||||||
|
area_id rxDescArea;
|
||||||
|
area_id txBufArea;
|
||||||
|
area_id rxBufArea;
|
||||||
|
|
||||||
|
void * txBuf[TX_DESC_COUNT];
|
||||||
|
void * rxBuf[RX_DESC_COUNT];
|
||||||
|
|
||||||
|
void * regAddr;
|
||||||
|
area_id refArea;
|
||||||
|
uint8 irq;
|
||||||
|
|
||||||
|
uint8 macaddr[6];
|
||||||
|
} rtl8169_device;
|
||||||
|
|
||||||
|
#define REG8(offset) ((volatile uint8 *)((char *)(device->regAddr) + (offset)))
|
||||||
|
#define REG16(offset) ((volatile uint16 *)((char *)(device->regAddr) + (offset)))
|
||||||
|
#define REG32(offset) ((volatile uint32 *)((char *)(device->regAddr) + (offset)))
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
/* Realtek RTL8169 Family Driver
|
||||||
|
* Copyright (C) 2004 Marcus Overhagen <[email protected]>. All rights reserved.
|
||||||
|
*/
|
||||||
|
#include <KernelExport.h>
|
||||||
|
#include <Errors.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "device.h"
|
||||||
|
#include "driver.h"
|
||||||
|
|
||||||
|
int32 api_version = B_CUR_DRIVER_API_VERSION;
|
||||||
|
|
||||||
|
pci_module_info *gPci;
|
||||||
|
|
||||||
|
char* gDevNameList[MAX_CARDS + 1];
|
||||||
|
pci_info *gDevList[MAX_CARDS];
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
init_hardware(void)
|
||||||
|
{
|
||||||
|
LOG("rtl8169: init_hardware()\n");
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
init_driver(void)
|
||||||
|
{
|
||||||
|
struct pci_info *item;
|
||||||
|
int index;
|
||||||
|
int cards;
|
||||||
|
|
||||||
|
LOG("rtl8169: init_driver()\n");
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
set_dprintf_enabled(true);
|
||||||
|
load_driver_symbols("rtl8169");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
item = (pci_info *)malloc(sizeof(pci_info));
|
||||||
|
if (!item)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
for (cards = 0, index = 0; gPci->get_nth_pci_info(index++, item) == B_OK; ) {
|
||||||
|
if (item->vendor_id == 0x10ec && item->device_id == 0x8169) {
|
||||||
|
char name[64];
|
||||||
|
sprintf(name, "net/rtl8169/%d", cards);
|
||||||
|
gDevList[cards] = item;
|
||||||
|
gDevNameList[cards] = strdup(name);
|
||||||
|
gDevNameList[cards + 1] = NULL;
|
||||||
|
cards++;
|
||||||
|
item = (pci_info *)malloc(sizeof(pci_info));
|
||||||
|
if (!item)
|
||||||
|
return B_OK; // already found 1 card, but out of memory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG("rtl8169: found %d cards\n", cards);
|
||||||
|
|
||||||
|
free(item);
|
||||||
|
|
||||||
|
if (!cards) {
|
||||||
|
put_module(B_PCI_MODULE_NAME);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
uninit_driver(void)
|
||||||
|
{
|
||||||
|
int32 i;
|
||||||
|
|
||||||
|
LOG("rtl8169: uninit_driver()\n");
|
||||||
|
|
||||||
|
for (i = 0; gDevNameList[i] != NULL; i++) {
|
||||||
|
free(gDevList[i]);
|
||||||
|
free(gDevNameList[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
put_module(B_PCI_MODULE_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_hooks
|
||||||
|
gDeviceHooks = {
|
||||||
|
rtl8169_open,
|
||||||
|
rtl8169_close,
|
||||||
|
rtl8169_free,
|
||||||
|
rtl8169_control,
|
||||||
|
rtl8169_read,
|
||||||
|
rtl8169_write,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const char**
|
||||||
|
publish_devices()
|
||||||
|
{
|
||||||
|
return (const char**)gDevNameList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_hooks*
|
||||||
|
find_device(const char* name)
|
||||||
|
{
|
||||||
|
return &gDeviceHooks;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
#ifndef __DRIVER_H
|
||||||
|
#define __DRIVER_H
|
||||||
|
|
||||||
|
#include <Drivers.h>
|
||||||
|
#include <PCI.h>
|
||||||
|
#include "ether_driver.h"
|
||||||
|
|
||||||
|
#define MAX_CARDS 8
|
||||||
|
|
||||||
|
extern pci_module_info *gPci;
|
||||||
|
|
||||||
|
extern char* gDevNameList[];
|
||||||
|
extern pci_info *gDevList[];
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#ifndef _ETHER_DRIVER_H
|
||||||
|
#define _ETHER_DRIVER_H
|
||||||
|
|
||||||
|
#include <Drivers.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ioctls: belongs in a public header file
|
||||||
|
* somewhere, so that the net_server and other ethernet drivers can use.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ETHER_GETADDR = B_DEVICE_OP_CODES_END, /* get ethernet address */
|
||||||
|
ETHER_INIT, /* set irq and port */
|
||||||
|
ETHER_NONBLOCK, /* set/unset nonblocking mode */
|
||||||
|
ETHER_ADDMULTI, /* add multicast addr */
|
||||||
|
ETHER_REMMULTI, /* rem multicast addr */
|
||||||
|
ETHER_SETPROMISC, /* set promiscuous */
|
||||||
|
ETHER_GETFRAMESIZE /* get frame size */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 48-bit ethernet address, passed back from ETHER_GETADDR
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned char ebyte[6];
|
||||||
|
} ether_address_t;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* info passed to ETHER_INIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct ether_init_params {
|
||||||
|
short port;
|
||||||
|
short irq;
|
||||||
|
unsigned long mem;
|
||||||
|
} ether_init_params_t;
|
||||||
|
|
||||||
|
#endif /* _ETHER_DRIVER_H */
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#ifndef __HARDWARE_H
|
||||||
|
#define __HARDWARE_H
|
||||||
|
|
||||||
|
#define PCI_PCICMD_IOS 0x01
|
||||||
|
#define PCI_PCICMD_MSE 0x02
|
||||||
|
#define PCI_PCICMD_BME 0x04
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32 stat_len;
|
||||||
|
uint32 vlan;
|
||||||
|
uint32 buf_low;
|
||||||
|
uint32 buf_high;
|
||||||
|
} _PACKED tx_desc;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TX_DESC_OWN = 0x80000000,
|
||||||
|
TX_DESC_EOR = 0x40000000,
|
||||||
|
TX_DESC_FS = 0x20000000,
|
||||||
|
TX_DESC_LS = 0x10000000,
|
||||||
|
TX_DESC_LEN_MASK = 0x00007fff,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32 stat_len;
|
||||||
|
uint32 vlan;
|
||||||
|
uint32 buf_low; // must be 8 byte aligned
|
||||||
|
uint32 buf_high;
|
||||||
|
} _PACKED rx_desc;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
RX_DESC_OWN = 0x80000000,
|
||||||
|
RX_DESC_EOR = 0x40000000,
|
||||||
|
RX_DESC_FS = 0x20000000,
|
||||||
|
RX_DESC_LS = 0x10000000,
|
||||||
|
RX_DESC_MAR = 0x08000000,
|
||||||
|
RX_DESC_PAM = 0x04000000,
|
||||||
|
RX_DESC_BAR = 0x02000000,
|
||||||
|
RX_DESC_BOVF = 0x01000000,
|
||||||
|
RX_DESC_FOVF = 0x00800000,
|
||||||
|
RX_DESC_RWT = 0x00400000,
|
||||||
|
RX_DESC_RES = 0x00200000,
|
||||||
|
RX_DESC_RUNT = 0x00100000,
|
||||||
|
RX_DESC_CRC = 0x00080000,
|
||||||
|
RX_DESC_LEN_MASK = 0x00007fff,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
REG_TNPDS_LOW = 0x20,
|
||||||
|
REG_TNPDS_HIGH = 0x24,
|
||||||
|
REG_THPDS_LOW = 0x28,
|
||||||
|
REG_THPDS_HIGH = 0x2c,
|
||||||
|
REG_RDSAR_LOW = 0xe4,
|
||||||
|
REG_RDSAR_HIGH = 0xe8,
|
||||||
|
|
||||||
|
REG_CR = 0x37,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
REG_CR_RST = 0x10,
|
||||||
|
REG_CR_RE = 0x08,
|
||||||
|
REG_CR_TE = 0x04,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
#include <Errors.h>
|
||||||
|
#include <OS.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
uint32 round_to_pagesize(uint32 size);
|
||||||
|
|
||||||
|
uint32 round_to_pagesize(uint32 size)
|
||||||
|
{
|
||||||
|
return (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
area_id
|
||||||
|
alloc_mem(void **virt, void **phy, size_t size, uint32 protection, const char *name)
|
||||||
|
{
|
||||||
|
physical_entry pe;
|
||||||
|
void * virtadr;
|
||||||
|
area_id areaid;
|
||||||
|
status_t rv;
|
||||||
|
|
||||||
|
LOG("allocating %ld bytes for %s\n", size, name);
|
||||||
|
|
||||||
|
size = round_to_pagesize(size);
|
||||||
|
areaid = create_area(name, &virtadr, B_ANY_KERNEL_ADDRESS, size, B_FULL_LOCK | B_CONTIGUOUS, protection);
|
||||||
|
if (areaid < B_OK) {
|
||||||
|
LOG("couldn't allocate area %s\n", name);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
rv = get_memory_map(virtadr, size, &pe, 1);
|
||||||
|
if (rv < B_OK) {
|
||||||
|
delete_area(areaid);
|
||||||
|
LOG("couldn't map %s\n", name);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
memset(virtadr, 0, size);
|
||||||
|
if (virt)
|
||||||
|
*virt = virtadr;
|
||||||
|
if (phy)
|
||||||
|
*phy = pe.address;
|
||||||
|
LOG("area = %ld, size = %ld, virt = %p, phy = %p\n", areaid, size, virtadr, pe.address);
|
||||||
|
return areaid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is not the most advanced method to map physical memory for io access.
|
||||||
|
* Perhaps using B_ANY_KERNEL_ADDRESS instead of B_ANY_KERNEL_BLOCK_ADDRESS
|
||||||
|
* makes the whole offset calculation and relocation obsolete. But the code
|
||||||
|
* below does work, and I can't test if using B_ANY_KERNEL_ADDRESS also works.
|
||||||
|
*/
|
||||||
|
area_id
|
||||||
|
map_mem(void **virt, void *phy, size_t size, uint32 protection, const char *name)
|
||||||
|
{
|
||||||
|
uint32 offset;
|
||||||
|
void *phyadr;
|
||||||
|
void *mapadr;
|
||||||
|
area_id area;
|
||||||
|
|
||||||
|
LOG("mapping physical address %p with %ld bytes for %s\n", phy, size, name);
|
||||||
|
|
||||||
|
offset = (uint32)phy & (B_PAGE_SIZE - 1);
|
||||||
|
phyadr = (char *)phy - offset;
|
||||||
|
size = round_to_pagesize(size + offset);
|
||||||
|
area = map_physical_memory(name, phyadr, size, B_ANY_KERNEL_BLOCK_ADDRESS, protection, &mapadr);
|
||||||
|
if (area < B_OK) {
|
||||||
|
LOG("mapping failed, error 0x%x (%s)\n", area, strerror(area));
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
|
||||||
|
*virt = (char *)mapadr + offset;
|
||||||
|
|
||||||
|
LOG("physical = %p, virtual = %p, offset = %ld, phyadr = %p, mapadr = %p, size = %ld, area = 0x%08lx\n",
|
||||||
|
phy, *virt, offset, phyadr, mapadr, size, area);
|
||||||
|
|
||||||
|
return area;
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef __UTIL_H
|
||||||
|
#define __UTIL_H
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
area_id alloc_mem(void **virt, void **phy, size_t size, uint32 protection, const char *name);
|
||||||
|
area_id map_mem(void **virt, void *phy, size_t size, uint32 protection, const char *name);
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user