From e11301109a9a149bcff8932489cda15903602cf9 Mon Sep 17 00:00:00 2001 From: beveloper Date: Mon, 3 May 2004 19:17:53 +0000 Subject: [PATCH] A BeOS driver for the VIA Rhine chipset, written by Richard Houle. Released under the BSD license. =========================================== From: "Richard Houle" Subject: RE: License question regarding beos via rhine driver. Date: Thu, 1 Apr 2004 08:48:02 -0500 Whoa. You talking about very old stuff. I don't even know if I kept a copy of that source code... If you have a copy of it, then you can do what you want. I don't have any objections or restrictions. For the license question, the driver was directly inspired by the FreeBSD driver's source code. Therefore, It's a BSD License. Richard Houle =========================================== git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7378 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/network/via-rhine/cmd.c | 56 ++ .../kernel/drivers/network/via-rhine/entry.c | 142 +++++ .../kernel/drivers/network/via-rhine/hook.c | 510 ++++++++++++++++++ .../kernel/drivers/network/via-rhine/mdio.c | 65 +++ .../kernel/drivers/network/via-rhine/pci.c | 144 +++++ .../kernel/drivers/network/via-rhine/res.c | 51 ++ .../kernel/drivers/network/via-rhine/ring.c | 92 ++++ .../kernel/drivers/network/via-rhine/util.c | 129 +++++ .../drivers/network/via-rhine/via-rhine.h | 313 +++++++++++ 9 files changed, 1502 insertions(+) create mode 100644 src/add-ons/kernel/drivers/network/via-rhine/cmd.c create mode 100644 src/add-ons/kernel/drivers/network/via-rhine/entry.c create mode 100644 src/add-ons/kernel/drivers/network/via-rhine/hook.c create mode 100644 src/add-ons/kernel/drivers/network/via-rhine/mdio.c create mode 100644 src/add-ons/kernel/drivers/network/via-rhine/pci.c create mode 100644 src/add-ons/kernel/drivers/network/via-rhine/res.c create mode 100644 src/add-ons/kernel/drivers/network/via-rhine/ring.c create mode 100644 src/add-ons/kernel/drivers/network/via-rhine/util.c create mode 100644 src/add-ons/kernel/drivers/network/via-rhine/via-rhine.h diff --git a/src/add-ons/kernel/drivers/network/via-rhine/cmd.c b/src/add-ons/kernel/drivers/network/via-rhine/cmd.c new file mode 100644 index 0000000000..ae5dab30bf --- /dev/null +++ b/src/add-ons/kernel/drivers/network/via-rhine/cmd.c @@ -0,0 +1,56 @@ +/* + * VIA VT86C100A Rhine-II and VIA VT3043 Rhine Based Card Driver + * for the BeOS Release 5 + */ + +/* + * Standard Libraries + */ +#include +#include +#include +#include + +/* + * Driver-Related Libraries + */ +#include +#include +#include +#include +#include + +/* + * VIA Rhine Libraries + */ +#include "via-rhine.h" + +/* + * VIA Rhine Commands + */ +void cmd_reset(viarhine_private *device) +{ + write16(device->addr + ChipCmd, CmdReset); + +#ifdef __VIARHINE_DEBUG__ + debug_printf("cmd_reset\n"); +#endif +} + +void cmd_getmacaddr(viarhine_private *device) +{ + int i; + + for (i = 0; i < 6; i++) + device->macaddr.ebyte[i] = read8(device->addr + StationAddr + i); + +#ifdef __VIARHINE_DEBUG__ + debug_printf("cmd_getmacaddr (%02x:%02x:%02x:%02x:%02x:%02x)\n", + (unsigned char)device->macaddr.ebyte[0], + (unsigned char)device->macaddr.ebyte[1], + (unsigned char)device->macaddr.ebyte[2], + (unsigned char)device->macaddr.ebyte[3], + (unsigned char)device->macaddr.ebyte[4], + (unsigned char)device->macaddr.ebyte[5]); +#endif +} diff --git a/src/add-ons/kernel/drivers/network/via-rhine/entry.c b/src/add-ons/kernel/drivers/network/via-rhine/entry.c new file mode 100644 index 0000000000..a8a86beeea --- /dev/null +++ b/src/add-ons/kernel/drivers/network/via-rhine/entry.c @@ -0,0 +1,142 @@ +/* + * VIA VT86C100A Rhine-II and VIA VT3043 Rhine Based Card Driver + * for the BeOS Release 5 + */ + +/* + * Standard Libraries + */ +#include +#include +#include +#include + +/* + * Driver-Related Libraries + */ +#include +#include +#include +#include +#include + +/* + * VIA Rhine Libraries + */ +#include "via-rhine.h" + +/* + * Standard Driver Entry Functions + */ +__declspec(dllexport) status_t init_driver (void); +__declspec(dllexport) void uninit_driver (void); +__declspec(dllexport) const char **publish_devices(void); +__declspec(dllexport) device_hooks *find_device (const char *name); + +char *pDevNameList[MAX_CARDS+1]; +pci_info *pDevList [MAX_CARDS+1]; +pci_module_info *pModuleInfo; + +const char **publish_devices(void) +{ +#ifdef __VIARHINE_DEBUG__ + debug_printf("publish_devices\n"); +#endif + return (const char **)pDevNameList; +} + +status_t init_hardware(void ) +{ +#ifdef __VIARHINE_DEBUG__ + debug_printf("init_hardware\n"); +#endif + return B_NO_ERROR; +} + +status_t init_driver() +{ + status_t status; + int32 entries; + char devName[64]; + int32 i; + +#ifdef __VIARHINE_DEBUG__ + debug_printf("init_driver\n"); +#endif + + if ((status = get_module(B_PCI_MODULE_NAME, (module_info **)&pModuleInfo)) != B_OK) + { +#ifdef __VIARHINE_DEBUG__ + debug_printf(DevName ": init_driver: get_module failed! (%s)\n", strerror(status)); +#endif + return status; + } + + // Find VIA Rhine Cards + if ((entries = pci_getlist(pDevList, MAX_CARDS)) == 0) + { +#ifdef __VIARHINE_DEBUG__ + debug_printf(DevName ": init_driver: Device(s) Not Found\n"); +#endif + pci_freelist(pDevList); + put_module (B_PCI_MODULE_NAME); + return B_ERROR; + } + + // Create Device Name List + for (i = 0; i < entries; i++) + { + sprintf(devName, "%s%ld", DevDir, i ); + pDevNameList[i] = (char*)malloc(strlen(devName) + 1); + strcpy(pDevNameList[i], devName); + } + + pDevNameList[i] = NULL; + return B_OK; +} + +void uninit_driver(void) +{ + int32 i; + void *item; + +#ifdef __VIARHINE_DEBUG__ + debug_printf("uninit_driver\n"); +#endif + + // Free Device Name List + for (i = 0; (item = pDevNameList[i]); i++) + free(item); + + // Free Device List + pci_freelist(pDevList); + put_module (B_PCI_MODULE_NAME); +} + +device_hooks *find_device(const char *name) +{ + int32 i; + char *item; + + if (name == NULL) + return NULL; + + // Find Device Name + for (i = 0; (item = pDevNameList[i]); i++) + { + if (strcmp(name, item) == 0) + { +#ifdef __VIARHINE_DEBUG__ + debug_printf("find_device: Device Found (%s)\n", name); +#endif + return &pDeviceHooks; + } + } + +#ifdef __VIARHINE_DEBUG__ + debug_printf("find_device: Device (%s) Not Found\n", name); +#endif + return NULL; +} + +int32 api_version = B_CUR_DRIVER_API_VERSION; diff --git a/src/add-ons/kernel/drivers/network/via-rhine/hook.c b/src/add-ons/kernel/drivers/network/via-rhine/hook.c new file mode 100644 index 0000000000..d07cad762d --- /dev/null +++ b/src/add-ons/kernel/drivers/network/via-rhine/hook.c @@ -0,0 +1,510 @@ +/* + * VIA VT86C100A Rhine-II and VIA VT3043 Rhine Based Card Driver + * for the BeOS Release 5 + */ + +/* + * Standard Libraries + */ +#include +#include +#include +#include + +/* + * Driver-Related Libraries + */ +#include +#include +#include +#include +#include + +/* + * VIA Rhine Libraries + */ +#include "via-rhine.h" + +int32 nOpenMask = 0; + +int32 hook_interrupt(void *_device) +{ + viarhine_private *device = (viarhine_private*)_device; + int32 handled = B_UNHANDLED_INTERRUPT; + int16 worklimit = 20; + uint16 reg; + uint32 i, j; + int wakeup_reader = 0; + int wakeup_writer = 0; + + do + { + reg = read16(device->addr + IntrStatus); + + // Acknowledge All of the Current Interrupt Sources ASAP. + write16(device->addr + IntrStatus, reg & 0xffff); + + if (reg == 0) + break; + + if (reg & IntrRxDone) + { + wakeup_reader++; + write16(device->addr, CmdRxDemand | device->cmd); + handled = B_HANDLED_INTERRUPT; + continue; + } + if (reg & IntrTxDone) + { + wakeup_writer++; + handled = B_HANDLED_INTERRUPT; + continue; + } + + if (reg & (IntrRxErr | IntrRxDropped | IntrRxWakeUp | IntrRxEmpty | IntrRxNoBuf)) + { + write16(device->addr, CmdRxDemand | device->cmd); + handled = B_HANDLED_INTERRUPT; + continue; + } + if (reg & IntrTxAbort) + { + /* Just restart Tx. */ + write16(device->addr, CmdTxDemand | device->cmd); + handled = B_HANDLED_INTERRUPT; + continue; + } + if (reg & IntrTxUnderrun) + { + if (device->tx_thresh < 0xE0) + write8(device->addr + TxConfig, device->tx_thresh += 0x20); + write16(device->addr, CmdTxDemand | device->cmd); + handled = B_HANDLED_INTERRUPT; + continue; + } +/* if (reg & IntrTxDone) + { + if (device->tx > 0) + device->tx--; + + if (device->tx > 0) + write16(device->addr, CmdTxDemand | device->cmd); + } +*/ + if (--worklimit < 0) + break; + } while (true); + + if (wakeup_reader) + { + for (i = 0, j = 0; i < RX_BUFFERS; i++) + { + if (!(device->rx_desc[i].rx_status & DescOwn)) + { + j++; + } + } + + device->cur_rx = j; + input_unwait(device, 1); + } + + if (wakeup_writer) + { + output_unwait(device, 1); + } + + return handled; +} + +status_t hook_open(const char *name, uint32 flags, void **cookie) +{ + char *devName; + int i; + int32 devID; + int32 mask; + area_id cookieID; + status_t status; + uint32 size; + viarhine_private *device; + + // Find Device Name + for (devID = 0; (devName = pDevNameList[devID]); devID++) + { + if (strcmp(name, devName) == 0) + break; + } + + if (!devName) + return EINVAL; + + // Check if the Device is Busy and Set in-use Flag if Not + mask = 1 << devID; + if (atomic_or(&nOpenMask, mask) & mask) + return B_BUSY; + + // Allocate Storage for the Cookie + size = RNDUP(sizeof(viarhine_private), B_PAGE_SIZE); + cookieID = create_area( DevName " cookie", + cookie, + B_ANY_KERNEL_ADDRESS, + size, + B_FULL_LOCK, + B_READ_AREA | B_WRITE_AREA); + + if (cookieID < 0) + { + status = B_NO_MEMORY; + goto Err0; + } + + device = (viarhine_private*)(*cookie); + memset(device, 0, sizeof(viarhine_private)); + + // Setup the Cookie + device->cookieID = cookieID; + device->devID = devID; + device->pciInfo = pDevList[devID]; + device->addr = device->pciInfo->u.h0.base_registers[0]; + + if ((status = res_allocate(device)) != B_OK) + goto Err1; + + cmd_reset(device); + snooze(2000); + cmd_getmacaddr(device); + + // Initialize MII Chip + if (cap_tbl[device->devID].flags & CanHaveMII) + { + int phy, + phy_idx = 0; + + device->mii_phys[0] = 1; // Standard for this chip. + for (phy = 1; (phy < 32) && (phy_idx < 4); phy++) + { + int mii_status = mdio_read(device, phy, 1); + + if ((mii_status != 0xffff) && (mii_status != 0x0000)) + { + device->mii_phys[phy_idx++] = phy; + device->mii_advertising = mdio_read(device, phy, 4); + } + } + + device->mii_cnt = phy_idx; + } + + // Allocate and Initialize Frame Buffer Rings & Descriptors + if (ring_init(device) != B_OK) + goto Err2; + + for (i = 0; i < 6; i++) + write8(device->addr + StationAddr + i, device->macaddr.ebyte[i]); + + write32(device->addr + TxRingPtr, mem_virt2phys(&device->tx_desc[0], sizeof(device->tx_desc[0]))); + write32(device->addr + RxRingPtr, mem_virt2phys(&device->rx_desc[0], sizeof(device->rx_desc[0]))); + + // Initialize Other Registers. + write16(device->addr + PCIBusConfig, 0x0006); + + // Configure the FIFO Thresholds. + device->tx_thresh = 0x20; + device->rx_thresh = 0x60; /* Written in device_rx_setmode(). */ + + write8(device->addr + TxConfig, 0x20); + rx_setmode(device); + + // Setup Interrupt Handler + install_io_interrupt_handler(device->pciInfo->u.h0.interrupt_line, hook_interrupt, *cookie, 0); + + // Enable interrupts by setting the interrupt mask. + write16(device->addr + IntrEnable, + IntrRxDone | IntrRxErr | IntrRxEmpty | IntrRxOverflow | + IntrTxDone | IntrTxAbort | IntrTxUnderrun | IntrRxDropped | + IntrPCIErr | IntrStatsMax | IntrLinkChange | IntrMIIChange); + + device->cmd = CmdStart | CmdTxOn | CmdRxOn | /*CmdNoTxPoll |*/ CmdRxDemand; + + if (device->duplex_lock) + device->cmd |= CmdFDuplex; + + write16(device->addr + ChipCmd, device->cmd); + + duplex_check(device); + +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_open success!\n"); +#endif + return B_NO_ERROR; + +Err2: + ring_free(device); + +Err1: + res_free(device); + delete_area(device->cookieID); + +Err0: + atomic_and(&nOpenMask, ~mask); +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_open failed!\n"); +#endif + return status; +} + +status_t hook_close(void *_data) +{ + viarhine_private *device = (viarhine_private*)_data; + + device->interrupted = 1; + input_unwait(device, 1); + output_unwait(device, 1); + + res_free(device); + +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_close\n"); +#endif + return B_NO_ERROR; +} + +status_t hook_free(void *_data) +{ + viarhine_private *device = (viarhine_private*)_data; + + // Remove Interrupt Handler + remove_io_interrupt_handler(device->pciInfo->u.h0.interrupt_line, hook_interrupt, _data); + write16(device->addr + ChipCmd, CmdStop); + + ring_free(device); + + // Device is Now Available Again + atomic_and(&nOpenMask, ~(1 << device->devID)); + + delete_area(device->cookieID); + +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_free\n"); +#endif + return B_NO_ERROR; +} + +status_t hook_ioctl(void *_data, uint32 msg, void *buf, size_t len) +{ + viarhine_private *device = (viarhine_private*)_data; + + switch (msg) + { + case ETHER_GETADDR: + if (_data == NULL) + return B_ERROR; + + memcpy(buf, &device->macaddr, 6); +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_control: getaddr\n"); +#endif + return B_NO_ERROR; + + case ETHER_INIT: +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_control: init\n"); +#endif + return B_NO_ERROR; + + case ETHER_GETFRAMESIZE: +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_control: getframesize (%u)\n", MAX_FRAME_SIZE); +#endif + *(uint32*)buf = MAX_FRAME_SIZE; + return B_NO_ERROR; + + case ETHER_SETPROMISC: +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_control: setpromiscuous\n"); +#endif + break; + + case ETHER_NONBLOCK: +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_control: nonblock\n"); +#endif + + if (device == NULL) + return B_ERROR; + + memcpy(&device->nonblocking, buf, sizeof(device->nonblocking)); + return B_NO_ERROR; + + case ETHER_ADDMULTI: +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_control: add multicast\n"); +#endif + break; + + default: +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_control: unknown msg %x\n", msg); +#endif + break; + } + + return B_ERROR; +} + +status_t hook_read(void *_data, off_t pos, void *buf, size_t *len) +{ + viarhine_private *device = (viarhine_private*)_data; + ulong buflen; + int packet_len = 0; + unsigned int entry; + char *addr; + uint32 data_size; + uint32 desc_status; + + buflen = *len; + atomic_add(&device->inrw, 1); + +ReturnInLoop: + write16(device->addr, CmdRxDemand | device->cmd); + while ((device->cur_rx == 0) && (!device->nonblocking)) + { + input_wait(device); + + if (device->interrupted) + { + *len = 0; + return B_INTERRUPTED; + } + } + + if (device->cur_rx != 0) + { + device->cur_rx--; + } + else if (device->nonblocking) + { + *len = 0; + atomic_add(&device->inrw, 1); + return 0; + } + + entry = 0; + while (device->rx_desc[entry].rx_status & DescOwn) + { + entry++; + entry %= RX_BUFFERS; + } + + desc_status = device->rx_desc[entry].rx_status; + data_size = (desc_status >> 16) - 4; + + if (buflen < data_size) + { + data_size = buflen; + } + + addr = &device->rx_buf[entry * BUFFER_SIZE]; + + if (!is_mine(device, addr)) + { + device->rx_desc[entry].desc_length = 1536; + device->rx_desc[entry].rx_status = DescOwn; + goto ReturnInLoop; + } + +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_read: received (%u)(%u) (%02x:%02x:%02x:%02x:%02x:%02x)\n", + data_size, + device->cur_rx, + (unsigned char)addr[0], + (unsigned char)addr[1], + (unsigned char)addr[2], + (unsigned char)addr[3], + (unsigned char)addr[4], + (unsigned char)addr[5]); +#endif + + *len = data_size; + memcpy(buf, addr, data_size); + + device->rx_desc[entry].desc_length = MAX_FRAME_SIZE; + device->rx_desc[entry].rx_status = DescOwn; + + atomic_add(&device->inrw, -1); + return B_OK; +} + +status_t hook_write(void *_data, off_t pos, const void *buf, size_t *len) +{ + viarhine_private *device = (viarhine_private*)_data; + ulong buflen; + status_t status; + unsigned int entry; + unsigned int i, j; + void *addr; + + buflen = *len; + atomic_add(&device->inrw, 1); + + do + { + if (device->interrupted) + { + atomic_add(&device->inrw, -1); + return B_INTERRUPTED; + } + + status = output_wait(device, ETHER_TRANSMIT_TIMEOUT); + if (status < B_NO_ERROR) + { + atomic_add(&device->inrw, -1); + return status; + } + + } while (device->tx_desc[device->cur_tx].tx_status & DescOwn); + + entry = device->cur_tx; + device->cur_tx++; + device->cur_tx %= TX_BUFFERS; + + device->tx_desc[entry].tx_status = DescOwn; + addr = &device->tx_buf[entry * BUFFER_SIZE]; + memcpy(addr, buf, buflen); + + if (buflen < 60) + { + buflen = 60; + } + + if (buflen & 3) + { + buflen &= (~3); + buflen += 4; + } + + device->tx_desc[entry].desc_length = 0x00E08000 | buflen; + write16(device->addr + ChipCmd, CmdTxDemand | device->cmd); + +#ifdef __VIARHINE_DEBUG__ + debug_printf("hook_write: sent (%u)(%u)\n", buflen, device->cur_tx); +#endif + + atomic_add(&device->inrw, -1); + *len = buflen; + return B_OK; +} + +device_hooks pDeviceHooks = +{ + hook_open, // open entry point + hook_close, // close entry point + hook_free, // free entry point + hook_ioctl, // ioctl entry point + hook_read, // read entry point + hook_write, // write entry point + NULL, // select entry point + NULL, // deselect entry point + NULL, // readv entry point + NULL // writev entry point +}; diff --git a/src/add-ons/kernel/drivers/network/via-rhine/mdio.c b/src/add-ons/kernel/drivers/network/via-rhine/mdio.c new file mode 100644 index 0000000000..62b7d2a62f --- /dev/null +++ b/src/add-ons/kernel/drivers/network/via-rhine/mdio.c @@ -0,0 +1,65 @@ +/* + * VIA VT86C100A Rhine-II and VIA VT3043 Rhine Based Card Driver + * for the BeOS Release 5 + */ + +/* + * Standard Libraries + */ +#include +#include +#include +#include +#include + +/* + * Driver-Related Libraries + */ +#include +#include +#include +#include +#include + +/* + * VIA Rhine Libraries + */ +#include "via-rhine.h" + +int mdio_read(viarhine_private *device, int phy_id, int regnum) +{ + int boguscnt = 1024; + + /* Wait for a previous command to complete. */ + while ((read8(device->addr + MIICmd) & 0x60) && --boguscnt > 0) + ; + + write8(device->addr + MIICmd, 0x00); + write8(device->addr + MIIPhyAddr, phy_id); + write8(device->addr + MIIRegAddr, regnum); + write8(device->addr + MIICmd, 0x40); /* Trigger Read */ + + boguscnt = 1024; + while ((read8(device->addr + MIICmd) & 0x40) && --boguscnt > 0) + ; + + return read16(device->addr + MIIData); +} + +void mdio_write(viarhine_private *device, int phy_id, int regnum, int value) +{ + int boguscnt = 1024; + + if ((phy_id == device->mii_phys[0]) && (regnum == 4)) + device->mii_advertising = value; + + /* Wait for a previous command to complete. */ + while ((read8(device->addr + MIICmd) & 0x60) && --boguscnt > 0) + ; + + write8(device->addr + MIICmd, 0x00); + write8(device->addr + MIIPhyAddr, phy_id); + write8(device->addr + MIIRegAddr, regnum); + write8(device->addr + MIIData, value); + write8(device->addr + MIICmd, 0x20); /* Trigger Write. */ +} diff --git a/src/add-ons/kernel/drivers/network/via-rhine/pci.c b/src/add-ons/kernel/drivers/network/via-rhine/pci.c new file mode 100644 index 0000000000..67283616b7 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/via-rhine/pci.c @@ -0,0 +1,144 @@ +/* + * VIA VT86C100A Rhine-II and VIA VT3043 Rhine Based Card Driver By Richard Houle + * for the BeOS Release 5 + */ + +/* + * Standard Libraries + */ +#include +#include +#include +#include +#include + +/* + * Driver-Related Libraries + */ +#include +#include +#include +#include +#include + +/* + * VIA Rhine Libraries + */ +#include "via-rhine.h" + +/* + * PCI Information Table (VT6102/VT6103/VT6105/VT6105M added by Karina Goddard, March 04, VT6103 and VT6105 seem to work, but buggy) + */ +struct viarhine_pci_id_info pci_tbl[] = +{ + {"VIA VT86C100A Rhine-II", 0x1106, 0x6100, 0xffff, PCI_command_io | PCI_command_master, 128}, + {"VIA VT3042 Rhine", 0x1106, 0x3043, 0xffff, PCI_command_io | PCI_command_master, 128}, + {"VIA VT6102 Rhine-II/VT6103 Tahoe 10/100M Fast Ethernet Adapter", 0x1106, 0x3065, 0xffff, PCI_command_io | PCI_command_master, 256}, + {"VIA VT6105 Rhine-III Management Adapter", 0x1106, 0x3106, 0xffff, PCI_command_io | PCI_command_master, 256}, + {"VIA VT6105M Rhine-III Management Adapter", 0x1106, 0x3053, 0xffff, PCI_command_io | PCI_command_master, 256}, + +{0} + +}; + +/* + * Chip Information Table + */ +struct viarhine_chip_info cap_tbl[] = +{ + {128, CanHaveMII}, + {128, CanHaveMII} +}; + +/* + * VIA Rhine PCI Functions + */ +int32 pci_getlist(pci_info *info[], int32 maxEntries) +{ + status_t status; + int32 i, j; + int32 entries; + pci_info *item; + + item = (pci_info*)malloc(sizeof(pci_info)); + + for (i = 0, entries = 0; entries < maxEntries; i++) + { + if ((status = pModuleInfo->get_nth_pci_info(i, item)) != B_OK) + break; + + j = 0; + while (pci_tbl[j].name != NULL) + { + if ((pci_tbl[j].vendor_id == item->vendor_id) && + (pci_tbl[j].device_id == item->device_id)) + { + // Check if the Device Really has an IRQ + if ((item->u.h0.interrupt_line == 0) || + (item->u.h0.interrupt_line == 0xFF)) + { +#ifdef __VIARHINE_DEBUG__ + debug_printf("pci_getlist: Found with Invalid IRQ - Check IRQ Assignement\n"); +#endif + goto next_entry; + } + +#ifdef __VIARHINE_DEBUG__ + debug_printf("pci_getlist: Found at IRQ %u\n", item->u.h0.interrupt_line); +#endif + + pModuleInfo->write_pci_config( + item->bus, + item->device, + item->function, + PCI_command, + 2, + pci_tbl[j].flags | pModuleInfo->read_pci_config( + item->bus, + item->device, + item->function, + PCI_command, + 2)); + + if (pci_tbl[j].flags & PCI_command_master) + { + if (item->latency < MIN_PCI_LATENCY) + { +#ifdef __VIARHINE_DEBUG__ + debug_printf("pci_getlist: latency too slow\n"); +#endif + pModuleInfo->write_pci_config( + item->bus, + item->device, + item->function, + PCI_latency, + 1, + MIN_PCI_LATENCY); + } + } + + info[entries++] = item; + item = (pci_info *)malloc(sizeof(pci_info)); + goto next_entry; + } + + j++; + } +next_entry: + } + + info[entries] = NULL; + free(item); + return entries; +} + +status_t pci_freelist(pci_info *info[]) +{ + int32 i; + pci_info *item; + + for (i = 0; (item = info[i]); i++) + free(item); + + return B_OK; +} diff --git a/src/add-ons/kernel/drivers/network/via-rhine/res.c b/src/add-ons/kernel/drivers/network/via-rhine/res.c new file mode 100644 index 0000000000..9881711099 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/via-rhine/res.c @@ -0,0 +1,51 @@ +/* + * VIA VT86C100A Rhine-II and VIA VT3043 Rhine Based Card Driver + * for the BeOS Release 5 + */ + +/* + * Standard Libraries + */ +#include +#include +#include +#include +#include + +/* + * Driver-Related Libraries + */ +#include +#include +#include +#include +#include + +/* + * VIA Rhine Libraries + */ +#include "via-rhine.h" + +status_t res_allocate(viarhine_private *device) +{ +#ifdef __VIARHINE_DEBUG__ + debug_printf("device_allocate_resources\n"); +#endif + + device->olock = create_sem(1, "via-rhine output"); + set_sem_owner(device->olock, B_SYSTEM_TEAM); + device->ilock = create_sem(0, "via-rhine input"); + set_sem_owner(device->ilock, B_SYSTEM_TEAM); + + return B_OK; +} + +void res_free(viarhine_private *device) +{ +#ifdef __VIARHINE_DEBUG__ + debug_printf("device_free_resources\n"); +#endif + + delete_sem(device->olock); + delete_sem(device->ilock); +} diff --git a/src/add-ons/kernel/drivers/network/via-rhine/ring.c b/src/add-ons/kernel/drivers/network/via-rhine/ring.c new file mode 100644 index 0000000000..7a9d804cae --- /dev/null +++ b/src/add-ons/kernel/drivers/network/via-rhine/ring.c @@ -0,0 +1,92 @@ +/* + * VIA VT86C100A Rhine-II and VIA VT3043 Rhine Based Card Driver + * for the BeOS Release 5 + */ + +/* + * Standard Libraries + */ +#include +#include +#include +#include +#include + +/* + * Driver-Related Libraries + */ +#include +#include +#include +#include +#include + +/* + * VIA Rhine Libraries + */ +#include "via-rhine.h" + +status_t ring_init(viarhine_private *device) +{ + uint32 size; + uint16 i; + + // Create Transmit Buffer Area + size = RNDUP(BUFFER_SIZE * TX_BUFFERS, B_PAGE_SIZE); + if ((device->tx_buf_area = create_area( DevName " tx buffers", + (void **)&device->tx_buf, + B_ANY_KERNEL_ADDRESS, + size, + B_FULL_LOCK, + B_READ_AREA | B_WRITE_AREA)) < 0) + { +#ifdef __VIARHINE_DEBUG__ + debug_printf(DevName ": Create TX Buffer Area Failed %x\n", device->tx_buf_area); +#endif + return device->tx_buf_area; + } + + // Initialize TX Buffer Descriptors + for ( i = 0; i < TX_BUFFERS; i++) + { + device->tx_desc[i].tx_status = 0; + device->tx_desc[i].desc_length = 0; + device->tx_desc[i].addr = mem_virt2phys(&device->tx_buf[i * BUFFER_SIZE], BUFFER_SIZE); + device->tx_desc[i].next = mem_virt2phys(&device->tx_desc[i + 1], sizeof(device->tx_desc[0])); + } + device->tx_desc[i - 1].next = mem_virt2phys(&device->tx_desc[0], sizeof(device->tx_desc[0])); + + // Create RX Buffer Area + size = RNDUP(BUFFER_SIZE * RX_BUFFERS, B_PAGE_SIZE); + if ((device->rx_buf_area = create_area( DevName " rx buffers", + (void **)&device->rx_buf, + B_ANY_KERNEL_ADDRESS, + size, + B_FULL_LOCK, + B_READ_AREA | B_WRITE_AREA)) < 0) + { +#ifdef __VIARHINE_DEBUG__ + debug_printf(DevName ": Create RX Buffer Area Failed %x\n", device->rx_buf_area); +#endif + delete_area(device->tx_buf_area); + return device->rx_buf_area; + } + + // Initialize RX Buffer Descriptors + for ( i = 0; i < RX_BUFFERS; i++) + { + device->rx_desc[i].rx_status = DescOwn; + device->rx_desc[i].desc_length = MAX_FRAME_SIZE; + device->rx_desc[i].addr = mem_virt2phys(&device->rx_buf[i * BUFFER_SIZE], BUFFER_SIZE); + device->rx_desc[i].next = mem_virt2phys(&device->rx_desc[i + 1], sizeof(device->rx_desc[0])); + } + device->rx_desc[i - 1].next = mem_virt2phys(&device->rx_desc[0], sizeof(device->tx_desc[0])); + + return B_OK; +} + +void ring_free(viarhine_private *device) +{ + delete_area(device->tx_buf_area); + delete_area(device->rx_buf_area); +} diff --git a/src/add-ons/kernel/drivers/network/via-rhine/util.c b/src/add-ons/kernel/drivers/network/via-rhine/util.c new file mode 100644 index 0000000000..a7e3ad0814 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/via-rhine/util.c @@ -0,0 +1,129 @@ +/* + * VIA VT86C100A Rhine-II and VIA VT3043 Rhine Based Card Driver + * for the BeOS Release 5 + */ + +/* + * Standard Libraries + */ +#include +#include +#include +#include +#include + +/* + * Driver-Related Libraries + */ +#include +#include +#include +#include +#include + +/* + * VIA Rhine Libraries + */ +#include "via-rhine.h" + +uint32 mem_virt2phys(void *addr, unsigned int length) +{ + physical_entry tbl; + + get_memory_map(addr, length, &tbl, 1); + return (uint32)tbl.address; +} + +void rx_setmode(viarhine_private *device) +{ + uint8 rx_mode; // Note: 0x02 = Accept Runt, 0x01 = Accept Errors + +#if defined(__VIARHINE_PROMISCUOUS___) + { + rx_mode = 0x1C; + } +#elif defined(__VIARHINE_ALLOW_MULTICAST__) + { + uint32 nMCFilter[2]; /* Multicast Hash Filter */ + int i; + + memset(nMCFilter, 0, sizeof(nMCFilter); + for (i = 0; i < device->nMulti; i++) + { +#error TODO: Code Multicast Filter + } + } + + rx_mode = 0x0C; +#else + + write32(device->addr + MulticastFilter0, 0); + write32(device->addr + MulticastFilter1, 0); + rx_mode = 0x1A; +#endif + + write8(device->addr + RxConfig, device->rx_thresh | rx_mode); +} + +void duplex_check(viarhine_private *device) +{ + int mii_reg5; + int negotiated; + int duplex; + + mii_reg5 = mdio_read(device, device->mii_phys[0], 5); + negotiated = mii_reg5 & device->mii_advertising; + + if (device->duplex_lock || mii_reg5 == 0xffff) + return; + + duplex = (negotiated & 0x0100) || (negotiated & 0x01C0) == 0x0040; + if (device->duplex_full != duplex) + { + device->duplex_full = duplex; + + if (duplex) + device->cmd |= CmdFDuplex; + else + device->cmd &= ~CmdFDuplex; + + write16(device->addr + ChipCmd, device->cmd); + } +} + +bool is_mine(viarhine_private *device, char *addr) +{ + static char broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + + if (memcmp(&device->macaddr, addr, 6) == 0) + { + return true; + } + + if (memcmp(broadcast, addr, 6) == 0) + { + return true; + } + + return false; +} + +#ifdef __VIARHINE_DEBUG__ +int debug_printf(char *format, ...) +{ + va_list vl; + char c[2048]; + int i; + static int f = 0; + + va_start(vl, format); + i = vsprintf(c, format, vl); + va_end(vl); + + if (f == 0) + f = open("/boot/via-rhine.log", O_WRONLY | O_APPEND | O_TEXT); + + write(f, c, strlen(c)); + return i; +} +#endif diff --git a/src/add-ons/kernel/drivers/network/via-rhine/via-rhine.h b/src/add-ons/kernel/drivers/network/via-rhine/via-rhine.h new file mode 100644 index 0000000000..5208267858 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/via-rhine/via-rhine.h @@ -0,0 +1,313 @@ + +/* + * I/O Ctls: Belongs in a Public Header File + */ +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 */ +}; + +/* + * Driver Informations + */ +#define DevName "via-rhine" +#define DevDir "net/" DevName "/" +#define DEVNAME_LENGTH 64 +#define MAX_CARDS 4 + +#define TX_BUFFERS 8 +#define RX_BUFFERS 16 + +#define BUFFER_SIZE 2048L /* Enough to hold a 1536 Frame */ +#define MAX_FRAME_SIZE 1536 /* 1536 */ +#define MAX_MULTI 32 /* Hardware Related, Do not change */ + +#define TRANSMIT_TIMEOUT ((bigtime_t)10000) /* 1/100 Second */ +#define ETHER_TRANSMIT_TIMEOUT ((bigtime_t)1000000) /* One Second */ + +#define MIN_PCI_LATENCY 64 + +/* + * PCI Communications + */ +#define IO_PORT_PCI_ACCESS true +//#define MEMORY_MAPPED_PCI_ACCESS true + +#if IO_PORT_PCI_ACCESS +#define write8(address, value) (*pModuleInfo->write_io_8)((address), (value)) +#define write16(address, value) (*pModuleInfo->write_io_16)((address), (value)) +#define write32(address, value) (*pModuleInfo->write_io_32)((address), (value)) +#define read8(address) ((*pModuleInfo->read_io_8)(address)) +#define read16(address) ((*pModuleInfo->read_io_16)(address)) +#define read32(address) ((*pModuleInfo->read_io_32)(address)) +#else /* MEMORY_MAPPED_PCI_ACCESS */ +#define read8(address) (*((volatile uint8*)(address))); __eieio() +#define read16(address) (*((volatile uint16*)(address))); __eieio() +#define read32(address) (*((volatile uint32*)(address))); __eieio() +#define write8(address, data) (*((volatile uint8 *)(address)) = data); __eieio() +#define write16(address, data) (*((volatile uint16 *)(address)) = (data)); __eieio() +#define write32(address, data) (*((volatile uint32 *)(address)) = (data)); __eieio() +#endif + +/* + * Registers Offsets + */ +enum viarhine_register_offsets +{ + StationAddr = 0x00, + RxConfig = 0x06, + TxConfig = 0x07, + ChipCmd = 0x08, + IntrStatus = 0x0C, + IntrEnable = 0x0E, + MulticastFilter0 = 0x10, + MulticastFilter1 = 0x14, + RxRingPtr = 0x18, + TxRingPtr = 0x1C, + MIIPhyAddr = 0x6C, + MIIStatus = 0x6D, + PCIBusConfig = 0x6E, + MIICmd = 0x70, + MIIRegAddr = 0x71, + MIIData = 0x72, + Config = 0x78, + RxMissed = 0x7C, + RxCRCErrs = 0x7E, +}; + +/* + * Command Bits + */ +enum viarhine_chip_cmd_bits +{ + CmdInit = 0x0001, + CmdStart = 0x0002, + CmdStop = 0x0004, + CmdRxOn = 0x0008, + CmdTxOn = 0x0010, + CmdTxDemand = 0x0020, + CmdRxDemand = 0x0040, + CmdEarlyRx = 0x0100, + CmdEarlyTx = 0x0200, + CmdFDuplex = 0x0400, + CmdNoTxPoll = 0x0800, + CmdReset = 0x8000 +}; + +/* + * Interrupt Status Bits + */ +enum viarhine_intr_status_bits +{ + IntrRxDone = 0x0001, + IntrRxErr = 0x0004, + IntrRxEmpty = 0x0020, + IntrTxDone = 0x0002, + IntrTxAbort = 0x0008, + IntrTxUnderrun = 0x0010, + IntrPCIErr = 0x0040, + IntrStatsMax = 0x0080, + IntrRxEarly = 0x0100, + IntrMIIChange = 0x0200, + IntrRxOverflow = 0x0400, + IntrRxDropped = 0x0800, + IntrRxNoBuf = 0x1000, + IntrTxAborted = 0x2000, + IntrLinkChange = 0x4000, + IntrRxWakeUp = 0x8000, + IntrNormalSummary = 0x0003, + IntrAbnormalSummary = 0xC260, +}; + +/* + * RX Status Bits + */ +enum viarhine_rx_status_bits +{ + RxOK = 0x8000, + RxWholePkt = 0x0300, + RxErr = 0x008F +}; + +/* + * Desc Status Bits + */ +enum viarhine_desc_status_bits +{ + DescOwn = 0x80000000, + DescEndPacket = 0x4000, + DescIntr = 0x1000 +}; + +/* + * PCI ID Information + */ +struct viarhine_pci_id_info +{ + const char *name; + uint16 vendor_id, + device_id, + device_id_mask, + flags; + int io_size; +}; + +/* + * Chip Compatibility + */ +enum viarhine_chip_capability_flags +{ + CanHaveMII = 1 +}; + +/* + * Chip Information + */ +struct viarhine_chip_info +{ + int io_size; + int flags; +}; + +/* + * RX Descriptor + */ +typedef struct +{ + uint32 rx_status; + uint32 desc_length; + + uint32 addr; + uint32 next; +} viarhine_rx_desc; + +/* + * TX Descriptor + */ +typedef struct +{ + uint32 tx_status; + uint32 desc_length; + + uint32 addr; + uint32 next; +} viarhine_tx_desc; + +typedef struct +{ + unsigned char ebyte[6]; +} ethernet_addr; + +/* + * Private Data + */ +typedef struct +{ + /* + * Rings + */ + viarhine_tx_desc tx_desc[TX_BUFFERS]; /* TX Frame Descriptor */ + viarhine_rx_desc rx_desc[RX_BUFFERS]; /* RX Frame Descriptor */ + area_id tx_buf_area; /* Transmit Descriptor and Buffer Areas */ + area_id rx_buf_area; /* Receive Descriptor and Buffer Areas */ + uchar *tx_buf; /* TX Buffer */ + uchar *rx_buf; /* RX Buffer */ + + area_id cookieID; /* Cookie Area ID */ + int32 devID; /* Device ID */ + uint32 addr; /* Base Address of HostRegs */ + pci_info *pciInfo; /* PCI Informations */ + ethernet_addr macaddr; /* Ethernet Address */ + + uint8 tx_thresh; + uint8 rx_thresh; + uint16 cmd; + uint8 interrupted; + + unsigned char duplex_full; /* Full-Duplex Operation Requested. */ + unsigned char duplex_lock; + + uint8 cur_tx; + uint8 cur_rx; + int32 inrw; /* In Read or Write Function */ + int nonblocking; + + /* + * Semaphores + */ + sem_id ilock; + sem_id olock; + + /* + * MII Transceiver Section + */ + int mii_cnt; /* MII Device Addresses. */ + uint16 mii_advertising; /* NWay Media Advertisement */ + unsigned char mii_phys[8]; /* MII Device Addresses. */ + +} viarhine_private; + +/* + * Semaphores Macros + */ +/* output_wait wakes up when the card is ready to transmit another packet */ +#define output_wait(data, t) acquire_sem_etc(data->olock, 1, B_TIMEOUT, t) +#define output_unwait(data, c) release_sem_etc(data->olock, c, B_DO_NOT_RESCHEDULE) + +/* input_wait wakes up when the card has at least one packet on it */ +#define input_wait(data) acquire_sem_etc(data->ilock ,1, B_CAN_INTERRUPT, 0) +#define input_unwait(data, c) release_sem_etc(data->ilock, c, B_DO_NOT_RESCHEDULE) + +/* + * Variables + */ +extern char *pDevNameList[MAX_CARDS+1]; +extern pci_info *pDevList [MAX_CARDS+1]; +extern pci_module_info *pModuleInfo; +extern device_hooks pDeviceHooks; +extern int32 nOpenMask; + +extern struct viarhine_pci_id_info pci_tbl[]; +extern struct viarhine_chip_info cap_tbl[]; + +/* + * Functions + */ + +// pci.c +int32 pci_getlist (pci_info *info[], int32 maxEntries); +status_t pci_freelist(pci_info *info[]); + +// res.c +status_t res_allocate(viarhine_private *device); +void res_free (viarhine_private *device); + +// misc.c +uint32 mem_virt2phys(void *addr, unsigned int length); +void rx_setmode (viarhine_private *device); +void duplex_check (viarhine_private *device); +bool is_mine (viarhine_private *device, char *addr); + +// ring.c +status_t ring_init(viarhine_private *device); +void ring_free(viarhine_private *device); + +// cmd.c +void cmd_reset (viarhine_private *device); +void cmd_getmacaddr(viarhine_private *device); + +/* + * Macro + */ +#define RNDUP(x, y) (((x) + (y) - 1) & ~((y) - 1)) +//#define __VIARHINE_DEBUG__ + +#ifdef __VIARHINE_DEBUG__ +int debug_printf(char *format, ...); +#endif