kolibrios/drivers/devman/acpi.c

976 lines
25 KiB
C
Raw Normal View History

#include <ddk.h>
#include <linux/errno.h>
#include <mutex.h>
#include <pci.h>
#include <syscall.h>
#include "acpi.h"
#include "acpi_bus.h"
#define PREFIX "ACPI: "
#define ACPI_BUS_CLASS "system_bus"
#define ACPI_BUS_HID "KLBSYBUS"
#define ACPI_BUS_DEVICE_NAME "System Bus"
#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent)
static LIST_HEAD(acpi_device_list);
static LIST_HEAD(acpi_bus_id_list);
struct acpi_device_bus_id
{
char bus_id[15];
unsigned int instance_no;
struct list_head node;
};
#define ACPI_NS_ROOT_PATH "\\"
#define ACPI_NS_SYSTEM_BUS "_SB_"
enum acpi_irq_model_id {
ACPI_IRQ_MODEL_PIC = 0,
ACPI_IRQ_MODEL_IOAPIC,
ACPI_IRQ_MODEL_IOSAPIC,
ACPI_IRQ_MODEL_PLATFORM,
ACPI_IRQ_MODEL_COUNT
};
enum acpi_bus_removal_type {
ACPI_BUS_REMOVAL_NORMAL = 0,
ACPI_BUS_REMOVAL_EJECT,
ACPI_BUS_REMOVAL_SUPRISE,
ACPI_BUS_REMOVAL_TYPE_COUNT
};
#define PCI_MAX_DEVICES 32
#define PCI_MAX_PINS 4
#define IRQ_TABLE_ENTRIES (PCI_MAX_DEVICES * PCI_MAX_PINS)
static int irqtable[IRQ_TABLE_ENTRIES];
static ACPI_HANDLE pci_root_handle;
#define addr_offset(addr, off) \
(addr_t)((addr_t)(addr) + (addr_t)(off))
//#define acpi_remap( addr ) \
// (addr_t)((addr_t)(addr) + OS_BASE)
#define acpi_remap( addr ) MapIoMem((void*)(addr),4096, 0x01)
void print_pci_irqs();
struct acpi_device *acpi_root;
extern struct resource iomem_resource;
extern struct resource ioport_resource;
enum pic_mode
{
IO_PIC = 0,
IO_APIC
};
static void set_pic_mode(enum pic_mode mode)
{
ACPI_OBJECT arg1;
ACPI_OBJECT_LIST args;
ACPI_STATUS as;
arg1.Type = ACPI_TYPE_INTEGER;
arg1.Integer.Value = mode;
args.Count = 1;
args.Pointer = &arg1;
as = AcpiEvaluateObject(ACPI_ROOT_OBJECT, "_PIC", &args, NULL);
/*
* We can silently ignore failure as it may not be implemented, ACPI should
* provide us with correct information anyway
*/
if (ACPI_SUCCESS(as))
dbgprintf(PREFIX "machine set to %s mode\n", mode ? "APIC" : "PIC");
}
void print_device_tree(struct acpi_device *device)
{
struct acpi_device *child;
dbgprintf("%s\n", device->pnp.bus_id);
list_for_each_entry(child, &device->children, node)
{
print_device_tree(child);
};
};
static bool pci_use_crs = false;
#define IORESOURCE_BUS 0x00001000
extern struct list_head acpi_pci_roots;
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge"
static ACPI_STATUS
get_root_bridge_busnr_callback(ACPI_RESOURCE *resource, void *data)
{
struct resource *res = data;
ACPI_RESOURCE_ADDRESS64 address;
if (resource->Type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
resource->Type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
resource->Type != ACPI_RESOURCE_TYPE_ADDRESS64)
return AE_OK;
AcpiResourceToAddress64(resource, &address);
if ((address.AddressLength > 0) &&
(address.ResourceType == ACPI_BUS_NUMBER_RANGE)) {
res->start = address.Minimum;
res->end = address.Minimum + address.AddressLength - 1;
}
return AE_OK;
}
static ACPI_STATUS try_get_root_bridge_busnr(ACPI_HANDLE handle,
struct resource *res)
{
ACPI_STATUS status;
res->start = -1;
status =
AcpiWalkResources(handle, METHOD_NAME__CRS,
get_root_bridge_busnr_callback, res);
if (ACPI_FAILURE(status))
return status;
if (res->start == -1)
return AE_ERROR;
return AE_OK;
}
static void acpi_pci_bridge_scan(struct acpi_device *device)
{
int status;
struct acpi_device *child = NULL;
if (device->flags.bus_address)
if (device->parent && device->parent->ops.bind) {
status = device->parent->ops.bind(device);
if (!status) {
list_for_each_entry(child, &device->children, node)
acpi_pci_bridge_scan(child);
}
}
}
struct pci_root_info
{
struct acpi_device *bridge;
char *name;
unsigned int res_num;
struct resource *res;
struct pci_bus *bus;
int busnum;
};
static ACPI_STATUS
resource_to_addr(ACPI_RESOURCE *resource, ACPI_RESOURCE_ADDRESS64 *addr)
{
ACPI_STATUS status;
struct acpi_resource_memory24 *memory24;
struct acpi_resource_memory32 *memory32;
struct acpi_resource_fixed_memory32 *fixed_memory32;
memset(addr, 0, sizeof(*addr));
switch (resource->Type) {
case ACPI_RESOURCE_TYPE_MEMORY24:
memory24 = &resource->Data.Memory24;
addr->ResourceType = ACPI_MEMORY_RANGE;
addr->Minimum = memory24->Minimum;
addr->AddressLength = memory24->AddressLength;
addr->Maximum = addr->Minimum + addr->AddressLength - 1;
return AE_OK;
case ACPI_RESOURCE_TYPE_MEMORY32:
memory32 = &resource->Data.Memory32;
addr->ResourceType = ACPI_MEMORY_RANGE;
addr->Minimum = memory32->Minimum;
addr->AddressLength = memory32->AddressLength;
addr->Maximum = addr->Minimum + addr->AddressLength - 1;
return AE_OK;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
fixed_memory32 = &resource->Data.FixedMemory32;
addr->ResourceType = ACPI_MEMORY_RANGE;
addr->Minimum = fixed_memory32->Address;
addr->AddressLength = fixed_memory32->AddressLength;
addr->Maximum = addr->Minimum + addr->AddressLength - 1;
return AE_OK;
case ACPI_RESOURCE_TYPE_ADDRESS16:
case ACPI_RESOURCE_TYPE_ADDRESS32:
case ACPI_RESOURCE_TYPE_ADDRESS64:
status = AcpiResourceToAddress64(resource, addr);
if (ACPI_SUCCESS(status) &&
(addr->ResourceType == ACPI_MEMORY_RANGE ||
addr->ResourceType == ACPI_IO_RANGE) &&
addr->AddressLength > 0) {
return AE_OK;
}
break;
}
return AE_ERROR;
}
static ACPI_STATUS
count_resource(ACPI_RESOURCE *acpi_res, void *data)
{
struct pci_root_info *info = data;
ACPI_RESOURCE_ADDRESS64 addr;
ACPI_STATUS status;
status = resource_to_addr(acpi_res, &addr);
if (ACPI_SUCCESS(status))
info->res_num++;
return AE_OK;
}
static ACPI_STATUS setup_resource(ACPI_RESOURCE *acpi_res, void *data)
{
struct pci_root_info *info = data;
struct resource *res;
struct acpi_resource_address64 addr;
ACPI_STATUS status;
unsigned long flags;
struct resource *root, *conflict;
u64 start, end;
status = resource_to_addr(acpi_res, &addr);
if (!ACPI_SUCCESS(status))
return AE_OK;
if (addr.ResourceType == ACPI_MEMORY_RANGE)
{
root = &iomem_resource;
flags = IORESOURCE_MEM;
if (addr.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY)
flags |= IORESOURCE_PREFETCH;
}
else if (addr.ResourceType == ACPI_IO_RANGE)
{
root = &ioport_resource;
flags = IORESOURCE_IO;
} else
return AE_OK;
start = addr.Minimum + addr.TranslationOffset;
end = addr.Maximum + addr.TranslationOffset;
res = &info->res[info->res_num];
res->name = info->name;
res->flags = flags;
res->start = start;
res->end = end;
res->child = NULL;
if (!pci_use_crs) {
printk("host bridge window %pR (ignored)\n", res);
return AE_OK;
}
#if 0
conflict = insert_resource_conflict(root, res);
if (conflict) {
dev_err(&info->bridge->dev,
"address space collision: host bridge window %pR "
"conflicts with %s %pR\n",
res, conflict->name, conflict);
} else {
pci_bus_add_resource(info->bus, res, 0);
info->res_num++;
if (addr.translation_offset)
dev_info(&info->bridge->dev, "host bridge window %pR "
"(PCI address [%#llx-%#llx])\n",
res, res->start - addr.translation_offset,
res->end - addr.translation_offset);
else
dev_info(&info->bridge->dev,
"host bridge window %pR\n", res);
}
return AE_OK;
#endif
}
static void
get_current_resources(struct acpi_device *device, int busnum,
int domain, struct pci_bus *bus)
{
struct pci_root_info info;
size_t size;
char buf[64];
// if (pci_use_crs)
// pci_bus_remove_resources(bus);
info.bridge = device;
info.bus = bus;
info.res_num = 0;
AcpiWalkResources(device->handle, METHOD_NAME__CRS, count_resource,
&info);
if (!info.res_num)
return;
size = sizeof(*info.res) * info.res_num;
info.res = kmalloc(size, GFP_KERNEL);
if (!info.res)
goto res_alloc_fail;
vsprintf(buf,"PCI Bus %04x:%02x", domain, busnum);
info.name = strdup(buf);
if (!info.name)
goto name_alloc_fail;
info.res_num = 0;
AcpiWalkResources(device->handle, METHOD_NAME__CRS, setup_resource,
&info);
return;
name_alloc_fail:
kfree(info.res);
res_alloc_fail:
return;
}
struct pci_ops pci_root_ops = {
.read = NULL,
.write = NULL,
};
struct pci_bus* pci_acpi_scan_root(struct acpi_pci_root *root)
{
struct acpi_device *device = root->device;
int domain = root->segment;
int busnum = root->secondary.start;
struct pci_bus *bus;
struct pci_sysdata *sd;
int node = 0;
if (domain ) {
printk(KERN_WARNING "pci_bus %04x:%02x: "
"ignored (multiple domains not supported)\n",
domain, busnum);
return NULL;
}
/* Allocate per-root-bus (not per bus) arch-specific data.
* TODO: leak; this memory is never freed.
* It's arguable whether it's worth the trouble to care.
*/
sd = kzalloc(sizeof(*sd), GFP_KERNEL);
if (!sd) {
printk(KERN_WARNING "pci_bus %04x:%02x: "
"ignored (out of memory)\n", domain, busnum);
return NULL;
}
sd->domain = domain;
sd->node = node;
/*
* Maybe the desired pci bus has been already scanned. In such case
* it is unnecessary to scan the pci bus with the given domain,busnum.
*/
bus = pci_find_bus(domain, busnum);
if (bus) {
/*
* If the desired bus exits, the content of bus->sysdata will
* be replaced by sd.
*/
memcpy(bus->sysdata, sd, sizeof(*sd));
kfree(sd);
} else {
bus = pci_create_bus(busnum, &pci_root_ops, sd);
if (bus) {
get_current_resources(device, busnum, domain, bus);
bus->subordinate = pci_scan_child_bus(bus);
}
}
if (!bus)
kfree(sd);
if (bus && node != -1) {
printk("on NUMA node %d\n", node);
}
return bus;
}
static int acpi_pci_root_add(struct acpi_device *device)
{
unsigned long long segment, bus;
ACPI_STATUS status;
int result;
struct acpi_pci_root *root;
ACPI_HANDLE handle;
struct acpi_device *child;
u32 flags, base_flags;
root = kzalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
return -ENOMEM;
segment = 0;
status = acpi_evaluate_integer(device->handle, METHOD_NAME__SEG, NULL,
&segment);
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
printk(KERN_ERR PREFIX "can't evaluate _SEG\n");
result = -ENODEV;
goto end;
}
/* Check _CRS first, then _BBN. If no _BBN, default to zero. */
root->secondary.flags = IORESOURCE_BUS;
status = try_get_root_bridge_busnr(device->handle, &root->secondary);
if (ACPI_FAILURE(status))
{
/*
* We need both the start and end of the downstream bus range
* to interpret _CBA (MMCONFIG base address), so it really is
* supposed to be in _CRS. If we don't find it there, all we
* can do is assume [_BBN-0xFF] or [0-0xFF].
*/
root->secondary.end = 0xFF;
printk(KERN_WARNING PREFIX
"no secondary bus range in _CRS\n");
status = acpi_evaluate_integer(device->handle, METHOD_NAME__BBN, NULL, &bus);
if (ACPI_SUCCESS(status))
root->secondary.start = bus;
else if (status == AE_NOT_FOUND)
root->secondary.start = 0;
else {
printk(KERN_ERR PREFIX "can't evaluate _BBN\n");
result = -ENODEV;
goto end;
}
}
INIT_LIST_HEAD(&root->node);
root->device = device;
root->segment = segment & 0xFFFF;
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
device->driver_data = root;
/*
* All supported architectures that use ACPI have support for
* PCI domains, so we indicate this in _OSC support capabilities.
*/
// flags = base_flags = OSC_PCI_SEGMENT_GROUPS_SUPPORT;
// acpi_pci_osc_support(root, flags);
/*
* TBD: Need PCI interface for enumeration/configuration of roots.
*/
/* TBD: Locking */
list_add_tail(&root->node, &acpi_pci_roots);
printk(KERN_INFO PREFIX "%s [%s] (domain %04x %pR)\n",
acpi_device_name(device), acpi_device_bid(device),
root->segment, &root->secondary);
/*
* Scan the Root Bridge
* --------------------
* Must do this prior to any attempt to bind the root device, as the
* PCI namespace does not get created until this call is made (and
* thus the root bridge's pci_dev does not exist).
*/
root->bus = pci_acpi_scan_root(root);
if (!root->bus) {
printk(KERN_ERR PREFIX
"Bus %04x:%02x not present in PCI namespace\n",
root->segment, (unsigned int)root->secondary.start);
result = -ENODEV;
goto end;
}
/*
* Attach ACPI-PCI Context
* -----------------------
* Thus binding the ACPI and PCI devices.
*/
result = acpi_pci_bind_root(device);
if (result)
goto end;
/*
* PCI Routing Table
* -----------------
* Evaluate and parse _PRT, if exists.
*/
status = AcpiGetHandle(device->handle, METHOD_NAME__PRT, &handle);
if (ACPI_SUCCESS(status))
result = acpi_pci_irq_add_prt(device->handle, root->bus);
/*
* Scan and bind all _ADR-Based Devices
*/
list_for_each_entry(child, &device->children, node)
acpi_pci_bridge_scan(child);
return 0;
end:
if (!list_empty(&root->node))
list_del(&root->node);
kfree(root);
return result;
}
static const struct acpi_device_ids root_device_ids[] =
{
{"PNP0A03", 0},
{"", 0},
};
void acpi_init_pci(struct acpi_device *device)
{
struct acpi_device *child;
if ( !acpi_match_device_ids(device, root_device_ids) )
{
dbgprintf(PREFIX "PCI root %s\n", device->pnp.bus_id);
acpi_pci_root_add(device);
};
list_for_each_entry(child, &device->children, node)
{
acpi_init_pci(child);
};
};
u32_t drvEntry(int action, char *cmdline)
{
u32_t retval;
ACPI_STATUS status;
int i;
if(action != 1)
return 0;
if( !dbg_open("/rd/1/drivers/acpi.log") )
{
printf("Can't open /rd/1/drivers/acpi.log\nExit\n");
return 0;
}
status = AcpiReallocateRootTable();
if (ACPI_FAILURE(status)) {
dbgprintf("Unable to reallocate ACPI tables\n");
goto err;
}
status = AcpiInitializeSubsystem();
if (status != AE_OK) {
dbgprintf("AcpiInitializeSubsystem failed (%s)\n",
AcpiFormatException(status));
goto err;
}
status = AcpiInitializeTables(NULL, 0, TRUE);
if (status != AE_OK) {
dbgprintf("AcpiInitializeTables failed (%s)\n",
AcpiFormatException(status));
goto err;
}
status = AcpiLoadTables();
if (status != AE_OK) {
dbgprintf("AcpiLoadTables failed (%s)\n",
AcpiFormatException(status));
goto err;
}
// u32_t mode = ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE;
status = AcpiEnableSubsystem(0);
if (status != AE_OK) {
dbgprintf("AcpiEnableSubsystem failed (%s)\n",
AcpiFormatException(status));
goto err;
}
status = AcpiInitializeObjects (0);
if (ACPI_FAILURE (status))
{
dbgprintf("AcpiInitializeObjects failed (%s)\n",
AcpiFormatException(status));
goto err;
}
set_pic_mode(IO_APIC);
acpi_scan();
// print_device_tree(acpi_root);
acpi_init_pci(acpi_root);
print_pci_irqs();
/*
ACPI_HANDLE bus_handle;
ACPI_HANDLE pci_root;
status = AcpiGetHandle(0, "\\_SB_", &bus_handle);
dbgprintf("system bus handle %x\n", bus_handle);
status = AcpiGetHandle(bus_handle, "PCI0", &pci_root);
if (status != AE_OK) {
dbgprintf("AcpiGetHandle failed (%s)\n",
AcpiFormatException(status));
goto err;
}
AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 100,
get_device_by_hid_callback, NULL, NULL, NULL);
*/
#if 0
AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 4,
get_device_by_hid_callback, NULL, NULL, NULL);
ACPI_OBJECT obj;
ACPI_HANDLE bus_handle;
ACPI_HANDLE pci_root;
status = AcpiGetHandle(0, "\\_SB_", &bus_handle);
dbgprintf("system bus handle %x\n", bus_handle);
status = AcpiGetHandle(bus_handle, "PCI0", &pci_root);
if (status != AE_OK) {
dbgprintf("AcpiGetHandle failed (%s)\n",
AcpiFormatException(status));
goto err;
}
dbgprintf("pci root handle %x\n\n", pci_root);
ACPI_BUFFER prt_buffer;
prt_buffer.Length = ACPI_ALLOCATE_BUFFER;
prt_buffer.Pointer = NULL;
status = AcpiGetIrqRoutingTable(pci_root, &prt_buffer);
if (status != AE_OK) {
dbgprintf("AcpiGetIrqRoutingTable failed (%s)\n",
AcpiFormatException(status));
goto err;
}
prt_walk_table(&prt_buffer);
ACPI_OBJECT arg = { ACPI_TYPE_INTEGER };
ACPI_OBJECT_LIST arg_list = { 1, &arg };
arg.Integer.Value = ACPI_IRQ_MODEL_IOAPIC;
dbgprintf("\nset ioapic mode\n\n");
status = AcpiEvaluateObject(NULL, "\\_PIC", &arg_list, NULL);
if (ACPI_FAILURE(status)) {
dbgprintf("AcpiEvaluateObject failed (%s)\n",
AcpiFormatException(status));
// goto err;
}
status = AcpiGetIrqRoutingTable(pci_root, &prt_buffer);
if (status != AE_OK) {
dbgprintf("AcpiGetIrqRoutingTable failed (%s)\n",
AcpiFormatException(status));
goto err;
}
prt_walk_table(&prt_buffer);
u8_t pin = PciRead8 (0, (31<<3) | 1, 0x3D);
dbgprintf("bus 0 device 31 function 1 pin %d\n", pin-1);
pin = PciRead8 (0, (31<<3) | 2, 0x3D);
dbgprintf("bus 0 device 31 function 2 pin %d\n", pin-1);
pin = PciRead8 (0, (31<<3) | 3, 0x3D);
dbgprintf("bus 0 device 31 function 3 pin %d\n", pin-1);
pin = PciRead8 (0, (31<<3) | 4, 0x3D);
dbgprintf("bus 0 device 31 function 4 pin %d\n", pin-1);
pin = PciRead8 (0, (31<<3) | 5, 0x3D);
dbgprintf("bus 0 device 31 function 5 pin %d\n", pin-1);
pin = PciRead8 (0, (31<<3) | 6, 0x3D);
dbgprintf("bus 0 device 31 function 6 pin %d\n", pin-1);
pin = PciRead8 (0, (31<<3) | 7, 0x3D);
dbgprintf("bus 0 device 31 function 7 pin %d\n", pin-1);
#endif
err:
return 0;
};
#if 0
ACPI_STATUS
get_device_by_hid_callback(ACPI_HANDLE obj, u32_t depth, void* context,
void** retval)
{
static u32_t counter = 0;
static char buff[256];
ACPI_STATUS status;
ACPI_BUFFER buffer;
ACPI_DEVICE_INFO *info;
// *retval = NULL;
buffer.Length = 255;
buffer.Pointer = buff;
status = AcpiGetName(obj, ACPI_FULL_PATHNAME, &buffer);
if (status != AE_OK) {
return AE_CTRL_TERMINATE;
}
buff[buffer.Length] = '\0';
dbgprintf("device %d %s ", counter, buff);
status = AcpiGetObjectInfo(obj, &info);
if (ACPI_SUCCESS (status))
{
if (info->Valid & ACPI_VALID_HID)
dbgprintf (" HID: %s", info->HardwareId.String);
};
dbgprintf("\n");
counter++;
return AE_OK;
}
prt_walk_table(ACPI_BUFFER *prt)
{
ACPI_PCI_ROUTING_TABLE *entry;
char *prtptr;
/* First check to see if there is a table to walk. */
if (prt == NULL || prt->Pointer == NULL)
return;
/* Walk the table executing the handler function for each entry. */
prtptr = prt->Pointer;
entry = (ACPI_PCI_ROUTING_TABLE *)prtptr;
while (entry->Length != 0)
{
dbgprintf("adress: %x %x ", (u32_t)(entry->Address>>32),
(u32_t)entry->Address);
dbgprintf("pin: %d index: %d source: %s\n",
entry->Pin,
entry->SourceIndex,
entry->Source);
// handler(entry, arg);
prtptr += entry->Length;
entry = (ACPI_PCI_ROUTING_TABLE *)prtptr;
}
}
static void add_irq(unsigned dev, unsigned pin, u8_t irq)
{
// assert(dev < PCI_MAX_DEVICES && pin < PCI_MAX_PINS);
irqtable[dev * PCI_MAX_PINS + pin] = irq;
}
static ACPI_STATUS get_irq_resource(ACPI_RESOURCE *res, void *context)
{
ACPI_PCI_ROUTING_TABLE *tbl = (ACPI_PCI_ROUTING_TABLE *) context;
if (res->Type == ACPI_RESOURCE_TYPE_IRQ)
{
ACPI_RESOURCE_IRQ *irq;
irq = &res->Data.Irq;
add_irq(tbl->Address >> 16, tbl->Pin,
irq->Interrupts[tbl->SourceIndex]);
} else if (res->Type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ)
{
ACPI_RESOURCE_EXTENDED_IRQ *irq;
add_irq(tbl->Address >> 16, tbl->Pin,
irq->Interrupts[tbl->SourceIndex]);
}
return AE_OK;
}
char buff[4096];
static ACPI_STATUS get_pci_irq_routing(ACPI_HANDLE handle)
{
ACPI_STATUS status;
ACPI_BUFFER abuff;
ACPI_PCI_ROUTING_TABLE *tbl;
abuff.Length = sizeof(buff);
abuff.Pointer = buff;
status = AcpiGetIrqRoutingTable(handle, &abuff);
if (ACPI_FAILURE(status)) {
return AE_OK;
}
for (tbl = (ACPI_PCI_ROUTING_TABLE *)abuff.Pointer; tbl->Length;
tbl = (ACPI_PCI_ROUTING_TABLE *)
((char *)tbl + tbl->Length))
{
ACPI_HANDLE src_handle;
if (*(char*)tbl->Source == '\0') {
add_irq(tbl->Address >> 16, tbl->Pin, tbl->SourceIndex);
continue;
}
status = AcpiGetHandle(handle, tbl->Source, &src_handle);
if (ACPI_FAILURE(status)) {
printf("Failed AcpiGetHandle\n");
continue;
}
status = AcpiWalkResources(src_handle, METHOD_NAME__CRS,
get_irq_resource, tbl);
if (ACPI_FAILURE(status)) {
printf("Failed IRQ resource\n");
continue;
}
}
return AE_OK;
}
static ACPI_STATUS add_pci_root_dev(ACPI_HANDLE handle,
UINT32 level,
void *context,
void **retval)
{
int i;
static unsigned called;
if (++called > 1) {
dbgprintf("ACPI: Warning! Multi rooted PCI is not supported!\n");
return AE_OK;
}
for (i = 0; i < IRQ_TABLE_ENTRIES; i++)
irqtable[i] = -1;
return get_pci_irq_routing(handle);
}
static ACPI_STATUS add_pci_dev(ACPI_HANDLE handle,
UINT32 level,
void *context,
void **retval)
{
/* skip pci root when we get to it again */
if (handle == pci_root_handle)
return AE_OK;
return get_pci_irq_routing(handle);
}
static void scan_devices(void)
{
ACPI_STATUS status;
/* get the root first */
status = AcpiGetDevices("PNP0A03", add_pci_root_dev, NULL, NULL);
if (status != AE_OK) {
dbgprintf("scan_devices failed (%s)\n",
AcpiFormatException(status));
return;
}
// assert(ACPI_SUCCESS(status));
/* get the rest of the devices that implement _PRT */
status = AcpiGetDevices(NULL, add_pci_dev, NULL, NULL);
// assert(ACPI_SUCCESS(status));
}
#endif
char* strdup(const char *str)
{
size_t len = strlen (str) + 1;
char *copy = malloc(len);
if (copy)
{
memcpy (copy, str, len);
}
return copy;
}