📄 pci.c
字号:
/* 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
*
*/
long pci_restore_state(struct pci_dev far * dev, u32 far * 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,
(unsigned char)dev->irq);
}
return 0;
}
#endif
long pcibios_enable_resources(struct pci_dev far * dev)
{
u16 cmd, old_cmd;
long idx;
struct resource far * r;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
for(idx=0; idx < 6; idx++)
{
r = &dev->resource[idx];
if (!r->start && r->end)
{
#ifdef DEBUG_VERSION
safe_printf("PCI: Device %s not available because of resource collisions\n",
dev->slot_name);
#endif
return -EINVAL;
}
if (r->flags & IORESOURCE_IO)
cmd |= PCI_COMMAND_IO;
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
if (dev->resource[PCI_ROM_RESOURCE].start)
cmd |= PCI_COMMAND_MEMORY;
if (cmd != old_cmd)
{
#ifdef DEBUG_VERSION
safe_printf("PCI: Enabling device %s (%04x -> %04x)\n", dev->slot_name, old_cmd, cmd);
#endif
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
return 0;
}
void pcibios_enable_irq(struct pci_dev far * dev)
{
u8 pin;
long status;
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if(pin)
status = pcibios_lookup_irq(dev, 1);
if (pin && !status && !dev->irq)
{
char *msg;
if (pci_probe & PCI_BIOS_IRQ_SCAN)
msg = "";
else
msg = " Please try using pci=biosirq.";
#ifdef DEBUG_VERSION
safe_printf("PCI: No IRQ known for interrupt pin %c of device %s.%s\n",
'A' + pin - 1, dev->slot_name, msg);
#endif
}
}
long pcibios_enable_device(struct pci_dev far * dev)
{
int err;
if ((err = pcibios_enable_resources(dev)) < 0)
return err;
pcibios_enable_irq(dev);
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.
*/
long pci_enable_device(struct pci_dev far * dev)
{
long 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 far * 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.
*
*/
long pci_enable_wake(struct pci_dev far * dev, u32 state, long enable)
{
long 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;
}
/**
* 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 far * pci_match_device(const struct pci_device_id far * ids,
const struct pci_dev far * 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;
}
extern struct pci_driver pci_compat_driver;
/**
* 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 far * pci_dev_driver(const struct pci_dev far * 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;
}
long pci_announce_device(struct pci_driver far * drv, struct pci_dev far * dev)
{
const struct pci_device_id far * id;
long ret = 0;
int i;
if (drv->id_table)
{
id = pci_match_device(drv->id_table, dev);
if (!id)
{
ret = 0;
goto out;
}
}
else
id = NULL;
local_irq_save(0);
if(drv->probe)
{
if(drv->probe(dev, id) >= 0)
{
dev->driver = drv;
ret = 1;
}
}
else
{
ret = 0;
}
local_irq_restore(0);
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.
*/
long pci_register_driver(struct pci_driver far * drv)
{
struct pci_dev far * 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 far * drv)
{
struct pci_dev far * dev;
list_del(&drv->node);
pci_for_each_dev(dev)
{
if (dev->driver == drv)
{
if (drv->remove)
drv->remove(dev);
dev->driver = NULL;
}
}
}
/*
* a helper function which helps ensure correct pci_driver
* setup and cleanup for commonly-encountered hotplug/modular cases
*
* This MUST stay in a header, as it checks for -DMODULE
*/
long pci_module_init(struct pci_driver far * drv)
{
int rc = pci_register_driver (drv);
if (rc > 0)
return 0;
/* if we get here, we need to clean up pci driver instance
* and return some sort of error */
pci_unregister_driver (drv);
return -1;
}
struct resource far * __request_region(struct resource far * parent, unsigned long start, unsigned long n,
const char far * name)
{
struct resource far * res = malloc(sizeof(struct resource));
if (res)
{
memset(res, 0, sizeof(*res));
res->name = name;
res->start = start;
res->end = start + n - 1;
res->flags = IORESOURCE_BUSY;
local_irq_save(0);
for (;;)
{
struct resource far * conflict;
conflict = __request_resource(parent, res);
if(!conflict)
break;
if(conflict != parent)
{
parent = conflict;
if (!(conflict->flags & IORESOURCE_BUSY))
continue;
}
free(res);
res = NULL;
break;
}
local_irq_restore(0);
}
return res;
}
long __check_region(struct resource far * parent, unsigned long start, unsigned long n)
{
struct resource far * res;
res = __request_region(parent, start, n, "check-region");
if (!res)
return -EBUSY;
release_resource(res);
free(res);
return 0;
}
void __release_region(struct resource *parent, unsigned long start, unsigned long n)
{
struct resource far **p;
unsigned long end;
p = &parent->child;
end = start + n - 1;
for (;;)
{
struct resource far * res = *p;
if (!res)
break;
if (res->start <= start && res->end >= end)
{
if (!(res->flags & IORESOURCE_BUSY))
{
p = &res->child;
continue;
}
if (res->start != start || res->end != end)
break;
*p = res->sibling;
free(res);
return;
}
p = &res->sibling;
}
#ifdef DEBUG_VERSION
safe_printf("Trying to free nonexistent resource <%08lx-%08lx>\n", start, end);
#endif
}
void pcibios_set_master(struct pci_dev far * dev)
{
u8 lat;
pci_read_config_byte(dev, PCI_LATENCY_TIMER, &lat);
if (lat >= 16)
return;
/*
** HP generally has fewer devices on the bus than other architectures.
*/
#ifdef DEBUG_VERSION
safe_printf("PCIBIOS: Setting latency timer of %s to 128\n", dev->slot_name);
#endif
pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
}
void pci_set_master(struct pci_dev far * dev)
{
u16 cmd;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_MASTER))
{
#ifdef DEBUG_VERSION
safe_printf("PCI: Enabling bus mastering for device %s\n", dev->slot_name);
#endif
cmd |= PCI_COMMAND_MASTER;
pci_write_config_word(dev, PCI_COMMAND, cmd);
}
pcibios_set_master(dev);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -