mirror of
https://github.com/KolibriOS/kolibrios.git
synced 2024-11-25 10:19:36 +03:00
4ccc803579
git-svn-id: svn://kolibrios.org@1633 a494cfbc-eb01-0410-851d-a64ba20cac60
976 lines
25 KiB
C
976 lines
25 KiB
C
|
|
#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;
|
|
}
|
|
|