!C99Shell v. 1.0 pre-release build #13!

Software: Apache/2.0.54 (Unix) mod_perl/1.99_09 Perl/v5.8.0 mod_ssl/2.0.54 OpenSSL/0.9.7l DAV/2 FrontPage/5.0.2.2635 PHP/4.4.0 mod_gzip/2.0.26.1a 

uname -a: Linux snow.he.net 4.4.276-v2-mono-1 #1 SMP Wed Jul 21 11:21:17 PDT 2021 i686 

uid=99(nobody) gid=98(nobody) groups=98(nobody) 

Safe-mode: OFF (not secure)

/usr/src/linux-2.4.18-xfs-1.1/drivers/pci/   drwxr-xr-x
Free 318.37 GB of 458.09 GB (69.5%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Feedback    Self remove    Logout    


Viewing file:     pci.c (53.41 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
/*
 *    $Id: pci.c,v 1.91 1999/01/21 13:34:01 davem Exp $
 *
 *    PCI Bus Services, see include/linux/pci.h for further explanation.
 *
 *    Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter,
 *    David Mosberger-Tang
 *
 *    Copyright 1997 -- 2000 Martin Mares <mj@ucw.cz>
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/kmod.h>        /* for hotplug_path */
#include <linux/bitops.h>
#include <linux/delay.h>

#include <asm/page.h>
#include <asm/dma.h>    /* isa_dma_bridge_buggy */

#undef DEBUG

#ifdef DEBUG
#define DBG(x...) printk(x)
#else
#define DBG(x...)
#endif

LIST_HEAD(pci_root_buses);
LIST_HEAD(pci_devices);

/**
 * pci_find_slot - locate PCI device from a given PCI slot
 * @bus: number of PCI bus on which desired PCI device resides
 * @devfn: encodes number of PCI slot in which the desired PCI 
 * device resides and the logical device number within that slot 
 * in case of multi-function devices.
 *
 * Given a PCI bus and slot/function number, the desired PCI device 
 * is located in system global list of PCI devices.  If the device
 * is found, a pointer to its data structure is returned.  If no 
 * device is found, %NULL is returned.
 */
struct pci_dev *
pci_find_slot(unsigned int bus, unsigned int devfn)
{
    struct pci_dev *dev;

    pci_for_each_dev(dev) {
        if (dev->bus->number == bus && dev->devfn == devfn)
            return dev;
    }
    return NULL;
}

/**
 * pci_find_subsys - begin or continue searching for a PCI device by vendor/subvendor/device/subdevice id
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
 * @ss_vendor: PCI subsystem vendor id to match, or %PCI_ANY_ID to match all vendor ids
 * @ss_device: PCI subsystem device id to match, or %PCI_ANY_ID to match all device ids
 * @from: Previous PCI device found in search, or %NULL for new search.
 *
 * Iterates through the list of known PCI devices.  If a PCI device is
 * found with a matching @vendor, @device, @ss_vendor and @ss_device, a pointer to its
 * device structure is returned.  Otherwise, %NULL is returned.
 * A new search is initiated by passing %NULL to the @from argument.
 * Otherwise if @from is not %NULL, searches continue from next device on the global list.
 */
struct pci_dev *
pci_find_subsys(unsigned int vendor, unsigned int device,
        unsigned int ss_vendor, unsigned int ss_device,
        const struct pci_dev *from)
{
    struct list_head *n = from ? from->global_list.next : pci_devices.next;

    while (n != &pci_devices) {
        struct pci_dev *dev = pci_dev_g(n);
        if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
            (device == PCI_ANY_ID || dev->device == device) &&
            (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
            (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
            return dev;
        n = n->next;
    }
    return NULL;
}


/**
 * pci_find_device - begin or continue searching for a PCI device by vendor/device id
 * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
 * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
 * @from: Previous PCI device found in search, or %NULL for new search.
 *
 * Iterates through the list of known PCI devices.  If a PCI device is
 * found with a matching @vendor and @device, a pointer to its device structure is
 * returned.  Otherwise, %NULL is returned.
 * A new search is initiated by passing %NULL to the @from argument.
 * Otherwise if @from is not %NULL, searches continue from next device on the global list.
 */
struct pci_dev *
pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from)
{
    return pci_find_subsys(vendor, device, PCI_ANY_ID, PCI_ANY_ID, from);
}


/**
 * pci_find_class - begin or continue searching for a PCI device by class
 * @class: search for a PCI device with this class designation
 * @from: Previous PCI device found in search, or %NULL for new search.
 *
 * Iterates through the list of known PCI devices.  If a PCI device is
 * found with a matching @class, a pointer to its device structure is
 * returned.  Otherwise, %NULL is returned.
 * A new search is initiated by passing %NULL to the @from argument.
 * Otherwise if @from is not %NULL, searches continue from next device
 * on the global list.
 */
struct pci_dev *
pci_find_class(unsigned int class, const struct pci_dev *from)
{
    struct list_head *n = from ? from->global_list.next : pci_devices.next;

    while (n != &pci_devices) {
        struct pci_dev *dev = pci_dev_g(n);
        if (dev->class == class)
            return dev;
        n = n->next;
    }
    return NULL;
}

/**
 * pci_find_capability - query for devices' capabilities 
 * @dev: PCI device to query
 * @cap: capability code
 *
 * Tell if a device supports a given PCI capability.
 * Returns the address of the requested capability structure within the
 * device's PCI configuration space or 0 in case the device does not
 * support it.  Possible values for @cap:
 *
 *  %PCI_CAP_ID_PM           Power Management 
 *
 *  %PCI_CAP_ID_AGP          Accelerated Graphics Port 
 *
 *  %PCI_CAP_ID_VPD          Vital Product Data 
 *
 *  %PCI_CAP_ID_SLOTID       Slot Identification 
 *
 *  %PCI_CAP_ID_MSI          Message Signalled Interrupts
 *
 *  %PCI_CAP_ID_CHSWP        CompactPCI HotSwap 
 */
int
pci_find_capability(struct pci_dev *dev, int cap)
{
    u16 status;
    u8 pos, id;
    int ttl = 48;

    pci_read_config_word(dev, PCI_STATUS, &status);
    if (!(status & PCI_STATUS_CAP_LIST))
        return 0;
    switch (dev->hdr_type) {
    case PCI_HEADER_TYPE_NORMAL:
    case PCI_HEADER_TYPE_BRIDGE:
        pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos);
        break;
    case PCI_HEADER_TYPE_CARDBUS:
        pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos);
        break;
    default:
        return 0;
    }
    while (ttl-- && pos >= 0x40) {
        pos &= ~3;
        pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id);
        if (id == 0xff)
            break;
        if (id == cap)
            return pos;
        pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos);
    }
    return 0;
}


/**
 * pci_find_parent_resource - return resource region of parent bus of given region
 * @dev: PCI device structure contains resources to be searched
 * @res: child resource record for which parent is sought
 *
 *  For given resource region of given device, return the resource
 *  region of parent bus the given region is contained in or where
 *  it should be allocated from.
 */
struct resource *
pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
{
    const struct pci_bus *bus = dev->bus;
    int i;
    struct resource *best = NULL;

    for(i=0; i<4; i++) {
        struct resource *r = bus->resource[i];
        if (!r)
            continue;
        if (res->start && !(res->start >= r->start && res->end <= r->end))
            continue;    /* Not contained */
        if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
            continue;    /* Wrong type */
        if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
            return r;    /* Exact match */
        if ((res->flags & IORESOURCE_PREFETCH) && !(r->flags & IORESOURCE_PREFETCH))
            best = r;    /* Approximating prefetchable by non-prefetchable */
    }
    return best;
}

/**
 * pci_set_power_state - Set the power state of a PCI device
 * @dev: PCI device to be suspended
 * @state: Power state we're entering
 *
 * Transition a device to a new power state, using the Power Management 
 * Capabilities in the device's config space.
 *
 * RETURN VALUE: 
 * -EINVAL if trying to enter a lower state than we're already in.
 * 0 if we're already in the requested state.
 * -EIO if device does not support PCI PM.
 * 0 if we can successfully change the power state.
 */

int
pci_set_power_state(struct pci_dev *dev, int state)
{
    int pm;
    u16 pmcsr;

    /* bound the state we're entering */
    if (state > 3) state = 3;

    /* Validate current state:
     * Can enter D0 from any state, but if we can only go deeper 
     * to sleep if we're already in a low power state
     */
    if (state > 0 && dev->current_state > state)
        return -EINVAL;
    else if (dev->current_state == state) 
        return 0;        /* we're already there */

    /* find PCI PM capability in list */
    pm = pci_find_capability(dev, PCI_CAP_ID_PM);
    
    /* abort if the device doesn't support PM capabilities */
    if (!pm) return -EIO; 

    /* check if this device supports the desired state */
    if (state == 1 || state == 2) {
        u16 pmc;
        pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc);
        if (state == 1 && !(pmc & PCI_PM_CAP_D1)) return -EIO;
        else if (state == 2 && !(pmc & PCI_PM_CAP_D2)) return -EIO;
    }

    /* If we're in D3, force entire word to 0.
     * This doesn't affect PME_Status, disables PME_En, and
     * sets PowerState to 0.
     */
    if (dev->current_state >= 3)
        pmcsr = 0;
    else {
        pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
        pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
        pmcsr |= state;
    }

    /* enter specified state */
    pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr);

    /* Mandatory power management transition delays */
    /* see PCI PM 1.1 5.6.1 table 18 */
    if(state == 3 || dev->current_state == 3)
    {
        set_current_state(TASK_UNINTERRUPTIBLE);
        schedule_timeout(HZ/100);
    }
    else if(state == 2 || dev->current_state == 2)
        udelay(200);
    dev->current_state = state;

    return 0;
}

/**
 * pci_save_state - save the PCI configuration space of a device before suspending
 * @dev: - PCI device that we're dealing with
 * @buffer: - buffer to hold config space context
 *
 * @buffer must be large enough to hold the entire PCI 2.2 config space 
 * (>= 64 bytes).
 */
int
pci_save_state(struct pci_dev *dev, u32 *buffer)
{
    int i;
    if (buffer) {
        /* XXX: 100% dword access ok here? */
        for (i = 0; i < 16; i++)
            pci_read_config_dword(dev, i * 4,&buffer[i]);
    }
    return 0;
}

/** 
 * pci_restore_state - Restore the saved state of a PCI device
 * @dev: - PCI device that we're dealing with
 * @buffer: - saved PCI config space
 *
 */
int 
pci_restore_state(struct pci_dev *dev, u32 *buffer)
{
    int i;

    if (buffer) {
        for (i = 0; i < 16; i++)
            pci_write_config_dword(dev,i * 4, buffer[i]);
    }
    /*
     * otherwise, write the context information we know from bootup.
     * This works around a problem where warm-booting from Windows
     * combined with a D3(hot)->D0 transition causes PCI config
     * header data to be forgotten.
     */    
    else {
        for (i = 0; i < 6; i ++)
            pci_write_config_dword(dev,
                           PCI_BASE_ADDRESS_0 + (i * 4),
                           dev->resource[i].start);
        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
    }
    return 0;
}

/**
 * pci_enable_device - Initialize device before it's used by a driver.
 * @dev: PCI device to be initialized
 *
 *  Initialize device before it's used by a driver. Ask low-level code
 *  to enable I/O and memory. Wake up the device if it was suspended.
 *  Beware, this function can fail.
 */
int
pci_enable_device(struct pci_dev *dev)
{
    int err;

    pci_set_power_state(dev, 0);
    if ((err = pcibios_enable_device(dev)) < 0)
        return err;
    return 0;
}

/**
 * pci_disable_device - Disable PCI device after use
 * @dev: PCI device to be disabled
 *
 * Signal to the system that the PCI device is not in use by the system
 * anymore.  This only involves disabling PCI bus-mastering, if active.
 */
void
pci_disable_device(struct pci_dev *dev)
{
    u16 pci_command;

    pci_read_config_word(dev, PCI_COMMAND, &pci_command);
    if (pci_command & PCI_COMMAND_MASTER) {
        pci_command &= ~PCI_COMMAND_MASTER;
        pci_write_config_word(dev, PCI_COMMAND, pci_command);
    }
}

/**
 * pci_enable_wake - enable device to generate PME# when suspended
 * @dev: - PCI device to operate on
 * @state: - Current state of device.
 * @enable: - Flag to enable or disable generation
 * 
 * Set the bits in the device's PM Capabilities to generate PME# when
 * the system is suspended. 
 *
 * -EIO is returned if device doesn't have PM Capabilities. 
 * -EINVAL is returned if device supports it, but can't generate wake events.
 * 0 if operation is successful.
 * 
 */
int pci_enable_wake(struct pci_dev *dev, u32 state, int enable)
{
    int pm;
    u16 value;

    /* find PCI PM capability in list */
    pm = pci_find_capability(dev, PCI_CAP_ID_PM);

    /* If device doesn't support PM Capabilities, but request is to disable
     * wake events, it's a nop; otherwise fail */
    if (!pm) 
        return enable ? -EIO : 0; 

    /* Check device's ability to generate PME# */
    pci_read_config_word(dev,pm+PCI_PM_PMC,&value);

    value &= PCI_PM_CAP_PME_MASK;
    value >>= ffs(value);   /* First bit of mask */

    /* Check if it can generate PME# from requested state. */
    if (!value || !(value & (1 << state))) 
        return enable ? -EINVAL : 0;

    pci_read_config_word(dev, pm + PCI_PM_CTRL, &value);

    /* Clear PME_Status by writing 1 to it and enable PME# */
    value |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE;

    if (!enable)
        value &= ~PCI_PM_CTRL_PME_ENABLE;

    pci_write_config_word(dev, pm + PCI_PM_CTRL, value);
    
    return 0;
}

int
pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge)
{
    u8 pin;

    pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
    if (!pin)
        return -1;
    pin--;
    while (dev->bus->self) {
        pin = (pin + PCI_SLOT(dev->devfn)) % 4;
        dev = dev->bus->self;
    }
    *bridge = dev;
    return pin;
}

/**
 *    pci_release_regions - Release reserved PCI I/O and memory resources
 *    @pdev: PCI device whose resources were previously reserved by pci_request_regions
 *
 *    Releases all PCI I/O and memory resources previously reserved by a
 *    successful call to pci_request_regions.  Call this function only
 *    after all use of the PCI regions has ceased.
 */
void pci_release_regions(struct pci_dev *pdev)
{
    int i;
    
    for (i = 0; i < 6; i++) {
        if (pci_resource_len(pdev, i) == 0)
            continue;

        if (pci_resource_flags(pdev, i) & IORESOURCE_IO)
            release_region(pci_resource_start(pdev, i),
                       pci_resource_len(pdev, i));

        else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM)
            release_mem_region(pci_resource_start(pdev, i),
                       pci_resource_len(pdev, i));
    }
}

/**
 *    pci_request_regions - Reserved PCI I/O and memory resources
 *    @pdev: PCI device whose resources are to be reserved
 *    @res_name: Name to be associated with resource.
 *
 *    Mark all PCI regions associated with PCI device @pdev as
 *    being reserved by owner @res_name.  Do not access any
 *    address inside the PCI regions unless this call returns
 *    successfully.
 *
 *    Returns 0 on success, or %EBUSY on error.  A warning
 *    message is also printed on failure.
 */
int pci_request_regions(struct pci_dev *pdev, char *res_name)
{
    int i;
    
    for (i = 0; i < 6; i++) {
        if (pci_resource_len(pdev, i) == 0)
            continue;

        if (pci_resource_flags(pdev, i) & IORESOURCE_IO) {
            if (!request_region(pci_resource_start(pdev, i),
                        pci_resource_len(pdev, i), res_name))
                goto err_out;
        }
        
        else if (pci_resource_flags(pdev, i) & IORESOURCE_MEM) {
            if (!request_mem_region(pci_resource_start(pdev, i),
                            pci_resource_len(pdev, i), res_name))
                goto err_out;
        }
    }
    
    return 0;

err_out:
    printk (KERN_WARNING "PCI: Unable to reserve %s region #%d:%lx@%lx for device %s\n",
        pci_resource_flags(pdev, i) & IORESOURCE_IO ? "I/O" : "mem",
        i + 1, /* PCI BAR # */
        pci_resource_len(pdev, i), pci_resource_start(pdev, i),
        pdev->slot_name);
    pci_release_regions(pdev);
    return -EBUSY;
}


/*
 *  Registration of PCI drivers and handling of hot-pluggable devices.
 */

static LIST_HEAD(pci_drivers);

/**
 * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
 * @ids: array of PCI device id structures to search in
 * @dev: the PCI device structure to match against
 * 
 * Used by a driver to check whether a PCI device present in the
 * system is in its list of supported devices.Returns the matching
 * pci_device_id structure or %NULL if there is no match.
 */
const struct pci_device_id *
pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
{
    while (ids->vendor || ids->subvendor || ids->class_mask) {
        if ((ids->vendor == PCI_ANY_ID || ids->vendor == dev->vendor) &&
            (ids->device == PCI_ANY_ID || ids->device == dev->device) &&
            (ids->subvendor == PCI_ANY_ID || ids->subvendor == dev->subsystem_vendor) &&
            (ids->subdevice == PCI_ANY_ID || ids->subdevice == dev->subsystem_device) &&
            !((ids->class ^ dev->class) & ids->class_mask))
            return ids;
        ids++;
    }
    return NULL;
}

static int
pci_announce_device(struct pci_driver *drv, struct pci_dev *dev)
{
    const struct pci_device_id *id;
    int ret = 0;

    if (drv->id_table) {
        id = pci_match_device(drv->id_table, dev);
        if (!id) {
            ret = 0;
            goto out;
        }
    } else
        id = NULL;

    dev_probe_lock();
    if (drv->probe(dev, id) >= 0) {
        dev->driver = drv;
        ret = 1;
    }
    dev_probe_unlock();
out:
    return ret;
}

/**
 * pci_register_driver - register a new pci driver
 * @drv: the driver structure to register
 * 
 * Adds the driver structure to the list of registered drivers
 * Returns the number of pci devices which were claimed by the driver
 * during registration.  The driver remains registered even if the
 * return value is zero.
 */
int
pci_register_driver(struct pci_driver *drv)
{
    struct pci_dev *dev;
    int count = 0;

    list_add_tail(&drv->node, &pci_drivers);
    pci_for_each_dev(dev) {
        if (!pci_dev_driver(dev))
            count += pci_announce_device(drv, dev);
    }
    return count;
}

/**
 * pci_unregister_driver - unregister a pci driver
 * @drv: the driver structure to unregister
 * 
 * Deletes the driver structure from the list of registered PCI drivers,
 * gives it a chance to clean up by calling its remove() function for
 * each device it was responsible for, and marks those devices as
 * driverless.
 */

void
pci_unregister_driver(struct pci_driver *drv)
{
    struct pci_dev *dev;

    list_del(&drv->node);
    pci_for_each_dev(dev) {
        if (dev->driver == drv) {
            if (drv->remove)
                drv->remove(dev);
            dev->driver = NULL;
        }
    }
}

#ifdef CONFIG_HOTPLUG

#ifndef FALSE
#define FALSE    (0)
#define TRUE    (!FALSE)
#endif

static void
run_sbin_hotplug(struct pci_dev *pdev, int insert)
{
    int i;
    char *argv[3], *envp[8];
    char id[20], sub_id[24], bus_id[24], class_id[20];

    if (!hotplug_path[0])
        return;

    sprintf(class_id, "PCI_CLASS=%04X", pdev->class);
    sprintf(id, "PCI_ID=%04X:%04X", pdev->vendor, pdev->device);
    sprintf(sub_id, "PCI_SUBSYS_ID=%04X:%04X", pdev->subsystem_vendor, pdev->subsystem_device);
    sprintf(bus_id, "PCI_SLOT_NAME=%s", pdev->slot_name);

    i = 0;
    argv[i++] = hotplug_path;
    argv[i++] = "pci";
    argv[i] = 0;

    i = 0;
    /* minimal command environment */
    envp[i++] = "HOME=/";
    envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
    
    /* other stuff we want to pass to /sbin/hotplug */
    envp[i++] = class_id;
    envp[i++] = id;
    envp[i++] = sub_id;
    envp[i++] = bus_id;
    if (insert)
        envp[i++] = "ACTION=add";
    else
        envp[i++] = "ACTION=remove";
    envp[i] = 0;

    call_usermodehelper (argv [0], argv, envp);
}

/**
 * pci_announce_device_to_drivers - tell the drivers a new device has appeared
 * @dev: the device that has shown up
 *
 * Notifys the drivers that a new device has appeared, and also notifys
 * userspace through /sbin/hotplug.
 */
void
pci_announce_device_to_drivers(struct pci_dev *dev)
{
    struct list_head *ln;

    for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) {
        struct pci_driver *drv = list_entry(ln, struct pci_driver, node);
        if (drv->remove && pci_announce_device(drv, dev))
            break;
    }

    /* notify userspace of new hotplug device */
    run_sbin_hotplug(dev, TRUE);
}

/**
 * pci_insert_device - insert a hotplug device
 * @dev: the device to insert
 * @bus: where to insert it
 *
 * Add a new device to the device lists and notify userspace (/sbin/hotplug).
 */
void
pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
{
    list_add_tail(&dev->bus_list, &bus->devices);
    list_add_tail(&dev->global_list, &pci_devices);
#ifdef CONFIG_PROC_FS
    pci_proc_attach_device(dev);
#endif
    pci_announce_device_to_drivers(dev);
}

static void
pci_free_resources(struct pci_dev *dev)
{
    int i;

    for (i = 0; i < PCI_NUM_RESOURCES; i++) {
        struct resource *res = dev->resource + i;
        if (res->parent)
            release_resource(res);
    }
}

/**
 * pci_remove_device - remove a hotplug device
 * @dev: the device to remove
 *
 * Delete the device structure from the device lists and 
 * notify userspace (/sbin/hotplug).
 */
void
pci_remove_device(struct pci_dev *dev)
{
    if (dev->driver) {
        if (dev->driver->remove)
            dev->driver->remove(dev);
        dev->driver = NULL;
    }
    list_del(&dev->bus_list);
    list_del(&dev->global_list);
    pci_free_resources(dev);
#ifdef CONFIG_PROC_FS
    pci_proc_detach_device(dev);
#endif

    /* notify userspace of hotplug device removal */
    run_sbin_hotplug(dev, FALSE);
}

#endif

static struct pci_driver pci_compat_driver = {
    name: "compat"
};

/**
 * pci_dev_driver - get the pci_driver of a device
 * @dev: the device to query
 *
 * Returns the appropriate pci_driver structure or %NULL if there is no 
 * registered driver for the device.
 */
struct pci_driver *
pci_dev_driver(const struct pci_dev *dev)
{
    if (dev->driver)
        return dev->driver;
    else {
        int i;
        for(i=0; i<=PCI_ROM_RESOURCE; i++)
            if (dev->resource[i].flags & IORESOURCE_BUSY)
                return &pci_compat_driver;
    }
    return NULL;
}


/*
 * This interrupt-safe spinlock protects all accesses to PCI
 * configuration space.
 */

static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED;

/*
 *  Wrappers for all PCI configuration access functions.  They just check
 *  alignment, do locking and call the low-level functions pointed to
 *  by pci_dev->ops.
 */

#define PCI_byte_BAD 0
#define PCI_word_BAD (pos & 1)
#define PCI_dword_BAD (pos & 3)

#define PCI_OP(rw,size,type) \
int pci_##rw##_config_##size (struct pci_dev *dev, int pos, type value) \
{                                    \
    int res;                            \
    unsigned long flags;                        \
    if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER;    \
    spin_lock_irqsave(&pci_lock, flags);                \
    res = dev->bus->ops->rw##_##size(dev, pos, value);        \
    spin_unlock_irqrestore(&pci_lock, flags);            \
    return res;                            \
}

PCI_OP(read, byte, u8 *)
PCI_OP(read, word, u16 *)
PCI_OP(read, dword, u32 *)
PCI_OP(write, byte, u8)
PCI_OP(write, word, u16)
PCI_OP(write, dword, u32)

/**
 * pci_set_master - enables bus-mastering for device dev
 * @dev: the PCI device to enable
 *
 * Enables bus-mastering on the device and calls pcibios_set_master()
 * to do the needed arch specific settings.
 */
void
pci_set_master(struct pci_dev *dev)
{
    u16 cmd;

    pci_read_config_word(dev, PCI_COMMAND, &cmd);
    if (! (cmd & PCI_COMMAND_MASTER)) {
        DBG("PCI: Enabling bus mastering for device %s\n", dev->slot_name);
        cmd |= PCI_COMMAND_MASTER;
        pci_write_config_word(dev, PCI_COMMAND, cmd);
    }
    pcibios_set_master(dev);
}

int
pci_set_dma_mask(struct pci_dev *dev, u64 mask)
{
    if (!pci_dma_supported(dev, mask))
        return -EIO;

    dev->dma_mask = mask;

    return 0;
}
    
int
pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask)
{
    if (!pci_dac_dma_supported(dev, mask))
        return -EIO;

    dev->dma_mask = mask;

    return 0;
}
    
/*
 * Translate the low bits of the PCI base
 * to the resource type
 */
static inline unsigned int pci_calc_resource_flags(unsigned int flags)
{
    if (flags & PCI_BASE_ADDRESS_SPACE_IO)
        return IORESOURCE_IO;

    if (flags & PCI_BASE_ADDRESS_MEM_PREFETCH)
        return IORESOURCE_MEM | IORESOURCE_PREFETCH;

    return IORESOURCE_MEM;
}

/*
 * Find the extent of a PCI decode..
 */
static u32 pci_size(u32 base, unsigned long mask)
{
    u32 size = mask & base;        /* Find the significant bits */
    size = size & ~(size-1);    /* Get the lowest of them to find the decode size */
    return size-1;            /* extent = size - 1 */
}

static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
{
    unsigned int pos, reg, next;
    u32 l, sz;
    struct resource *res;

    for(pos=0; pos<howmany; pos = next) {
        next = pos+1;
        res = &dev->resource[pos];
        res->name = dev->name;
        reg = PCI_BASE_ADDRESS_0 + (pos << 2);
        pci_read_config_dword(dev, reg, &l);
        pci_write_config_dword(dev, reg, ~0);
        pci_read_config_dword(dev, reg, &sz);
        pci_write_config_dword(dev, reg, l);
        if (!sz || sz == 0xffffffff)
            continue;
        if (l == 0xffffffff)
            l = 0;
        if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
            res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
            sz = pci_size(sz, PCI_BASE_ADDRESS_MEM_MASK);
        } else {
            res->start = l & PCI_BASE_ADDRESS_IO_MASK;
            sz = pci_size(sz, PCI_BASE_ADDRESS_IO_MASK & 0xffff);
        }
        res->end = res->start + (unsigned long) sz;
        res->flags |= (l & 0xf) | pci_calc_resource_flags(l);
        if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
            == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
            pci_read_config_dword(dev, reg+4, &l);
            next++;
#if BITS_PER_LONG == 64
            res->start |= ((unsigned long) l) << 32;
            res->end = res->start + sz;
            pci_write_config_dword(dev, reg+4, ~0);
            pci_read_config_dword(dev, reg+4, &sz);
            pci_write_config_dword(dev, reg+4, l);
            if (~sz)
                res->end = res->start + 0xffffffff +
                        (((unsigned long) ~sz) << 32);
#else
            if (l) {
                printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", dev->slot_name);
                res->start = 0;
                res->flags = 0;
                continue;
            }
#endif
        }
    }
    if (rom) {
        dev->rom_base_reg = rom;
        res = &dev->resource[PCI_ROM_RESOURCE];
        pci_read_config_dword(dev, rom, &l);
        pci_write_config_dword(dev, rom, ~PCI_ROM_ADDRESS_ENABLE);
        pci_read_config_dword(dev, rom, &sz);
        pci_write_config_dword(dev, rom, l);
        if (l == 0xffffffff)
            l = 0;
        if (sz && sz != 0xffffffff) {
            res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
              IORESOURCE_MEM | IORESOURCE_PREFETCH | IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
            res->start = l & PCI_ROM_ADDRESS_MASK;
            sz = pci_size(sz, PCI_ROM_ADDRESS_MASK);
            res->end = res->start + (unsigned long) sz;
        }
        res->name = dev->name;
    }
}

void __devinit  pci_read_bridge_bases(struct pci_bus *child)
{
    struct pci_dev *dev = child->self;
    u8 io_base_lo, io_limit_lo;
    u16 mem_base_lo, mem_limit_lo;
    unsigned long base, limit;
    struct resource *res;
    int i;

    if (!dev)        /* It's a host bus, nothing to read */
        return;

    for(i=0; i<3; i++)
        child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];

    res = child->resource[0];
    pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
    pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
    base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
    limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;

    if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
        u16 io_base_hi, io_limit_hi;
        pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
        pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
        base |= (io_base_hi << 16);
        limit |= (io_limit_hi << 16);
    }

    if (base && base <= limit) {
        res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
        res->start = base;
        res->end = limit + 0xfff;
        res->name = child->name;
    } else {
        /*
         * Ugh. We don't know enough about this bridge. Just assume
         * that it's entirely transparent.
         */
        printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 0);
        child->resource[0] = child->parent->resource[0];
    }

    res = child->resource[1];
    pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
    pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
    base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
    limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
    if (base && base <= limit) {
        res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
        res->start = base;
        res->end = limit + 0xfffff;
        res->name = child->name;
    } else {
        /* See comment above. Same thing */
        printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 1);
        child->resource[1] = child->parent->resource[1];
    }

    res = child->resource[2];
    pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
    pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
    base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
    limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;

    if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
        u32 mem_base_hi, mem_limit_hi;
        pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
        pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
#if BITS_PER_LONG == 64
        base |= ((long) mem_base_hi) << 32;
        limit |= ((long) mem_limit_hi) << 32;
#else
        if (mem_base_hi || mem_limit_hi) {
            printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name);
            return;
        }
#endif
    }
    if (base && base <= limit) {
        res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
        res->start = base;
        res->end = limit + 0xfffff;
        res->name = child->name;
    } else {
        /* See comments above */
        printk(KERN_ERR "Unknown bridge resource %d: assuming transparent\n", 2);
        child->resource[2] = child->parent->resource[2];
    }
}

static struct pci_bus * __devinit  pci_alloc_bus(void)
{
    struct pci_bus *b;

    b = kmalloc(sizeof(*b), GFP_KERNEL);
    if (b) {
        memset(b, 0, sizeof(*b));
        INIT_LIST_HEAD(&b->children);
        INIT_LIST_HEAD(&b->devices);
    }
    return b;
}

struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr)
{
    struct pci_bus *child;
    int i;

    /*
     * Allocate a new bus, and inherit stuff from the parent..
     */
    child = pci_alloc_bus();

    list_add_tail(&child->node, &parent->children);
    child->self = dev;
    dev->subordinate = child;
    child->parent = parent;
    child->ops = parent->ops;
    child->sysdata = parent->sysdata;

    /*
     * Set up the primary, secondary and subordinate
     * bus numbers.
     */
    child->number = child->secondary = busnr;
    child->primary = parent->secondary;
    child->subordinate = 0xff;

    /* Set up default resource pointers.. */
    for (i = 0; i < 4; i++)
        child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];

    return child;
}

unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus);

/*
 * If it's a bridge, configure it and scan the bus behind it.
 * For CardBus bridges, we don't scan behind as the devices will
 * be handled by the bridge driver itself.
 *
 * We need to process bridges in two passes -- first we scan those
 * already configured by the BIOS and after we are done with all of
 * them, we proceed to assigning numbers to the remaining buses in
 * order to avoid overlaps between old and new bus numbers.
 */
static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
{
    unsigned int buses;
    unsigned short cr;
    struct pci_bus *child;
    int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);

    pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
    DBG("Scanning behind PCI bridge %s, config %06x, pass %d\n", dev->slot_name, buses & 0xffffff, pass);
    if ((buses & 0xffff00) && !pcibios_assign_all_busses()) {
        /*
         * Bus already configured by firmware, process it in the first
         * pass and just note the configuration.
         */
        if (pass)
            return max;
        child = pci_add_new_bus(bus, dev, 0);
        child->primary = buses & 0xFF;
        child->secondary = (buses >> 8) & 0xFF;
        child->subordinate = (buses >> 16) & 0xFF;
        child->number = child->secondary;
        if (!is_cardbus) {
            unsigned int cmax = pci_do_scan_bus(child);
            if (cmax > max) max = cmax;
        } else {
            unsigned int cmax = child->subordinate;
            if (cmax > max) max = cmax;
        }
    } else {
        /*
         * We need to assign a number to this bus which we always
         * do in the second pass. We also keep all address decoders
         * on the bridge disabled during scanning.  FIXME: Why?
         */
        if (!pass)
            return max;
        pci_read_config_word(dev, PCI_COMMAND, &cr);
        pci_write_config_word(dev, PCI_COMMAND, 0x0000);
        pci_write_config_word(dev, PCI_STATUS, 0xffff);

        child = pci_add_new_bus(bus, dev, ++max);
        buses = (buses & 0xff000000)
              | ((unsigned int)(child->primary)     <<  0)
              | ((unsigned int)(child->secondary)   <<  8)
              | ((unsigned int)(child->subordinate) << 16);
        /*
         * We need to blast all three values with a single write.
         */
        pci_write_config_dword(dev, PCI_PRIMARY_BUS, buses);
        if (!is_cardbus) {
            /* Now we can scan all subordinate buses... */
            max = pci_do_scan_bus(child);
        } else {
            /*
             * For CardBus bridges, we leave 4 bus numbers
             * as cards with a PCI-to-PCI bridge can be
             * inserted later.
             */
            max += 3;
        }
        /*
         * Set the subordinate bus number to its real value.
         */
        child->subordinate = max;
        pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
        pci_write_config_word(dev, PCI_COMMAND, cr);
    }
    sprintf(child->name, (is_cardbus ? "PCI CardBus #%02x" : "PCI Bus #%02x"), child->number);
    return max;
}

/*
 * Read interrupt line and base address registers.
 * The architecture-dependent code can tweak these, of course.
 */
static void pci_read_irq(struct pci_dev *dev)
{
    unsigned char irq;

    pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq);
    if (irq)
        pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
    dev->irq = irq;
}

/**
 * pci_setup_device - fill in class and map information of a device
 * @dev: the device structure to fill
 *
 * Initialize the device structure with information about the device's 
 * vendor,class,memory and IO-space addresses,IRQ lines etc.
 * Called at initialisation of the PCI subsystem and by CardBus services.
 * Returns 0 on success and -1 if unknown type of device (not normal, bridge
 * or CardBus).
 */
int pci_setup_device(struct pci_dev * dev)
{
    u32 class;

    sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
    sprintf(dev->name, "PCI device %04x:%04x", dev->vendor, dev->device);
    
    pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
    class >>= 8;                    /* upper 3 bytes */
    dev->class = class;
    class >>= 8;

    DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);

    /* "Unknown power state" */
    dev->current_state = 4;

    switch (dev->hdr_type) {            /* header type */
    case PCI_HEADER_TYPE_NORMAL:            /* standard header */
        if (class == PCI_CLASS_BRIDGE_PCI)
            goto bad;
        pci_read_irq(dev);
        pci_read_bases(dev, 6, PCI_ROM_ADDRESS);
        pci_read_config_word(dev, PCI_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
        pci_read_config_word(dev, PCI_SUBSYSTEM_ID, &dev->subsystem_device);
        break;

    case PCI_HEADER_TYPE_BRIDGE:            /* bridge header */
        if (class != PCI_CLASS_BRIDGE_PCI)
            goto bad;
        pci_read_bases(dev, 2, PCI_ROM_ADDRESS1);
        break;

    case PCI_HEADER_TYPE_CARDBUS:            /* CardBus bridge header */
        if (class != PCI_CLASS_BRIDGE_CARDBUS)
            goto bad;
        pci_read_irq(dev);
        pci_read_bases(dev, 1, 0);
        pci_read_config_word(dev, PCI_CB_SUBSYSTEM_VENDOR_ID, &dev->subsystem_vendor);
        pci_read_config_word(dev, PCI_CB_SUBSYSTEM_ID, &dev->subsystem_device);
        break;

    default:                    /* unknown header */
        printk(KERN_ERR "PCI: device %s has unknown header type %02x, ignoring.\n",
            dev->slot_name, dev->hdr_type);
        return -1;

    bad:
        printk(KERN_ERR "PCI: %s: class %x doesn't match header type %02x. Ignoring class.\n",
               dev->slot_name, class, dev->hdr_type);
        dev->class = PCI_CLASS_NOT_DEFINED;
    }

    /* We found a fine healthy device, go go go... */
    return 0;
}

/*
 * Read the config data for a PCI device, sanity-check it
 * and fill in the dev structure...
 */
struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
{
    struct pci_dev *dev;
    u32 l;

    if (pci_read_config_dword(temp, PCI_VENDOR_ID, &l))
        return NULL;

    /* some broken boards return 0 or ~0 if a slot is empty: */
    if (l == 0xffffffff || l == 0x00000000 || l == 0x0000ffff || l == 0xffff0000)
        return NULL;

    dev = kmalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev)
        return NULL;

    memcpy(dev, temp, sizeof(*dev));
    dev->vendor = l & 0xffff;
    dev->device = (l >> 16) & 0xffff;

    /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
       set this higher, assuming the system even supports it.  */
    dev->dma_mask = 0xffffffff;
    if (pci_setup_device(dev) < 0) {
        kfree(dev);
        dev = NULL;
    }
    return dev;
}

struct pci_dev * __devinit pci_scan_slot(struct pci_dev *temp)
{
    struct pci_bus *bus = temp->bus;
    struct pci_dev *dev;
    struct pci_dev *first_dev = NULL;
    int func = 0;
    int is_multi = 0;
    u8 hdr_type;

    for (func = 0; func < 8; func++, temp->devfn++) {
        if (func && !is_multi)        /* not a multi-function device */
            continue;
        if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
            continue;
        temp->hdr_type = hdr_type & 0x7f;

        dev = pci_scan_device(temp);
        if (!dev)
            continue;
        pci_name_device(dev);
        if (!func) {
            is_multi = hdr_type & 0x80;
            first_dev = dev;
        }

        /*
         * Link the device to both the global PCI device chain and
         * the per-bus list of devices.
         */
        list_add_tail(&dev->global_list, &pci_devices);
        list_add_tail(&dev->bus_list, &bus->devices);

        /* Fix up broken headers */
        pci_fixup_device(PCI_FIXUP_HEADER, dev);
    }
    return first_dev;
}

unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
{
    unsigned int devfn, max, pass;
    struct list_head *ln;
    struct pci_dev *dev, dev0;

    DBG("Scanning bus %02x\n", bus->number);
    max = bus->secondary;

    /* Create a device template */
    memset(&dev0, 0, sizeof(dev0));
    dev0.bus = bus;
    dev0.sysdata = bus->sysdata;

    /* Go find them, Rover! */
    for (devfn = 0; devfn < 0x100; devfn += 8) {
        dev0.devfn = devfn;
        pci_scan_slot(&dev0);
    }

    /*
     * After performing arch-dependent fixup of the bus, look behind
     * all PCI-to-PCI bridges on this bus.
     */
    DBG("Fixups for bus %02x\n", bus->number);
    pcibios_fixup_bus(bus);
    for (pass=0; pass < 2; pass++)
        for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
            dev = pci_dev_b(ln);
            if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
                max = pci_scan_bridge(bus, dev, max, pass);
        }

    /*
     * We've scanned the bus and so we know all about what's on
     * the other side of any bridges that may be on this bus plus
     * any devices.
     *
     * Return how far we've got finding sub-buses.
     */
    DBG("Bus scan for %02x returning with max=%02x\n", bus->number, max);
    return max;
}

int __devinit  pci_bus_exists(const struct list_head *list, int nr)
{
    const struct list_head *l;

    for(l=list->next; l != list; l = l->next) {
        const struct pci_bus *b = pci_bus_b(l);
        if (b->number == nr || pci_bus_exists(&b->children, nr))
            return 1;
    }
    return 0;
}

struct pci_bus * __devinit  pci_alloc_primary_bus(int bus)
{
    struct pci_bus *b;

    if (pci_bus_exists(&pci_root_buses, bus)) {
        /* If we already got to this bus through a different bridge, ignore it */
        DBG("PCI: Bus %02x already known\n", bus);
        return NULL;
    }

    b = pci_alloc_bus();
    list_add_tail(&b->node, &pci_root_buses);

    b->number = b->secondary = bus;
    b->resource[0] = &ioport_resource;
    b->resource[1] = &iomem_resource;
    return b;
}

struct pci_bus * __devinit  pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
{
    struct pci_bus *b = pci_alloc_primary_bus(bus);
    if (b) {
        b->sysdata = sysdata;
        b->ops = ops;
        b->subordinate = pci_do_scan_bus(b);
    }
    return b;
}

#ifdef CONFIG_PM

/*
 * PCI Power management..
 *
 * This needs to be done centralized, so that we power manage PCI
 * devices in the right order: we should not shut down PCI bridges
 * before we've shut down the devices behind them, and we should
 * not wake up devices before we've woken up the bridge to the
 * device.. Eh?
 *
 * We do not touch devices that don't have a driver that exports
 * a suspend/resume function. That is just too dangerous. If the default
 * PCI suspend/resume functions work for a device, the driver can
 * easily implement them (ie just have a suspend function that calls
 * the pci_set_power_state() function).
 */

static int pci_pm_save_state_device(struct pci_dev *dev, u32 state)
{
    int error = 0;
    if (dev) {
        struct pci_driver *driver = dev->driver;
        if (driver && driver->save_state) 
            error = driver->save_state(dev,state);
    }
    return error;
}

static int pci_pm_suspend_device(struct pci_dev *dev, u32 state)
{
    int error = 0;
    if (dev) {
        struct pci_driver *driver = dev->driver;
        if (driver && driver->suspend)
            error = driver->suspend(dev,state);
    }
    return error;
}

static int pci_pm_resume_device(struct pci_dev *dev)
{
    int error = 0;
    if (dev) {
        struct pci_driver *driver = dev->driver;
        if (driver && driver->resume)
            error = driver->resume(dev);
    }
    return error;
}

static int pci_pm_save_state_bus(struct pci_bus *bus, u32 state)
{
    struct list_head *list;
    int error = 0;

    list_for_each(list, &bus->children) {
        error = pci_pm_save_state_bus(pci_bus_b(list),state);
        if (error) return error;
    }
    list_for_each(list, &bus->devices) {
        error = pci_pm_save_state_device(pci_dev_b(list),state);
        if (error) return error;
    }
    return 0;
}

static int pci_pm_suspend_bus(struct pci_bus *bus, u32 state)
{
    struct list_head *list;

    /* Walk the bus children list */
    list_for_each(list, &bus->children) 
        pci_pm_suspend_bus(pci_bus_b(list),state);

    /* Walk the device children list */
    list_for_each(list, &bus->devices)
        pci_pm_suspend_device(pci_dev_b(list),state);
    return 0;
}

static int pci_pm_resume_bus(struct pci_bus *bus)
{
    struct list_head *list;

    /* Walk the device children list */
    list_for_each(list, &bus->devices)
        pci_pm_resume_device(pci_dev_b(list));

    /* And then walk the bus children */
    list_for_each(list, &bus->children)
        pci_pm_resume_bus(pci_bus_b(list));
    return 0;
}

static int pci_pm_save_state(u32 state)
{
    struct list_head *list;
    struct pci_bus *bus;
    int error = 0;

    list_for_each(list, &pci_root_buses) {
        bus = pci_bus_b(list);
        error = pci_pm_save_state_bus(bus,state);
        if (!error)
            error = pci_pm_save_state_device(bus->self,state);
    }
    return error;
}

static int pci_pm_suspend(u32 state)
{
    struct list_head *list;
    struct pci_bus *bus;

    list_for_each(list, &pci_root_buses) {
        bus = pci_bus_b(list);
        pci_pm_suspend_bus(bus,state);
        pci_pm_suspend_device(bus->self,state);
    }
    return 0;
}

static int pci_pm_resume(void)
{
    struct list_head *list;
    struct pci_bus *bus;

    list_for_each(list, &pci_root_buses) {
        bus = pci_bus_b(list);
        pci_pm_resume_device(bus->self);
        pci_pm_resume_bus(bus);
    }
    return 0;
}

static int 
pci_pm_callback(struct pm_dev *pm_device, pm_request_t rqst, void *data)
{
    int error = 0;

    switch (rqst) {
    case PM_SAVE_STATE:
        error = pci_pm_save_state((u32)data);
        break;
    case PM_SUSPEND:
        error = pci_pm_suspend((u32)data);
        break;
    case PM_RESUME:
        error = pci_pm_resume();
        break;
    default: break;
    }
    return error;
}

#endif

/*
 * Pool allocator ... wraps the pci_alloc_consistent page allocator, so
 * small blocks are easily used by drivers for bus mastering controllers.
 * This should probably be sharing the guts of the slab allocator.
 */

struct pci_pool {    /* the pool */
    struct list_head    page_list;
    spinlock_t        lock;
    size_t            blocks_per_page;
    size_t            size;
    int            flags;
    struct pci_dev        *dev;
    size_t            allocation;
    char            name [32];
    wait_queue_head_t    waitq;
};

struct pci_page {    /* cacheable header for 'allocation' bytes */
    struct list_head    page_list;
    void            *vaddr;
    dma_addr_t        dma;
    unsigned long        bitmap [0];
};

#define    POOL_TIMEOUT_JIFFIES    ((100 /* msec */ * HZ) / 1000)
#define    POOL_POISON_BYTE    0xa7

// #define CONFIG_PCIPOOL_DEBUG


/**
 * pci_pool_create - Creates a pool of pci consistent memory blocks, for dma.
 * @name: name of pool, for diagnostics
 * @pdev: pci device that will be doing the DMA
 * @size: size of the blocks in this pool.
 * @align: alignment requirement for blocks; must be a power of two
 * @allocation: returned blocks won't cross this boundary (or zero)
 * @flags: SLAB_* flags (not all are supported).
 *
 * Returns a pci allocation pool with the requested characteristics, or
 * null if one can't be created.  Given one of these pools, pci_pool_alloc()
 * may be used to allocate memory.  Such memory will all have "consistent"
 * DMA mappings, accessible by the device and its driver without using
 * cache flushing primitives.  The actual size of blocks allocated may be
 * larger than requested because of alignment.
 *
 * If allocation is nonzero, objects returned from pci_pool_alloc() won't
 * cross that size boundary.  This is useful for devices which have
 * addressing restrictions on individual DMA transfers, such as not crossing
 * boundaries of 4KBytes.
 */
struct pci_pool *
pci_pool_create (const char *name, struct pci_dev *pdev,
    size_t size, size_t align, size_t allocation, int flags)
{
    struct pci_pool        *retval;

    if (align == 0)
        align = 1;
    if (size == 0)
        return 0;
    else if (size < align)
        size = align;
    else if ((size % align) != 0) {
        size += align + 1;
        size &= ~(align - 1);
    }

    if (allocation == 0) {
        if (PAGE_SIZE < size)
            allocation = size;
        else
            allocation = PAGE_SIZE;
        // FIXME: round up for less fragmentation
    } else if (allocation < size)
        return 0;

    if (!(retval = kmalloc (sizeof *retval, flags)))
        return retval;

#ifdef    CONFIG_PCIPOOL_DEBUG
    flags |= SLAB_POISON;
#endif

    strncpy (retval->name, name, sizeof retval->name);
    retval->name [sizeof retval->name - 1] = 0;

    retval->dev = pdev;
    INIT_LIST_HEAD (&retval->page_list);
    spin_lock_init (&retval->lock);
    retval->size = size;
    retval->flags = flags;
    retval->allocation = allocation;
    retval->blocks_per_page = allocation / size;
    init_waitqueue_head (&retval->waitq);

#ifdef CONFIG_PCIPOOL_DEBUG
    printk (KERN_DEBUG "pcipool create %s/%s size %d, %d/page (%d alloc)\n",
        pdev ? pdev->slot_name : NULL, retval->name, size,
        retval->blocks_per_page, allocation);
#endif

    return retval;
}


static struct pci_page *
pool_alloc_page (struct pci_pool *pool, int mem_flags)
{
    struct pci_page    *page;
    int        mapsize;

    mapsize = pool->blocks_per_page;
    mapsize = (mapsize + BITS_PER_LONG - 1) / BITS_PER_LONG;
    mapsize *= sizeof (long);

    page = (struct pci_page *) kmalloc (mapsize + sizeof *page, mem_flags);
    if (!page)
        return 0;
    page->vaddr = pci_alloc_consistent (pool->dev,
                        pool->allocation,
                        &page->dma);
    if (page->vaddr) {
        memset (page->bitmap, 0xff, mapsize);    // bit set == free
        if (pool->flags & SLAB_POISON)
            memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
        list_add (&page->page_list, &pool->page_list);
    } else {
        kfree (page);
        page = 0;
    }
    return page;
}


static inline int
is_page_busy (int blocks, unsigned long *bitmap)
{
    while (blocks > 0) {
        if (*bitmap++ != ~0UL)
            return 1;
        blocks -= BITS_PER_LONG;
    }
    return 0;
}

static void
pool_free_page (struct pci_pool *pool, struct pci_page *page)
{
    dma_addr_t    dma = page->dma;

    if (pool->flags & SLAB_POISON)
        memset (page->vaddr, POOL_POISON_BYTE, pool->allocation);
    pci_free_consistent (pool->dev, pool->allocation, page->vaddr, dma);
    list_del (&page->page_list);
    kfree (page);
}


/**
 * pci_pool_destroy - destroys a pool of pci memory blocks.
 * @pool: pci pool that will be destroyed
 *
 * Caller guarantees that no more memory from the pool is in use,
 * and that nothing will try to use the pool after this call.
 */
void
pci_pool_destroy (struct pci_pool *pool)
{
    unsigned long        flags;

#ifdef CONFIG_PCIPOOL_DEBUG
    printk (KERN_DEBUG "pcipool destroy %s/%s\n",
        pool->dev ? pool->dev->slot_name : NULL,
        pool->name);
#endif

    spin_lock_irqsave (&pool->lock, flags);
    while (!list_empty (&pool->page_list)) {
        struct pci_page        *page;
        page = list_entry (pool->page_list.next,
                struct pci_page, page_list);
        if (is_page_busy (pool->blocks_per_page, page->bitmap)) {
            printk (KERN_ERR "pci_pool_destroy %s/%s, %p busy\n",
                pool->dev ? pool->dev->slot_name : NULL,
                pool->name, page->vaddr);
            /* leak the still-in-use consistent memory */
            list_del (&page->page_list);
            kfree (page);
        } else
            pool_free_page (pool, page);
    }
    spin_unlock_irqrestore (&pool->lock, flags);
    kfree (pool);
}


/**
 * pci_pool_alloc - get a block of consistent memory
 * @pool: pci pool that will produce the block
 * @mem_flags: SLAB_KERNEL or SLAB_ATOMIC
 * @handle: pointer to dma address of block
 *
 * This returns the kernel virtual address of a currently unused block,
 * and reports its dma address through the handle.
 * If such a memory block can't be allocated, null is returned.
 */
void *
pci_pool_alloc (struct pci_pool *pool, int mem_flags, dma_addr_t *handle)
{
    unsigned long        flags;
    struct list_head    *entry;
    struct pci_page        *page;
    int            map, block;
    size_t            offset;
    void            *retval;

restart:
    spin_lock_irqsave (&pool->lock, flags);
    list_for_each (entry, &pool->page_list) {
        int        i;
        page = list_entry (entry, struct pci_page, page_list);
        /* only cachable accesses here ... */
        for (map = 0, i = 0;
                i < pool->blocks_per_page;
                i += BITS_PER_LONG, map++) {
            if (page->bitmap [map] == 0)
                continue;
            block = ffz (~ page->bitmap [map]);
            if ((i + block) < pool->blocks_per_page) {
                clear_bit (block, &page->bitmap [map]);
                offset = (BITS_PER_LONG * map) + block;
                offset *= pool->size;
                goto ready;
            }
        }
    }
    if (!(page = pool_alloc_page (pool, mem_flags))) {
        if (mem_flags == SLAB_KERNEL) {
            DECLARE_WAITQUEUE (wait, current);

            current->state = TASK_INTERRUPTIBLE;
            add_wait_queue (&pool->waitq, &wait);
            spin_unlock_irqrestore (&pool->lock, flags);

            schedule_timeout (POOL_TIMEOUT_JIFFIES);

            current->state = TASK_RUNNING;
            remove_wait_queue (&pool->waitq, &wait);
            goto restart;
        }
        retval = 0;
        goto done;
    }

    clear_bit (0, &page->bitmap [0]);
    offset = 0;
ready:
    retval = offset + page->vaddr;
    *handle = offset + page->dma;
done:
    spin_unlock_irqrestore (&pool->lock, flags);
    return retval;
}


static struct pci_page *
pool_find_page (struct pci_pool *pool, dma_addr_t dma)
{
    unsigned long        flags;
    struct list_head    *entry;
    struct pci_page        *page;

    spin_lock_irqsave (&pool->lock, flags);
    list_for_each (entry, &pool->page_list) {
        page = list_entry (entry, struct pci_page, page_list);
        if (dma < page->dma)
            continue;
        if (dma < (page->dma + pool->allocation))
            goto done;
    }
    page = 0;
done:
    spin_unlock_irqrestore (&pool->lock, flags);
    return page;
}


/**
 * pci_pool_free - put block back into pci pool
 * @pool: the pci pool holding the block
 * @vaddr: virtual address of block
 * @dma: dma address of block
 *
 * Caller promises neither device nor driver will again touch this block
 * unless it is first re-allocated.
 */
void
pci_pool_free (struct pci_pool *pool, void *vaddr, dma_addr_t dma)
{
    struct pci_page        *page;
    unsigned long        flags;
    int            map, block;

    if ((page = pool_find_page (pool, dma)) == 0) {
        printk (KERN_ERR "pci_pool_free %s/%s, %p/%x (bad dma)\n",
            pool->dev ? pool->dev->slot_name : NULL,
            pool->name, vaddr, (int) (dma & 0xffffffff));
        return;
    }
#ifdef    CONFIG_PCIPOOL_DEBUG
    if (((dma - page->dma) + (void *)page->vaddr) != vaddr) {
        printk (KERN_ERR "pci_pool_free %s/%s, %p (bad vaddr)/%x\n",
            pool->dev ? pool->dev->slot_name : NULL,
            pool->name, vaddr, (int) (dma & 0xffffffff));
        return;
    }
#endif

    block = dma - page->dma;
    block /= pool->size;
    map = block / BITS_PER_LONG;
    block %= BITS_PER_LONG;

#ifdef    CONFIG_PCIPOOL_DEBUG
    if (page->bitmap [map] & (1UL << block)) {
        printk (KERN_ERR "pci_pool_free %s/%s, dma %x already free\n",
            pool->dev ? pool->dev->slot_name : NULL,
            pool->name, dma);
        return;
    }
#endif
    if (pool->flags & SLAB_POISON)
        memset (vaddr, POOL_POISON_BYTE, pool->size);

    spin_lock_irqsave (&pool->lock, flags);
    set_bit (block, &page->bitmap [map]);
    if (waitqueue_active (&pool->waitq))
        wake_up (&pool->waitq);
    /*
     * Resist a temptation to do
     *    if (!is_page_busy(bpp, page->bitmap)) pool_free_page(pool, page);
     * it is not interrupt safe. Better have empty pages hang around.
     */
    spin_unlock_irqrestore (&pool->lock, flags);
}


void __devinit  pci_init(void)
{
    struct pci_dev *dev;

    pcibios_init();

    pci_for_each_dev(dev) {
        pci_fixup_device(PCI_FIXUP_FINAL, dev);
    }

#ifdef CONFIG_PM
    pm_register(PM_PCI_DEV, 0, pci_pm_callback);
#endif
}

static int __devinit  pci_setup(char *str)
{
    while (str) {
        char *k = strchr(str, ',');
        if (k)
            *k++ = 0;
        if (*str && (str = pcibios_setup(str)) && *str) {
            /* PCI layer options should be handled here */
            printk(KERN_ERR "PCI: Unknown option `%s'\n", str);
        }
        str = k;
    }
    return 1;
}

__setup("pci=", pci_setup);

EXPORT_SYMBOL(pci_read_config_byte);
EXPORT_SYMBOL(pci_read_config_word);
EXPORT_SYMBOL(pci_read_config_dword);
EXPORT_SYMBOL(pci_write_config_byte);
EXPORT_SYMBOL(pci_write_config_word);
EXPORT_SYMBOL(pci_write_config_dword);
EXPORT_SYMBOL(pci_devices);
EXPORT_SYMBOL(pci_root_buses);
EXPORT_SYMBOL(pci_enable_device);
EXPORT_SYMBOL(pci_disable_device);
EXPORT_SYMBOL(pci_find_capability);
EXPORT_SYMBOL(pci_release_regions);
EXPORT_SYMBOL(pci_request_regions);
EXPORT_SYMBOL(pci_find_class);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_slot);
EXPORT_SYMBOL(pci_find_subsys);
EXPORT_SYMBOL(pci_set_master);
EXPORT_SYMBOL(pci_set_dma_mask);
EXPORT_SYMBOL(pci_dac_set_dma_mask);
EXPORT_SYMBOL(pci_assign_resource);
EXPORT_SYMBOL(pci_register_driver);
EXPORT_SYMBOL(pci_unregister_driver);
EXPORT_SYMBOL(pci_dev_driver);
EXPORT_SYMBOL(pci_match_device);
EXPORT_SYMBOL(pci_find_parent_resource);

#ifdef CONFIG_HOTPLUG
EXPORT_SYMBOL(pci_setup_device);
EXPORT_SYMBOL(pci_insert_device);
EXPORT_SYMBOL(pci_remove_device);
EXPORT_SYMBOL(pci_announce_device_to_drivers);
EXPORT_SYMBOL(pci_add_new_bus);
EXPORT_SYMBOL(pci_do_scan_bus);
EXPORT_SYMBOL(pci_scan_slot);
EXPORT_SYMBOL(pci_proc_attach_device);
EXPORT_SYMBOL(pci_proc_detach_device);
EXPORT_SYMBOL(pci_proc_attach_bus);
EXPORT_SYMBOL(pci_proc_detach_bus);
#endif

EXPORT_SYMBOL(pci_set_power_state);
EXPORT_SYMBOL(pci_save_state);
EXPORT_SYMBOL(pci_restore_state);
EXPORT_SYMBOL(pci_enable_wake);

/* Obsolete functions */

EXPORT_SYMBOL(pcibios_present);
EXPORT_SYMBOL(pcibios_read_config_byte);
EXPORT_SYMBOL(pcibios_read_config_word);
EXPORT_SYMBOL(pcibios_read_config_dword);
EXPORT_SYMBOL(pcibios_write_config_byte);
EXPORT_SYMBOL(pcibios_write_config_word);
EXPORT_SYMBOL(pcibios_write_config_dword);
EXPORT_SYMBOL(pcibios_find_class);
EXPORT_SYMBOL(pcibios_find_device);

/* Quirk info */

EXPORT_SYMBOL(isa_dma_bridge_buggy);
EXPORT_SYMBOL(pci_pci_problems);

/* Pool allocator */

EXPORT_SYMBOL (pci_pool_create);
EXPORT_SYMBOL (pci_pool_destroy);
EXPORT_SYMBOL (pci_pool_alloc);
EXPORT_SYMBOL (pci_pool_free);


:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 1.0 pre-release build #13 powered by Captain Crunch Security Team | http://ccteam.ru | Generation time: 0.0326 ]--