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

📄 cpqphp_pci.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Compaq Hot Plug Controller Driver * * Copyright (c) 1995,2001 Compaq Computer Corporation * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) * Copyright (c) 2001 IBM Corp. * * All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT.  See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * Send feedback to <greg@kroah.com> * */#include <linux/config.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/proc_fs.h>#include <linux/pci.h>#include "cpqphp.h"#include "cpqphp_nvram.h"#include "../../arch/i386/kernel/pci-i386.h"	/* horrible hack showing how processor dependant we are... */u8 cpqhp_nic_irq;u8 cpqhp_disk_irq;static u16 unused_IRQ;static int is_pci_dev_in_use(struct pci_dev* dev) {	/* 	 * dev->driver will be set if the device is in use by a new-style 	 * driver -- otherwise, check the device's regions to see if any	 * driver has claimed them	 */	int i, inuse=0;	if (dev->driver) return 1; //assume driver feels responsible	for (i = 0; !dev->driver && !inuse && (i < 6); i++) {		if (!pci_resource_start(dev, i))			continue;		if (pci_resource_flags(dev, i) & IORESOURCE_IO)			inuse = check_region(pci_resource_start(dev, i),					     pci_resource_len(dev, i));		else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)			inuse = check_mem_region(pci_resource_start(dev, i),						 pci_resource_len(dev, i));	}	return inuse;}static int pci_hp_remove_device(struct pci_dev *dev){	if (is_pci_dev_in_use(dev)) {		err("***Cannot safely power down device -- "		       "it appears to be in use***\n");		return -EBUSY;	}	pci_remove_device(dev);	return 0;}/* * detect_HRT_floating_pointer * * find the Hot Plug Resource Table in the specified region of memory. * */static void *detect_HRT_floating_pointer(void *begin, void *end){	void *fp;	void *endp;	u8 temp1, temp2, temp3, temp4;	int status = 0;	endp = (end - sizeof(struct hrt) + 1);	for (fp = begin; fp <= endp; fp += 16) {		temp1 = readb(fp + SIG0);		temp2 = readb(fp + SIG1);		temp3 = readb(fp + SIG2);		temp4 = readb(fp + SIG3);		if (temp1 == '$' &&		    temp2 == 'H' &&		    temp3 == 'R' &&		    temp4 == 'T') {			status = 1;			break;		}	}	if (!status)		fp = NULL;	dbg("Discovered Hotplug Resource Table at %p\n", fp);	return fp;}static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) {	struct pci_bus* bus = wrapped_bus->bus;	struct pci_dev* dev = wrapped_dev->dev;	struct pci_func *temp_func;	int i=0;	//We need to fix up the hotplug function representation with the linux representation	do {		temp_func = cpqhp_slot_find(dev->bus->number, dev->devfn >> 3, i++);	} while (temp_func && (temp_func->function != (dev->devfn & 0x07)));	if (temp_func) {		temp_func->pci_dev = dev;	} else {		//We did not even find a hotplug rep of the function, create it		//This code might be taken out if we can guarantee the creation of functions		//in parallel (hotplug and Linux at the same time).		dbg("@@@@@@@@@@@ cpqhp_slot_create in "__FUNCTION__"\n");		temp_func = cpqhp_slot_create(bus->number);		if (temp_func == NULL)			return -ENOMEM;		temp_func->pci_dev = dev;	}	//Create /proc/bus/pci proc entry for this device and bus device is on	//Notify the drivers of the change	if (temp_func->pci_dev) {		pci_proc_attach_device(temp_func->pci_dev);		pci_announce_device_to_drivers(temp_func->pci_dev);	}	return 0;}static int unconfigure_visit_pci_dev_phase2 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) {	struct pci_dev* dev = wrapped_dev->dev;	struct pci_func *temp_func;	int i=0;	//We need to remove the hotplug function representation with the linux representation	do {		temp_func = cpqhp_slot_find(dev->bus->number, dev->devfn >> 3, i++);		if (temp_func) {			dbg("temp_func->function = %d\n", temp_func->function);		}	} while (temp_func && (temp_func->function != (dev->devfn & 0x07)));	//Now, remove the Linux Representation	if (dev) {		if (pci_hp_remove_device(dev) == 0) {			kfree(dev); //Now, remove		} else {			return -1; // problems while freeing, abort visitation		}	}	if (temp_func) {		temp_func->pci_dev = NULL;	} else {		dbg("No pci_func representation for bus, devfn = %d, %x\n", dev->bus->number, dev->devfn);	}	return 0;}static int unconfigure_visit_pci_bus_phase2 (struct pci_bus_wrapped *wrapped_bus, struct pci_dev_wrapped *wrapped_dev) {	struct pci_bus* bus = wrapped_bus->bus;	//The cleanup code for proc entries regarding buses should be in the kernel...	if (bus->procdir)		dbg("detach_pci_bus %s\n", bus->procdir->name);	pci_proc_detach_bus(bus);	// The cleanup code should live in the kernel...	bus->self->subordinate = NULL;	// unlink from parent bus	list_del(&bus->node);	// Now, remove	if (bus)		kfree(bus);	return 0;}static int unconfigure_visit_pci_dev_phase1 (struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_bus) {	struct pci_dev* dev = wrapped_dev->dev;	dbg("attempting removal of driver for device (%x, %x, %x)\n", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));	//Now, remove the Linux Driver Representation 	if (dev->driver) {		if (dev->driver->remove) {			dev->driver->remove(dev);			dbg("driver was properly removed\n");		}		dev->driver = NULL;	}	return is_pci_dev_in_use(dev);}static struct pci_visit configure_functions = {	visit_pci_dev:		configure_visit_pci_dev,};static struct pci_visit unconfigure_functions_phase1 = {	post_visit_pci_dev:	unconfigure_visit_pci_dev_phase1};static struct pci_visit unconfigure_functions_phase2 = {	post_visit_pci_bus:	unconfigure_visit_pci_bus_phase2,               	post_visit_pci_dev:	unconfigure_visit_pci_dev_phase2};int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func)  {	unsigned char bus;	struct pci_dev dev0;	struct pci_bus *child;	struct pci_dev* temp;	int rc = 0;	struct pci_dev_wrapped wrapped_dev;	struct pci_bus_wrapped wrapped_bus;	memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));	memset(&dev0, 0, sizeof(struct pci_dev));	if (func->pci_dev == NULL)		func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7));	//Still NULL ? Well then scan for it !	if (func->pci_dev == NULL) {		dbg("INFO: pci_dev still null\n");		dev0.bus = ctrl->pci_dev->bus;		dev0.devfn = (func->device << 3) + (func->function & 0x7);		dev0.sysdata = ctrl->pci_dev->sysdata;		//this will generate pci_dev structures for all functions, but we will only call this case when lookup fails		func->pci_dev = pci_scan_slot(&dev0);		if (func->pci_dev == NULL) {			dbg("ERROR: pci_dev still null\n");			return 0;		}	}	if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);		child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);		pci_do_scan_bus(child);	}	temp = func->pci_dev;	if (temp) {		wrapped_dev.dev = temp;		wrapped_bus.bus = temp->bus;		rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);	}	return rc;}int cpqhp_unconfigure_device(struct pci_func* func) {	int rc = 0;	int j;	struct pci_dev_wrapped wrapped_dev;	struct pci_bus_wrapped wrapped_bus;		memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));	dbg(__FUNCTION__": bus/dev/func = %x/%x/%x\n",func->bus, func->device, func->function);	for (j=0; j<8 ; j++) {		struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j);		if (temp) {			wrapped_dev.dev = temp;			wrapped_bus.bus = temp->bus;			rc = pci_visit_dev(&unconfigure_functions_phase1, &wrapped_dev, &wrapped_bus);			if (rc)				break;			rc = pci_visit_dev(&unconfigure_functions_phase2, &wrapped_dev, &wrapped_bus);			if (rc)				break;		}	}	return rc;}static int PCI_RefinedAccessConfig(struct pci_ops *ops, u8 bus, u8 device, u8 function, u8 offset, u32 *value){	u32 vendID = 0;	if (pci_read_config_dword_nodev (ops, bus, device, function, PCI_VENDOR_ID, &vendID) == -1)		return -1;	if (vendID == 0xffffffff)		return -1;	return pci_read_config_dword_nodev (ops, bus, device, function, offset, value);}/* * cpqhp_set_irq * * @bus_num: bus number of PCI device * @dev_num: device number of PCI device * @slot: pointer to u8 where slot number will be returned */int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num){	int rc;	u16 temp_word;	struct pci_dev fakedev;	struct pci_bus fakebus;	fakedev.devfn = dev_num << 3;	fakedev.bus = &fakebus;	fakebus.number = bus_num;	dbg(__FUNCTION__": dev %d, bus %d, pin %d, num %d\n",	    dev_num, bus_num, int_pin, irq_num);	rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num);	dbg(__FUNCTION__":rc %d\n", rc);	if (rc)		return rc;	// set the Edge Level Control Register (ELCR)	temp_word = inb(0x4d0);	temp_word |= inb(0x4d1) << 8;	temp_word |= 0x01 << irq_num;	// This should only be for x86 as it sets the Edge Level Control Register	outb((u8) (temp_word & 0xFF), 0x4d0);	outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1);	return 0;}/* * WTF??? This function isn't in the code, yet a function calls it, but the  * compiler optimizes it away?  strange.  Here as a placeholder to keep the  * compiler happy. */static int PCI_ScanBusNonBridge (u8 bus, u8 device){	return 0;}static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num){	u8 tdevice;	u32 work;	u8 tbus;	for (tdevice = 0; tdevice < 0x100; tdevice++) {		//Scan for access first		if (PCI_RefinedAccessConfig(ctrl->pci_ops, bus_num, tdevice >> 3, tdevice & 0x7, 0x08, &work) == -1)			continue;		dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice);		//Yep we got one. Not a bridge ?		if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) {			*dev_num = tdevice;			dbg("found it !\n");			return 0;		}	}	for (tdevice = 0; tdevice < 0x100; tdevice++) {		//Scan for access first		if (PCI_RefinedAccessConfig(ctrl->pci_ops, bus_num, tdevice >> 3, tdevice & 0x7, 0x08, &work) == -1)			continue;		dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice);		//Yep we got one. bridge ?		if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) {			pci_read_config_byte_nodev (ctrl->pci_ops, tbus, tdevice, 0, PCI_SECONDARY_BUS, &tbus);			dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice);			if (PCI_ScanBusNonBridge(tbus, tdevice) == 0)				return 0;		}	}	return -1;}static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge){	struct irq_routing_table *PCIIRQRoutingInfoLength;	long len;	long loop;	u32 work;	u8 tbus, tdevice, tslot;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -