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:
Augustin Cavalier
2019-11-22 22:19:43 -05:00
parent a70e506a80
commit 56cb682b80
7 changed files with 1030 additions and 1067 deletions
+2 -2
View File
@@ -16,11 +16,10 @@ KernelStaticLibrary libfreebsd_network.a :
bus.cpp
callout.cpp
clock.c
compat.c
compat_cpp.cpp
condvar.c
Condvar.cpp
device.c
device_hooks.c
driver.c
eventhandler.c
fbsd_busdma_x86.c
@@ -38,6 +37,7 @@ KernelStaticLibrary libfreebsd_network.a :
firmware.c
if.c
libkern.cpp
malloc.cpp
mbuf.c
mii.c
mutex.c
-726
View File
@@ -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 */
+623 -266
View File
@@ -1,305 +1,662 @@
/*
* Copyright 2007-2009, Axel Dörfler, [email protected].
* Copyright 2007, Hugo Santos. All Rights Reserved.
* 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 <stdlib.h>
#include <sys/sockio.h>
#include <stdio.h>
#include <Drivers.h>
#include <ether_driver.h>
#include <compat/sys/haiku-module.h>
#include <KernelExport.h>
#include <image.h>
#include <kernel/heap.h>
#include <compat/machine/resource.h>
#include <compat/dev/mii/mii.h>
#include <compat/sys/bus.h>
#include <compat/sys/mbuf.h>
#include <compat/net/ethernet.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;
struct ifreq ifr;
int i;
status_t status;
list_init_etc(&device->children, offsetof(struct device, link));
device->unit = sNextUnit++;
for (i = 0; i < MAX_DEVICES; i++) {
if (gDevices[i] != NULL && !strcmp(gDevices[i]->device_name, name))
break;
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;
}
if (i == MAX_DEVICES)
return B_ERROR;
return dev;
}
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);
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;
}
}
ifp->if_flags |= IFF_UP;
ifp->flags &= ~DEVICE_CLOSED;
ifp->if_ioctl(ifp, SIOCSIFFLAGS, NULL);
*cookie = ifp;
return B_OK;
return B_ENTRY_NOT_FOUND;
}
static status_t
compat_close(void *cookie)
static device_method_signature_t
resolve_method(driver_t *driver, const char *name)
{
struct ifnet *ifp = cookie;
device_method_signature_t method = NULL;
int i;
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;
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
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)
int
resource_int_value(const char *name, int unit, const char *resname,
int *result)
{
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);
/* no support for hints */
return -1;
}
static status_t
compat_control(void *cookie, uint32 op, void *arg, size_t length)
int
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,
// 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);
error = resource_int_value(name, unit, "disabled", &value);
if (error)
return (0);
return (value);
}
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,
};
+100
View File
@@ -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;
}