Completely renovated the FreeBSD compatibility layer:

* Removed NETDEV() and DEVNET() macros and functionality.
* The exported devices are now attached to ifnet objects only, therefore, the
  ifnet object now has the receive queue, and everything else a device could
  need.
* There is now a root device where everything else is attached, it currently
  only holds the pci_info structure, so it's more or less a PCI child.
* This simplified the device handling a bit everywhere.
* We now attach drivers already in init_driver() - this is needed as drivers
  may publish more than one interface when being attached.
* Implemented device_delete_child(), device_attach() (which bus_generic_attach()
  now uses), device_is_attached(), and device_is_alive().
* Therefore, if_initname() does now the actual job of registering the devices.
* On open, if_init() is called which comes pretty close to what our open()
  is supposed to do.
* Updated ukphy.c to the one from FreeBSD 7 where used (we should probably
  move that into the compat layer, anyway).
* The MII driver array must now be NULL terminated; therefore you don't need
  to specify the count anymore.
* Moved PCI code from compat.c to bus.c.
* Moved the driver code from device.c to driver.c.
* Removed superfluous init_compat_layer() function.
* Fixed a few bugs, a few things weren't brought down correctly.
* The rtl8139 interrupt routine now checks if it really was the cause of the
  interrupt - this code is not tested, either, it may not work (which would
  then require a work-around like I did for the 3com driver).
* The HAIKU_PROTECT_INTR_REGISTER in the rtl8139 driver was pretty much useless
  which is why I removed it.
* Probably introduced a lot of new bugs, though - I haven't tested this code
  at all yet. It will probably just crash :-)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@23019 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-11-29 18:56:03 +00:00
parent 423e822abe
commit 080b265acd
19 changed files with 999 additions and 743 deletions

View File

@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/dev/mii/ukphy.c,v 1.17 2005/01/06 01:42:56 imp Exp $");
__FBSDID("$FreeBSD: src/sys/dev/mii/ukphy.c,v 1.20 2007/01/20 00:52:29 marius Exp $");
/*
* driver for generic unknown PHYs
@ -114,34 +114,27 @@ DRIVER_MODULE(ukphy, miibus, ukphy_driver, ukphy_devclass, 0, 0);
static int ukphy_service(struct mii_softc *, struct mii_data *, int);
static int
ukphy_probe(dev)
device_t dev;
ukphy_probe(device_t dev)
{
/*
* We know something is here, so always match at a low priority.
*/
device_set_desc(dev, "Generic IEEE 802.3u media interface");
return (-100);
return (BUS_PROBE_GENERIC);
}
static int
ukphy_attach(dev)
device_t dev;
ukphy_attach(device_t dev)
{
struct mii_softc *sc;
struct mii_attach_args *ma;
struct mii_data *mii;
static int ppp;
if (ppp++ > 0)
panic("oops");
sc = device_get_softc(dev);
ma = device_get_ivars(dev);
sc->mii_dev = device_get_parent(dev);
mii = device_get_softc(sc->mii_dev);
device_printf(dev, "insert into %p\n", mii);
device_printf(sc->mii_dev, "this is the parent\n");
LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
if (bootverbose)
@ -156,8 +149,6 @@ device_printf(sc->mii_dev, "this is the parent\n");
mii->mii_instance++;
sc->mii_flags |= MIIF_NOISOLATE;
mii_phy_reset(sc);
sc->mii_capabilities =
@ -171,14 +162,11 @@ device_printf(sc->mii_dev, "this is the parent\n");
MIIBUS_MEDIAINIT(sc->mii_dev);
mii_phy_setmedia(sc);
return(0);
return (0);
}
static int
ukphy_service(sc, mii, cmd)
struct mii_softc *sc;
struct mii_data *mii;
int cmd;
ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int reg;

View File

@ -23,10 +23,11 @@ __haiku_select_miibus_driver(device_t dev)
driver_t *drivers[] = {
DRIVER_MODULE_NAME(bmtphy, miibus),
DRIVER_MODULE_NAME(xlphy, miibus),
DRIVER_MODULE_NAME(ukphy, miibus)
DRIVER_MODULE_NAME(ukphy, miibus),
NULL
};
return __haiku_probe_miibus(dev, drivers, 3);
return __haiku_probe_miibus(dev, drivers);
}

View File

@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/dev/mii/ukphy.c,v 1.17 2005/01/06 01:42:56 imp Exp $");
__FBSDID("$FreeBSD: src/sys/dev/mii/ukphy.c,v 1.20 2007/01/20 00:52:29 marius Exp $");
/*
* driver for generic unknown PHYs
@ -114,34 +114,27 @@ DRIVER_MODULE(ukphy, miibus, ukphy_driver, ukphy_devclass, 0, 0);
static int ukphy_service(struct mii_softc *, struct mii_data *, int);
static int
ukphy_probe(dev)
device_t dev;
ukphy_probe(device_t dev)
{
/*
* We know something is here, so always match at a low priority.
*/
device_set_desc(dev, "Generic IEEE 802.3u media interface");
return (-100);
return (BUS_PROBE_GENERIC);
}
static int
ukphy_attach(dev)
device_t dev;
ukphy_attach(device_t dev)
{
struct mii_softc *sc;
struct mii_attach_args *ma;
struct mii_data *mii;
static int ppp;
if (ppp++ > 0)
panic("oops");
sc = device_get_softc(dev);
ma = device_get_ivars(dev);
sc->mii_dev = device_get_parent(dev);
mii = device_get_softc(sc->mii_dev);
device_printf(dev, "insert into %p\n", mii);
device_printf(sc->mii_dev, "this is the parent\n");
LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
if (bootverbose)
@ -156,8 +149,6 @@ device_printf(sc->mii_dev, "this is the parent\n");
mii->mii_instance++;
sc->mii_flags |= MIIF_NOISOLATE;
mii_phy_reset(sc);
sc->mii_capabilities =
@ -171,14 +162,11 @@ device_printf(sc->mii_dev, "this is the parent\n");
MIIBUS_MEDIAINIT(sc->mii_dev);
mii_phy_setmedia(sc);
return(0);
return (0);
}
static int
ukphy_service(sc, mii, cmd)
struct mii_softc *sc;
struct mii_data *mii;
int cmd;
ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int reg;

View File

@ -19,10 +19,11 @@ __haiku_select_miibus_driver(device_t dev)
{
driver_t *drivers[] = {
DRIVER_MODULE_NAME(e1000phy, miibus),
DRIVER_MODULE_NAME(ukphy, miibus)
DRIVER_MODULE_NAME(ukphy, miibus),
NULL
};
return __haiku_probe_miibus(dev, drivers, 2);
return __haiku_probe_miibus(dev, drivers);
}
NO_HAIKU_CHECK_DISABLE_INTERRUPTS();

View File

@ -6,21 +6,33 @@ HAIKU_FBSD_DRIVER_GLUE(rtl8139, rl, pci);
HAIKU_FBSD_MII_DRIVER(rlphy);
HAIKU_DRIVER_REQUIREMENTS(0);
int
HAIKU_CHECK_DISABLE_INTERRUPTS(device_t dev) {
HAIKU_CHECK_DISABLE_INTERRUPTS(device_t dev)
{
struct rl_softc *sc = device_get_softc(dev);
uint16_t status;
HAIKU_PROTECT_INTR_REGISTER(CSR_WRITE_2(sc, RL_IMR, 0));
status = CSR_READ_2(sc, RL_ISR);
if (status == 0xffff)
return 0;
if (status != 0 && (status & RL_INTRS) == 0) {
CSR_WRITE_2(sc, RL_ISR, status);
return 0;
}
if ((status & RL_INTRS) == 0)
return 0;
/* we don't read the status register, so we just assume it was for us. */
CSR_WRITE_2(sc, RL_IMR, 0);
return 1;
}
void
HAIKU_REENABLE_INTERRUPTS(device_t dev)
{
struct rl_softc *sc = device_get_softc(dev);
RL_LOCK(sc);
HAIKU_PROTECT_INTR_REGISTER(CSR_WRITE_2(sc, RL_IMR, RL_INTRS));
CSR_WRITE_2(sc, RL_IMR, RL_INTRS);
RL_UNLOCK(sc);
}

View File

@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/dev/mii/ukphy.c,v 1.17 2005/01/06 01:42:56 imp Exp $");
__FBSDID("$FreeBSD: src/sys/dev/mii/ukphy.c,v 1.20 2007/01/20 00:52:29 marius Exp $");
/*
* driver for generic unknown PHYs
@ -114,20 +114,18 @@ DRIVER_MODULE(ukphy, miibus, ukphy_driver, ukphy_devclass, 0, 0);
static int ukphy_service(struct mii_softc *, struct mii_data *, int);
static int
ukphy_probe(dev)
device_t dev;
ukphy_probe(device_t dev)
{
/*
* We know something is here, so always match at a low priority.
*/
device_set_desc(dev, "Generic IEEE 802.3u media interface");
return (-100);
return (BUS_PROBE_GENERIC);
}
static int
ukphy_attach(dev)
device_t dev;
ukphy_attach(device_t dev)
{
struct mii_softc *sc;
struct mii_attach_args *ma;
@ -151,8 +149,6 @@ ukphy_attach(dev)
mii->mii_instance++;
sc->mii_flags |= MIIF_NOISOLATE;
mii_phy_reset(sc);
sc->mii_capabilities =
@ -166,14 +162,11 @@ ukphy_attach(dev)
MIIBUS_MEDIAINIT(sc->mii_dev);
mii_phy_setmedia(sc);
return(0);
return (0);
}
static int
ukphy_service(sc, mii, cmd)
struct mii_softc *sc;
struct mii_data *mii;
int cmd;
ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
{
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int reg;

View File

@ -20,9 +20,10 @@ __haiku_select_miibus_driver(device_t dev)
{
driver_t *drivers[] = {
DRIVER_MODULE_NAME(ciphy, miibus),
DRIVER_MODULE_NAME(ukphy, miibus)
DRIVER_MODULE_NAME(ukphy, miibus),
NULL
};
return __haiku_probe_miibus(dev, drivers, 2);
return __haiku_probe_miibus(dev, drivers);
}

View File

@ -13,6 +13,7 @@ KernelStaticLibrary libfreebsd_network.a :
callout.c
compat.c
device.c
driver.c
fbsd_busdma_x86.c
fbsd_ether.c
fbsd_if_media.c
@ -23,5 +24,6 @@ KernelStaticLibrary libfreebsd_network.a :
mbuf.c
mii.c
mutex.c
pci.c
taskqueue.c
;

View File

@ -11,6 +11,7 @@
#include <arch/cpu.h>
#include <compat/dev/pci/pcireg.h>
#include <compat/dev/pci/pcivar.h>
#include <compat/machine/resource.h>
#include <compat/sys/bus.h>
@ -24,6 +25,14 @@
# define TRACE_BUS_SPACE_RW(x)
#endif
//#define DEBUG_PCI
#ifdef DEBUG_PCI
# define TRACE_PCI(dev, format, args...) device_printf(dev, format , ##args)
#else
# define TRACE_PCI(dev, format, args...) do { } while (0)
#endif
#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
// TODO: x86 specific!
@ -306,7 +315,7 @@ bus_setup_intr(device_t dev, struct resource *res, int flags,
status = install_io_interrupt_handler(intr->irq,
intr_fast_wrapper, intr, 0);
} else {
snprintf(semName, sizeof(semName), "%s intr", dev->dev_name);
snprintf(semName, sizeof(semName), "%s intr", dev->device_name);
intr->sem = create_sem(0, semName);
if (intr->sem < B_OK) {
@ -314,7 +323,7 @@ bus_setup_intr(device_t dev, struct resource *res, int flags,
return B_NO_MEMORY;
}
snprintf(semName, sizeof(semName), "%s intr handler", dev->dev_name);
snprintf(semName, sizeof(semName), "%s intr handler", dev->device_name);
intr->thread = spawn_kernel_thread(intr_handler, semName,
B_REAL_TIME_DISPLAY_PRIORITY, intr);
@ -450,3 +459,184 @@ BUS_SPACE_READ(4, uint32_t, in32)
BUS_SPACE_WRITE(1, uint8_t, out8)
BUS_SPACE_WRITE(2, uint16_t, out16)
BUS_SPACE_WRITE(4, uint32_t, out32)
// #pragma mark - PCI functions
uint32_t
pci_read_config(device_t dev, int offset, int size)
{
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
uint32_t value = gPci->read_pci_config(info->bus, info->device,
info->function, offset, size);
TRACE_PCI(dev, "pci_read_config(%i, %i) = 0x%x\n", offset, size, value);
return value;
}
void
pci_write_config(device_t dev, int offset, uint32_t value, int size)
{
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
TRACE_PCI(dev, "pci_write_config(%i, 0x%x, %i)\n", offset, value, size);
gPci->write_pci_config(info->bus, info->device, info->function, offset,
size, value);
}
uint16_t
pci_get_vendor(device_t dev)
{
return pci_read_config(dev, PCI_vendor_id, 2);
}
uint16_t
pci_get_device(device_t dev)
{
return pci_read_config(dev, PCI_device_id, 2);
}
uint16_t
pci_get_subvendor(device_t dev)
{
return pci_read_config(dev, PCI_subsystem_vendor_id, 2);
}
uint16_t
pci_get_subdevice(device_t dev)
{
return pci_read_config(dev, PCI_subsystem_id, 2);
}
uint8_t
pci_get_revid(device_t dev)
{
return pci_read_config(dev, PCI_revision, 1);
}
static void
pci_set_command_bit(device_t dev, uint16_t bit)
{
uint16_t command = pci_read_config(dev, PCI_command, 2);
pci_write_config(dev, PCI_command, command | bit, 2);
}
int
pci_enable_busmaster(device_t dev)
{
pci_set_command_bit(dev, PCI_command_master);
return 0;
}
int
pci_enable_io(device_t dev, int space)
{
/* adapted from FreeBSD's pci_enable_io_method */
int bit = 0;
switch (space) {
case SYS_RES_IOPORT:
bit = PCI_command_io;
break;
case SYS_RES_MEMORY:
bit = PCI_command_memory;
break;
default:
return EINVAL;
}
pci_set_command_bit(dev, bit);
if (pci_read_config(dev, PCI_command, 2) & bit)
return 0;
device_printf(dev, "pci_enable_io(%d) failed.\n", space);
return ENXIO;
}
int
pci_find_extcap(device_t child, int capability, int *_capabilityRegister)
{
uint8 capabilityPointer;
uint8 headerType;
uint16 status;
status = pci_read_config(child, PCIR_STATUS, 2);
if ((status & PCIM_STATUS_CAPPRESENT) == 0)
return ENXIO;
headerType = pci_read_config(child, PCI_header_type, 1);
switch (headerType & PCIM_HDRTYPE) {
case 0:
case 1:
capabilityPointer = PCIR_CAP_PTR;
break;
case 2:
capabilityPointer = PCIR_CAP_PTR_2;
break;
default:
return ENXIO;
}
capabilityPointer = pci_read_config(child, capabilityPointer, 1);
while (capabilityPointer != 0) {
if (pci_read_config(child, capabilityPointer + PCICAP_ID, 1)
== capability) {
if (_capabilityRegister != NULL)
*_capabilityRegister = capabilityPointer;
return 0;
}
capabilityPointer = pci_read_config(child,
capabilityPointer + PCICAP_NEXTPTR, 1);
}
return ENOENT;
}
int
pci_msi_count(device_t dev)
{
return 0;
}
int
pci_alloc_msi(device_t dev, int *count)
{
return ENODEV;
}
int
pci_release_msi(device_t dev)
{
return ENODEV;
}
int
pci_msix_count(device_t dev)
{
return 0;
}
int
pci_alloc_msix(device_t dev, int *count)
{
return ENODEV;
}

View File

@ -14,201 +14,85 @@
#include <image.h>
#include <compat/machine/resource.h>
#include <compat/dev/pci/pcireg.h>
#include <compat/dev/pci/pcivar.h>
#include <compat/dev/mii/mii.h>
#include <compat/sys/bus.h>
#include <compat/dev/mii/miivar.h>
//#define DEBUG_PCI
#ifdef DEBUG_PCI
# define TRACE_PCI(dev, format, args...) device_printf(dev, format , ##args)
#else
# define TRACE_PCI(dev, format, args...) do { } while (0)
#endif
spinlock __haiku_intr_spinlock;
struct net_stack_module_info *gStack;
pci_module_info *gPci;
// #pragma mark - PCI
static struct list sRootDevices;
static int sNextUnit;
uint32_t
pci_read_config(device_t dev, int offset, int size)
// #pragma mark - private functions
static device_t
init_device(device_t device, driver_t *driver)
{
uint32_t value = gPci->read_pci_config(NETDEV(dev)->pci_info.bus,
NETDEV(dev)->pci_info.device, NETDEV(dev)->pci_info.function,
offset, size);
TRACE_PCI(dev, "pci_read_config(%i, %i) = 0x%x\n", offset, size, value);
return value;
list_init_etc(&device->children, offsetof(struct device, link));
device->unit = sNextUnit++;
if (driver != NULL && device_set_driver(device, driver) < 0)
return NULL;
return device;
}
void
pci_write_config(device_t dev, int offset, uint32_t value, int size)
static device_t
new_device(driver_t *driver)
{
TRACE_PCI(dev, "pci_write_config(%i, 0x%x, %i)\n", offset, value, size);
device_t dev = malloc(sizeof(struct device));
if (dev == NULL)
return NULL;
gPci->write_pci_config(NETDEV(dev)->pci_info.bus,
NETDEV(dev)->pci_info.device, NETDEV(dev)->pci_info.function,
offset, size, value);
}
memset(dev, 0, sizeof(struct device));
uint16_t
pci_get_vendor(device_t dev)
{
return pci_read_config(dev, PCI_vendor_id, 2);
}
uint16_t
pci_get_device(device_t dev)
{
return pci_read_config(dev, PCI_device_id, 2);
}
uint16_t
pci_get_subvendor(device_t dev)
{
return pci_read_config(dev, PCI_subsystem_vendor_id, 2);
}
uint16_t
pci_get_subdevice(device_t dev)
{
return pci_read_config(dev, PCI_subsystem_id, 2);
}
uint8_t
pci_get_revid(device_t dev)
{
return pci_read_config(dev, PCI_revision, 1);
}
static void
pci_set_command_bit(device_t dev, uint16_t bit)
{
uint16_t command = pci_read_config(dev, PCI_command, 2);
pci_write_config(dev, PCI_command, command | bit, 2);
}
int
pci_enable_busmaster(device_t dev)
{
pci_set_command_bit(dev, PCI_command_master);
return 0;
}
int
pci_enable_io(device_t dev, int space)
{
/* adapted from FreeBSD's pci_enable_io_method */
int bit = 0;
switch (space) {
case SYS_RES_IOPORT:
bit = PCI_command_io;
break;
case SYS_RES_MEMORY:
bit = PCI_command_memory;
break;
default:
return EINVAL;
if (init_device(dev, driver) == NULL) {
free(dev);
return NULL;
}
pci_set_command_bit(dev, bit);
if (pci_read_config(dev, PCI_command, 2) & bit)
return 0;
device_printf(dev, "pci_enable_io(%d) failed.\n", space);
return ENXIO;
return dev;
}
int
pci_find_extcap(device_t child, int capability, int *_capabilityRegister)
static image_id
find_own_image()
{
uint8 capabilityPointer;
uint8 headerType;
uint16 status;
status = pci_read_config(child, PCIR_STATUS, 2);
if ((status & PCIM_STATUS_CAPPRESENT) == 0)
return ENXIO;
headerType = pci_read_config(child, PCI_header_type, 1);
switch (headerType & PCIM_HDRTYPE) {
case 0:
case 1:
capabilityPointer = PCIR_CAP_PTR;
break;
case 2:
capabilityPointer = PCIR_CAP_PTR_2;
break;
default:
return ENXIO;
}
capabilityPointer = pci_read_config(child, capabilityPointer, 1);
while (capabilityPointer != 0) {
if (pci_read_config(child, capabilityPointer + PCICAP_ID, 1)
== capability) {
if (_capabilityRegister != NULL)
*_capabilityRegister = capabilityPointer;
return 0;
int32 cookie = 0;
image_info info;
while (get_next_image_info(B_SYSTEM_TEAM, &cookie, &info) == B_OK) {
if (((uint32)info.text <= (uint32)find_own_image
&& (uint32)info.text + (uint32)info.text_size
> (uint32)find_own_image)) {
// found our own image
return info.id;
}
capabilityPointer = pci_read_config(child,
capabilityPointer + PCICAP_NEXTPTR, 1);
}
return ENOENT;
return B_ENTRY_NOT_FOUND;
}
int
pci_msi_count(device_t dev)
static device_method_signature_t
resolve_method(driver_t *driver, const char *name)
{
return 0;
}
device_method_signature_t method = NULL;
int i;
for (i = 0; method == NULL && driver->methods[i].name != NULL; i++) {
if (strcmp(driver->methods[i].name, name) == 0)
method = driver->methods[i].method;
}
int
pci_alloc_msi(device_t dev, int *count)
{
return ENODEV;
}
int
pci_release_msi(device_t dev)
{
return ENODEV;
}
int
pci_msix_count(device_t dev)
{
return 0;
}
int
pci_alloc_msix(device_t dev, int *count)
{
return ENODEV;
return method;
}
@ -251,7 +135,7 @@ device_printf(device_t dev, const char *format, ...)
va_list vl;
va_start(vl, format);
driver_vprintf_etc(dev->dev_name, format, vl);
driver_vprintf_etc(dev->device_name, format, vl);
va_end(vl);
return 0;
}
@ -300,22 +184,13 @@ device_get_ivars(device_t dev)
}
void
device_sprintf_name(device_t dev, const char *format, ...)
{
va_list vl;
va_start(vl, format);
vsnprintf(dev->dev_name, sizeof(dev->dev_name), format, vl);
va_end(vl);
}
const char *
device_get_name(device_t dev)
{
if (dev)
return dev->dev_name;
return NULL;
if (dev == NULL)
return NULL;
return dev->device_name;
}
@ -340,18 +215,6 @@ device_get_softc(device_t dev)
}
device_t
init_device(device_t dev, driver_t *driver)
{
list_init_etc(&dev->children, offsetof(struct device, link));
if (driver != NULL && device_set_driver(dev, driver) < 0)
return NULL;
return dev;
}
int
device_set_driver(device_t dev, driver_t *driver)
{
@ -397,60 +260,14 @@ device_set_driver(device_t dev, driver_t *driver)
int
device_is_alive(device_t dev)
device_is_alive(device_t device)
{
return dev->driver != NULL;
}
void
uninit_device(device_t dev)
{
if (dev->flags & DEVICE_DESC_ALLOCED)
free((char *)dev->description);
if (dev->softc)
free(dev->softc);
}
static device_t
new_device(driver_t *driver)
{
device_t dev = malloc(sizeof(struct device));
if (dev == NULL)
return NULL;
memset(dev, 0, sizeof(struct device));
if (init_device(dev, driver) == NULL) {
free(dev);
return NULL;
}
return dev;
}
static image_id
find_own_image()
{
int32 cookie = 0;
image_info info;
while (get_next_image_info(B_SYSTEM_TEAM, &cookie, &info) == B_OK) {
if (((uint32)info.text <= (uint32)find_own_image
&& (uint32)info.text + (uint32)info.text_size
> (uint32)find_own_image)) {
// found our own image
return info.id;
}
}
return B_ENTRY_NOT_FOUND;
return (device->flags & DEVICE_ATTACHED) != 0;
}
device_t
device_add_child(device_t dev, const char *name, int order)
device_add_child(device_t parent, const char *name, int unit)
{
device_t child = NULL;
@ -462,13 +279,11 @@ device_add_child(device_t dev, const char *name, int order)
driver_t **driver;
char symbol[128];
snprintf(symbol, sizeof(symbol), "__fbsd_%s%s", name, dev->driver->name);
snprintf(symbol, sizeof(symbol), "__fbsd_%s%s", name,
parent->driver->name);
if (get_image_symbol(find_own_image(), symbol, B_SYMBOL_TYPE_DATA,
(void **)&driver) == B_OK)
child = new_device(*driver);
// inherit the device name of our parent
name = dev->dev_name;
}
} else
child = new_device(NULL);
@ -477,37 +292,76 @@ device_add_child(device_t dev, const char *name, int order)
return NULL;
if (name != NULL)
strlcpy(child->dev_name, name, sizeof(child->dev_name));
child->parent = dev;
list_add_item(&dev->children, child);
strlcpy(child->device_name, name, sizeof(child->device_name));
child->parent = parent;
if (parent != NULL) {
list_add_item(&parent->children, child);
child->root = parent->root;
} else {
if (sRootDevices.link.next == NULL)
list_init_etc(&sRootDevices, offsetof(struct device, link));
list_add_item(&sRootDevices, child);
}
return child;
}
driver_t *
__haiku_probe_miibus(device_t dev, driver_t *drivers[], int count)
/*! Delete the child and all of its children. Detach as necessary.
*/
int
device_delete_child(device_t parent, device_t child)
{
driver_t *selected = NULL;
int i, selcost = 0;
if (child == NULL)
return 0;
for (i = 0; i < count; i++) {
device_probe_t *probe = (device_probe_t *)
_resolve_method(drivers[i], "device_probe");
if (probe) {
int result = probe(dev);
// the ukphy driver (fallback for unknown PHYs) return -100 here
if (result >= -100) {
if (selected == NULL || result > selcost) {
selected = drivers[i];
selcost = result;
device_printf(dev, "Found MII: %s\n", selected->name);
}
}
}
if (parent != NULL)
list_remove_item(&parent->children, child);
parent = child;
while ((child = list_remove_head_item(&parent->children)) != NULL) {
device_delete_child(NULL, child);
}
return selected;
if ((atomic_and(&parent->flags, ~DEVICE_ATTACHED) & DEVICE_ATTACHED) != 0
&& parent->methods.detach != NULL) {
int status = parent->methods.detach(parent);
if (status != 0)
return status;
}
if (parent->flags & DEVICE_DESC_ALLOCED)
free((char *)parent->description);
free(parent->softc);
free(parent);
return 0;
}
int
device_is_attached(device_t device)
{
return (device->flags & DEVICE_ATTACHED) != 0;
}
int
device_attach(device_t device)
{
int result;
if (device->driver == NULL)
return B_ERROR;
result = device->methods.attach(device);
if (result == 0)
atomic_or(&device->flags, DEVICE_ATTACHED);
return result;
}
@ -522,15 +376,15 @@ bus_generic_attach(device_t dev)
if (driver == NULL) {
struct mii_attach_args *ma = device_get_ivars(child);
device_printf(dev, "No PHY module found (%x/%x)!\n", ma->mii_id1,
ma->mii_id2);
device_printf(dev, "No PHY module found (%x/%x)!\n",
MII_OUI(ma->mii_id1, ma->mii_id2), MII_MODEL(ma->mii_id2));
} else
device_set_driver(child, driver);
} else if (child->driver == &miibus_driver)
} else if (child->driver != &miibus_driver)
child->methods.probe(child);
if (child->driver != NULL) {
int result = child->methods.attach(child);
int result = device_attach(child);
if (result != 0)
return result;
}
@ -540,25 +394,51 @@ bus_generic_attach(device_t dev)
}
int
device_delete_child(device_t dev, device_t child)
{
UNIMPLEMENTED();
return -1;
}
int
device_is_attached(device_t dev)
{
UNIMPLEMENTED();
return -1;
}
// #pragma mark - Misc, Malloc
device_t
find_root_device(int unit)
{
device_t device = NULL;
while ((device = list_get_next_item(&sRootDevices, device)) != NULL) {
if (device->unit <= unit)
return device;
}
return NULL;
}
driver_t *
__haiku_probe_miibus(device_t dev, driver_t *drivers[])
{
driver_t *selected = NULL;
int i, selectedResult = 0;
if (drivers == NULL)
return NULL;
for (i = 0; drivers[i]; i++) {
device_probe_t *probe = (device_probe_t *)
resolve_method(drivers[i], "device_probe");
if (probe) {
int result = probe(dev);
if (result >= 0) {
if (selected == NULL || result < selectedResult) {
selected = drivers[i];
selectedResult = result;
device_printf(dev, "Found MII: %s\n", selected->name);
}
}
}
}
return selected;
}
int
printf(const char *format, ...)
{
@ -665,10 +545,3 @@ pmap_kextract(vm_offset_t virtualAddress)
return (vm_paddr_t)entry.address;
}
status_t
init_compat_layer()
{
__haiku_intr_spinlock = 0;
return B_OK;
}

View File

@ -186,8 +186,14 @@ struct ifnet {
struct mtx if_addr_mtx; /* mutex to protect address lists */
/* Haiku additions */
struct sockaddr_dl if_lladdr;
struct device *if_dev;
struct sockaddr_dl if_lladdr;
char device_name[128];
struct device *root_device;
struct ifqueue receive_queue;
sem_id receive_sem;
sem_id link_state_sem;
int32 open_count;
int32 flags;
};
typedef void if_init_f_t(void *);

View File

@ -88,6 +88,13 @@ enum intr_type {
#define FILTER_HANDLED B_HANDLED_INTERRUPT
#define FILTER_SCHEDULE_THREAD B_INVOKE_SCHEDULER
/* Note that we reversed the original order, so whenever actual (negative)
numbers are used in a driver, we have to change it. */
#define BUS_PROBE_SPECIFIC 0
#define BUS_PROBE_LOW_PRIORITY 10
#define BUS_PROBE_DEFAULT 20
#define BUS_PROBE_GENERIC 100
int bus_generic_detach(device_t dev);
int bus_generic_suspend(device_t dev);
int bus_generic_resume(device_t dev);
@ -136,6 +143,7 @@ void *device_get_ivars(device_t dev);
device_t device_add_child(device_t dev, const char *name, int unit);
int device_delete_child(device_t dev, device_t child);
int device_is_attached(device_t dev);
int device_attach(device_t dev);
int bus_generic_print_child(device_t dev, device_t child);
void bus_generic_driver_added(device_t dev, driver_t *driver);
int bus_generic_attach(device_t dev);

View File

@ -41,19 +41,16 @@ typedef struct {
size_t softc_size;
} driver_t;
#define BUS_PROBE_LOW_PRIORITY 10
#define BUS_PROBE_DEFAULT 20
#define DRIVER_MODULE_NAME(name, busname) \
__fbsd_##name##busname
__fbsd_ ## name ## _ ## busname
status_t _fbsd_init_hardware(driver_t *);
status_t _fbsd_init_driver(driver_t *);
void _fbsd_uninit_driver(driver_t *);
status_t _fbsd_init_hardware(driver_t *driver);
status_t _fbsd_init_driver(driver_t *driver);
void _fbsd_uninit_driver(driver_t *driver);
extern const char gDriverName[];
extern const char *gDriverName;
driver_t *__haiku_select_miibus_driver(device_t dev);
driver_t *__haiku_probe_miibus(device_t dev, driver_t *drivers[], int count);
driver_t *__haiku_probe_miibus(device_t dev, driver_t *drivers[]);
/* we define the driver methods with HAIKU_FBSD_DRIVER_GLUE to
* force the rest of the stuff to be linked back with the driver.
@ -61,10 +58,10 @@ driver_t *__haiku_probe_miibus(device_t dev, driver_t *drivers[], int count);
* the final binary, gcc 4.x rightfuly doesn't. */
#define HAIKU_FBSD_DRIVER_GLUE(publicname, name, busname) \
extern const char *gDevNameList[]; \
extern const char *gDeviceNameList[]; \
extern device_hooks gDeviceHooks; \
extern driver_t *DRIVER_MODULE_NAME(name, busname); \
const char gDriverName[] = #publicname; \
const char *gDriverName = #publicname; \
int32 api_version = B_CUR_DRIVER_API_VERSION; \
status_t init_hardware() \
{ \
@ -77,14 +74,14 @@ driver_t *__haiku_probe_miibus(device_t dev, driver_t *drivers[], int count);
void uninit_driver() \
{ _fbsd_uninit_driver(DRIVER_MODULE_NAME(name, busname)); } \
const char **publish_devices() \
{ return gDevNameList; } \
{ return gDeviceNameList; } \
device_hooks *find_device(const char *name) \
{ return &gDeviceHooks; }
#define HAIKU_FBSD_RETURN_MII_DRIVER(drivers, count) \
#define HAIKU_FBSD_RETURN_MII_DRIVER(drivers) \
driver_t *__haiku_select_miibus_driver(device_t dev) \
{ \
return __haiku_probe_miibus(dev, drivers, count); \
return __haiku_probe_miibus(dev, drivers); \
}
#define HAIKU_FBSD_MII_DRIVER(name) \
@ -92,13 +89,14 @@ driver_t *__haiku_probe_miibus(device_t dev, driver_t *drivers[], int count);
driver_t *__haiku_select_miibus_driver(device_t dev) \
{ \
driver_t *drivers[] = { \
DRIVER_MODULE_NAME(name, miibus) \
DRIVER_MODULE_NAME(name, miibus), \
NULL \
}; \
return __haiku_probe_miibus(dev, drivers, 1); \
return __haiku_probe_miibus(dev, drivers); \
}
#define NO_HAIKU_FBSD_MII_DRIVER() \
HAIKU_FBSD_RETURN_MII_DRIVER(NULL, 0)
HAIKU_FBSD_RETURN_MII_DRIVER(NULL)
extern spinlock __haiku_intr_spinlock;
extern int __haiku_disable_interrupts(device_t dev);

View File

@ -1,5 +1,6 @@
/*
* Copyright 2007, Hugo Santos. All Rights Reserved.
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved.
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
*
* Distributed under the terms of the MIT License.
@ -20,142 +21,54 @@
#include <compat/net/ethernet.h>
#define MAX_DEVICES 8
struct network_device *gDevices[MAX_DEVICES];
const char *gDevNameList[MAX_DEVICES + 1];
static struct network_device *
allocate_device(driver_t *driver)
{
char semName[64];
struct network_device *dev = malloc(sizeof(struct network_device));
if (dev == NULL)
return NULL;
memset(dev, 0, sizeof(struct device));
if (init_device(DEVNET(dev), driver) == NULL) {
free(dev);
return NULL;
}
snprintf(semName, sizeof(semName), "%s rcv", gDriverName);
dev->receive_sem = create_sem(0, semName);
if (dev->receive_sem < 0) {
uninit_device(DEVNET(dev));
free(dev);
return NULL;
}
dev->link_state_sem = -1;
ifq_init(&dev->receive_queue, semName);
return dev;
}
static void
free_device(struct network_device *dev)
{
delete_sem(dev->receive_sem);
ifq_uninit(&dev->receive_queue);
uninit_device(DEVNET(dev));
free(dev);
}
device_method_signature_t
_resolve_method(driver_t *driver, const char *name)
{
device_method_signature_t method = NULL;
int i;
for (i = 0; method == NULL && driver->methods[i].name != NULL; i++) {
if (strcmp(driver->methods[i].name, name) == 0)
method = driver->methods[i].method;
}
return method;
}
static status_t
compat_open(const char *name, uint32 flags, void **cookie)
{
struct network_device *device;
status_t status;
struct ifnet *ifp;
struct ifreq ifr;
int i;
driver_printf("compat_open(%s, 0x%lx)\n", name, flags);
status = get_module(NET_STACK_MODULE_NAME, (module_info **)&gStack);
if (status < B_OK)
return status;
for (i = 0; gDevNameList[i] != NULL; i++) {
if (strcmp(gDevNameList[i], name) == 0)
for (i = 0; gDeviceNameList[i] != NULL; i++) {
if (strcmp(gDeviceNameList[i], name) == 0)
break;
}
if (gDevNameList[i] == NULL)
if (gDeviceNameList[i] == NULL)
return B_ERROR;
device = gDevices[i];
ifp = gDevices[i];
if_printf(ifp, "compat_open(0x%lx)\n", flags);
if (!atomic_test_and_set(&device->open, 1, 0))
if (!atomic_test_and_set(&ifp->open_count, 1, 0))
return B_BUSY;
/* some drivers expect the softc to be zero'ed out */
memset(device->base.softc, 0, device->base.driver->softc_size);
ifp->if_flags &= ~IFF_UP;
ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
status = DEVNET(device)->methods.attach(DEVNET(device));
if (status != 0)
atomic_and(&device->open, 0);
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_media = IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0);
ifp->if_ioctl(ifp, SIOCSIFMEDIA, (caddr_t)&ifr);
driver_printf(" ... status = 0x%ld\n", status);
ifp->if_flags |= IFF_UP;
ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
if (status == 0) {
struct ifnet *ifp = device->ifp;
struct ifreq ifr;
ifp->if_init(ifp->if_softc);
ifp->if_flags &= ~IFF_UP;
ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_media = IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0);
ifp->if_ioctl(ifp, SIOCSIFMEDIA, (caddr_t)&ifr);
ifp->if_flags |= IFF_UP;
ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
ifp->if_init(ifp->if_softc);
}
*cookie = device;
return status;
*cookie = ifp;
return B_OK;
}
static status_t
compat_close(void *cookie)
{
struct network_device *dev = cookie;
struct ifnet *ifp = cookie;
device_printf(DEVNET(dev), "compat_close()\n");
if_printf(ifp, "compat_close()\n");
atomic_or(&DEVNET(dev)->flags, DEVICE_CLOSED);
/* do we need a memory barrier in read() or is the atomic_or
* (and the implicit 'lock') enough? */
release_sem_etc(dev->receive_sem, 1, B_RELEASE_ALL);
atomic_or(&ifp->flags, DEVICE_CLOSED);
release_sem_etc(ifp->receive_sem, 1, B_RELEASE_ALL);
return B_OK;
}
@ -163,17 +76,13 @@ compat_close(void *cookie)
static status_t
compat_free(void *cookie)
{
struct network_device *dev = cookie;
struct ifnet *ifp = cookie;
device_printf(DEVNET(dev), "compat_free()\n");
if_printf(ifp, "compat_free()\n");
DEVNET(dev)->methods.detach(DEVNET(dev));
/* XXX empty out the send queue */
atomic_and(&dev->open, 0);
put_module(NET_STACK_MODULE_NAME);
/* TODO: empty out the send queue */
atomic_and(&ifp->open_count, 0);
return B_OK;
}
@ -181,24 +90,24 @@ compat_free(void *cookie)
static status_t
compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
{
struct network_device *dev = cookie;
struct ifnet *ifp = cookie;
uint32 semFlags = B_CAN_INTERRUPT;
status_t status;
struct mbuf *mb;
size_t length;
//device_printf(DEVNET(dev), "compat_read(%lld, %p, [%lu])\n", position,
//if_printf(ifp, "compat_read(%lld, %p, [%lu])\n", position,
// buffer, *numBytes);
if (DEVNET(dev)->flags & DEVICE_CLOSED)
if (ifp->flags & DEVICE_CLOSED)
return B_INTERRUPTED;
if (DEVNET(dev)->flags & DEVICE_NON_BLOCK)
if (ifp->flags & DEVICE_NON_BLOCK)
semFlags |= B_RELATIVE_TIMEOUT;
do {
status = acquire_sem_etc(dev->receive_sem, 1, semFlags, 0);
if (DEVNET(dev)->flags & DEVICE_CLOSED)
status = acquire_sem_etc(ifp->receive_sem, 1, semFlags, 0);
if (ifp->flags & DEVICE_CLOSED)
return B_INTERRUPTED;
if (status == B_WOULD_BLOCK) {
@ -207,7 +116,7 @@ compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
} else if (status < B_OK)
return status;
IF_DEQUEUE(&dev->receive_queue, mb);
IF_DEQUEUE(&ifp->receive_queue, mb);
} while (mb == NULL);
length = min_c(max_c((size_t)mb->m_len, 0), *numBytes);
@ -232,10 +141,10 @@ static status_t
compat_write(void *cookie, off_t position, const void *buffer,
size_t *numBytes)
{
struct network_device *dev = cookie;
struct ifnet *ifp = cookie;
struct mbuf *mb;
//device_printf(DEVNET(dev), "compat_write(%lld, %p, [%lu])\n", position,
//if_printf(ifp, "compat_write(%lld, %p, [%lu])\n", position,
// buffer, *numBytes);
mb = m_getcl(0, MT_DATA, M_PKTHDR);
@ -247,17 +156,16 @@ compat_write(void *cookie, off_t position, const void *buffer,
mb->m_len = min_c(*numBytes, (size_t)MCLBYTES);
memcpy(mtod(mb, void *), buffer, mb->m_len);
return dev->ifp->if_output(dev->ifp, mb, NULL, NULL);
return ifp->if_output(ifp, mb, NULL, NULL);
}
static status_t
compat_control(void *cookie, uint32 op, void *arg, size_t length)
{
struct network_device *dev = cookie;
struct ifnet *ifp = dev->ifp;
struct ifnet *ifp = cookie;
//device_printf(DEVNET(dev), "compat_control(op %lu, %p, [%lu])\n", op,
//if_printf(ifp, "compat_control(op %lu, %p, [%lu])\n", op,
// arg, length);
switch (op) {
@ -275,9 +183,9 @@ compat_control(void *cookie, uint32 op, void *arg, size_t length)
if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
return B_BAD_ADDRESS;
if (value)
DEVNET(dev)->flags |= DEVICE_NON_BLOCK;
ifp->flags |= DEVICE_NON_BLOCK;
else
DEVNET(dev)->flags &= ~DEVICE_NON_BLOCK;
ifp->flags &= ~DEVICE_NON_BLOCK;
return B_OK;
}
@ -297,11 +205,12 @@ compat_control(void *cookie, uint32 op, void *arg, size_t length)
case ETHER_GETFRAMESIZE:
{
uint32 frame_size;
uint32 frameSize;
if (length < 4)
return B_BAD_VALUE;
frame_size = dev->ifp->if_mtu + ETHER_HDR_LEN;
return user_memcpy(arg, &frame_size, 4);
frameSize = ifp->if_mtu + ETHER_HDR_LEN;
return user_memcpy(arg, &frameSize, 4);
}
case ETHER_ADDMULTI:
@ -309,7 +218,7 @@ compat_control(void *cookie, uint32 op, void *arg, size_t length)
{
struct sockaddr_dl address;
if (!(ifp->if_flags & IFF_MULTICAST) == 0)
if ((ifp->if_flags & IFF_MULTICAST) == 0)
return EOPNOTSUPP;
memset(&address, 0, sizeof(address));
@ -351,8 +260,8 @@ compat_control(void *cookie, uint32 op, void *arg, size_t length)
}
case ETHER_SET_LINK_STATE_SEM:
if (user_memcpy(&dev->link_state_sem, arg, sizeof(sem_id)) < B_OK) {
dev->link_state_sem = -1;
if (user_memcpy(&ifp->link_state_sem, arg, sizeof(sem_id)) < B_OK) {
ifp->link_state_sem = -1;
return B_BAD_ADDRESS;
}
return B_OK;
@ -371,160 +280,3 @@ device_hooks gDeviceHooks = {
compat_write,
};
status_t
_fbsd_init_hardware(driver_t *driver)
{
struct network_device fakeDevice;
device_probe_t *probe;
int i;
dprintf("%s: init_hardware(%p)\n", gDriverName, driver);
if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
return B_ERROR;
probe = (device_probe_t *)_resolve_method(driver, "device_probe");
if (probe == NULL) {
dprintf("%s: driver has no device_probe method.\n", gDriverName);
return B_ERROR;
}
memset(&fakeDevice, 0, sizeof(struct device));
// Some drivers, like the rtl8139 one require softc to be initialized
// before probe() is called.
// TODO(bga): Check if the fact that whatever initialization that is
// made here is essential as fakeDevice is local to this function and
// ceases to exist after we return.
DEVNET(&fakeDevice)->softc = malloc(driver->softc_size);
if (DEVNET(&fakeDevice)->softc == NULL)
return B_NO_MEMORY;
for (i = 0; gPci->get_nth_pci_info(i, &fakeDevice.pci_info) == B_OK; i++) {
int result;
result = probe(DEVNET(&fakeDevice));
if (result >= 0) {
dprintf("%s, found %s at %d\n", gDriverName,
device_get_desc(DEVNET(&fakeDevice)), i);
if (DEVNET(&fakeDevice)->flags & DEVICE_DESC_ALLOCED)
free((char *)DEVNET(&fakeDevice)->description);
put_module(B_PCI_MODULE_NAME);
// Clean up softc.
free(DEVNET(&fakeDevice)->softc);
return B_OK;
}
}
dprintf("%s: no hardware found.\n", gDriverName);
put_module(B_PCI_MODULE_NAME);
// Clean up softc.
free(DEVNET(&fakeDevice)->softc);
return B_ERROR;
}
status_t
_fbsd_init_driver(driver_t *driver)
{
int i, ncards = 0;
status_t status;
struct network_device *dev;
dprintf("%s: init_driver(%p)\n", gDriverName, driver);
status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPci);
if (status < B_OK) {
driver_printf("Failed to load PCI module.\n");
return status;
}
dev = allocate_device(driver);
if (dev == NULL)
goto err_1;
status = init_compat_layer();
if (status < B_OK)
goto err_2;
status = init_mutexes();
if (status < B_OK)
goto err_3;
if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) {
status = init_taskqueues();
if (status < B_OK)
goto err_4;
}
status = init_mbufs();
if (status < B_OK)
goto err_5;
init_bounce_pages();
for (i = 0; dev != NULL
&& gPci->get_nth_pci_info(i, &dev->pci_info) == B_OK; i++) {
device_t base = DEVNET(dev);
if (base->methods.probe(base) >= 0) {
device_sprintf_name(base, "net/%s/%i", gDriverName, ncards);
dprintf("%s, adding %s @%d -> /dev/%s\n", gDriverName,
device_get_desc(base), i, device_get_name(base));
gDevices[ncards] = dev;
gDevNameList[ncards] = device_get_name(base);
ncards++;
if (ncards < MAX_DEVICES)
dev = allocate_device(driver);
else
dev = NULL;
}
}
if (dev != NULL)
free_device(dev);
dprintf("%s, ... %d cards.\n", gDriverName, ncards);
gDevNameList[ncards + 1] = NULL;
return B_OK;
err_5:
if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
uninit_taskqueues();
err_4:
uninit_mutexes();
err_3:
err_2:
free(dev);
err_1:
put_module(B_PCI_MODULE_NAME);
return status;
}
void
_fbsd_uninit_driver(driver_t *driver)
{
int i;
dprintf("%s: uninit_driver(%p)\n", gDriverName, driver);
for (i = 0; gDevNameList[i] != NULL; i++) {
free_device(gDevices[i]);
}
uninit_bounce_pages();
uninit_mbufs();
if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
uninit_taskqueues();
uninit_mutexes();
put_module(B_PCI_MODULE_NAME);
}

View File

@ -1,14 +1,13 @@
/*
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved.
* Copyright 2007, Hugo Santos. All Rights Reserved.
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
*
* Distributed under the terms of the MIT License.
*
* Authors:
* Hugo Santos, hugosantos@gmail.com
*
* Some of this code is based on previous work by Marcus Overhagen.
*/
#ifndef _DEVICE_H_
#define _DEVICE_H_
#ifndef DEVICE_H
#define DEVICE_H
#include <stdint.h>
#include <stdio.h>
@ -24,22 +23,26 @@
#include <compat/net/if.h>
#include <compat/net/if_var.h>
#define MAX_DEVICES 8
struct ifnet;
struct device {
struct device * parent;
char dev_name[128];
struct device *parent;
struct device *root;
driver_t *driver;
struct list children;
int32 flags;
char device_name[128];
int unit;
char nameunit[64];
const char * description;
void * softc;
void * ivars;
const char *description;
void *softc;
void *ivars;
struct {
int (*probe)(device_t dev);
@ -59,35 +62,27 @@ struct device {
struct list_link link;
};
struct network_device {
struct device base;
pci_info pci_info;
int32 open;
struct ifqueue receive_queue;
sem_id receive_sem;
sem_id link_state_sem;
struct ifnet * ifp;
struct root_device_softc {
struct pci_info pci_info;
};
#define DEVNET(dev) ((device_t)(&(dev)->base))
#define NETDEV(base) ((struct network_device *)(base))
enum {
DEVICE_OPEN = 1 << 0,
DEVICE_CLOSED = 1 << 1,
DEVICE_NON_BLOCK = 1 << 2,
DEVICE_DESC_ALLOCED = 1 << 3,
DEVICE_ATTACHED = 1 << 4
};
extern struct net_stack_module_info *gStack;
extern pci_module_info *gPci;
extern const char *gDeviceNameList[];
extern struct ifnet *gDevices[];
extern int32 gDeviceCount;
static inline void
__unimplemented(const char *method)
{
@ -105,11 +100,11 @@ void uninit_mbufs(void);
status_t init_mutexes(void);
void uninit_mutexes(void);
status_t init_compat_layer(void);
status_t init_taskqueues(void);
void uninit_taskqueues(void);
device_t find_root_device(int unit);
/* busdma_machdep.c */
void init_bounce_pages(void);
void uninit_bounce_pages(void);
@ -121,17 +116,7 @@ void driver_vprintf(const char *format, va_list vl);
void device_sprintf_name(device_t dev, const char *format, ...)
__attribute__ ((format (__printf__, 2, 3)));
device_t init_device(device_t dev, driver_t *driver);
void uninit_device(device_t dev);
device_method_signature_t _resolve_method(driver_t *driver, const char *name);
void ifq_init(struct ifqueue *ifq, const char *name);
void ifq_uninit(struct ifqueue *ifq);
extern struct net_stack_module_info *gStack;
extern pci_module_info *gPci;
extern const char *gDevNameList[];
extern struct network_device *gDevices[];
#endif
#endif /* DEVICE_H */

View File

@ -0,0 +1,224 @@
/*
* Copyright 2007, Hugo Santos. All Rights Reserved.
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved.
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
*
* Distributed under the terms of the MIT License.
*/
/*! Driver functions that adapt the FreeBSD driver to Haiku's driver API.
The actual driver functions are exported by the HAIKU_FBSD_DRIVER_GLUE
macro, and just call the functions here.
*/
#include "device.h"
#include <stdlib.h>
#include <sys/sockio.h>
#include <Drivers.h>
#include <ether_driver.h>
#include <compat/sys/haiku-module.h>
#include <compat/sys/bus.h>
#include <compat/sys/mbuf.h>
#include <compat/net/ethernet.h>
#define TRACE_DRIVER
#ifdef TRACE_DRIVER
# define TRACE(x) dprintf x
#else
# define TRACE(x)
#endif
const char *gDeviceNameList[MAX_DEVICES + 1];
struct ifnet *gDevices[MAX_DEVICES];
int32 gDeviceCount;
static status_t
init_root_device(driver_t *driver, device_t *_root, device_t *_child)
{
device_t child;
device_t root = device_add_child(NULL, NULL, 0);
if (root == NULL)
return B_NO_MEMORY;
root->softc = malloc(sizeof(struct root_device_softc));
if (root->softc == NULL) {
device_delete_child(NULL, root);
return B_NO_MEMORY;
}
child = device_add_child(root, driver->name, 0);
if (child == NULL) {
device_delete_child(NULL, root);
return B_ERROR;
}
if (_root != NULL)
*_root = root;
if (_child != NULL)
*_child = child;
return B_OK;
}
static pci_info *
get_pci_info(struct device *device)
{
return &((struct root_device_softc *)device->softc)->pci_info;
}
// #pragma mark - Haiku Driver API
status_t
_fbsd_init_hardware(driver_t *driver)
{
status_t status = B_ENTRY_NOT_FOUND;
device_t child, root;
pci_info *info;
int i;
if (get_module(B_PCI_MODULE_NAME, (module_info **)&gPci) < B_OK)
return B_ERROR;
if (init_root_device(driver, &root, &child) != B_OK) {
dprintf("%s: creating device failed.\n", gDriverName);
put_module(B_PCI_MODULE_NAME);
return B_ERROR;
}
TRACE(("%s: init_hardware(%p)\n", gDriverName, driver));
if (child->methods.probe == NULL) {
dprintf("%s: driver has no device_probe method.\n", gDriverName);
device_delete_child(NULL, root);
put_module(B_PCI_MODULE_NAME);
return B_ERROR;
}
info = get_pci_info(root);
for (i = 0; gPci->get_nth_pci_info(i, info) == B_OK; i++) {
int result;
result = child->methods.probe(child);
if (result >= 0) {
TRACE(("%s, found %s at %d\n", gDriverName,
device_get_desc(child), i));
status = B_OK;
break;
}
}
if (status < B_OK)
TRACE(("%s: no hardware found.\n", gDriverName));
device_delete_child(NULL, root);
put_module(B_PCI_MODULE_NAME);
return status;
}
status_t
_fbsd_init_driver(driver_t *driver)
{
int i, found = 0;
status_t status;
dprintf("%s: init_driver(%p)\n", gDriverName, driver);
status = get_module(B_PCI_MODULE_NAME, (module_info **)&gPci);
if (status < B_OK)
return status;
status = init_mutexes();
if (status < B_OK)
goto err1;
status = init_mbufs();
if (status < B_OK)
goto err2;
init_bounce_pages();
if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES)) {
status = init_taskqueues();
if (status < B_OK)
goto err3;
}
i = 0;
while (gDeviceCount < MAX_DEVICES) {
device_t root, device;
bool found = false;
pci_info *info;
status = init_root_device(driver, &root, &device);
if (status < B_OK)
break;
info = get_pci_info(root);
for (; gPci->get_nth_pci_info(i, info) == B_OK; i++) {
if (device->methods.probe(device) < 0)
continue;
if (device_attach(device) == 0) {
found = true;
break;
}
}
if (!found) {
device_delete_child(NULL, root);
break;
}
}
if (gDeviceCount > 0) {
TRACE(("%s, ... %d cards.\n", gDriverName, found));
return B_OK;
} else if (status == B_OK)
status = B_ERROR;
if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
uninit_taskqueues();
err3:
uninit_mbufs();
err2:
uninit_mutexes();
err1:
put_module(B_PCI_MODULE_NAME);
return status;
}
void
_fbsd_uninit_driver(driver_t *driver)
{
int i;
TRACE(("%s: uninit_driver(%p)\n", gDriverName, driver));
for (i = 0; gDeviceNameList[i] != NULL; i++) {
device_delete_child(NULL, gDevices[i]->root_device);
}
uninit_bounce_pages();
uninit_mbufs();
if (HAIKU_DRIVER_REQUIRES(FBSD_TASKQUEUES))
uninit_taskqueues();
uninit_mutexes();
put_module(B_PCI_MODULE_NAME);
}

View File

@ -173,8 +173,11 @@ miibus_attach(device_t dev)
struct mii_data *mii;
mii = device_get_softc(dev);
mii->mii_ifp = NETDEV(device_get_parent(dev))->ifp;
/*
* Note that each NIC's softc must start with an ifnet pointer.
* XXX: EVIL HACK!
*/
mii->mii_ifp = *(struct ifnet**)device_get_softc(device_get_parent(dev));
v = device_get_ivars(dev);
ifmedia_upd = v[0];
ifmedia_sts = v[1];
@ -247,7 +250,11 @@ miibus_statchg(device_t dev)
mii = device_get_softc(dev);
ifp = NETDEV(parent)->ifp;
/*
* Note that each NIC's softc must start with an ifnet pointer.
* XXX: EVIL HACK!
*/
ifp = *(struct ifnet **)device_get_softc(parent);
ifp->if_baudrate = ifmedia_baudrate(mii->mii_media_active);
return;
}
@ -272,7 +279,11 @@ miibus_linkchg(device_t dev)
} else
link_state = LINK_STATE_UNKNOWN;
if_link_state_change(NETDEV(parent)->ifp, link_state);
/*
* Note that each NIC's softc must start with an ifnet pointer.
* XXX: EVIL HACK!
*/
if_link_state_change(*(struct ifnet**)device_get_softc(parent), link_state);
}
static void

View File

@ -1,13 +1,12 @@
/*
* Copyright 2007, Hugo Santos. All Rights Reserved.
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved.
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
*
* Distributed under the terms of the MIT License.
*
* Authors:
* Hugo Santos, hugosantos@gmail.com
*
* Some of this code is based on previous work by Marcus Overhagen.
*/
#include "device.h"
#include <stdio.h>
@ -24,25 +23,43 @@
#include <compat/net/ethernet.h>
struct ifnet *
if_alloc(u_char type)
{
char semName[64];
struct ifnet *ifp = _kernel_malloc(sizeof(struct ifnet), M_ZERO);
if (ifp == NULL)
return NULL;
snprintf(semName, sizeof(semName), "%s receive", gDriverName);
ifp->receive_sem = create_sem(0, semName);
if (ifp->receive_sem < B_OK)
goto err1;
if (type == IFT_ETHER) {
ifp->if_l2com = _kernel_malloc(sizeof(struct arpcom), M_ZERO);
if (ifp->if_l2com == NULL) {
_kernel_free(ifp);
return NULL;
}
if (ifp->if_l2com == NULL)
goto err2;
IFP2AC(ifp)->ac_ifp = ifp;
}
ifp->link_state_sem = -1;
ifp->flags = 0;
ifq_init(&ifp->receive_queue, semName);
ifp->if_type = type;
IF_ADDR_LOCK_INIT(ifp);
return ifp;
err2:
delete_sem(ifp->receive_sem);
err1:
_kernel_free(ifp);
return NULL;
}
@ -53,6 +70,9 @@ if_free(struct ifnet *ifp)
if (ifp->if_type == IFT_ETHER)
_kernel_free(ifp->if_l2com);
delete_sem(ifp->receive_sem);
ifq_uninit(&ifp->receive_queue);
_kernel_free(ifp);
}
@ -60,28 +80,29 @@ if_free(struct ifnet *ifp)
void
if_initname(struct ifnet *ifp, const char *name, int unit)
{
int i;
dprintf("if_initname(%p, %s, %d)\n", ifp, name, unit);
if (name == NULL)
panic("interface goes unamed");
if (gDeviceCount >= MAX_DEVICES)
panic("unit too large");
ifp->if_dname = name;
ifp->if_dunit = unit;
ifp->if_index = gDeviceCount++;
strlcpy(ifp->if_xname, name, sizeof(ifp->if_xname));
for (i = 0; gDevNameList[i] != NULL; i++) {
if (strcmp(gDevNameList[i], name) == 0)
break;
}
snprintf(ifp->device_name, sizeof(ifp->device_name), "net/%s/%i",
gDriverName, ifp->if_index);
if (gDevNameList[i] == NULL)
panic("unknown interface");
driver_printf("%s: /dev/%s\n", gDriverName, ifp->device_name);
ifp->if_dev = DEVNET(gDevices[i]);
gDevices[i]->ifp = ifp;
gDeviceNameList[ifp->if_index] = ifp->device_name;
gDevices[ifp->if_index] = ifp;
ifp->root_device = find_root_device(unit);
}
@ -146,21 +167,19 @@ if_printf(struct ifnet *ifp, const char *format, ...)
vsnprintf(buf, sizeof(buf), format, vl);
va_end(vl);
dprintf("[%s] %s", ifp->if_xname, buf);
dprintf("[%s] %s", ifp->device_name, buf);
return 0;
}
void
if_link_state_change(struct ifnet *ifp, int link_state)
if_link_state_change(struct ifnet *ifp, int linkState)
{
if (ifp->if_link_state == link_state)
if (ifp->if_link_state == linkState)
return;
ifp->if_link_state = link_state;
release_sem_etc(NETDEV(ifp->if_dev)->link_state_sem, 1,
B_DO_NOT_RESCHEDULE);
ifp->if_link_state = linkState;
release_sem_etc(ifp->link_state_sem, 1, B_DO_NOT_RESCHEDULE);
}
@ -281,10 +300,8 @@ ether_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
static void
ether_input(struct ifnet *ifp, struct mbuf *m)
{
device_t dev = ifp->if_dev;
IF_ENQUEUE(&NETDEV(dev)->receive_queue, m);
release_sem_etc(NETDEV(dev)->receive_sem, 1, B_DO_NOT_RESCHEDULE);
IF_ENQUEUE(&ifp->receive_queue, m);
release_sem_etc(ifp->receive_sem, 1, B_DO_NOT_RESCHEDULE);
}

View File

@ -0,0 +1,206 @@
/*
* Copyright 2007, Hugo Santos, hugosantos@gmail.com. All Rights Reserved.
* Copyright 2007, Axel Dörfler, axeld@pinc-software.de. All Rights Reserved.
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
*
* Distributed under the terms of the MIT License.
*/
#include "device.h"
#include <stdio.h>
#include <KernelExport.h>
#include <image.h>
#include <compat/machine/resource.h>
#include <compat/dev/pci/pcireg.h>
#include <compat/dev/pci/pcivar.h>
#include <compat/sys/bus.h>
#include <compat/dev/mii/miivar.h>
//#define DEBUG_PCI
#ifdef DEBUG_PCI
# define TRACE_PCI(dev, format, args...) device_printf(dev, format , ##args)
#else
# define TRACE_PCI(dev, format, args...) do { } while (0)
#endif
uint32_t
pci_read_config(device_t dev, int offset, int size)
{
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
uint32_t value = gPci->read_pci_config(info->bus, info->device,
info->function, offset, size);
TRACE_PCI(dev, "pci_read_config(%i, %i) = 0x%x\n", offset, size, value);
return value;
}
void
pci_write_config(device_t dev, int offset, uint32_t value, int size)
{
pci_info *info = &((struct root_device_softc *)dev->root->softc)->pci_info;
TRACE_PCI(dev, "pci_write_config(%i, 0x%x, %i)\n", offset, value, size);
gPci->write_pci_config(info->bus, info->device, info->function, offset,
size, value);
}
uint16_t
pci_get_vendor(device_t dev)
{
return pci_read_config(dev, PCI_vendor_id, 2);
}
uint16_t
pci_get_device(device_t dev)
{
return pci_read_config(dev, PCI_device_id, 2);
}
uint16_t
pci_get_subvendor(device_t dev)
{
return pci_read_config(dev, PCI_subsystem_vendor_id, 2);
}
uint16_t
pci_get_subdevice(device_t dev)
{
return pci_read_config(dev, PCI_subsystem_id, 2);
}
uint8_t
pci_get_revid(device_t dev)
{
return pci_read_config(dev, PCI_revision, 1);
}
static void
pci_set_command_bit(device_t dev, uint16_t bit)
{
uint16_t command = pci_read_config(dev, PCI_command, 2);
pci_write_config(dev, PCI_command, command | bit, 2);
}
int
pci_enable_busmaster(device_t dev)
{
pci_set_command_bit(dev, PCI_command_master);
return 0;
}
int
pci_enable_io(device_t dev, int space)
{
/* adapted from FreeBSD's pci_enable_io_method */
int bit = 0;
switch (space) {
case SYS_RES_IOPORT:
bit = PCI_command_io;
break;
case SYS_RES_MEMORY:
bit = PCI_command_memory;
break;
default:
return EINVAL;
}
pci_set_command_bit(dev, bit);
if (pci_read_config(dev, PCI_command, 2) & bit)
return 0;
device_printf(dev, "pci_enable_io(%d) failed.\n", space);
return ENXIO;
}
int
pci_find_extcap(device_t child, int capability, int *_capabilityRegister)
{
uint8 capabilityPointer;
uint8 headerType;
uint16 status;
status = pci_read_config(child, PCIR_STATUS, 2);
if ((status & PCIM_STATUS_CAPPRESENT) == 0)
return ENXIO;
headerType = pci_read_config(child, PCI_header_type, 1);
switch (headerType & PCIM_HDRTYPE) {
case 0:
case 1:
capabilityPointer = PCIR_CAP_PTR;
break;
case 2:
capabilityPointer = PCIR_CAP_PTR_2;
break;
default:
return ENXIO;
}
capabilityPointer = pci_read_config(child, capabilityPointer, 1);
while (capabilityPointer != 0) {
if (pci_read_config(child, capabilityPointer + PCICAP_ID, 1)
== capability) {
if (_capabilityRegister != NULL)
*_capabilityRegister = capabilityPointer;
return 0;
}
capabilityPointer = pci_read_config(child,
capabilityPointer + PCICAP_NEXTPTR, 1);
}
return ENOENT;
}
int
pci_msi_count(device_t dev)
{
return 0;
}
int
pci_alloc_msi(device_t dev, int *count)
{
return ENODEV;
}
int
pci_release_msi(device_t dev)
{
return ENODEV;
}
int
pci_msix_count(device_t dev)
{
return 0;
}
int
pci_alloc_msix(device_t dev, int *count)
{
return ENODEV;
}