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:
parent
423e822abe
commit
080b265acd
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
224
src/libs/compat/freebsd_network/driver.c
Normal file
224
src/libs/compat/freebsd_network/driver.c
Normal 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);
|
||||
}
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
206
src/libs/compat/freebsd_network/pci.c
Normal file
206
src/libs/compat/freebsd_network/pci.c
Normal 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user