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

📄 cpqphp_core.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * 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> * * Jan 12, 2003 -	Added 66/100/133MHz PCI-X support, * 			Torben Mathiasen <torben.mathiasen@hp.com> * */#include <linux/config.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/kernel.h>#include <linux/types.h>#include <linux/proc_fs.h>#include <linux/slab.h>#include <linux/workqueue.h>#include <linux/pci.h>#include <linux/init.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include "cpqphp.h"#include "cpqphp_nvram.h"#include "../../../arch/i386/pci/pci.h"	/* horrible hack showing how processor dependent we are... *//* Global variables */int cpqhp_debug;int cpqhp_legacy_mode;struct controller *cpqhp_ctrl_list;	/* = NULL */struct pci_func *cpqhp_slot_list[256];/* local variables */static void *smbios_table;static void *smbios_start;static void *cpqhp_rom_start;static int power_mode;static int debug;#define DRIVER_VERSION	"0.9.8"#define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"#define DRIVER_DESC	"Compaq Hot Plug PCI Controller Driver"MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");module_param(power_mode, bool, 644);MODULE_PARM_DESC(power_mode, "Power mode enabled or not");module_param(debug, bool, 644);MODULE_PARM_DESC(debug, "Debugging mode enabled or not");#define CPQHPC_MODULE_MINOR 208static int one_time_init	(void);static int set_attention_status	(struct hotplug_slot *slot, u8 value);static int process_SI		(struct hotplug_slot *slot);static int process_SS		(struct hotplug_slot *slot);static int hardware_test	(struct hotplug_slot *slot, u32 value);static int get_power_status	(struct hotplug_slot *slot, u8 *value);static int get_attention_status	(struct hotplug_slot *slot, u8 *value);static int get_latch_status	(struct hotplug_slot *slot, u8 *value);static int get_adapter_status	(struct hotplug_slot *slot, u8 *value);static int get_max_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);static int get_cur_bus_speed	(struct hotplug_slot *slot, enum pci_bus_speed *value);static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = {	.owner =		THIS_MODULE,	.set_attention_status =	set_attention_status,	.enable_slot =		process_SI,	.disable_slot =		process_SS,	.hardware_test =	hardware_test,	.get_power_status =	get_power_status,	.get_attention_status =	get_attention_status,	.get_latch_status =	get_latch_status,	.get_adapter_status =	get_adapter_status,  	.get_max_bus_speed =	get_max_bus_speed,  	.get_cur_bus_speed =	get_cur_bus_speed,};static inline int is_slot64bit(struct slot *slot){	return (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) ? 1 : 0;}static inline int is_slot66mhz(struct slot *slot){	return (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) ? 1 : 0;}/** * detect_SMBIOS_pointer - find the System Management BIOS Table in mem region. * * @begin: begin pointer for region to be scanned. * @end: end pointer for region to be scanned. * * Returns pointer to the head of the SMBIOS tables (or NULL) * */static void * detect_SMBIOS_pointer(void *begin, void *end){	void *fp;	void *endp;	u8 temp1, temp2, temp3, temp4;	int status = 0;	endp = (end - sizeof(u32) + 1);	for (fp = begin; fp <= endp; fp += 16) {		temp1 = readb(fp);		temp2 = readb(fp+1);		temp3 = readb(fp+2);		temp4 = readb(fp+3);		if (temp1 == '_' &&		    temp2 == 'S' &&		    temp3 == 'M' &&		    temp4 == '_') {			status = 1;			break;		}	}		if (!status)		fp = NULL;	dbg("Discovered SMBIOS Entry point at %p\n", fp);	return fp;}/** * init_SERR - Initializes the per slot SERR generation. * * For unexpected switch opens * */static int init_SERR(struct controller * ctrl){	u32 tempdword;	u32 number_of_slots;	u8 physical_slot;	if (!ctrl)		return 1;	tempdword = ctrl->first_slot;	number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F;	// Loop through slots	while (number_of_slots) {		physical_slot = tempdword;		writeb(0, ctrl->hpc_reg + SLOT_SERR);		tempdword++;		number_of_slots--;	}	return 0;}/* nice debugging output */static int pci_print_IRQ_route (void){	struct irq_routing_table *routing_table;	int len;	int loop;	u8 tbus, tdevice, tslot;	routing_table = pcibios_get_irq_routing_table();	if (routing_table == NULL) {		err("No BIOS Routing Table??? Not good\n");		return -ENOMEM;	}	len = (routing_table->size - sizeof(struct irq_routing_table)) /			sizeof(struct irq_info);	// Make sure I got at least one entry	if (len == 0) {		kfree(routing_table);		return -1;	}	dbg("bus dev func slot\n");	for (loop = 0; loop < len; ++loop) {		tbus = routing_table->slots[loop].bus;		tdevice = routing_table->slots[loop].devfn;		tslot = routing_table->slots[loop].slot;		dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot);	}	kfree(routing_table);	return 0;}/** * get_subsequent_smbios_entry: get the next entry from bios table. * * Gets the first entry if previous == NULL * Otherwise, returns the next entry * Uses global SMBIOS Table pointer * * @curr: %NULL or pointer to previously returned structure * * returns a pointer to an SMBIOS structure or NULL if none found */static void *get_subsequent_smbios_entry(void *smbios_start,			void *smbios_table, void *curr){	u8 bail = 0;	u8 previous_byte = 1;	void *p_temp;	void *p_max;	if (!smbios_table || !curr)		return(NULL);	// set p_max to the end of the table	p_max = smbios_start + readw(smbios_table + ST_LENGTH);	p_temp = curr;	p_temp += readb(curr + SMBIOS_GENERIC_LENGTH);	while ((p_temp < p_max) && !bail) {		/* Look for the double NULL terminator		 * The first condition is the previous byte		 * and the second is the curr */		if (!previous_byte && !(readb(p_temp))) {			bail = 1;		}		previous_byte = readb(p_temp);		p_temp++;	}	if (p_temp < p_max) {		return p_temp;	} else {		return NULL;	}}/** * get_SMBIOS_entry * * @type:SMBIOS structure type to be returned * @previous: %NULL or pointer to previously returned structure * * Gets the first entry of the specified type if previous == NULL * Otherwise, returns the next entry of the given type. * Uses global SMBIOS Table pointer * Uses get_subsequent_smbios_entry * * returns a pointer to an SMBIOS structure or %NULL if none found */static void *get_SMBIOS_entry(void *smbios_start, void *smbios_table, u8 type,			void * previous){	if (!smbios_table)		return NULL;	if (!previous) {		  		previous = smbios_start;	} else {		previous = get_subsequent_smbios_entry(smbios_start,					smbios_table, previous);	}	while (previous) {	       	if (readb(previous + SMBIOS_GENERIC_TYPE) != type) {			previous = get_subsequent_smbios_entry(smbios_start,						smbios_table, previous);		} else {			break;		}	}	return previous;}static void release_slot(struct hotplug_slot *hotplug_slot){	struct slot *slot = hotplug_slot->private;	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);	kfree(slot->hotplug_slot->info);	kfree(slot->hotplug_slot->name);	kfree(slot->hotplug_slot);	kfree(slot);}static int ctrl_slot_setup(struct controller * ctrl, void *smbios_start,			void *smbios_table){	struct slot *new_slot;	u8 number_of_slots;	u8 slot_device;	u8 slot_number;	u8 ctrl_slot;	u32 tempdword;	void *slot_entry= NULL;	int result = -ENOMEM;	dbg("%s\n", __FUNCTION__);	tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR);	number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F;	slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4;	slot_number = ctrl->first_slot;	while (number_of_slots) {		new_slot = kmalloc(sizeof(*new_slot), GFP_KERNEL);		if (!new_slot)			goto error;		memset(new_slot, 0, sizeof(struct slot));		new_slot->hotplug_slot = kmalloc(sizeof(*(new_slot->hotplug_slot)),						GFP_KERNEL);		if (!new_slot->hotplug_slot)			goto error_slot;		memset(new_slot->hotplug_slot, 0, sizeof(struct hotplug_slot));		new_slot->hotplug_slot->info =				kmalloc(sizeof(*(new_slot->hotplug_slot->info)),							GFP_KERNEL);		if (!new_slot->hotplug_slot->info)			goto error_hpslot;		memset(new_slot->hotplug_slot->info, 0,				sizeof(struct hotplug_slot_info));		new_slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);		if (!new_slot->hotplug_slot->name)			goto error_info;		new_slot->ctrl = ctrl;		new_slot->bus = ctrl->bus;		new_slot->device = slot_device;		new_slot->number = slot_number;		dbg("slot->number = %d\n",new_slot->number);		slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9,					slot_entry);		while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) {			slot_entry = get_SMBIOS_entry(smbios_start,						smbios_table, 9, slot_entry);		}		new_slot->p_sm_slot = slot_entry;		init_timer(&new_slot->task_event);		new_slot->task_event.expires = jiffies + 5 * HZ;		new_slot->task_event.function = cpqhp_pushbutton_thread;		//FIXME: these capabilities aren't used but if they are		//       they need to be correctly implemented		new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED;		new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED;		if (is_slot64bit(new_slot))			new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED;		if (is_slot66mhz(new_slot))			new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED;		if (ctrl->speed == PCI_SPEED_66MHz)			new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION;		ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4);		// Check presence		new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02;		// Check the switch state		new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01;		// Check the slot enable		new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04;		/* register this slot with the hotplug pci core */		new_slot->hotplug_slot->release = &release_slot;		new_slot->hotplug_slot->private = new_slot;		make_slot_name(new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot);		new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops;				new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot);		new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot);		new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot);		new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot);				dbg ("registering bus %d, dev %d, number %d, "				"ctrl->slot_device_offset %d, slot %d\n",				new_slot->bus, new_slot->device,				new_slot->number, ctrl->slot_device_offset,				slot_number);		result = pci_hp_register (new_slot->hotplug_slot);		if (result) {			err ("pci_hp_register failed with error %d\n", result);			goto error_name;		}				new_slot->next = ctrl->slot;		ctrl->slot = new_slot;		number_of_slots--;		slot_device++;		slot_number++;	}	return 0;error_name:	kfree(new_slot->hotplug_slot->name);error_info:	kfree(new_slot->hotplug_slot->info);error_hpslot:	kfree(new_slot->hotplug_slot);error_slot:	kfree(new_slot);error:	return result;}static int ctrl_slot_cleanup (struct controller * ctrl){	struct slot *old_slot, *next_slot;	old_slot = ctrl->slot;	ctrl->slot = NULL;	while (old_slot) {		/* memory will be freed by the release_slot callback */		next_slot = old_slot->next;		pci_hp_deregister (old_slot->hotplug_slot);		old_slot = next_slot;	}	//Free IRQ associated with hot plug device	free_irq(ctrl->interrupt, ctrl);	//Unmap the memory	iounmap(ctrl->hpc_reg);	//Finally reclaim PCI mem	release_mem_region(pci_resource_start(ctrl->pci_dev, 0),			   pci_resource_len(ctrl->pci_dev, 0));	return(0);}//============================================================================// function:	get_slot_mapping//// Description: Attempts to determine a logical slot mapping for a PCI//		device.  Won't work for more than one PCI-PCI bridge//		in a slot.//// Input:	u8 bus_num - bus number of PCI device//		u8 dev_num - device number of PCI device//		u8 *slot - Pointer to u8 where slot number will//			be returned//// Output:	SUCCESS or FAILURE//=============================================================================static intget_slot_mapping(struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot){	struct irq_routing_table *PCIIRQRoutingInfoLength;	u32 work;	long len;	long loop;	u8 tbus, tdevice, tslot, bridgeSlot;	dbg("%s: %p, %d, %d, %p\n", __FUNCTION__, bus, bus_num, dev_num, slot);	bridgeSlot = 0xFF;

⌨️ 快捷键说明

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