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:
@@ -67,7 +67,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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
|
* 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_service(struct mii_softc *, struct mii_data *, int);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ukphy_probe(dev)
|
ukphy_probe(device_t dev)
|
||||||
device_t dev;
|
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We know something is here, so always match at a low priority.
|
* We know something is here, so always match at a low priority.
|
||||||
*/
|
*/
|
||||||
device_set_desc(dev, "Generic IEEE 802.3u media interface");
|
device_set_desc(dev, "Generic IEEE 802.3u media interface");
|
||||||
return (-100);
|
return (BUS_PROBE_GENERIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ukphy_attach(dev)
|
ukphy_attach(device_t dev)
|
||||||
device_t dev;
|
|
||||||
{
|
{
|
||||||
struct mii_softc *sc;
|
struct mii_softc *sc;
|
||||||
struct mii_attach_args *ma;
|
struct mii_attach_args *ma;
|
||||||
struct mii_data *mii;
|
struct mii_data *mii;
|
||||||
|
|
||||||
static int ppp;
|
|
||||||
if (ppp++ > 0)
|
|
||||||
panic("oops");
|
|
||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
ma = device_get_ivars(dev);
|
ma = device_get_ivars(dev);
|
||||||
sc->mii_dev = device_get_parent(dev);
|
sc->mii_dev = device_get_parent(dev);
|
||||||
mii = device_get_softc(sc->mii_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);
|
LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
|
||||||
|
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
@@ -156,8 +149,6 @@ device_printf(sc->mii_dev, "this is the parent\n");
|
|||||||
|
|
||||||
mii->mii_instance++;
|
mii->mii_instance++;
|
||||||
|
|
||||||
sc->mii_flags |= MIIF_NOISOLATE;
|
|
||||||
|
|
||||||
mii_phy_reset(sc);
|
mii_phy_reset(sc);
|
||||||
|
|
||||||
sc->mii_capabilities =
|
sc->mii_capabilities =
|
||||||
@@ -171,14 +162,11 @@ device_printf(sc->mii_dev, "this is the parent\n");
|
|||||||
MIIBUS_MEDIAINIT(sc->mii_dev);
|
MIIBUS_MEDIAINIT(sc->mii_dev);
|
||||||
mii_phy_setmedia(sc);
|
mii_phy_setmedia(sc);
|
||||||
|
|
||||||
return(0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ukphy_service(sc, mii, cmd)
|
ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
|
||||||
struct mii_softc *sc;
|
|
||||||
struct mii_data *mii;
|
|
||||||
int cmd;
|
|
||||||
{
|
{
|
||||||
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
|
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
|
||||||
int reg;
|
int reg;
|
||||||
|
|||||||
@@ -23,10 +23,11 @@ __haiku_select_miibus_driver(device_t dev)
|
|||||||
driver_t *drivers[] = {
|
driver_t *drivers[] = {
|
||||||
DRIVER_MODULE_NAME(bmtphy, miibus),
|
DRIVER_MODULE_NAME(bmtphy, miibus),
|
||||||
DRIVER_MODULE_NAME(xlphy, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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
|
* 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_service(struct mii_softc *, struct mii_data *, int);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ukphy_probe(dev)
|
ukphy_probe(device_t dev)
|
||||||
device_t dev;
|
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We know something is here, so always match at a low priority.
|
* We know something is here, so always match at a low priority.
|
||||||
*/
|
*/
|
||||||
device_set_desc(dev, "Generic IEEE 802.3u media interface");
|
device_set_desc(dev, "Generic IEEE 802.3u media interface");
|
||||||
return (-100);
|
return (BUS_PROBE_GENERIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ukphy_attach(dev)
|
ukphy_attach(device_t dev)
|
||||||
device_t dev;
|
|
||||||
{
|
{
|
||||||
struct mii_softc *sc;
|
struct mii_softc *sc;
|
||||||
struct mii_attach_args *ma;
|
struct mii_attach_args *ma;
|
||||||
struct mii_data *mii;
|
struct mii_data *mii;
|
||||||
|
|
||||||
static int ppp;
|
|
||||||
if (ppp++ > 0)
|
|
||||||
panic("oops");
|
|
||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
ma = device_get_ivars(dev);
|
ma = device_get_ivars(dev);
|
||||||
sc->mii_dev = device_get_parent(dev);
|
sc->mii_dev = device_get_parent(dev);
|
||||||
mii = device_get_softc(sc->mii_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);
|
LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
|
||||||
|
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
@@ -156,8 +149,6 @@ device_printf(sc->mii_dev, "this is the parent\n");
|
|||||||
|
|
||||||
mii->mii_instance++;
|
mii->mii_instance++;
|
||||||
|
|
||||||
sc->mii_flags |= MIIF_NOISOLATE;
|
|
||||||
|
|
||||||
mii_phy_reset(sc);
|
mii_phy_reset(sc);
|
||||||
|
|
||||||
sc->mii_capabilities =
|
sc->mii_capabilities =
|
||||||
@@ -171,14 +162,11 @@ device_printf(sc->mii_dev, "this is the parent\n");
|
|||||||
MIIBUS_MEDIAINIT(sc->mii_dev);
|
MIIBUS_MEDIAINIT(sc->mii_dev);
|
||||||
mii_phy_setmedia(sc);
|
mii_phy_setmedia(sc);
|
||||||
|
|
||||||
return(0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ukphy_service(sc, mii, cmd)
|
ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
|
||||||
struct mii_softc *sc;
|
|
||||||
struct mii_data *mii;
|
|
||||||
int cmd;
|
|
||||||
{
|
{
|
||||||
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
|
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
|
||||||
int reg;
|
int reg;
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ __haiku_select_miibus_driver(device_t dev)
|
|||||||
{
|
{
|
||||||
driver_t *drivers[] = {
|
driver_t *drivers[] = {
|
||||||
DRIVER_MODULE_NAME(e1000phy, miibus),
|
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();
|
NO_HAIKU_CHECK_DISABLE_INTERRUPTS();
|
||||||
|
|||||||
@@ -6,21 +6,33 @@ HAIKU_FBSD_DRIVER_GLUE(rtl8139, rl, pci);
|
|||||||
HAIKU_FBSD_MII_DRIVER(rlphy);
|
HAIKU_FBSD_MII_DRIVER(rlphy);
|
||||||
HAIKU_DRIVER_REQUIREMENTS(0);
|
HAIKU_DRIVER_REQUIREMENTS(0);
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
HAIKU_CHECK_DISABLE_INTERRUPTS(device_t dev) {
|
HAIKU_CHECK_DISABLE_INTERRUPTS(device_t dev)
|
||||||
|
{
|
||||||
struct rl_softc *sc = device_get_softc(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;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
HAIKU_REENABLE_INTERRUPTS(device_t dev)
|
HAIKU_REENABLE_INTERRUPTS(device_t dev)
|
||||||
{
|
{
|
||||||
struct rl_softc *sc = device_get_softc(dev);
|
struct rl_softc *sc = device_get_softc(dev);
|
||||||
RL_LOCK(sc);
|
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);
|
RL_UNLOCK(sc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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
|
* 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_service(struct mii_softc *, struct mii_data *, int);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ukphy_probe(dev)
|
ukphy_probe(device_t dev)
|
||||||
device_t dev;
|
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We know something is here, so always match at a low priority.
|
* We know something is here, so always match at a low priority.
|
||||||
*/
|
*/
|
||||||
device_set_desc(dev, "Generic IEEE 802.3u media interface");
|
device_set_desc(dev, "Generic IEEE 802.3u media interface");
|
||||||
return (-100);
|
return (BUS_PROBE_GENERIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ukphy_attach(dev)
|
ukphy_attach(device_t dev)
|
||||||
device_t dev;
|
|
||||||
{
|
{
|
||||||
struct mii_softc *sc;
|
struct mii_softc *sc;
|
||||||
struct mii_attach_args *ma;
|
struct mii_attach_args *ma;
|
||||||
@@ -151,8 +149,6 @@ ukphy_attach(dev)
|
|||||||
|
|
||||||
mii->mii_instance++;
|
mii->mii_instance++;
|
||||||
|
|
||||||
sc->mii_flags |= MIIF_NOISOLATE;
|
|
||||||
|
|
||||||
mii_phy_reset(sc);
|
mii_phy_reset(sc);
|
||||||
|
|
||||||
sc->mii_capabilities =
|
sc->mii_capabilities =
|
||||||
@@ -166,14 +162,11 @@ ukphy_attach(dev)
|
|||||||
MIIBUS_MEDIAINIT(sc->mii_dev);
|
MIIBUS_MEDIAINIT(sc->mii_dev);
|
||||||
mii_phy_setmedia(sc);
|
mii_phy_setmedia(sc);
|
||||||
|
|
||||||
return(0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ukphy_service(sc, mii, cmd)
|
ukphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
|
||||||
struct mii_softc *sc;
|
|
||||||
struct mii_data *mii;
|
|
||||||
int cmd;
|
|
||||||
{
|
{
|
||||||
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
|
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
|
||||||
int reg;
|
int reg;
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ __haiku_select_miibus_driver(device_t dev)
|
|||||||
{
|
{
|
||||||
driver_t *drivers[] = {
|
driver_t *drivers[] = {
|
||||||
DRIVER_MODULE_NAME(ciphy, miibus),
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ KernelStaticLibrary libfreebsd_network.a :
|
|||||||
callout.c
|
callout.c
|
||||||
compat.c
|
compat.c
|
||||||
device.c
|
device.c
|
||||||
|
driver.c
|
||||||
fbsd_busdma_x86.c
|
fbsd_busdma_x86.c
|
||||||
fbsd_ether.c
|
fbsd_ether.c
|
||||||
fbsd_if_media.c
|
fbsd_if_media.c
|
||||||
@@ -23,5 +24,6 @@ KernelStaticLibrary libfreebsd_network.a :
|
|||||||
mbuf.c
|
mbuf.c
|
||||||
mii.c
|
mii.c
|
||||||
mutex.c
|
mutex.c
|
||||||
|
pci.c
|
||||||
taskqueue.c
|
taskqueue.c
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
|
|
||||||
|
#include <compat/dev/pci/pcireg.h>
|
||||||
#include <compat/dev/pci/pcivar.h>
|
#include <compat/dev/pci/pcivar.h>
|
||||||
#include <compat/machine/resource.h>
|
#include <compat/machine/resource.h>
|
||||||
#include <compat/sys/bus.h>
|
#include <compat/sys/bus.h>
|
||||||
@@ -24,6 +25,14 @@
|
|||||||
# define TRACE_BUS_SPACE_RW(x)
|
# define TRACE_BUS_SPACE_RW(x)
|
||||||
#endif
|
#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))
|
#define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1))
|
||||||
|
|
||||||
// TODO: x86 specific!
|
// 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,
|
status = install_io_interrupt_handler(intr->irq,
|
||||||
intr_fast_wrapper, intr, 0);
|
intr_fast_wrapper, intr, 0);
|
||||||
} else {
|
} 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);
|
intr->sem = create_sem(0, semName);
|
||||||
if (intr->sem < B_OK) {
|
if (intr->sem < B_OK) {
|
||||||
@@ -314,7 +323,7 @@ bus_setup_intr(device_t dev, struct resource *res, int flags,
|
|||||||
return B_NO_MEMORY;
|
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,
|
intr->thread = spawn_kernel_thread(intr_handler, semName,
|
||||||
B_REAL_TIME_DISPLAY_PRIORITY, intr);
|
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(1, uint8_t, out8)
|
||||||
BUS_SPACE_WRITE(2, uint16_t, out16)
|
BUS_SPACE_WRITE(2, uint16_t, out16)
|
||||||
BUS_SPACE_WRITE(4, uint32_t, out32)
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,201 +14,85 @@
|
|||||||
#include <image.h>
|
#include <image.h>
|
||||||
|
|
||||||
#include <compat/machine/resource.h>
|
#include <compat/machine/resource.h>
|
||||||
#include <compat/dev/pci/pcireg.h>
|
#include <compat/dev/mii/mii.h>
|
||||||
#include <compat/dev/pci/pcivar.h>
|
|
||||||
#include <compat/sys/bus.h>
|
#include <compat/sys/bus.h>
|
||||||
|
|
||||||
#include <compat/dev/mii/miivar.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;
|
spinlock __haiku_intr_spinlock;
|
||||||
|
|
||||||
struct net_stack_module_info *gStack;
|
struct net_stack_module_info *gStack;
|
||||||
pci_module_info *gPci;
|
pci_module_info *gPci;
|
||||||
|
|
||||||
|
static struct list sRootDevices;
|
||||||
// #pragma mark - PCI
|
static int sNextUnit;
|
||||||
|
|
||||||
|
|
||||||
uint32_t
|
// #pragma mark - private functions
|
||||||
pci_read_config(device_t dev, int offset, int size)
|
|
||||||
|
|
||||||
|
static device_t
|
||||||
|
init_device(device_t device, driver_t *driver)
|
||||||
{
|
{
|
||||||
uint32_t value = gPci->read_pci_config(NETDEV(dev)->pci_info.bus,
|
list_init_etc(&device->children, offsetof(struct device, link));
|
||||||
NETDEV(dev)->pci_info.device, NETDEV(dev)->pci_info.function,
|
device->unit = sNextUnit++;
|
||||||
offset, size);
|
|
||||||
TRACE_PCI(dev, "pci_read_config(%i, %i) = 0x%x\n", offset, size, value);
|
if (driver != NULL && device_set_driver(device, driver) < 0)
|
||||||
return value;
|
return NULL;
|
||||||
|
|
||||||
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
static device_t
|
||||||
pci_write_config(device_t dev, int offset, uint32_t value, int size)
|
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,
|
memset(dev, 0, sizeof(struct device));
|
||||||
NETDEV(dev)->pci_info.device, NETDEV(dev)->pci_info.function,
|
|
||||||
offset, size, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (init_device(dev, driver) == NULL) {
|
||||||
uint16_t
|
free(dev);
|
||||||
pci_get_vendor(device_t dev)
|
return NULL;
|
||||||
{
|
|
||||||
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);
|
return dev;
|
||||||
if (pci_read_config(dev, PCI_command, 2) & bit)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
device_printf(dev, "pci_enable_io(%d) failed.\n", space);
|
|
||||||
|
|
||||||
return ENXIO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
static image_id
|
||||||
pci_find_extcap(device_t child, int capability, int *_capabilityRegister)
|
find_own_image()
|
||||||
{
|
{
|
||||||
uint8 capabilityPointer;
|
int32 cookie = 0;
|
||||||
uint8 headerType;
|
image_info info;
|
||||||
uint16 status;
|
while (get_next_image_info(B_SYSTEM_TEAM, &cookie, &info) == B_OK) {
|
||||||
|
if (((uint32)info.text <= (uint32)find_own_image
|
||||||
status = pci_read_config(child, PCIR_STATUS, 2);
|
&& (uint32)info.text + (uint32)info.text_size
|
||||||
if ((status & PCIM_STATUS_CAPPRESENT) == 0)
|
> (uint32)find_own_image)) {
|
||||||
return ENXIO;
|
// found our own image
|
||||||
|
return info.id;
|
||||||
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;
|
return B_ENTRY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
static device_method_signature_t
|
||||||
pci_msi_count(device_t dev)
|
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
|
return method;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -251,7 +135,7 @@ device_printf(device_t dev, const char *format, ...)
|
|||||||
va_list vl;
|
va_list vl;
|
||||||
|
|
||||||
va_start(vl, format);
|
va_start(vl, format);
|
||||||
driver_vprintf_etc(dev->dev_name, format, vl);
|
driver_vprintf_etc(dev->device_name, format, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
return 0;
|
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 *
|
const char *
|
||||||
device_get_name(device_t dev)
|
device_get_name(device_t dev)
|
||||||
{
|
{
|
||||||
if (dev)
|
if (dev == NULL)
|
||||||
return dev->dev_name;
|
return 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
|
int
|
||||||
device_set_driver(device_t dev, driver_t *driver)
|
device_set_driver(device_t dev, driver_t *driver)
|
||||||
{
|
{
|
||||||
@@ -397,60 +260,14 @@ device_set_driver(device_t dev, driver_t *driver)
|
|||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
device_is_alive(device_t dev)
|
device_is_alive(device_t device)
|
||||||
{
|
{
|
||||||
return dev->driver != NULL;
|
return (device->flags & DEVICE_ATTACHED) != 0;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
device_t
|
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;
|
device_t child = NULL;
|
||||||
|
|
||||||
@@ -462,13 +279,11 @@ device_add_child(device_t dev, const char *name, int order)
|
|||||||
driver_t **driver;
|
driver_t **driver;
|
||||||
char symbol[128];
|
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,
|
if (get_image_symbol(find_own_image(), symbol, B_SYMBOL_TYPE_DATA,
|
||||||
(void **)&driver) == B_OK)
|
(void **)&driver) == B_OK)
|
||||||
child = new_device(*driver);
|
child = new_device(*driver);
|
||||||
|
|
||||||
// inherit the device name of our parent
|
|
||||||
name = dev->dev_name;
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
child = new_device(NULL);
|
child = new_device(NULL);
|
||||||
@@ -477,37 +292,76 @@ device_add_child(device_t dev, const char *name, int order)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (name != NULL)
|
if (name != NULL)
|
||||||
strlcpy(child->dev_name, name, sizeof(child->dev_name));
|
strlcpy(child->device_name, name, sizeof(child->device_name));
|
||||||
child->parent = dev;
|
|
||||||
list_add_item(&dev->children, child);
|
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;
|
return child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
driver_t *
|
/*! Delete the child and all of its children. Detach as necessary.
|
||||||
__haiku_probe_miibus(device_t dev, driver_t *drivers[], int count)
|
*/
|
||||||
|
int
|
||||||
|
device_delete_child(device_t parent, device_t child)
|
||||||
{
|
{
|
||||||
driver_t *selected = NULL;
|
if (child == NULL)
|
||||||
int i, selcost = 0;
|
return 0;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
if (parent != NULL)
|
||||||
device_probe_t *probe = (device_probe_t *)
|
list_remove_item(&parent->children, child);
|
||||||
_resolve_method(drivers[i], "device_probe");
|
|
||||||
if (probe) {
|
parent = child;
|
||||||
int result = probe(dev);
|
|
||||||
// the ukphy driver (fallback for unknown PHYs) return -100 here
|
while ((child = list_remove_head_item(&parent->children)) != NULL) {
|
||||||
if (result >= -100) {
|
device_delete_child(NULL, child);
|
||||||
if (selected == NULL || result > selcost) {
|
|
||||||
selected = drivers[i];
|
|
||||||
selcost = result;
|
|
||||||
device_printf(dev, "Found MII: %s\n", selected->name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
if (driver == NULL) {
|
||||||
struct mii_attach_args *ma = device_get_ivars(child);
|
struct mii_attach_args *ma = device_get_ivars(child);
|
||||||
|
|
||||||
device_printf(dev, "No PHY module found (%x/%x)!\n", ma->mii_id1,
|
device_printf(dev, "No PHY module found (%x/%x)!\n",
|
||||||
ma->mii_id2);
|
MII_OUI(ma->mii_id1, ma->mii_id2), MII_MODEL(ma->mii_id2));
|
||||||
} else
|
} else
|
||||||
device_set_driver(child, driver);
|
device_set_driver(child, driver);
|
||||||
} else if (child->driver == &miibus_driver)
|
} else if (child->driver != &miibus_driver)
|
||||||
child->methods.probe(child);
|
child->methods.probe(child);
|
||||||
|
|
||||||
if (child->driver != NULL) {
|
if (child->driver != NULL) {
|
||||||
int result = child->methods.attach(child);
|
int result = device_attach(child);
|
||||||
if (result != 0)
|
if (result != 0)
|
||||||
return result;
|
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
|
// #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
|
int
|
||||||
printf(const char *format, ...)
|
printf(const char *format, ...)
|
||||||
{
|
{
|
||||||
@@ -665,10 +545,3 @@ pmap_kextract(vm_offset_t virtualAddress)
|
|||||||
return (vm_paddr_t)entry.address;
|
return (vm_paddr_t)entry.address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
init_compat_layer()
|
|
||||||
{
|
|
||||||
__haiku_intr_spinlock = 0;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -186,8 +186,14 @@ struct ifnet {
|
|||||||
struct mtx if_addr_mtx; /* mutex to protect address lists */
|
struct mtx if_addr_mtx; /* mutex to protect address lists */
|
||||||
|
|
||||||
/* Haiku additions */
|
/* Haiku additions */
|
||||||
struct sockaddr_dl if_lladdr;
|
struct sockaddr_dl if_lladdr;
|
||||||
struct device *if_dev;
|
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 *);
|
typedef void if_init_f_t(void *);
|
||||||
|
|||||||
@@ -88,6 +88,13 @@ enum intr_type {
|
|||||||
#define FILTER_HANDLED B_HANDLED_INTERRUPT
|
#define FILTER_HANDLED B_HANDLED_INTERRUPT
|
||||||
#define FILTER_SCHEDULE_THREAD B_INVOKE_SCHEDULER
|
#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_detach(device_t dev);
|
||||||
int bus_generic_suspend(device_t dev);
|
int bus_generic_suspend(device_t dev);
|
||||||
int bus_generic_resume(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);
|
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_delete_child(device_t dev, device_t child);
|
||||||
int device_is_attached(device_t dev);
|
int device_is_attached(device_t dev);
|
||||||
|
int device_attach(device_t dev);
|
||||||
int bus_generic_print_child(device_t dev, device_t child);
|
int bus_generic_print_child(device_t dev, device_t child);
|
||||||
void bus_generic_driver_added(device_t dev, driver_t *driver);
|
void bus_generic_driver_added(device_t dev, driver_t *driver);
|
||||||
int bus_generic_attach(device_t dev);
|
int bus_generic_attach(device_t dev);
|
||||||
|
|||||||
@@ -41,19 +41,16 @@ typedef struct {
|
|||||||
size_t softc_size;
|
size_t softc_size;
|
||||||
} driver_t;
|
} driver_t;
|
||||||
|
|
||||||
#define BUS_PROBE_LOW_PRIORITY 10
|
|
||||||
#define BUS_PROBE_DEFAULT 20
|
|
||||||
|
|
||||||
#define DRIVER_MODULE_NAME(name, busname) \
|
#define DRIVER_MODULE_NAME(name, busname) \
|
||||||
__fbsd_##name##busname
|
__fbsd_ ## name ## _ ## busname
|
||||||
|
|
||||||
status_t _fbsd_init_hardware(driver_t *);
|
status_t _fbsd_init_hardware(driver_t *driver);
|
||||||
status_t _fbsd_init_driver(driver_t *);
|
status_t _fbsd_init_driver(driver_t *driver);
|
||||||
void _fbsd_uninit_driver(driver_t *);
|
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_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
|
/* we define the driver methods with HAIKU_FBSD_DRIVER_GLUE to
|
||||||
* force the rest of the stuff to be linked back with the driver.
|
* 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. */
|
* the final binary, gcc 4.x rightfuly doesn't. */
|
||||||
|
|
||||||
#define HAIKU_FBSD_DRIVER_GLUE(publicname, name, busname) \
|
#define HAIKU_FBSD_DRIVER_GLUE(publicname, name, busname) \
|
||||||
extern const char *gDevNameList[]; \
|
extern const char *gDeviceNameList[]; \
|
||||||
extern device_hooks gDeviceHooks; \
|
extern device_hooks gDeviceHooks; \
|
||||||
extern driver_t *DRIVER_MODULE_NAME(name, busname); \
|
extern driver_t *DRIVER_MODULE_NAME(name, busname); \
|
||||||
const char gDriverName[] = #publicname; \
|
const char *gDriverName = #publicname; \
|
||||||
int32 api_version = B_CUR_DRIVER_API_VERSION; \
|
int32 api_version = B_CUR_DRIVER_API_VERSION; \
|
||||||
status_t init_hardware() \
|
status_t init_hardware() \
|
||||||
{ \
|
{ \
|
||||||
@@ -77,14 +74,14 @@ driver_t *__haiku_probe_miibus(device_t dev, driver_t *drivers[], int count);
|
|||||||
void uninit_driver() \
|
void uninit_driver() \
|
||||||
{ _fbsd_uninit_driver(DRIVER_MODULE_NAME(name, busname)); } \
|
{ _fbsd_uninit_driver(DRIVER_MODULE_NAME(name, busname)); } \
|
||||||
const char **publish_devices() \
|
const char **publish_devices() \
|
||||||
{ return gDevNameList; } \
|
{ return gDeviceNameList; } \
|
||||||
device_hooks *find_device(const char *name) \
|
device_hooks *find_device(const char *name) \
|
||||||
{ return &gDeviceHooks; }
|
{ 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) \
|
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) \
|
#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 *__haiku_select_miibus_driver(device_t dev) \
|
||||||
{ \
|
{ \
|
||||||
driver_t *drivers[] = { \
|
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() \
|
#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 spinlock __haiku_intr_spinlock;
|
||||||
extern int __haiku_disable_interrupts(device_t dev);
|
extern int __haiku_disable_interrupts(device_t dev);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||||
|
* Copyright 2007, Axel Dörfler, [email protected]. All Rights Reserved.
|
||||||
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
|
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
@@ -20,142 +21,54 @@
|
|||||||
#include <compat/net/ethernet.h>
|
#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
|
static status_t
|
||||||
compat_open(const char *name, uint32 flags, void **cookie)
|
compat_open(const char *name, uint32 flags, void **cookie)
|
||||||
{
|
{
|
||||||
struct network_device *device;
|
struct ifnet *ifp;
|
||||||
status_t status;
|
struct ifreq ifr;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
driver_printf("compat_open(%s, 0x%lx)\n", name, flags);
|
for (i = 0; gDeviceNameList[i] != NULL; i++) {
|
||||||
|
if (strcmp(gDeviceNameList[i], name) == 0)
|
||||||
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)
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gDevNameList[i] == NULL)
|
if (gDeviceNameList[i] == NULL)
|
||||||
return B_ERROR;
|
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;
|
return B_BUSY;
|
||||||
|
|
||||||
/* some drivers expect the softc to be zero'ed out */
|
ifp->if_flags &= ~IFF_UP;
|
||||||
memset(device->base.softc, 0, device->base.driver->softc_size);
|
ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
|
||||||
|
|
||||||
status = DEVNET(device)->methods.attach(DEVNET(device));
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
if (status != 0)
|
ifr.ifr_media = IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, 0);
|
||||||
atomic_and(&device->open, 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) {
|
ifp->if_init(ifp->if_softc);
|
||||||
struct ifnet *ifp = device->ifp;
|
|
||||||
struct ifreq ifr;
|
|
||||||
|
|
||||||
ifp->if_flags &= ~IFF_UP;
|
*cookie = ifp;
|
||||||
ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
|
return B_OK;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static status_t
|
||||||
compat_close(void *cookie)
|
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);
|
atomic_or(&ifp->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);
|
|
||||||
|
|
||||||
|
release_sem_etc(ifp->receive_sem, 1, B_RELEASE_ALL);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,17 +76,13 @@ compat_close(void *cookie)
|
|||||||
static status_t
|
static status_t
|
||||||
compat_free(void *cookie)
|
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));
|
/* TODO: empty out the send queue */
|
||||||
|
|
||||||
/* XXX empty out the send queue */
|
|
||||||
|
|
||||||
atomic_and(&dev->open, 0);
|
|
||||||
put_module(NET_STACK_MODULE_NAME);
|
|
||||||
|
|
||||||
|
atomic_and(&ifp->open_count, 0);
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,24 +90,24 @@ compat_free(void *cookie)
|
|||||||
static status_t
|
static status_t
|
||||||
compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
|
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;
|
uint32 semFlags = B_CAN_INTERRUPT;
|
||||||
status_t status;
|
status_t status;
|
||||||
struct mbuf *mb;
|
struct mbuf *mb;
|
||||||
size_t length;
|
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);
|
// buffer, *numBytes);
|
||||||
|
|
||||||
if (DEVNET(dev)->flags & DEVICE_CLOSED)
|
if (ifp->flags & DEVICE_CLOSED)
|
||||||
return B_INTERRUPTED;
|
return B_INTERRUPTED;
|
||||||
|
|
||||||
if (DEVNET(dev)->flags & DEVICE_NON_BLOCK)
|
if (ifp->flags & DEVICE_NON_BLOCK)
|
||||||
semFlags |= B_RELATIVE_TIMEOUT;
|
semFlags |= B_RELATIVE_TIMEOUT;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
status = acquire_sem_etc(dev->receive_sem, 1, semFlags, 0);
|
status = acquire_sem_etc(ifp->receive_sem, 1, semFlags, 0);
|
||||||
if (DEVNET(dev)->flags & DEVICE_CLOSED)
|
if (ifp->flags & DEVICE_CLOSED)
|
||||||
return B_INTERRUPTED;
|
return B_INTERRUPTED;
|
||||||
|
|
||||||
if (status == B_WOULD_BLOCK) {
|
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)
|
} else if (status < B_OK)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
IF_DEQUEUE(&dev->receive_queue, mb);
|
IF_DEQUEUE(&ifp->receive_queue, mb);
|
||||||
} while (mb == NULL);
|
} while (mb == NULL);
|
||||||
|
|
||||||
length = min_c(max_c((size_t)mb->m_len, 0), *numBytes);
|
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,
|
compat_write(void *cookie, off_t position, const void *buffer,
|
||||||
size_t *numBytes)
|
size_t *numBytes)
|
||||||
{
|
{
|
||||||
struct network_device *dev = cookie;
|
struct ifnet *ifp = cookie;
|
||||||
struct mbuf *mb;
|
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);
|
// buffer, *numBytes);
|
||||||
|
|
||||||
mb = m_getcl(0, MT_DATA, M_PKTHDR);
|
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);
|
mb->m_len = min_c(*numBytes, (size_t)MCLBYTES);
|
||||||
memcpy(mtod(mb, void *), buffer, mb->m_len);
|
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
|
static status_t
|
||||||
compat_control(void *cookie, uint32 op, void *arg, size_t length)
|
compat_control(void *cookie, uint32 op, void *arg, size_t length)
|
||||||
{
|
{
|
||||||
struct network_device *dev = cookie;
|
struct ifnet *ifp = cookie;
|
||||||
struct ifnet *ifp = dev->ifp;
|
|
||||||
|
|
||||||
//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);
|
// arg, length);
|
||||||
|
|
||||||
switch (op) {
|
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)
|
if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
if (value)
|
if (value)
|
||||||
DEVNET(dev)->flags |= DEVICE_NON_BLOCK;
|
ifp->flags |= DEVICE_NON_BLOCK;
|
||||||
else
|
else
|
||||||
DEVNET(dev)->flags &= ~DEVICE_NON_BLOCK;
|
ifp->flags &= ~DEVICE_NON_BLOCK;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,11 +205,12 @@ compat_control(void *cookie, uint32 op, void *arg, size_t length)
|
|||||||
|
|
||||||
case ETHER_GETFRAMESIZE:
|
case ETHER_GETFRAMESIZE:
|
||||||
{
|
{
|
||||||
uint32 frame_size;
|
uint32 frameSize;
|
||||||
if (length < 4)
|
if (length < 4)
|
||||||
return B_BAD_VALUE;
|
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:
|
case ETHER_ADDMULTI:
|
||||||
@@ -309,7 +218,7 @@ compat_control(void *cookie, uint32 op, void *arg, size_t length)
|
|||||||
{
|
{
|
||||||
struct sockaddr_dl address;
|
struct sockaddr_dl address;
|
||||||
|
|
||||||
if (!(ifp->if_flags & IFF_MULTICAST) == 0)
|
if ((ifp->if_flags & IFF_MULTICAST) == 0)
|
||||||
return EOPNOTSUPP;
|
return EOPNOTSUPP;
|
||||||
|
|
||||||
memset(&address, 0, sizeof(address));
|
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:
|
case ETHER_SET_LINK_STATE_SEM:
|
||||||
if (user_memcpy(&dev->link_state_sem, arg, sizeof(sem_id)) < B_OK) {
|
if (user_memcpy(&ifp->link_state_sem, arg, sizeof(sem_id)) < B_OK) {
|
||||||
dev->link_state_sem = -1;
|
ifp->link_state_sem = -1;
|
||||||
return B_BAD_ADDRESS;
|
return B_BAD_ADDRESS;
|
||||||
}
|
}
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -371,160 +280,3 @@ device_hooks gDeviceHooks = {
|
|||||||
compat_write,
|
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,14 +1,13 @@
|
|||||||
/*
|
/*
|
||||||
|
* Copyright 2007, Axel Dörfler, [email protected]. All Rights Reserved.
|
||||||
* Copyright 2007, Hugo Santos. 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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Hugo Santos, [email protected]
|
|
||||||
*
|
|
||||||
* Some of this code is based on previous work by Marcus Overhagen.
|
|
||||||
*/
|
*/
|
||||||
#ifndef _DEVICE_H_
|
#ifndef DEVICE_H
|
||||||
#define _DEVICE_H_
|
#define DEVICE_H
|
||||||
|
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -24,22 +23,26 @@
|
|||||||
#include <compat/net/if.h>
|
#include <compat/net/if.h>
|
||||||
#include <compat/net/if_var.h>
|
#include <compat/net/if_var.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define MAX_DEVICES 8
|
||||||
|
|
||||||
struct ifnet;
|
struct ifnet;
|
||||||
|
|
||||||
struct device {
|
struct device {
|
||||||
struct device * parent;
|
struct device *parent;
|
||||||
char dev_name[128];
|
struct device *root;
|
||||||
|
|
||||||
driver_t *driver;
|
driver_t *driver;
|
||||||
struct list children;
|
struct list children;
|
||||||
|
|
||||||
int32 flags;
|
int32 flags;
|
||||||
|
|
||||||
|
char device_name[128];
|
||||||
int unit;
|
int unit;
|
||||||
char nameunit[64];
|
char nameunit[64];
|
||||||
const char * description;
|
const char *description;
|
||||||
void * softc;
|
void *softc;
|
||||||
void * ivars;
|
void *ivars;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
int (*probe)(device_t dev);
|
int (*probe)(device_t dev);
|
||||||
@@ -59,35 +62,27 @@ struct device {
|
|||||||
struct list_link link;
|
struct list_link link;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct root_device_softc {
|
||||||
struct network_device {
|
struct pci_info pci_info;
|
||||||
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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define DEVNET(dev) ((device_t)(&(dev)->base))
|
|
||||||
#define NETDEV(base) ((struct network_device *)(base))
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
DEVICE_OPEN = 1 << 0,
|
DEVICE_OPEN = 1 << 0,
|
||||||
DEVICE_CLOSED = 1 << 1,
|
DEVICE_CLOSED = 1 << 1,
|
||||||
DEVICE_NON_BLOCK = 1 << 2,
|
DEVICE_NON_BLOCK = 1 << 2,
|
||||||
DEVICE_DESC_ALLOCED = 1 << 3,
|
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
|
static inline void
|
||||||
__unimplemented(const char *method)
|
__unimplemented(const char *method)
|
||||||
{
|
{
|
||||||
@@ -105,11 +100,11 @@ void uninit_mbufs(void);
|
|||||||
status_t init_mutexes(void);
|
status_t init_mutexes(void);
|
||||||
void uninit_mutexes(void);
|
void uninit_mutexes(void);
|
||||||
|
|
||||||
status_t init_compat_layer(void);
|
|
||||||
|
|
||||||
status_t init_taskqueues(void);
|
status_t init_taskqueues(void);
|
||||||
void uninit_taskqueues(void);
|
void uninit_taskqueues(void);
|
||||||
|
|
||||||
|
device_t find_root_device(int unit);
|
||||||
|
|
||||||
/* busdma_machdep.c */
|
/* busdma_machdep.c */
|
||||||
void init_bounce_pages(void);
|
void init_bounce_pages(void);
|
||||||
void uninit_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, ...)
|
void device_sprintf_name(device_t dev, const char *format, ...)
|
||||||
__attribute__ ((format (__printf__, 2, 3)));
|
__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_init(struct ifqueue *ifq, const char *name);
|
||||||
void ifq_uninit(struct ifqueue *ifq);
|
void ifq_uninit(struct ifqueue *ifq);
|
||||||
|
|
||||||
extern struct net_stack_module_info *gStack;
|
#endif /* DEVICE_H */
|
||||||
extern pci_module_info *gPci;
|
|
||||||
|
|
||||||
extern const char *gDevNameList[];
|
|
||||||
extern struct network_device *gDevices[];
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||||
|
* Copyright 2007, Axel Dörfler, [email protected]. 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);
|
||||||
|
}
|
||||||
@@ -173,8 +173,11 @@ miibus_attach(device_t dev)
|
|||||||
struct mii_data *mii;
|
struct mii_data *mii;
|
||||||
|
|
||||||
mii = device_get_softc(dev);
|
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);
|
v = device_get_ivars(dev);
|
||||||
ifmedia_upd = v[0];
|
ifmedia_upd = v[0];
|
||||||
ifmedia_sts = v[1];
|
ifmedia_sts = v[1];
|
||||||
@@ -247,7 +250,11 @@ miibus_statchg(device_t dev)
|
|||||||
|
|
||||||
mii = device_get_softc(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);
|
ifp->if_baudrate = ifmedia_baudrate(mii->mii_media_active);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -272,7 +279,11 @@ miibus_linkchg(device_t dev)
|
|||||||
} else
|
} else
|
||||||
link_state = LINK_STATE_UNKNOWN;
|
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
|
static void
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||||
|
* Copyright 2007, Axel Dörfler, [email protected]. All Rights Reserved.
|
||||||
|
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
|
||||||
|
*
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
|
||||||
* Authors:
|
|
||||||
* Hugo Santos, [email protected]
|
|
||||||
*
|
|
||||||
* Some of this code is based on previous work by Marcus Overhagen.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -24,25 +23,43 @@
|
|||||||
|
|
||||||
#include <compat/net/ethernet.h>
|
#include <compat/net/ethernet.h>
|
||||||
|
|
||||||
|
|
||||||
struct ifnet *
|
struct ifnet *
|
||||||
if_alloc(u_char type)
|
if_alloc(u_char type)
|
||||||
{
|
{
|
||||||
|
char semName[64];
|
||||||
|
|
||||||
struct ifnet *ifp = _kernel_malloc(sizeof(struct ifnet), M_ZERO);
|
struct ifnet *ifp = _kernel_malloc(sizeof(struct ifnet), M_ZERO);
|
||||||
if (ifp == NULL)
|
if (ifp == NULL)
|
||||||
return 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) {
|
if (type == IFT_ETHER) {
|
||||||
ifp->if_l2com = _kernel_malloc(sizeof(struct arpcom), M_ZERO);
|
ifp->if_l2com = _kernel_malloc(sizeof(struct arpcom), M_ZERO);
|
||||||
if (ifp->if_l2com == NULL) {
|
if (ifp->if_l2com == NULL)
|
||||||
_kernel_free(ifp);
|
goto err2;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
IFP2AC(ifp)->ac_ifp = ifp;
|
IFP2AC(ifp)->ac_ifp = ifp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ifp->link_state_sem = -1;
|
||||||
|
ifp->flags = 0;
|
||||||
|
ifq_init(&ifp->receive_queue, semName);
|
||||||
|
|
||||||
ifp->if_type = type;
|
ifp->if_type = type;
|
||||||
IF_ADDR_LOCK_INIT(ifp);
|
IF_ADDR_LOCK_INIT(ifp);
|
||||||
return 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)
|
if (ifp->if_type == IFT_ETHER)
|
||||||
_kernel_free(ifp->if_l2com);
|
_kernel_free(ifp->if_l2com);
|
||||||
|
|
||||||
|
delete_sem(ifp->receive_sem);
|
||||||
|
ifq_uninit(&ifp->receive_queue);
|
||||||
|
|
||||||
_kernel_free(ifp);
|
_kernel_free(ifp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,28 +80,29 @@ if_free(struct ifnet *ifp)
|
|||||||
void
|
void
|
||||||
if_initname(struct ifnet *ifp, const char *name, int unit)
|
if_initname(struct ifnet *ifp, const char *name, int unit)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
|
|
||||||
dprintf("if_initname(%p, %s, %d)\n", ifp, name, unit);
|
dprintf("if_initname(%p, %s, %d)\n", ifp, name, unit);
|
||||||
|
|
||||||
if (name == NULL)
|
if (name == NULL)
|
||||||
panic("interface goes unamed");
|
panic("interface goes unamed");
|
||||||
|
|
||||||
|
if (gDeviceCount >= MAX_DEVICES)
|
||||||
|
panic("unit too large");
|
||||||
|
|
||||||
ifp->if_dname = name;
|
ifp->if_dname = name;
|
||||||
ifp->if_dunit = unit;
|
ifp->if_dunit = unit;
|
||||||
|
ifp->if_index = gDeviceCount++;
|
||||||
|
|
||||||
strlcpy(ifp->if_xname, name, sizeof(ifp->if_xname));
|
strlcpy(ifp->if_xname, name, sizeof(ifp->if_xname));
|
||||||
|
|
||||||
for (i = 0; gDevNameList[i] != NULL; i++) {
|
snprintf(ifp->device_name, sizeof(ifp->device_name), "net/%s/%i",
|
||||||
if (strcmp(gDevNameList[i], name) == 0)
|
gDriverName, ifp->if_index);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gDevNameList[i] == NULL)
|
driver_printf("%s: /dev/%s\n", gDriverName, ifp->device_name);
|
||||||
panic("unknown interface");
|
|
||||||
|
|
||||||
ifp->if_dev = DEVNET(gDevices[i]);
|
gDeviceNameList[ifp->if_index] = ifp->device_name;
|
||||||
gDevices[i]->ifp = ifp;
|
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);
|
vsnprintf(buf, sizeof(buf), format, vl);
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
|
|
||||||
dprintf("[%s] %s", ifp->if_xname, buf);
|
dprintf("[%s] %s", ifp->device_name, buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
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;
|
return;
|
||||||
|
|
||||||
ifp->if_link_state = link_state;
|
ifp->if_link_state = linkState;
|
||||||
|
release_sem_etc(ifp->link_state_sem, 1, B_DO_NOT_RESCHEDULE);
|
||||||
release_sem_etc(NETDEV(ifp->if_dev)->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
|
static void
|
||||||
ether_input(struct ifnet *ifp, struct mbuf *m)
|
ether_input(struct ifnet *ifp, struct mbuf *m)
|
||||||
{
|
{
|
||||||
device_t dev = ifp->if_dev;
|
IF_ENQUEUE(&ifp->receive_queue, m);
|
||||||
|
release_sem_etc(ifp->receive_sem, 1, B_DO_NOT_RESCHEDULE);
|
||||||
IF_ENQUEUE(&NETDEV(dev)->receive_queue, m);
|
|
||||||
release_sem_etc(NETDEV(dev)->receive_sem, 1, B_DO_NOT_RESCHEDULE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007, Hugo Santos, [email protected]. All Rights Reserved.
|
||||||
|
* Copyright 2007, Axel Dörfler, [email protected]. 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;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user