#include <ddk.h>
#include <linux/errno.h>
#include <mutex.h>
#include <pci.h>
#include <syscall.h>

#include "acpi.h"
#include "acpi_bus.h"
#include "dmdev.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)

LIST_HEAD(acpi_device_list);
LIST_HEAD(acpi_bus_id_list);
LIST_HEAD(dmdev_tree);


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)

char* strdup(const char *str);
int sprintf(char *buf, const char *fmt, ...);

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 ACPI_STATUS
resource_to_addr(ACPI_RESOURCE *resource, ACPI_RESOURCE_ADDRESS64 *addr);

static void create_dm_list();

static void print_dm_list();

int write_device_dat(char *path);


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");
}



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;
    u64 start, end;

    status = resource_to_addr(acpi_res, &addr);
    if (!ACPI_SUCCESS(status))
        return AE_OK;

    if (addr.ResourceType == ACPI_MEMORY_RANGE)
    {
        flags = IORESOURCE_MEM;
        if (addr.Info.Mem.Caching == ACPI_PREFETCHABLE_MEMORY)
            flags |= IORESOURCE_PREFETCH;
    }
    else if (addr.ResourceType == ACPI_IO_RANGE)
    {
        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;
    }

    info->res_num++;
    if (addr.TranslationOffset)
        dev_info(NULL, "host bridge window %pR "
             "(PCI address [%#llx-%#llx])\n",
             res, res->start - addr.TranslationOffset,
             res->end - addr.TranslationOffset);
    else
        dev_info(NULL,
             "host bridge window %pR\n", res);

    return AE_OK;
}



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;

    sprintf(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;
    }

	node = -1;
    /* 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 = AcpiInitializeSubsystem();
    if (status != AE_OK) {
          dbgprintf("AcpiInitializeSubsystem failed (%s)\n",
                     AcpiFormatException(status));
          goto err;
    }

    status = AcpiInitializeTables (NULL, 16, FALSE);
    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(ACPI_NO_HANDLER_INIT | ACPI_NO_HARDWARE_INIT);
    if (status != AE_OK) {
        dbgprintf("AcpiEnableSubsystem failed (%s)\n",
            AcpiFormatException(status));
        goto err;
    }

    status = AcpiInitializeObjects (ACPI_FULL_INITIALIZATION);
    if (ACPI_FAILURE (status))
    {
        dbgprintf("AcpiInitializeObjects failed (%s)\n",
            AcpiFormatException(status));
        goto err;
    }


    set_pic_mode(IO_APIC);

    acpi_scan();

    acpi_init_pci(acpi_root);

    print_pci_irqs();

    create_dm_list();

    print_dm_list();

    write_device_dat("/RD/1/DRIVERS/DEVICES.DAT");

err:

    return 0;

};

char* strdup(const char *str)
{
    size_t len = strlen (str) + 1;
    char *copy = malloc(len);
    if (copy)
    {
        memcpy (copy, str, len);
    }
    return copy;
}


static void dm_add_pci_bus(struct pci_bus *bus)
{
    struct pci_bus *tbus;
    struct pci_dev *dev;
    dmdev_t        *dmdev;

    dmdev = (dmdev_t*)kzalloc(sizeof(dmdev_t),GFP_KERNEL);

//    INIT_LIST_HEAD(&dmdev->list);
//    dmdev->type = 1;
//    dmdev->acpi_dev = bus->self->acpi_dev;
//    dmdev->pci_dev = bus->self;
//    list_add_tail(&dmdev->list, &dmdev_tree);

    list_for_each_entry(dev, &bus->devices, bus_list)
    {
        dmdev = (dmdev_t*)kzalloc(sizeof(dmdev_t),GFP_KERNEL);

        INIT_LIST_HEAD(&dmdev->list);
        dmdev->type = 1;
        dmdev->acpi_dev = dev->acpi_dev;
        dmdev->pci_dev = dev;
        list_add_tail(&dmdev->list, &dmdev_tree);
    };

    list_for_each_entry(tbus, &bus->children, node)
    {
        dm_add_pci_bus(tbus);
    };

};

static ACPI_STATUS
count_dev_resources(ACPI_RESOURCE *acpi_res, void *data)
{
    (*(int*)data)++;
    return AE_OK;
}


static void dm_add_acpi(struct acpi_device *device)
{
    struct acpi_device *child;
    ACPI_DEVICE_INFO *info = NULL;
    ACPI_STATUS status;

    dmdev_t  *dmdev;
    uint32_t  res_num = 0;

    status = AcpiGetObjectInfo(device->handle, &info);

    if ( (status == AE_OK) && (info->Valid & ACPI_VALID_HID))
    {
        if( strcmp(info->HardwareId.String,"PNP0C0F") == 0)
        {
            kfree(info);
            return;
        };
    };

    kfree(info);

    if(device->pci_dev == NULL)
    {
        AcpiWalkResources(device->handle, METHOD_NAME__CRS,
                          count_dev_resources, &res_num);

        if(res_num != 0)
        {
            dmdev = (dmdev_t*)kzalloc(sizeof(dmdev_t),GFP_KERNEL);

            INIT_LIST_HEAD(&dmdev->list);
            dmdev->type = 0;
            dmdev->acpi_dev = device;
            dmdev->pci_dev = NULL;
            list_add_tail(&dmdev->list, &dmdev_tree);
        };
    };
    list_for_each_entry(child, &device->children, node)
    {
        dm_add_acpi(child);
    };
};

static void create_dm_list()
{
    struct acpi_pci_root *root;


    list_for_each_entry(root, &acpi_pci_roots, node)
    {
        struct pci_bus *pbus, *tbus;
        struct pci_dev *dev;

        pbus = root->bus;

        dm_add_pci_bus(pbus);
    };

    dm_add_acpi(acpi_root);
};

static void print_pci_resource(struct resource *res)
{
    if(res->flags !=0 )
    {
        if(res->flags & IORESOURCE_IO)
            dbgprintf("  IO range ");
        else if(res->flags & IORESOURCE_MEM)
            dbgprintf("  MMIO range ");
        dbgprintf("%x - %x\n", res->start, res->end);
    };
};

static ACPI_STATUS
print_acpi_resource(ACPI_RESOURCE *acpi_res, void *data)
{
    ACPI_RESOURCE_ADDRESS64 addr;
    ACPI_STATUS status;
    int i;

    switch (acpi_res->Type)
    {
        case ACPI_RESOURCE_TYPE_IRQ:
        {
            ACPI_RESOURCE_IRQ *irq_data = (ACPI_RESOURCE_IRQ*)&acpi_res->Data;
            dbgprintf(" IRQ %d\n", irq_data->Interrupts[0]);
        };
        break;

        case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
        {
            ACPI_RESOURCE_EXTENDED_IRQ *irq_data = (ACPI_RESOURCE_EXTENDED_IRQ*)&acpi_res->Data;
            dbgprintf(" IRQ %d\n", irq_data->Interrupts[0]);
        };
        break;

        case ACPI_RESOURCE_TYPE_DMA:
        {
            ACPI_RESOURCE_DMA *dma_data = (ACPI_RESOURCE_DMA*) &acpi_res->Data;
            for(i=0; i < dma_data->ChannelCount; i++)
            {
                dbgprintf(" DMA %s channel %d\n",
                          dma_data->Type == ACPI_TYPE_A ? "Type A":
                          dma_data->Type == ACPI_TYPE_B ? "Type B" :
                          dma_data->Type == ACPI_TYPE_F ? "Type F" : "",
                          dma_data->Channels[i]);
            }
        };
        break;

        case ACPI_RESOURCE_TYPE_IO:
        {
            ACPI_RESOURCE_IO *io_data = (ACPI_RESOURCE_IO*) &acpi_res->Data;

            dbgprintf(" IO range 0%x-0%x\n",io_data->Minimum,
                       io_data->Minimum+io_data->AddressLength-1);
        }
        break;

        case ACPI_RESOURCE_TYPE_FIXED_IO:
        {
            ACPI_RESOURCE_FIXED_IO *io_data = (ACPI_RESOURCE_FIXED_IO*) &acpi_res->Data;
            dbgprintf(" Fixed IO range 0%x-0%x\n",io_data->Address,
                       io_data->Address+io_data->AddressLength-1);
        };
        break;

        case ACPI_RESOURCE_TYPE_MEMORY24:
        case ACPI_RESOURCE_TYPE_MEMORY32:
        case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
        {
            ACPI_RESOURCE_ADDRESS64 addr64;
            resource_to_addr(acpi_res, &addr64);
            dbgprintf(" Memory range 0%x-0%x\n",
                       (uint32_t)addr64.Minimum, (uint32_t)addr64.Maximum);
        }
        break;

        case ACPI_RESOURCE_TYPE_ADDRESS16:
        case ACPI_RESOURCE_TYPE_ADDRESS32:
        case ACPI_RESOURCE_TYPE_ADDRESS64:
        {
            ACPI_RESOURCE_ADDRESS64 addr64;
            ACPI_STATUS status;

            status = AcpiResourceToAddress64(acpi_res, &addr64);
            if (ACPI_SUCCESS(status))
            {
                dbgprintf(" Address range 0%x-0%x\n",
                       (uint32_t)addr64.Minimum, (uint32_t)addr64.Maximum);
            }
        };
        break;
    };

    return AE_OK;
};


static void print_dm_list()
{
    struct pci_dev     *pcidev;
    struct acpi_device *acpidev;
    dmdev_t  *dmdev;
    uint32_t  i;

    dbgprintf("\nDevices:\n");

    list_for_each_entry(dmdev, &dmdev_tree, list)
    {
        switch(dmdev->type)
        {
            case 0:
               if(dmdev->acpi_dev != NULL)
               {
                    acpidev = dmdev->acpi_dev;
                    dbgprintf("\n%s\n", acpidev->pnp.bus_id);
                    AcpiWalkResources(acpidev->handle, METHOD_NAME__CRS,
                                      print_acpi_resource, NULL);
               };
               break;

            case 1:
               if(dmdev->pci_dev != NULL)
               {
                   pcidev = dmdev->pci_dev;
                   dbgprintf("\nPCI_%x_%x bus:%d devfn: %x\n",
                               pcidev->vendor, pcidev->device,
                               pcidev->busnr, pcidev->devfn);

                   for(i = 0; i < DEVICE_COUNT_RESOURCE; i++)
                       print_pci_resource(&pcidev->resource[i]);

                   if(pcidev->pin)
                       dbgprintf("  APIC IRQ: %d\n", acpi_get_irq(pcidev));
               };
               break;
        };
    };
};


typedef struct
{
    uint32_t  busaddr;
    uint32_t  devid;
    uint32_t  irq;
    uint32_t  unused;
}devinfo_t;

#pragma pack(push, 1)
typedef struct
{
  char sec;
  char min;
  char hour;
  char rsv;
}detime_t;

typedef struct
{
  char  day;
  char  month;
  short year;
}dedate_t;

typedef struct
{
  unsigned    attr;
  unsigned    flags;
  union
  {
     detime_t  ctime;
     unsigned  cr_time;
  };
  union
  {
     dedate_t  cdate;
     unsigned  cr_date;
  };
  union
  {
     detime_t  atime;
     unsigned  acc_time;
  };
  union
  {
     dedate_t  adate;
     unsigned  acc_date;
  };
  union
  {
     detime_t  mtime;
     unsigned  mod_time;
  };
  union
  {
     dedate_t  mdate;
     unsigned  mod_date;
  };
  unsigned    size;
  unsigned    size_high;
} FILEINFO;

#pragma pack(pop)


int write_device_dat(char *path)
{
    struct pci_dev   *pcidev;
    dmdev_t          *dmdev;
    devinfo_t        *data;
    int               writes;
    int               len;
    int i = 0;

    list_for_each_entry(dmdev, &dmdev_tree, list)
    {
        if(dmdev->type ==1)
        {
            if(dmdev->pci_dev != NULL)
            {
                pcidev = dmdev->pci_dev;
                if(pcidev->pin)
                    i++;
            };
        };
    };

    len = sizeof(devinfo_t)*i + 4;
    data = (devinfo_t*)malloc(len);

    i = 0;

    list_for_each_entry(dmdev, &dmdev_tree, list)
    {
        if(dmdev->type == 1)
        {

            if(dmdev->pci_dev != NULL)
            {
                pcidev = dmdev->pci_dev;
                if(pcidev->pin && (acpi_get_irq(pcidev) != -1) )
                {
                    data[i].busaddr = (pcidev->busnr<<8)|pcidev->devfn;
                    data[i].devid   = ((uint32_t)pcidev->device<<16) |
                                       pcidev->vendor;
                    data[i].irq     =  acpi_get_irq(pcidev);
                    data[i].unused  =  0;
                    i++;
                }
            };
        };
    };

    data[i].busaddr = -1;

    FILEINFO info;

    int offset = 0;

    if(get_fileinfo(path,&info))
    {
        if( create_file(path))
        {
            free(data);
            return false;
        }
    }
    else
        set_file_size(path, 0);

    write_file(path, data, 0, len, &writes);

    return true;
};