From 6ba61f712faade383a111b7d974908756444ff03 Mon Sep 17 00:00:00 2001 From: beveloper Date: Mon, 3 May 2004 23:21:39 +0000 Subject: [PATCH] The device driver interface to the network stack, either BeOS R5, BONE, or OpenBeOS. Initialized attaches and detaches the core driver, sends and receives packets git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7395 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../kernel/drivers/network/ipro1000/device.c | 304 ++++++++++++++++++ .../kernel/drivers/network/ipro1000/device.h | 37 +++ 2 files changed, 341 insertions(+) create mode 100644 src/add-ons/kernel/drivers/network/ipro1000/device.c create mode 100644 src/add-ons/kernel/drivers/network/ipro1000/device.h diff --git a/src/add-ons/kernel/drivers/network/ipro1000/device.c b/src/add-ons/kernel/drivers/network/ipro1000/device.c new file mode 100644 index 0000000000..dc49c2afe9 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/ipro1000/device.c @@ -0,0 +1,304 @@ +/* Intel PRO/1000 Family Driver + * Copyright (C) 2004 Marcus Overhagen . All rights reserved. + */ +#include +#include +#include +#include +#include +#include + +//#define DEBUG + +#include "debug.h" +#include "device.h" +#include "driver.h" +#include "util.h" +#include "if_em.h" +#include "if_compat.h" + +#undef malloc +#undef free + +static int32 gOpenMask = 0; + +int em_attach(device_t); +int em_detach(device_t); + +status_t +ipro1000_open(const char *name, uint32 flags, void** cookie) +{ + ipro1000_device *device; + char *deviceName; + uint32 val; + int dev_id; + int mask; + int i; + + TRACE("ipro1000_open()\n"); + + for (dev_id = 0; (deviceName = gDevNameList[dev_id]) != NULL; dev_id++) { + if (!strcmp(name, deviceName)) + break; + } + if (deviceName == NULL) { + ERROR("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 = (ipro1000_device *)malloc(sizeof(ipro1000_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->nonblocking = (flags & O_NONBLOCK) ? true : false; + device->closed = false; + + device->pciBus = device->pciInfo->bus; + device->pciDev = device->pciInfo->device; + device->pciFunc = device->pciInfo->function; + device->adapter = 0; + + if (em_attach(device) != 0) { + TRACE("em_attach failed\n"); + goto err; + } + + return B_OK; + +err: + free(device); + atomic_and(&gOpenMask, ~(1 << dev_id)); + return B_ERROR; +} + + +status_t +ipro1000_close(void* cookie) +{ + ipro1000_device *device = (ipro1000_device *)cookie; + struct ifnet *ifp = &device->adapter->interface_data.ac_if; + TRACE("ipro1000_close()\n"); + + device->closed = true; + release_sem(ifp->if_rcv_sem); +// release_sem(device->txFreeSem); + + return B_OK; +} + + +status_t +ipro1000_free(void* cookie) +{ + ipro1000_device *device = (ipro1000_device *)cookie; + TRACE("ipro1000_free()\n"); + + if (em_detach(device) != 0) { + TRACE("em_detach failed\n"); + } + + free(device); + atomic_and(&gOpenMask, ~(1 << device->devId)); + return B_OK; +} + + +status_t +ipro1000_read(void* cookie, off_t position, void *buf, size_t* num_bytes) +{ + ipro1000_device *device = (ipro1000_device *)cookie; + struct ifnet *ifp = &device->adapter->interface_data.ac_if; + struct mbuf *mb; + status_t stat; + int len; + +// TRACE("ipro1000_read() enter\n"); + + if (device->closed) { + TRACE("ipro1000_read() interrupted 1\n"); + return B_INTERRUPTED; + } +retry: + stat = acquire_sem_etc(ifp->if_rcv_sem, 1, B_CAN_INTERRUPT | (device->nonblocking ? B_TIMEOUT : 0), 0); + if (device->closed) { + // TRACE("ipro1000_read() interrupted 2\n"); // net_server will crash if we print this (race condition in net_server?) + return B_INTERRUPTED; + } + if (stat == B_WOULD_BLOCK) { + TRACE("ipro1000_read() would block (OK 0 bytes)\n"); + *num_bytes = 0; + return B_OK; + } + if (stat != B_OK) { + TRACE("ipro1000_read() error\n"); + return B_ERROR; + } + + IF_DEQUEUE(&ifp->if_rcv, mb); + if (!mb) { + ERROR("ipro1000_read() mbuf not ready\n"); + goto retry; + } + + len = mb->m_len; + if (len < 0) + len = 0; + if (len > *num_bytes) + len = *num_bytes; + + memcpy(buf, mtod(mb, uint8 *), len); // XXX this is broken for jumbo frames + *num_bytes = len; + + m_freem(mb); + +// TRACE("ipro1000_read() leave, %d bytes\n", len); + return B_OK; +} + + +status_t +ipro1000_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes) +{ +// bigtime_t t = system_time(); + ipro1000_device *device = (ipro1000_device *)cookie; + struct ifnet *ifp = &device->adapter->interface_data.ac_if; + struct mbuf *mb; + +// TRACE("ipro1000_write() enter\n"); + + // allocate mbuf + for (;;) { + MGETHDR(mb, M_DONTWAIT, MT_DATA); + if (mb) + break; + snooze(700); + if (device->closed) + return B_INTERRUPTED; + } + +// TRACE("ipro1000_write() 1\n"); + + // allocate memory + for (;;) { + MCLGET(mb, M_DONTWAIT); + if (mb->m_flags & M_EXT) + break; + snooze(700); + if (device->closed) { + m_freem(mb); + return B_INTERRUPTED; + } + } + +// TRACE("ipro1000_write() 2\n"); + + // copy data + mb->m_len = *num_bytes; + if (mb->m_len > MCLBYTES) + mb->m_len = MCLBYTES; + memcpy(mtod(mb, uint8 *), buffer, mb->m_len); + +// TRACE("ipro1000_write() 3\n"); + + // add mbuf to send queue + IF_APPEND(&ifp->if_snd, mb); + +// TRACE("ipro1000_write() 4\n"); + + // wait for output available + while (ifp->if_flags & IFF_OACTIVE) { + snooze(700); + if (device->closed) + return B_INTERRUPTED; + } + +// TRACE("ipro1000_write() 5\n"); + + // send everything (if still required) + if (ifp->if_snd.ifq_head != NULL) + ifp->if_start(ifp); + +// while (ifp->if_snd.ifq_head != NULL) { +// ifp->if_start(ifp); +// if (ifp->if_snd.ifq_head != NULL) { +// snooze(1000); +// if (device->closed) +// return B_INTERRUPTED; +// } +// } + +// t = system_time() - t; + +// if (t > 20) +// TRACE("write %Ld\n", t); + +// TRACE("ipro1000_write() finished\n"); + + return B_OK; +} + + +status_t +ipro1000_control(void *cookie, uint32 op, void *arg, size_t len) +{ + ipro1000_device *device = (ipro1000_device *)cookie; + + switch (op) { + case ETHER_INIT: + TRACE("ipro1000_control() ETHER_INIT\n"); + return B_OK; + + case ETHER_GETADDR: + TRACE("ipro1000_control() ETHER_GETADDR\n"); + memcpy(arg, &device->macaddr, sizeof(device->macaddr)); + return B_OK; + + case ETHER_NONBLOCK: + if (*(int32 *)arg) { + TRACE("non blocking mode on\n"); + device->nonblocking = true; + } else { + TRACE("non blocking mode off\n"); + device->nonblocking = false; + } + return B_OK; + + case ETHER_ADDMULTI: + TRACE("ipro1000_control() ETHER_ADDMULTI not supported\n"); + break; + + case ETHER_REMMULTI: + TRACE("ipro1000_control() ETHER_REMMULTI not supported\n"); + return B_OK; + + case ETHER_SETPROMISC: + if (*(int32 *)arg) { + TRACE("promiscuous mode on not supported\n"); + } else { + TRACE("promiscuous mode off\n"); + } + return B_OK; + + case ETHER_GETFRAMESIZE: + TRACE("ipro1000_control() ETHER_GETFRAMESIZE\n"); + *(uint32*)arg = MAXIMUM_ETHERNET_FRAME_SIZE; + return B_OK; + + default: + TRACE("ipro1000_control() Invalid command\n"); + break; + } + + return B_ERROR; +} diff --git a/src/add-ons/kernel/drivers/network/ipro1000/device.h b/src/add-ons/kernel/drivers/network/ipro1000/device.h new file mode 100644 index 0000000000..335ff0ad12 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/ipro1000/device.h @@ -0,0 +1,37 @@ +/* Intel PRO/1000 Family Driver + * Copyright (C) 2004 Marcus Overhagen . All rights reserved. + */ +#ifndef __DEVICE_H +#define __DEVICE_H + +#include +#include "setup.h" + +extern pci_module_info *gPci; + +status_t ipro1000_open(const char *name, uint32 flags, void** cookie); +status_t ipro1000_read(void* cookie, off_t position, void *buf, size_t* num_bytes); +status_t ipro1000_write(void* cookie, off_t position, const void* buffer, size_t* num_bytes); +status_t ipro1000_control(void *cookie, uint32 op, void *arg, size_t len); +status_t ipro1000_close(void* cookie); +status_t ipro1000_free(void* cookie); + +struct adapter; + +typedef struct device { + int devId; + pci_info * pciInfo; + + struct adapter * adapter; + uint8 pciBus; + uint8 pciDev; + uint8 pciFunc; + void * regAddr; + + volatile bool nonblocking; + volatile bool closed; + + uint8 macaddr[6]; +} ipro1000_device; + +#endif