⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pci.c

📁 DOS_PCI_DRIVER,DOS环境下运行的PCI驱动程序,个人觉得比较好用.
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* 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 + -