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
This commit is contained in:
parent
21482d71c1
commit
6ba61f712f
304
src/add-ons/kernel/drivers/network/ipro1000/device.c
Normal file
304
src/add-ons/kernel/drivers/network/ipro1000/device.c
Normal file
@ -0,0 +1,304 @@
|
||||
/* Intel PRO/1000 Family Driver
|
||||
* Copyright (C) 2004 Marcus Overhagen <marcus@overhagen.de>. All rights reserved.
|
||||
*/
|
||||
#include <KernelExport.h>
|
||||
#include <Errors.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
//#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;
|
||||
}
|
37
src/add-ons/kernel/drivers/network/ipro1000/device.h
Normal file
37
src/add-ons/kernel/drivers/network/ipro1000/device.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* Intel PRO/1000 Family Driver
|
||||
* Copyright (C) 2004 Marcus Overhagen <marcus@overhagen.de>. All rights reserved.
|
||||
*/
|
||||
#ifndef __DEVICE_H
|
||||
#define __DEVICE_H
|
||||
|
||||
#include <PCI.h>
|
||||
#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
|
Loading…
Reference in New Issue
Block a user