freebsd_network: Moderate reorganization.
* Rename device.c to device_hooks.c, as this is what it really contains. * Rename compat.c to device.c, as it implements the generic "device" related functions, both for compat layer internals and FreeBSD public ones. * Move malloc and related operations out of the now-device.c, and place them in a new "malloc.cpp", which also incorporates compat_cpp.cpp. No functional change intended.
This commit is contained in:
@@ -16,11 +16,10 @@ KernelStaticLibrary libfreebsd_network.a :
|
|||||||
bus.cpp
|
bus.cpp
|
||||||
callout.cpp
|
callout.cpp
|
||||||
clock.c
|
clock.c
|
||||||
compat.c
|
|
||||||
compat_cpp.cpp
|
|
||||||
condvar.c
|
condvar.c
|
||||||
Condvar.cpp
|
Condvar.cpp
|
||||||
device.c
|
device.c
|
||||||
|
device_hooks.c
|
||||||
driver.c
|
driver.c
|
||||||
eventhandler.c
|
eventhandler.c
|
||||||
fbsd_busdma_x86.c
|
fbsd_busdma_x86.c
|
||||||
@@ -38,6 +37,7 @@ KernelStaticLibrary libfreebsd_network.a :
|
|||||||
firmware.c
|
firmware.c
|
||||||
if.c
|
if.c
|
||||||
libkern.cpp
|
libkern.cpp
|
||||||
|
malloc.cpp
|
||||||
mbuf.c
|
mbuf.c
|
||||||
mii.c
|
mii.c
|
||||||
mutex.c
|
mutex.c
|
||||||
|
|||||||
@@ -1,726 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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 <kernel/heap.h>
|
|
||||||
|
|
||||||
#include <util/BitUtils.h>
|
|
||||||
|
|
||||||
#include <compat/machine/resource.h>
|
|
||||||
#include <compat/dev/mii/mii.h>
|
|
||||||
#include <compat/sys/bus.h>
|
|
||||||
#include <compat/sys/malloc.h>
|
|
||||||
#include <compat/net/if_media.h>
|
|
||||||
|
|
||||||
#include <compat/dev/mii/miivar.h>
|
|
||||||
|
|
||||||
#include "compat_cpp.h"
|
|
||||||
|
|
||||||
|
|
||||||
spinlock __haiku_intr_spinlock;
|
|
||||||
|
|
||||||
struct net_stack_module_info *gStack;
|
|
||||||
pci_module_info *gPci;
|
|
||||||
struct pci_x86_module_info *gPCIx86;
|
|
||||||
|
|
||||||
static struct list sRootDevices;
|
|
||||||
static int sNextUnit;
|
|
||||||
|
|
||||||
// #pragma mark - private functions
|
|
||||||
|
|
||||||
|
|
||||||
static device_t
|
|
||||||
init_device(device_t device, driver_t *driver)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 (((addr_t)info.text <= (addr_t)find_own_image
|
|
||||||
&& (addr_t)info.text + (addr_t)info.text_size
|
|
||||||
> (addr_t)find_own_image)) {
|
|
||||||
// found our own image
|
|
||||||
return info.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return B_ENTRY_NOT_FOUND;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (method == NULL)
|
|
||||||
panic("resolve_method: method%s not found\n", name);
|
|
||||||
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Device
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
driver_printf(const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list vl;
|
|
||||||
va_start(vl, format);
|
|
||||||
driver_vprintf(format, vl);
|
|
||||||
va_end(vl);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
driver_vprintf_etc(const char *extra, const char *format, va_list vl)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
int ret = vsnprintf(buf, sizeof(buf), format, vl);
|
|
||||||
|
|
||||||
if (extra)
|
|
||||||
dprintf("[%s] (%s) %s", gDriverName, extra, buf);
|
|
||||||
else
|
|
||||||
dprintf("[%s] %s", gDriverName, buf);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
driver_vprintf(const char *format, va_list vl)
|
|
||||||
{
|
|
||||||
return driver_vprintf_etc(NULL, format, vl);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
device_printf(device_t dev, const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list vl;
|
|
||||||
|
|
||||||
va_start(vl, format);
|
|
||||||
driver_vprintf_etc(dev->device_name, format, vl);
|
|
||||||
va_end(vl);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
device_set_desc(device_t dev, const char *desc)
|
|
||||||
{
|
|
||||||
dev->description = desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
device_set_desc_copy(device_t dev, const char *desc)
|
|
||||||
{
|
|
||||||
dev->description = strdup(desc);
|
|
||||||
dev->flags |= DEVICE_DESC_ALLOCED;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *
|
|
||||||
device_get_desc(device_t dev)
|
|
||||||
{
|
|
||||||
return dev->description;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
device_t
|
|
||||||
device_get_parent(device_t dev)
|
|
||||||
{
|
|
||||||
return dev->parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
devclass_t
|
|
||||||
device_get_devclass(device_t dev)
|
|
||||||
{
|
|
||||||
// TODO find out what to do
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
device_get_children(device_t dev, device_t **devlistp, int *devcountp)
|
|
||||||
{
|
|
||||||
int count;
|
|
||||||
device_t child = NULL;
|
|
||||||
device_t *list;
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
while ((child = list_get_next_item(&dev->children, child)) != NULL) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
list = malloc(count * sizeof(device_t));
|
|
||||||
if (!list)
|
|
||||||
return (ENOMEM);
|
|
||||||
|
|
||||||
count = 0;
|
|
||||||
while ((child = list_get_next_item(&dev->children, child)) != NULL) {
|
|
||||||
list[count] = child;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
*devlistp = list;
|
|
||||||
*devcountp = count;
|
|
||||||
|
|
||||||
return (0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
device_set_ivars(device_t dev, void *ivars)
|
|
||||||
{
|
|
||||||
dev->ivars = ivars;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void *
|
|
||||||
device_get_ivars(device_t dev)
|
|
||||||
{
|
|
||||||
return dev->ivars;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *
|
|
||||||
device_get_name(device_t dev)
|
|
||||||
{
|
|
||||||
if (dev == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return dev->device_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
device_get_unit(device_t dev)
|
|
||||||
{
|
|
||||||
return dev->unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const char *
|
|
||||||
device_get_nameunit(device_t dev)
|
|
||||||
{
|
|
||||||
return dev->nameunit;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void *
|
|
||||||
device_get_softc(device_t dev)
|
|
||||||
{
|
|
||||||
return dev->softc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
device_set_softc(device_t dev, void *softc)
|
|
||||||
{
|
|
||||||
if (dev->softc == softc)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if ((dev->flags & DEVICE_SOFTC_SET) == 0) {
|
|
||||||
// Not externally allocated. We own it so we must clean it up.
|
|
||||||
free(dev->softc);
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->softc = softc;
|
|
||||||
if (dev->softc != NULL)
|
|
||||||
dev->flags |= DEVICE_SOFTC_SET;
|
|
||||||
else
|
|
||||||
dev->flags &= ~DEVICE_SOFTC_SET;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
u_int32_t
|
|
||||||
device_get_flags(device_t dev)
|
|
||||||
{
|
|
||||||
return dev->flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
device_set_driver(device_t dev, driver_t *driver)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
dev->softc = malloc(driver->size);
|
|
||||||
if (dev->softc == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
memset(dev->softc, 0, driver->size);
|
|
||||||
dev->driver = driver;
|
|
||||||
|
|
||||||
for (i = 0; driver->methods[i].name != NULL; i++) {
|
|
||||||
device_method_t *mth = &driver->methods[i];
|
|
||||||
|
|
||||||
if (strcmp(mth->name, "device_register") == 0)
|
|
||||||
dev->methods.device_register = (void *)mth->method;
|
|
||||||
else if (strcmp(mth->name, "device_probe") == 0)
|
|
||||||
dev->methods.probe = (void *)mth->method;
|
|
||||||
else if (strcmp(mth->name, "device_attach") == 0)
|
|
||||||
dev->methods.attach = (void *)mth->method;
|
|
||||||
else if (strcmp(mth->name, "device_detach") == 0)
|
|
||||||
dev->methods.detach = (void *)mth->method;
|
|
||||||
else if (strcmp(mth->name, "device_suspend") == 0)
|
|
||||||
dev->methods.suspend = (void *)mth->method;
|
|
||||||
else if (strcmp(mth->name, "device_resume") == 0)
|
|
||||||
dev->methods.resume = (void *)mth->method;
|
|
||||||
else if (strcmp(mth->name, "device_shutdown") == 0)
|
|
||||||
dev->methods.shutdown = (void *)mth->method;
|
|
||||||
else if (strcmp(mth->name, "miibus_readreg") == 0)
|
|
||||||
dev->methods.miibus_readreg = (void *)mth->method;
|
|
||||||
else if (strcmp(mth->name, "miibus_writereg") == 0)
|
|
||||||
dev->methods.miibus_writereg = (void *)mth->method;
|
|
||||||
else if (strcmp(mth->name, "miibus_statchg") == 0)
|
|
||||||
dev->methods.miibus_statchg = (void *)mth->method;
|
|
||||||
else if (!strcmp(mth->name, "miibus_linkchg"))
|
|
||||||
dev->methods.miibus_linkchg = (void *)mth->method;
|
|
||||||
else if (!strcmp(mth->name, "miibus_mediainit"))
|
|
||||||
dev->methods.miibus_mediainit = (void *)mth->method;
|
|
||||||
else if (!strcmp(mth->name, "bus_child_location_str"))
|
|
||||||
dev->methods.bus_child_location_str = (void *)mth->method;
|
|
||||||
else if (!strcmp(mth->name, "bus_child_pnpinfo_str"))
|
|
||||||
dev->methods.bus_child_pnpinfo_str = (void *)mth->method;
|
|
||||||
else if (!strcmp(mth->name, "bus_hinted_child"))
|
|
||||||
dev->methods.bus_hinted_child = (void *)mth->method;
|
|
||||||
else if (!strcmp(mth->name, "bus_print_child"))
|
|
||||||
dev->methods.bus_print_child = (void *)mth->method;
|
|
||||||
else if (!strcmp(mth->name, "bus_read_ivar"))
|
|
||||||
dev->methods.bus_read_ivar = (void *)mth->method;
|
|
||||||
else if (!strcmp(mth->name, "bus_get_dma_tag"))
|
|
||||||
dev->methods.bus_get_dma_tag = (void *)mth->method;
|
|
||||||
else
|
|
||||||
panic("device_set_driver: method %s not found\n", mth->name);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
device_is_alive(device_t device)
|
|
||||||
{
|
|
||||||
return (device->flags & DEVICE_ATTACHED) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
device_t
|
|
||||||
device_add_child_driver(device_t parent, const char* name, driver_t* _driver,
|
|
||||||
int unit)
|
|
||||||
{
|
|
||||||
device_t child = NULL;
|
|
||||||
|
|
||||||
if (_driver == NULL && name != NULL) {
|
|
||||||
if (strcmp(name, "miibus") == 0)
|
|
||||||
child = new_device(&miibus_driver);
|
|
||||||
else {
|
|
||||||
// find matching driver structure
|
|
||||||
driver_t** driver;
|
|
||||||
char symbol[128];
|
|
||||||
|
|
||||||
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);
|
|
||||||
} else
|
|
||||||
device_printf(parent, "couldn't find symbol %s\n", symbol);
|
|
||||||
}
|
|
||||||
} else if (_driver != NULL) {
|
|
||||||
child = new_device(_driver);
|
|
||||||
} else
|
|
||||||
child = new_device(NULL);
|
|
||||||
|
|
||||||
if (child == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (name != NULL)
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
device_t
|
|
||||||
device_add_child(device_t parent, const char* name, int unit)
|
|
||||||
{
|
|
||||||
return device_add_child_driver(parent, name, NULL, unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! Delete the child and all of its children. Detach as necessary.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
device_delete_child(device_t parent, device_t child)
|
|
||||||
{
|
|
||||||
int status;
|
|
||||||
|
|
||||||
if (child == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (parent != NULL)
|
|
||||||
list_remove_item(&parent->children, child);
|
|
||||||
else
|
|
||||||
list_remove_item(&sRootDevices, child);
|
|
||||||
|
|
||||||
// We differentiate from the FreeBSD logic here - it will first delete
|
|
||||||
// the children, and will then detach the device.
|
|
||||||
// This has the problem that you cannot safely call device_delete_child()
|
|
||||||
// as you don't know if one of the children deletes its own children this
|
|
||||||
// way when it is detached.
|
|
||||||
// Therefore, we'll detach first, and then delete whatever is left.
|
|
||||||
|
|
||||||
parent = child;
|
|
||||||
child = NULL;
|
|
||||||
|
|
||||||
// detach children
|
|
||||||
while ((child = list_get_next_item(&parent->children, child)) != NULL) {
|
|
||||||
device_detach(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
// detach device
|
|
||||||
status = device_detach(parent);
|
|
||||||
if (status != 0)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
// delete children
|
|
||||||
while ((child = list_get_first_item(&parent->children)) != NULL) {
|
|
||||||
device_delete_child(parent, child);
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete device
|
|
||||||
if (parent->flags & DEVICE_DESC_ALLOCED)
|
|
||||||
free((char *)parent->description);
|
|
||||||
|
|
||||||
// Delete softc if we were the ones to allocate it.
|
|
||||||
if ((parent->flags & DEVICE_SOFTC_SET) == 0)
|
|
||||||
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
|
|
||||||
|| device->methods.attach == NULL)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
result = device->methods.attach(device);
|
|
||||||
|
|
||||||
if (result == 0)
|
|
||||||
atomic_or(&device->flags, DEVICE_ATTACHED);
|
|
||||||
|
|
||||||
if (result == 0 && HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE))
|
|
||||||
result = start_wlan(device);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
device_detach(device_t device)
|
|
||||||
{
|
|
||||||
if (device->driver == NULL)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
if ((atomic_and(&device->flags, ~DEVICE_ATTACHED) & DEVICE_ATTACHED) != 0
|
|
||||||
&& device->methods.detach != NULL) {
|
|
||||||
int result = 0;
|
|
||||||
if (HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE))
|
|
||||||
result = stop_wlan(device);
|
|
||||||
if (result != 0 && result != B_BAD_VALUE) {
|
|
||||||
atomic_or(&device->flags, DEVICE_ATTACHED);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = device->methods.detach(device);
|
|
||||||
if (result != 0) {
|
|
||||||
atomic_or(&device->flags, DEVICE_ATTACHED);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
bus_generic_attach(device_t dev)
|
|
||||||
{
|
|
||||||
device_t child = NULL;
|
|
||||||
|
|
||||||
while ((child = list_get_next_item(&dev->children, child)) != NULL) {
|
|
||||||
if (child->driver == NULL) {
|
|
||||||
driver_t *driver = __haiku_select_miibus_driver(child);
|
|
||||||
if (driver == NULL) {
|
|
||||||
struct mii_attach_args *ma = device_get_ivars(child);
|
|
||||||
|
|
||||||
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
|
|
||||||
child->methods.probe(child);
|
|
||||||
|
|
||||||
if (child->driver != NULL) {
|
|
||||||
int result = device_attach(child);
|
|
||||||
if (result != 0)
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
bus_generic_detach(device_t device)
|
|
||||||
{
|
|
||||||
device_t child = NULL;
|
|
||||||
|
|
||||||
if ((device->flags & DEVICE_ATTACHED) == 0)
|
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
child = list_get_next_item(&device->children, child);
|
|
||||||
if (child == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
device_detach(child);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// #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, ...)
|
|
||||||
{
|
|
||||||
char buf[256];
|
|
||||||
va_list vl;
|
|
||||||
va_start(vl, format);
|
|
||||||
vsnprintf(buf, sizeof(buf), format, vl);
|
|
||||||
va_end(vl);
|
|
||||||
dprintf(buf);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __clang__
|
|
||||||
int
|
|
||||||
ffs(int value)
|
|
||||||
{
|
|
||||||
int i = 1;
|
|
||||||
|
|
||||||
if (value == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (; !(value & 1); i++)
|
|
||||||
value >>= 1;
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
resource_int_value(const char *name, int unit, const char *resname,
|
|
||||||
int *result)
|
|
||||||
{
|
|
||||||
/* no support for hints */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
resource_disabled(const char *name, int unit)
|
|
||||||
{
|
|
||||||
int error, value;
|
|
||||||
|
|
||||||
error = resource_int_value(name, unit, "disabled", &value);
|
|
||||||
if (error)
|
|
||||||
return (0);
|
|
||||||
return (value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void *
|
|
||||||
_kernel_malloc(size_t size, int flags)
|
|
||||||
{
|
|
||||||
// According to the FreeBSD kernel malloc man page the allocator is expected
|
|
||||||
// to return power of two aligned addresses for allocations up to one page
|
|
||||||
// size. While it also states that this shouldn't be relied upon, at least
|
|
||||||
// bus_dmamem_alloc expects it and drivers may depend on it as well.
|
|
||||||
void *ptr
|
|
||||||
= memalign_etc(size >= PAGESIZE ? PAGESIZE : next_power_of_2(size), size,
|
|
||||||
(flags & M_NOWAIT) ? HEAP_DONT_WAIT_FOR_MEMORY : 0);
|
|
||||||
if (ptr == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (flags & M_ZERO)
|
|
||||||
memset(ptr, 0, size);
|
|
||||||
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
_kernel_free(void *ptr)
|
|
||||||
{
|
|
||||||
free(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void *
|
|
||||||
_kernel_contigmalloc(const char *file, int line, size_t size, int flags,
|
|
||||||
vm_paddr_t low, vm_paddr_t high, unsigned long alignment,
|
|
||||||
unsigned long boundary)
|
|
||||||
{
|
|
||||||
return _kernel_contigmalloc_cpp(file, line, size, low, high,
|
|
||||||
alignment, boundary, (flags & M_ZERO) != 0, (flags & M_NOWAIT) != 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
_kernel_contigfree(void *addr, size_t size)
|
|
||||||
{
|
|
||||||
delete_area(area_for(addr));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
vm_paddr_t
|
|
||||||
pmap_kextract(vm_offset_t virtualAddress)
|
|
||||||
{
|
|
||||||
physical_entry entry;
|
|
||||||
status_t status = get_memory_map((void *)virtualAddress, 1, &entry, 1);
|
|
||||||
if (status < B_OK) {
|
|
||||||
panic("fbsd compat: get_memory_map failed for %p, error %08" B_PRIx32
|
|
||||||
"\n", (void *)virtualAddress, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (vm_paddr_t)entry.address;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010, Ingo Weinhold, [email protected].
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "compat_cpp.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <kernel/vm/vm.h>
|
|
||||||
|
|
||||||
|
|
||||||
void*
|
|
||||||
_kernel_contigmalloc_cpp(const char* file, int line, size_t size,
|
|
||||||
phys_addr_t low, phys_addr_t high, phys_size_t alignment,
|
|
||||||
phys_size_t boundary, bool zero, bool dontWait)
|
|
||||||
{
|
|
||||||
size = ROUNDUP(size, B_PAGE_SIZE);
|
|
||||||
|
|
||||||
uint32 creationFlags = (zero ? 0 : CREATE_AREA_DONT_CLEAR)
|
|
||||||
| (dontWait ? CREATE_AREA_DONT_WAIT : 0);
|
|
||||||
|
|
||||||
char name[B_OS_NAME_LENGTH];
|
|
||||||
const char* baseName = strrchr(file, '/');
|
|
||||||
baseName = baseName != NULL ? baseName + 1 : file;
|
|
||||||
snprintf(name, sizeof(name), "contig:%s:%d", baseName, line);
|
|
||||||
|
|
||||||
virtual_address_restrictions virtualRestrictions = {};
|
|
||||||
|
|
||||||
physical_address_restrictions physicalRestrictions = {};
|
|
||||||
physicalRestrictions.low_address = low;
|
|
||||||
physicalRestrictions.high_address = high;
|
|
||||||
physicalRestrictions.alignment = alignment;
|
|
||||||
physicalRestrictions.boundary = boundary;
|
|
||||||
|
|
||||||
void* address;
|
|
||||||
area_id area = create_area_etc(B_SYSTEM_TEAM, name, size, B_CONTIGUOUS,
|
|
||||||
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, creationFlags, 0,
|
|
||||||
&virtualRestrictions, &physicalRestrictions, &address);
|
|
||||||
if (area < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010, Ingo Weinhold, [email protected].
|
|
||||||
* Distributed under the terms of the MIT License.
|
|
||||||
*/
|
|
||||||
#ifndef _FREE_BSD_NETWORK_COMPAT_CPP_H
|
|
||||||
#define _FREE_BSD_NETWORK_COMPAT_CPP_H
|
|
||||||
|
|
||||||
|
|
||||||
#include <SupportDefs.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
void* _kernel_contigmalloc_cpp(const char* file, int line, size_t size,
|
|
||||||
phys_addr_t low, phys_addr_t high, phys_size_t alignment,
|
|
||||||
phys_size_t boundary, bool zero, bool dontWait);
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* _FREE_BSD_NETWORK_COMPAT_CPP_H */
|
|
||||||
@@ -1,305 +1,662 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007-2009, Axel Dörfler, [email protected].
|
* Copyright 2007, Hugo Santos, [email protected]. 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdio.h>
|
||||||
#include <sys/sockio.h>
|
|
||||||
|
|
||||||
#include <Drivers.h>
|
#include <KernelExport.h>
|
||||||
#include <ether_driver.h>
|
#include <image.h>
|
||||||
|
#include <kernel/heap.h>
|
||||||
#include <compat/sys/haiku-module.h>
|
|
||||||
|
|
||||||
|
#include <compat/machine/resource.h>
|
||||||
|
#include <compat/dev/mii/mii.h>
|
||||||
#include <compat/sys/bus.h>
|
#include <compat/sys/bus.h>
|
||||||
#include <compat/sys/mbuf.h>
|
|
||||||
#include <compat/net/ethernet.h>
|
|
||||||
#include <compat/net/if_media.h>
|
#include <compat/net/if_media.h>
|
||||||
|
|
||||||
|
#include <compat/dev/mii/miivar.h>
|
||||||
|
|
||||||
static status_t
|
|
||||||
compat_open(const char *name, uint32 flags, void **cookie)
|
spinlock __haiku_intr_spinlock;
|
||||||
|
|
||||||
|
struct net_stack_module_info *gStack;
|
||||||
|
pci_module_info *gPci;
|
||||||
|
struct pci_x86_module_info *gPCIx86;
|
||||||
|
|
||||||
|
static struct list sRootDevices;
|
||||||
|
static int sNextUnit;
|
||||||
|
|
||||||
|
// #pragma mark - private functions
|
||||||
|
|
||||||
|
|
||||||
|
static device_t
|
||||||
|
init_device(device_t device, driver_t *driver)
|
||||||
{
|
{
|
||||||
struct ifnet *ifp;
|
list_init_etc(&device->children, offsetof(struct device, link));
|
||||||
struct ifreq ifr;
|
device->unit = sNextUnit++;
|
||||||
|
|
||||||
|
if (driver != NULL && device_set_driver(device, driver) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 (((addr_t)info.text <= (addr_t)find_own_image
|
||||||
|
&& (addr_t)info.text + (addr_t)info.text_size
|
||||||
|
> (addr_t)find_own_image)) {
|
||||||
|
// found our own image
|
||||||
|
return info.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static device_method_signature_t
|
||||||
|
resolve_method(driver_t *driver, const char *name)
|
||||||
|
{
|
||||||
|
device_method_signature_t method = NULL;
|
||||||
int i;
|
int i;
|
||||||
status_t status;
|
|
||||||
|
|
||||||
for (i = 0; i < MAX_DEVICES; i++) {
|
for (i = 0; method == NULL && driver->methods[i].name != NULL; i++) {
|
||||||
if (gDevices[i] != NULL && !strcmp(gDevices[i]->device_name, name))
|
if (strcmp(driver->methods[i].name, name) == 0)
|
||||||
break;
|
method = driver->methods[i].method;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == MAX_DEVICES)
|
if (method == NULL)
|
||||||
return B_ERROR;
|
panic("resolve_method: method%s not found\n", name);
|
||||||
|
|
||||||
if (get_module(NET_STACK_MODULE_NAME, (module_info **)&gStack) != B_OK)
|
return method;
|
||||||
return B_ERROR;
|
|
||||||
|
|
||||||
ifp = gDevices[i];
|
|
||||||
if_printf(ifp, "compat_open(0x%" B_PRIx32 ")\n", flags);
|
|
||||||
|
|
||||||
if (atomic_or(&ifp->open_count, 1)) {
|
|
||||||
put_module(NET_STACK_MODULE_NAME);
|
|
||||||
return B_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
ifp->if_init(ifp->if_softc);
|
|
||||||
|
|
||||||
if (!HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE)) {
|
|
||||||
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);
|
|
||||||
status = ifp->if_ioctl(ifp, SIOCSIFMEDIA, (caddr_t)&ifr);
|
|
||||||
if (status != B_OK) {
|
|
||||||
ifr.ifr_media = IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0);
|
|
||||||
status = ifp->if_ioctl(ifp, SIOCSIFMEDIA, (caddr_t)&ifr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ifp->if_flags |= IFF_UP;
|
|
||||||
ifp->flags &= ~DEVICE_CLOSED;
|
|
||||||
ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
|
|
||||||
|
|
||||||
*cookie = ifp;
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
// #pragma mark - Device
|
||||||
compat_close(void *cookie)
|
|
||||||
|
|
||||||
|
void
|
||||||
|
driver_printf(const char *format, ...)
|
||||||
{
|
{
|
||||||
struct ifnet *ifp = cookie;
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
if_printf(ifp, "compat_close()\n");
|
driver_vprintf(format, vl);
|
||||||
|
va_end(vl);
|
||||||
atomic_or(&ifp->flags, DEVICE_CLOSED);
|
|
||||||
|
|
||||||
wlan_close(cookie);
|
|
||||||
|
|
||||||
release_sem_etc(ifp->receive_sem, 1, B_RELEASE_ALL);
|
|
||||||
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
static int
|
||||||
compat_free(void *cookie)
|
driver_vprintf_etc(const char *extra, const char *format, va_list vl)
|
||||||
{
|
{
|
||||||
struct ifnet *ifp = cookie;
|
char buf[256];
|
||||||
|
int ret = vsnprintf(buf, sizeof(buf), format, vl);
|
||||||
|
|
||||||
if_printf(ifp, "compat_free()\n");
|
if (extra)
|
||||||
|
dprintf("[%s] (%s) %s", gDriverName, extra, buf);
|
||||||
|
else
|
||||||
|
dprintf("[%s] %s", gDriverName, buf);
|
||||||
|
|
||||||
// TODO: empty out the send queue
|
return ret;
|
||||||
|
|
||||||
atomic_and(&ifp->open_count, 0);
|
|
||||||
put_module(NET_STACK_MODULE_NAME);
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
int
|
||||||
compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
|
driver_vprintf(const char *format, va_list vl)
|
||||||
{
|
{
|
||||||
struct ifnet *ifp = cookie;
|
return driver_vprintf_etc(NULL, format, vl);
|
||||||
uint32 semFlags = B_CAN_INTERRUPT;
|
}
|
||||||
status_t status;
|
|
||||||
struct mbuf *mb;
|
|
||||||
size_t length;
|
|
||||||
|
|
||||||
//if_printf(ifp, "compat_read(%lld, %p, [%lu])\n", position,
|
|
||||||
// buffer, *numBytes);
|
|
||||||
|
|
||||||
if (ifp->flags & DEVICE_CLOSED)
|
int
|
||||||
return B_INTERRUPTED;
|
device_printf(device_t dev, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list vl;
|
||||||
|
|
||||||
if (ifp->flags & DEVICE_NON_BLOCK)
|
va_start(vl, format);
|
||||||
semFlags |= B_RELATIVE_TIMEOUT;
|
driver_vprintf_etc(dev->device_name, format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
do {
|
|
||||||
status = acquire_sem_etc(ifp->receive_sem, 1, semFlags, 0);
|
|
||||||
if (ifp->flags & DEVICE_CLOSED)
|
|
||||||
return B_INTERRUPTED;
|
|
||||||
|
|
||||||
if (status == B_WOULD_BLOCK) {
|
void
|
||||||
*numBytes = 0;
|
device_set_desc(device_t dev, const char *desc)
|
||||||
return B_OK;
|
{
|
||||||
} else if (status < B_OK)
|
dev->description = desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
device_set_desc_copy(device_t dev, const char *desc)
|
||||||
|
{
|
||||||
|
dev->description = strdup(desc);
|
||||||
|
dev->flags |= DEVICE_DESC_ALLOCED;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *
|
||||||
|
device_get_desc(device_t dev)
|
||||||
|
{
|
||||||
|
return dev->description;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_t
|
||||||
|
device_get_parent(device_t dev)
|
||||||
|
{
|
||||||
|
return dev->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
devclass_t
|
||||||
|
device_get_devclass(device_t dev)
|
||||||
|
{
|
||||||
|
// TODO find out what to do
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
device_get_children(device_t dev, device_t **devlistp, int *devcountp)
|
||||||
|
{
|
||||||
|
int count;
|
||||||
|
device_t child = NULL;
|
||||||
|
device_t *list;
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
while ((child = list_get_next_item(&dev->children, child)) != NULL) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
list = malloc(count * sizeof(device_t));
|
||||||
|
if (!list)
|
||||||
|
return (ENOMEM);
|
||||||
|
|
||||||
|
count = 0;
|
||||||
|
while ((child = list_get_next_item(&dev->children, child)) != NULL) {
|
||||||
|
list[count] = child;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*devlistp = list;
|
||||||
|
*devcountp = count;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
device_set_ivars(device_t dev, void *ivars)
|
||||||
|
{
|
||||||
|
dev->ivars = ivars;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
device_get_ivars(device_t dev)
|
||||||
|
{
|
||||||
|
return dev->ivars;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *
|
||||||
|
device_get_name(device_t dev)
|
||||||
|
{
|
||||||
|
if (dev == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return dev->device_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
device_get_unit(device_t dev)
|
||||||
|
{
|
||||||
|
return dev->unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *
|
||||||
|
device_get_nameunit(device_t dev)
|
||||||
|
{
|
||||||
|
return dev->nameunit;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
device_get_softc(device_t dev)
|
||||||
|
{
|
||||||
|
return dev->softc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
device_set_softc(device_t dev, void *softc)
|
||||||
|
{
|
||||||
|
if (dev->softc == softc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((dev->flags & DEVICE_SOFTC_SET) == 0) {
|
||||||
|
// Not externally allocated. We own it so we must clean it up.
|
||||||
|
free(dev->softc);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->softc = softc;
|
||||||
|
if (dev->softc != NULL)
|
||||||
|
dev->flags |= DEVICE_SOFTC_SET;
|
||||||
|
else
|
||||||
|
dev->flags &= ~DEVICE_SOFTC_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
u_int32_t
|
||||||
|
device_get_flags(device_t dev)
|
||||||
|
{
|
||||||
|
return dev->flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
device_set_driver(device_t dev, driver_t *driver)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
dev->softc = malloc(driver->size);
|
||||||
|
if (dev->softc == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset(dev->softc, 0, driver->size);
|
||||||
|
dev->driver = driver;
|
||||||
|
|
||||||
|
for (i = 0; driver->methods[i].name != NULL; i++) {
|
||||||
|
device_method_t *mth = &driver->methods[i];
|
||||||
|
|
||||||
|
if (strcmp(mth->name, "device_register") == 0)
|
||||||
|
dev->methods.device_register = (void *)mth->method;
|
||||||
|
else if (strcmp(mth->name, "device_probe") == 0)
|
||||||
|
dev->methods.probe = (void *)mth->method;
|
||||||
|
else if (strcmp(mth->name, "device_attach") == 0)
|
||||||
|
dev->methods.attach = (void *)mth->method;
|
||||||
|
else if (strcmp(mth->name, "device_detach") == 0)
|
||||||
|
dev->methods.detach = (void *)mth->method;
|
||||||
|
else if (strcmp(mth->name, "device_suspend") == 0)
|
||||||
|
dev->methods.suspend = (void *)mth->method;
|
||||||
|
else if (strcmp(mth->name, "device_resume") == 0)
|
||||||
|
dev->methods.resume = (void *)mth->method;
|
||||||
|
else if (strcmp(mth->name, "device_shutdown") == 0)
|
||||||
|
dev->methods.shutdown = (void *)mth->method;
|
||||||
|
else if (strcmp(mth->name, "miibus_readreg") == 0)
|
||||||
|
dev->methods.miibus_readreg = (void *)mth->method;
|
||||||
|
else if (strcmp(mth->name, "miibus_writereg") == 0)
|
||||||
|
dev->methods.miibus_writereg = (void *)mth->method;
|
||||||
|
else if (strcmp(mth->name, "miibus_statchg") == 0)
|
||||||
|
dev->methods.miibus_statchg = (void *)mth->method;
|
||||||
|
else if (!strcmp(mth->name, "miibus_linkchg"))
|
||||||
|
dev->methods.miibus_linkchg = (void *)mth->method;
|
||||||
|
else if (!strcmp(mth->name, "miibus_mediainit"))
|
||||||
|
dev->methods.miibus_mediainit = (void *)mth->method;
|
||||||
|
else if (!strcmp(mth->name, "bus_child_location_str"))
|
||||||
|
dev->methods.bus_child_location_str = (void *)mth->method;
|
||||||
|
else if (!strcmp(mth->name, "bus_child_pnpinfo_str"))
|
||||||
|
dev->methods.bus_child_pnpinfo_str = (void *)mth->method;
|
||||||
|
else if (!strcmp(mth->name, "bus_hinted_child"))
|
||||||
|
dev->methods.bus_hinted_child = (void *)mth->method;
|
||||||
|
else if (!strcmp(mth->name, "bus_print_child"))
|
||||||
|
dev->methods.bus_print_child = (void *)mth->method;
|
||||||
|
else if (!strcmp(mth->name, "bus_read_ivar"))
|
||||||
|
dev->methods.bus_read_ivar = (void *)mth->method;
|
||||||
|
else if (!strcmp(mth->name, "bus_get_dma_tag"))
|
||||||
|
dev->methods.bus_get_dma_tag = (void *)mth->method;
|
||||||
|
else
|
||||||
|
panic("device_set_driver: method %s not found\n", mth->name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
device_is_alive(device_t device)
|
||||||
|
{
|
||||||
|
return (device->flags & DEVICE_ATTACHED) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_t
|
||||||
|
device_add_child_driver(device_t parent, const char* name, driver_t* _driver,
|
||||||
|
int unit)
|
||||||
|
{
|
||||||
|
device_t child = NULL;
|
||||||
|
|
||||||
|
if (_driver == NULL && name != NULL) {
|
||||||
|
if (strcmp(name, "miibus") == 0)
|
||||||
|
child = new_device(&miibus_driver);
|
||||||
|
else {
|
||||||
|
// find matching driver structure
|
||||||
|
driver_t** driver;
|
||||||
|
char symbol[128];
|
||||||
|
|
||||||
|
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);
|
||||||
|
} else
|
||||||
|
device_printf(parent, "couldn't find symbol %s\n", symbol);
|
||||||
|
}
|
||||||
|
} else if (_driver != NULL) {
|
||||||
|
child = new_device(_driver);
|
||||||
|
} else
|
||||||
|
child = new_device(NULL);
|
||||||
|
|
||||||
|
if (child == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (name != NULL)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_t
|
||||||
|
device_add_child(device_t parent, const char* name, int unit)
|
||||||
|
{
|
||||||
|
return device_add_child_driver(parent, name, NULL, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! Delete the child and all of its children. Detach as necessary.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
device_delete_child(device_t parent, device_t child)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (child == NULL)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (parent != NULL)
|
||||||
|
list_remove_item(&parent->children, child);
|
||||||
|
else
|
||||||
|
list_remove_item(&sRootDevices, child);
|
||||||
|
|
||||||
|
// We differentiate from the FreeBSD logic here - it will first delete
|
||||||
|
// the children, and will then detach the device.
|
||||||
|
// This has the problem that you cannot safely call device_delete_child()
|
||||||
|
// as you don't know if one of the children deletes its own children this
|
||||||
|
// way when it is detached.
|
||||||
|
// Therefore, we'll detach first, and then delete whatever is left.
|
||||||
|
|
||||||
|
parent = child;
|
||||||
|
child = NULL;
|
||||||
|
|
||||||
|
// detach children
|
||||||
|
while ((child = list_get_next_item(&parent->children, child)) != NULL) {
|
||||||
|
device_detach(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
// detach device
|
||||||
|
status = device_detach(parent);
|
||||||
|
if (status != 0)
|
||||||
return status;
|
return status;
|
||||||
|
|
||||||
IF_DEQUEUE(&ifp->receive_queue, mb);
|
// delete children
|
||||||
} while (mb == NULL);
|
while ((child = list_get_first_item(&parent->children)) != NULL) {
|
||||||
|
device_delete_child(parent, child);
|
||||||
|
}
|
||||||
|
|
||||||
length = min_c(max_c((size_t)mb->m_pkthdr.len, 0), *numBytes);
|
// delete device
|
||||||
|
if (parent->flags & DEVICE_DESC_ALLOCED)
|
||||||
|
free((char *)parent->description);
|
||||||
|
|
||||||
#if 0
|
// Delete softc if we were the ones to allocate it.
|
||||||
mb = m_defrag(mb, 0);
|
if ((parent->flags & DEVICE_SOFTC_SET) == 0)
|
||||||
if (mb == NULL) {
|
free(parent->softc);
|
||||||
*numBytes = 0;
|
|
||||||
return B_NO_MEMORY;
|
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
|
||||||
|
|| device->methods.attach == NULL)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
result = device->methods.attach(device);
|
||||||
|
|
||||||
|
if (result == 0)
|
||||||
|
atomic_or(&device->flags, DEVICE_ATTACHED);
|
||||||
|
|
||||||
|
if (result == 0 && HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE))
|
||||||
|
result = start_wlan(device);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
device_detach(device_t device)
|
||||||
|
{
|
||||||
|
if (device->driver == NULL)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if ((atomic_and(&device->flags, ~DEVICE_ATTACHED) & DEVICE_ATTACHED) != 0
|
||||||
|
&& device->methods.detach != NULL) {
|
||||||
|
int result = 0;
|
||||||
|
if (HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE))
|
||||||
|
result = stop_wlan(device);
|
||||||
|
if (result != 0 && result != B_BAD_VALUE) {
|
||||||
|
atomic_or(&device->flags, DEVICE_ATTACHED);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = device->methods.detach(device);
|
||||||
|
if (result != 0) {
|
||||||
|
atomic_or(&device->flags, DEVICE_ATTACHED);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
bus_generic_attach(device_t dev)
|
||||||
|
{
|
||||||
|
device_t child = NULL;
|
||||||
|
|
||||||
|
while ((child = list_get_next_item(&dev->children, child)) != NULL) {
|
||||||
|
if (child->driver == NULL) {
|
||||||
|
driver_t *driver = __haiku_select_miibus_driver(child);
|
||||||
|
if (driver == NULL) {
|
||||||
|
struct mii_attach_args *ma = device_get_ivars(child);
|
||||||
|
|
||||||
|
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
|
||||||
|
child->methods.probe(child);
|
||||||
|
|
||||||
|
if (child->driver != NULL) {
|
||||||
|
int result = device_attach(child);
|
||||||
|
if (result != 0)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
bus_generic_detach(device_t device)
|
||||||
|
{
|
||||||
|
device_t child = NULL;
|
||||||
|
|
||||||
|
if ((device->flags & DEVICE_ATTACHED) == 0)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
child = list_get_next_item(&device->children, child);
|
||||||
|
if (child == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
device_detach(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #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, ...)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl, format);
|
||||||
|
vsnprintf(buf, sizeof(buf), format, vl);
|
||||||
|
va_end(vl);
|
||||||
|
dprintf(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __clang__
|
||||||
|
int
|
||||||
|
ffs(int value)
|
||||||
|
{
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
if (value == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (; !(value & 1); i++)
|
||||||
|
value >>= 1;
|
||||||
|
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_copydata(mb, 0, length, buffer);
|
|
||||||
*numBytes = length;
|
|
||||||
|
|
||||||
m_freem(mb);
|
int
|
||||||
return B_OK;
|
resource_int_value(const char *name, int unit, const char *resname,
|
||||||
}
|
int *result)
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
|
||||||
compat_write(void *cookie, off_t position, const void *buffer,
|
|
||||||
size_t *numBytes)
|
|
||||||
{
|
{
|
||||||
struct ifnet *ifp = cookie;
|
/* no support for hints */
|
||||||
struct mbuf *mb;
|
return -1;
|
||||||
|
|
||||||
//if_printf(ifp, "compat_write(%lld, %p, [%lu])\n", position,
|
|
||||||
// buffer, *numBytes);
|
|
||||||
|
|
||||||
if (*numBytes > MHLEN) {
|
|
||||||
mb = m_getcl(0, MT_DATA, M_PKTHDR);
|
|
||||||
*numBytes = min_c(*numBytes, (size_t)MCLBYTES);
|
|
||||||
} else {
|
|
||||||
mb = m_gethdr(0, MT_DATA);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mb == NULL)
|
|
||||||
return ENOBUFS;
|
|
||||||
|
|
||||||
// if we waited, check after if the ifp is still valid
|
|
||||||
|
|
||||||
mb->m_pkthdr.len = mb->m_len = *numBytes;
|
|
||||||
memcpy(mtod(mb, void *), buffer, mb->m_len);
|
|
||||||
|
|
||||||
return ifp->if_output(ifp, mb, NULL, NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static status_t
|
int
|
||||||
compat_control(void *cookie, uint32 op, void *arg, size_t length)
|
resource_disabled(const char *name, int unit)
|
||||||
{
|
{
|
||||||
struct ifnet *ifp = cookie;
|
int error, value;
|
||||||
|
|
||||||
//if_printf(ifp, "compat_control(op %lu, %p, [%lu])\n", op,
|
error = resource_int_value(name, unit, "disabled", &value);
|
||||||
// arg, length);
|
if (error)
|
||||||
|
return (0);
|
||||||
switch (op) {
|
return (value);
|
||||||
case ETHER_INIT:
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
case ETHER_GETADDR:
|
|
||||||
return user_memcpy(arg, IF_LLADDR(ifp), ETHER_ADDR_LEN);
|
|
||||||
|
|
||||||
case ETHER_NONBLOCK:
|
|
||||||
{
|
|
||||||
int32 value;
|
|
||||||
if (length < 4)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
if (value)
|
|
||||||
ifp->flags |= DEVICE_NON_BLOCK;
|
|
||||||
else
|
|
||||||
ifp->flags &= ~DEVICE_NON_BLOCK;
|
|
||||||
return B_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case ETHER_SETPROMISC:
|
|
||||||
{
|
|
||||||
int32 value;
|
|
||||||
if (length < 4)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
|
|
||||||
return B_BAD_ADDRESS;
|
|
||||||
if (value)
|
|
||||||
ifp->if_flags |= IFF_PROMISC;
|
|
||||||
else
|
|
||||||
ifp->if_flags &= ~IFF_PROMISC;
|
|
||||||
return ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
case ETHER_GETFRAMESIZE:
|
|
||||||
{
|
|
||||||
uint32 frameSize;
|
|
||||||
if (length < 4)
|
|
||||||
return B_BAD_VALUE;
|
|
||||||
|
|
||||||
frameSize = ifp->if_mtu + ETHER_HDR_LEN;
|
|
||||||
return user_memcpy(arg, &frameSize, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
case ETHER_ADDMULTI:
|
|
||||||
case ETHER_REMMULTI:
|
|
||||||
{
|
|
||||||
struct sockaddr_dl address;
|
|
||||||
|
|
||||||
if ((ifp->if_flags & IFF_MULTICAST) == 0)
|
|
||||||
return B_NOT_SUPPORTED;
|
|
||||||
|
|
||||||
memset(&address, 0, sizeof(address));
|
|
||||||
address.sdl_family = AF_LINK;
|
|
||||||
memcpy(LLADDR(&address), arg, ETHER_ADDR_LEN);
|
|
||||||
|
|
||||||
if (op == ETHER_ADDMULTI)
|
|
||||||
return if_addmulti(ifp, (struct sockaddr *)&address, NULL);
|
|
||||||
|
|
||||||
return if_delmulti(ifp, (struct sockaddr *)&address);
|
|
||||||
}
|
|
||||||
|
|
||||||
case ETHER_GET_LINK_STATE:
|
|
||||||
{
|
|
||||||
struct ifmediareq mediareq;
|
|
||||||
ether_link_state_t state;
|
|
||||||
status_t status;
|
|
||||||
|
|
||||||
if (length < sizeof(ether_link_state_t))
|
|
||||||
return EINVAL;
|
|
||||||
|
|
||||||
memset(&mediareq, 0, sizeof(mediareq));
|
|
||||||
status = ifp->if_ioctl(ifp, SIOCGIFMEDIA, (caddr_t)&mediareq);
|
|
||||||
if (status < B_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
state.media = mediareq.ifm_active;
|
|
||||||
if ((mediareq.ifm_status & IFM_ACTIVE) != 0)
|
|
||||||
state.media |= IFM_ACTIVE;
|
|
||||||
if ((mediareq.ifm_active & IFM_10_T) != 0)
|
|
||||||
state.speed = 10000000;
|
|
||||||
else if ((mediareq.ifm_active & IFM_100_TX) != 0)
|
|
||||||
state.speed = 100000000;
|
|
||||||
else
|
|
||||||
state.speed = 1000000000;
|
|
||||||
state.quality = 1000;
|
|
||||||
|
|
||||||
return user_memcpy(arg, &state, sizeof(ether_link_state_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
case ETHER_SET_LINK_STATE_SEM:
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return wlan_control(cookie, op, arg, length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
device_hooks gDeviceHooks = {
|
|
||||||
compat_open,
|
|
||||||
compat_close,
|
|
||||||
compat_free,
|
|
||||||
compat_control,
|
|
||||||
compat_read,
|
|
||||||
compat_write,
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -0,0 +1,305 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2007-2009, Axel Dörfler, [email protected].
|
||||||
|
* Copyright 2007, Hugo Santos. All Rights Reserved.
|
||||||
|
* Copyright 2004, Marcus Overhagen. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#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>
|
||||||
|
#include <compat/net/if_media.h>
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
compat_open(const char *name, uint32 flags, void **cookie)
|
||||||
|
{
|
||||||
|
struct ifnet *ifp;
|
||||||
|
struct ifreq ifr;
|
||||||
|
int i;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
for (i = 0; i < MAX_DEVICES; i++) {
|
||||||
|
if (gDevices[i] != NULL && !strcmp(gDevices[i]->device_name, name))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i == MAX_DEVICES)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
if (get_module(NET_STACK_MODULE_NAME, (module_info **)&gStack) != B_OK)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
ifp = gDevices[i];
|
||||||
|
if_printf(ifp, "compat_open(0x%" B_PRIx32 ")\n", flags);
|
||||||
|
|
||||||
|
if (atomic_or(&ifp->open_count, 1)) {
|
||||||
|
put_module(NET_STACK_MODULE_NAME);
|
||||||
|
return B_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
|
ifp->if_init(ifp->if_softc);
|
||||||
|
|
||||||
|
if (!HAIKU_DRIVER_REQUIRES(FBSD_WLAN_FEATURE)) {
|
||||||
|
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);
|
||||||
|
status = ifp->if_ioctl(ifp, SIOCSIFMEDIA, (caddr_t)&ifr);
|
||||||
|
if (status != B_OK) {
|
||||||
|
ifr.ifr_media = IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, 0);
|
||||||
|
status = ifp->if_ioctl(ifp, SIOCSIFMEDIA, (caddr_t)&ifr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ifp->if_flags |= IFF_UP;
|
||||||
|
ifp->flags &= ~DEVICE_CLOSED;
|
||||||
|
ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
|
||||||
|
|
||||||
|
*cookie = ifp;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
compat_close(void *cookie)
|
||||||
|
{
|
||||||
|
struct ifnet *ifp = cookie;
|
||||||
|
|
||||||
|
if_printf(ifp, "compat_close()\n");
|
||||||
|
|
||||||
|
atomic_or(&ifp->flags, DEVICE_CLOSED);
|
||||||
|
|
||||||
|
wlan_close(cookie);
|
||||||
|
|
||||||
|
release_sem_etc(ifp->receive_sem, 1, B_RELEASE_ALL);
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
compat_free(void *cookie)
|
||||||
|
{
|
||||||
|
struct ifnet *ifp = cookie;
|
||||||
|
|
||||||
|
if_printf(ifp, "compat_free()\n");
|
||||||
|
|
||||||
|
// TODO: empty out the send queue
|
||||||
|
|
||||||
|
atomic_and(&ifp->open_count, 0);
|
||||||
|
put_module(NET_STACK_MODULE_NAME);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
compat_read(void *cookie, off_t position, void *buffer, size_t *numBytes)
|
||||||
|
{
|
||||||
|
struct ifnet *ifp = cookie;
|
||||||
|
uint32 semFlags = B_CAN_INTERRUPT;
|
||||||
|
status_t status;
|
||||||
|
struct mbuf *mb;
|
||||||
|
size_t length;
|
||||||
|
|
||||||
|
//if_printf(ifp, "compat_read(%lld, %p, [%lu])\n", position,
|
||||||
|
// buffer, *numBytes);
|
||||||
|
|
||||||
|
if (ifp->flags & DEVICE_CLOSED)
|
||||||
|
return B_INTERRUPTED;
|
||||||
|
|
||||||
|
if (ifp->flags & DEVICE_NON_BLOCK)
|
||||||
|
semFlags |= B_RELATIVE_TIMEOUT;
|
||||||
|
|
||||||
|
do {
|
||||||
|
status = acquire_sem_etc(ifp->receive_sem, 1, semFlags, 0);
|
||||||
|
if (ifp->flags & DEVICE_CLOSED)
|
||||||
|
return B_INTERRUPTED;
|
||||||
|
|
||||||
|
if (status == B_WOULD_BLOCK) {
|
||||||
|
*numBytes = 0;
|
||||||
|
return B_OK;
|
||||||
|
} else if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
IF_DEQUEUE(&ifp->receive_queue, mb);
|
||||||
|
} while (mb == NULL);
|
||||||
|
|
||||||
|
length = min_c(max_c((size_t)mb->m_pkthdr.len, 0), *numBytes);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
mb = m_defrag(mb, 0);
|
||||||
|
if (mb == NULL) {
|
||||||
|
*numBytes = 0;
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_copydata(mb, 0, length, buffer);
|
||||||
|
*numBytes = length;
|
||||||
|
|
||||||
|
m_freem(mb);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
compat_write(void *cookie, off_t position, const void *buffer,
|
||||||
|
size_t *numBytes)
|
||||||
|
{
|
||||||
|
struct ifnet *ifp = cookie;
|
||||||
|
struct mbuf *mb;
|
||||||
|
|
||||||
|
//if_printf(ifp, "compat_write(%lld, %p, [%lu])\n", position,
|
||||||
|
// buffer, *numBytes);
|
||||||
|
|
||||||
|
if (*numBytes > MHLEN) {
|
||||||
|
mb = m_getcl(0, MT_DATA, M_PKTHDR);
|
||||||
|
*numBytes = min_c(*numBytes, (size_t)MCLBYTES);
|
||||||
|
} else {
|
||||||
|
mb = m_gethdr(0, MT_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mb == NULL)
|
||||||
|
return ENOBUFS;
|
||||||
|
|
||||||
|
// if we waited, check after if the ifp is still valid
|
||||||
|
|
||||||
|
mb->m_pkthdr.len = mb->m_len = *numBytes;
|
||||||
|
memcpy(mtod(mb, void *), buffer, mb->m_len);
|
||||||
|
|
||||||
|
return ifp->if_output(ifp, mb, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
compat_control(void *cookie, uint32 op, void *arg, size_t length)
|
||||||
|
{
|
||||||
|
struct ifnet *ifp = cookie;
|
||||||
|
|
||||||
|
//if_printf(ifp, "compat_control(op %lu, %p, [%lu])\n", op,
|
||||||
|
// arg, length);
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case ETHER_INIT:
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
case ETHER_GETADDR:
|
||||||
|
return user_memcpy(arg, IF_LLADDR(ifp), ETHER_ADDR_LEN);
|
||||||
|
|
||||||
|
case ETHER_NONBLOCK:
|
||||||
|
{
|
||||||
|
int32 value;
|
||||||
|
if (length < 4)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
if (value)
|
||||||
|
ifp->flags |= DEVICE_NON_BLOCK;
|
||||||
|
else
|
||||||
|
ifp->flags &= ~DEVICE_NON_BLOCK;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ETHER_SETPROMISC:
|
||||||
|
{
|
||||||
|
int32 value;
|
||||||
|
if (length < 4)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
if (user_memcpy(&value, arg, sizeof(int32)) < B_OK)
|
||||||
|
return B_BAD_ADDRESS;
|
||||||
|
if (value)
|
||||||
|
ifp->if_flags |= IFF_PROMISC;
|
||||||
|
else
|
||||||
|
ifp->if_flags &= ~IFF_PROMISC;
|
||||||
|
return ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
case ETHER_GETFRAMESIZE:
|
||||||
|
{
|
||||||
|
uint32 frameSize;
|
||||||
|
if (length < 4)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
frameSize = ifp->if_mtu + ETHER_HDR_LEN;
|
||||||
|
return user_memcpy(arg, &frameSize, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
case ETHER_ADDMULTI:
|
||||||
|
case ETHER_REMMULTI:
|
||||||
|
{
|
||||||
|
struct sockaddr_dl address;
|
||||||
|
|
||||||
|
if ((ifp->if_flags & IFF_MULTICAST) == 0)
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
memset(&address, 0, sizeof(address));
|
||||||
|
address.sdl_family = AF_LINK;
|
||||||
|
memcpy(LLADDR(&address), arg, ETHER_ADDR_LEN);
|
||||||
|
|
||||||
|
if (op == ETHER_ADDMULTI)
|
||||||
|
return if_addmulti(ifp, (struct sockaddr *)&address, NULL);
|
||||||
|
|
||||||
|
return if_delmulti(ifp, (struct sockaddr *)&address);
|
||||||
|
}
|
||||||
|
|
||||||
|
case ETHER_GET_LINK_STATE:
|
||||||
|
{
|
||||||
|
struct ifmediareq mediareq;
|
||||||
|
ether_link_state_t state;
|
||||||
|
status_t status;
|
||||||
|
|
||||||
|
if (length < sizeof(ether_link_state_t))
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
memset(&mediareq, 0, sizeof(mediareq));
|
||||||
|
status = ifp->if_ioctl(ifp, SIOCGIFMEDIA, (caddr_t)&mediareq);
|
||||||
|
if (status < B_OK)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
state.media = mediareq.ifm_active;
|
||||||
|
if ((mediareq.ifm_status & IFM_ACTIVE) != 0)
|
||||||
|
state.media |= IFM_ACTIVE;
|
||||||
|
if ((mediareq.ifm_active & IFM_10_T) != 0)
|
||||||
|
state.speed = 10000000;
|
||||||
|
else if ((mediareq.ifm_active & IFM_100_TX) != 0)
|
||||||
|
state.speed = 100000000;
|
||||||
|
else
|
||||||
|
state.speed = 1000000000;
|
||||||
|
state.quality = 1000;
|
||||||
|
|
||||||
|
return user_memcpy(arg, &state, sizeof(ether_link_state_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
case ETHER_SET_LINK_STATE_SEM:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wlan_control(cookie, op, arg, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
device_hooks gDeviceHooks = {
|
||||||
|
compat_open,
|
||||||
|
compat_close,
|
||||||
|
compat_free,
|
||||||
|
compat_control,
|
||||||
|
compat_read,
|
||||||
|
compat_write,
|
||||||
|
};
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010, Ingo Weinhold, [email protected].
|
||||||
|
* Copyright 2019, Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <compat/sys/malloc.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <util/BitUtils.h>
|
||||||
|
|
||||||
|
#include <kernel/vm/vm.h>
|
||||||
|
|
||||||
|
|
||||||
|
void*
|
||||||
|
_kernel_malloc(size_t size, int flags)
|
||||||
|
{
|
||||||
|
// According to the FreeBSD kernel malloc man page the allocator is expected
|
||||||
|
// to return power of two aligned addresses for allocations up to one page
|
||||||
|
// size. While it also states that this shouldn't be relied upon, at least
|
||||||
|
// bus_dmamem_alloc expects it and drivers may depend on it as well.
|
||||||
|
void *ptr
|
||||||
|
= memalign_etc(size >= PAGESIZE ? PAGESIZE : next_power_of_2(size), size,
|
||||||
|
(flags & M_NOWAIT) ? HEAP_DONT_WAIT_FOR_MEMORY : 0);
|
||||||
|
if (ptr == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (flags & M_ZERO)
|
||||||
|
memset(ptr, 0, size);
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
_kernel_free(void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
_kernel_contigmalloc(const char *file, int line, size_t size, int flags,
|
||||||
|
vm_paddr_t low, vm_paddr_t high, unsigned long alignment,
|
||||||
|
unsigned long boundary)
|
||||||
|
{
|
||||||
|
const bool zero = (flags & M_ZERO) != 0, dontWait = (flags & M_NOWAIT) != 0;
|
||||||
|
|
||||||
|
size = ROUNDUP(size, B_PAGE_SIZE);
|
||||||
|
|
||||||
|
uint32 creationFlags = (zero ? 0 : CREATE_AREA_DONT_CLEAR)
|
||||||
|
| (dontWait ? CREATE_AREA_DONT_WAIT : 0);
|
||||||
|
|
||||||
|
char name[B_OS_NAME_LENGTH];
|
||||||
|
const char* baseName = strrchr(file, '/');
|
||||||
|
baseName = baseName != NULL ? baseName + 1 : file;
|
||||||
|
snprintf(name, sizeof(name), "contig:%s:%d", baseName, line);
|
||||||
|
|
||||||
|
virtual_address_restrictions virtualRestrictions = {};
|
||||||
|
|
||||||
|
physical_address_restrictions physicalRestrictions = {};
|
||||||
|
physicalRestrictions.low_address = low;
|
||||||
|
physicalRestrictions.high_address = high;
|
||||||
|
physicalRestrictions.alignment = alignment;
|
||||||
|
physicalRestrictions.boundary = boundary;
|
||||||
|
|
||||||
|
void* address;
|
||||||
|
area_id area = create_area_etc(B_SYSTEM_TEAM, name, size, B_CONTIGUOUS,
|
||||||
|
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA, creationFlags, 0,
|
||||||
|
&virtualRestrictions, &physicalRestrictions, &address);
|
||||||
|
if (area < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
_kernel_contigfree(void *addr, size_t size)
|
||||||
|
{
|
||||||
|
delete_area(area_for(addr));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vm_paddr_t
|
||||||
|
pmap_kextract(vm_offset_t virtualAddress)
|
||||||
|
{
|
||||||
|
physical_entry entry;
|
||||||
|
status_t status = get_memory_map((void *)virtualAddress, 1, &entry, 1);
|
||||||
|
if (status < B_OK) {
|
||||||
|
panic("fbsd compat: get_memory_map failed for %p, error %08" B_PRIx32
|
||||||
|
"\n", (void *)virtualAddress, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (vm_paddr_t)entry.address;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user