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

📄 ipmi_kcs_intf.c

📁 一个2.4.21版本的嵌入式linux内核
💻 C
📖 第 1 页 / 共 3 页
字号:
MODULE_PARM(kcs_addrs, "1-4l");MODULE_PARM(kcs_irqs, "1-4i");MODULE_PARM(kcs_ports, "1-4i");/* Returns 0 if initialized, or negative on an error. */static int init_one_kcs(int kcs_port, 			int irq, 			unsigned long kcs_physaddr,			struct kcs_info **kcs){	int		rv;	struct kcs_info *new_kcs;	/* Did anything get passed in at all?  Both == zero disables the	   driver. */	if (!(kcs_port || kcs_physaddr)) 		return -ENODEV;		/* Only initialize a port OR a physical address on this call.	   Also, IRQs can go with either ports or addresses. */	if (kcs_port && kcs_physaddr)		return -EINVAL;	new_kcs = kmalloc(sizeof(*new_kcs), GFP_KERNEL);	if (!new_kcs) {		printk(KERN_ERR "ipmi_kcs: out of memory\n");		return -ENOMEM;	}	/* So we know not to free it unless we have allocated one. */	new_kcs->kcs_sm = NULL;	new_kcs->addr = NULL;	new_kcs->physaddr = kcs_physaddr;	new_kcs->port = kcs_port;	if (kcs_port) {		if (request_region(kcs_port, 2, DEVICE_NAME) == NULL) {			kfree(new_kcs);			printk(KERN_ERR 			       "ipmi_kcs: can't reserve port @ 0x%4.4x\n",		       	       kcs_port);			return -EIO;		}	} else {		if (request_mem_region(kcs_physaddr, 2, DEVICE_NAME) == NULL) {			kfree(new_kcs);			printk(KERN_ERR 			       "ipmi_kcs: can't reserve memory @ 0x%lx\n",		       	       kcs_physaddr);			return -EIO;		}		if ((new_kcs->addr = ioremap(kcs_physaddr, 2)) == NULL) {			kfree(new_kcs);			printk(KERN_ERR 			       "ipmi_kcs: can't remap memory at 0x%lx\n",		       	       kcs_physaddr);			return -EIO;		}	}	new_kcs->kcs_sm = kmalloc(kcs_size(), GFP_KERNEL);	if (!new_kcs->kcs_sm) {		printk(KERN_ERR "ipmi_kcs: out of memory\n");		rv = -ENOMEM;		goto out_err;	}	init_kcs_data(new_kcs->kcs_sm, kcs_port, new_kcs->addr);	spin_lock_init(&(new_kcs->kcs_lock));	spin_lock_init(&(new_kcs->msg_lock));	rv = ipmi_kcs_detect_hardware(kcs_port, new_kcs->addr, new_kcs->kcs_sm);	if (rv) {		if (kcs_port) 			printk(KERN_ERR 			       "ipmi_kcs: No KCS @ port 0x%4.4x\n", 			       kcs_port);		else			printk(KERN_ERR 			       "ipmi_kcs: No KCS @ addr 0x%lx\n", 			       kcs_physaddr);		goto out_err;	}	if (irq != 0) {		rv = request_irq(irq,				 kcs_irq_handler,				 SA_INTERRUPT,				 DEVICE_NAME,				 new_kcs);		if (rv) {			printk(KERN_WARNING			       "ipmi_kcs: %s unable to claim interrupt %d,"			       " running polled\n",			       DEVICE_NAME, irq);			irq = 0;		}	}	new_kcs->irq = irq;	INIT_LIST_HEAD(&(new_kcs->xmit_msgs));	INIT_LIST_HEAD(&(new_kcs->hp_xmit_msgs));	new_kcs->curr_msg = NULL;	atomic_set(&new_kcs->req_events, 0);	new_kcs->run_to_completion = 0;	start_clear_flags(new_kcs);	if (irq) {		new_kcs->kcs_state = KCS_CLEARING_FLAGS_THEN_SET_IRQ;		printk(KERN_INFO 		       "ipmi_kcs: Acquiring BMC @ port=0x%x irq=%d\n",		       kcs_port, irq);	} else {		if (kcs_port)			printk(KERN_INFO 			       "ipmi_kcs: Acquiring BMC @ port=0x%x\n",		       	       kcs_port);		else			printk(KERN_INFO 			       "ipmi_kcs: Acquiring BMC @ addr=0x%lx\n",		       	       kcs_physaddr);	}	rv = ipmi_register_smi(&handlers,			       new_kcs,			       ipmi_version_major,			       ipmi_version_minor,			       &(new_kcs->intf));	if (rv) {		free_irq(irq, new_kcs);		printk(KERN_ERR 		       "ipmi_kcs: Unable to register device: error %d\n",		       rv);		goto out_err;	}	new_kcs->interrupt_disabled = 0;	new_kcs->timer_stopped = 0;	new_kcs->stop_operation = 0;	init_timer(&(new_kcs->kcs_timer));	new_kcs->kcs_timer.data = (long) new_kcs;	new_kcs->kcs_timer.function = kcs_timeout;	new_kcs->last_timeout_jiffies = jiffies;	new_kcs->kcs_timer.expires = jiffies + KCS_TIMEOUT_JIFFIES;	add_timer(&(new_kcs->kcs_timer));	*kcs = new_kcs;	return 0; out_err:	if (kcs_port) 		release_region (kcs_port, 2);	if (new_kcs->addr) 		iounmap(new_kcs->addr);	if (kcs_physaddr) 		release_mem_region(kcs_physaddr, 2);	if (new_kcs->kcs_sm)		kfree(new_kcs->kcs_sm);	kfree(new_kcs);	return rv;}#ifdef CONFIG_ACPI/* Retrieve the base physical address from ACPI tables.  Originally   from Hewlett-Packard simple bmc.c, a GPL KCS driver. */#include <linux/acpi.h>/* A real hack, but everything's not there yet in 2.4. */#define COMPILER_DEPENDENT_UINT64 unsigned long#include <../drivers/acpi/include/acpi.h>#include <../drivers/acpi/include/actypes.h>struct SPMITable {	s8	Signature[4];	u32	Length;	u8	Revision;	u8	Checksum;	s8	OEMID[6];	s8	OEMTableID[8];	s8	OEMRevision[4];	s8	CreatorID[4];	s8	CreatorRevision[4];	s16	InterfaceType;	s16	SpecificationRevision;	u8	InterruptType;	u8	GPE;	s16	Reserved;	u64	GlobalSystemInterrupt;	u8	BaseAddress[12];	u8	UID[4];} __attribute__ ((packed));static unsigned long acpi_find_bmc(void){	acpi_status       status;	acpi_table_header *spmi;	static unsigned long io_base = 0;	if (io_base != 0)		return io_base;	status = acpi_get_firmware_table("SPMI", 1,			ACPI_LOGICAL_ADDRESSING, &spmi);	if (status != AE_OK) {		printk(KERN_ERR "ipmi_kcs: SPMI table not found.\n");		return 0;	}	memcpy(&io_base, ((struct SPMITable *)spmi)->BaseAddress,			sizeof(io_base));		return io_base;}#endifstatic __init int init_ipmi_kcs(void){	int		rv = 0;	int		pos = 0;	int		i = 0;#ifdef CONFIG_ACPI	unsigned long	physaddr = 0;#endif	if (initialized)		return 0;	initialized = 1;	/* First do the "command-line" parameters */	for (i=0; i < KCS_MAX_PARMS; i++) {		rv = init_one_kcs(kcs_ports[i], 				  kcs_irqs[i], 				  0, 				  &(kcs_infos[pos]));		if (rv == 0)			pos++;		rv = init_one_kcs(0, 				  kcs_irqs[i], 				  kcs_addrs[i], 				  &(kcs_infos[pos]));		if (rv == 0)			pos++;	}	/* Only try the defaults if enabled and resources are available	   (because they weren't already specified above). */	if (kcs_trydefaults) {#ifdef CONFIG_ACPI		if ((physaddr = acpi_find_bmc())) {			if (!check_mem_region(physaddr, 2)) {				rv = init_one_kcs(0, 						  0, 						  physaddr, 						  &(kcs_infos[pos]));				if (rv == 0)					pos++;			}		}#endif		if (!check_region(DEFAULT_IO_PORT, 2)) {			rv = init_one_kcs(DEFAULT_IO_PORT, 					  0, 					  0, 					  &(kcs_infos[pos]));			if (rv == 0)				pos++;		}	}	if (kcs_infos[0] == NULL) {		printk("ipmi_kcs: Unable to find any KCS interfaces\n");		return -ENODEV;	} 	return 0;}module_init(init_ipmi_kcs);#ifdef MODULEvoid __exit cleanup_one_kcs(struct kcs_info *to_clean){	int           rv;	unsigned long flags;	if (! to_clean)		return;	/* Tell the timer and interrupt handlers that we are shutting	   down. */	spin_lock_irqsave(&(to_clean->kcs_lock), flags);	spin_lock(&(to_clean->msg_lock));	to_clean->stop_operation = 1;	if (to_clean->irq != 0)		free_irq(to_clean->irq, to_clean);	if (to_clean->port) {		printk(KERN_INFO 		       "ipmi_kcs: Releasing BMC @ port=0x%x\n",		       to_clean->port);		release_region (to_clean->port, 2);	}	if (to_clean->addr) {		printk(KERN_INFO 		       "ipmi_kcs: Releasing BMC @ addr=0x%lx\n",		       to_clean->physaddr);		iounmap(to_clean->addr);		release_mem_region(to_clean->physaddr, 2);	}	spin_unlock(&(to_clean->msg_lock));	spin_unlock_irqrestore(&(to_clean->kcs_lock), flags);	/* Wait for the timer to stop.  This avoids problems with race	   conditions removing the timer here.  Hopefully this will be	   long enough to avoid problems with interrupts still	   running. */	schedule_timeout(2);	while (!to_clean->timer_stopped) {		schedule_timeout(1);	}	rv = ipmi_unregister_smi(to_clean->intf);	if (rv) {		printk(KERN_ERR 		       "ipmi_kcs: Unable to unregister device: errno=%d\n",		       rv);	}	initialized = 0;	kfree(to_clean->kcs_sm);	kfree(to_clean);}static __exit void cleanup_ipmi_kcs(void){	int i;	if (!initialized)		return;	for (i=0; i<KCS_MAX_DRIVERS; i++) {		cleanup_one_kcs(kcs_infos[i]);	}}module_exit(cleanup_ipmi_kcs);#else/* Unfortunately, cmdline::get_options() only returns integers, not   longs.  Since we need ulongs (64-bit physical addresses) parse the    comma-separated list manually.  Arguments can be one of these forms:   m0xaabbccddeeff	A physical memory address without an IRQ   m0xaabbccddeeff:cc	A physical memory address with an IRQ   p0xaabb		An IO port without an IRQ   p0xaabb:cc		An IO port with an IRQ   nodefaults		Suppress trying the default IO port or ACPI address    For example, to pass one IO port with an IRQ, one address, and    suppress the use of the default IO port and ACPI address,   use this option string: ipmi_kcs=p0xCA2:5,m0xFF5B0022,nodefaults   Remember, ipmi_kcs_setup() is passed the string after the equal sign. */static int __init ipmi_kcs_setup(char *str){	unsigned long val;	char *cur, *colon;	int pos;	pos = 0;		cur = strsep(&str, ",");	while ((cur) && (*cur) && (pos < KCS_MAX_PARMS)) {		switch (*cur) {		case 'n':			if (strcmp(cur, "nodefaults") == 0)				kcs_trydefaults = 0;			else				printk(KERN_INFO 				       "ipmi_kcs: bad parameter value %s\n",				       cur);			break;				case 'm':		case 'p':			val = simple_strtoul(cur + 1,					     &colon,					     0);			if (*cur == 'p')				kcs_ports[pos] = val;			else				kcs_addrs[pos] = val;			if (*colon == ':') {				val = simple_strtoul(colon + 1,						     &colon,						     0);				kcs_irqs[pos] = val;			}			pos++;			break;		default:			printk(KERN_INFO 			       "ipmi_kcs: bad parameter value %s\n",			       cur);		}		cur = strsep(&str, ",");	}	return 1;}__setup("ipmi_kcs=", ipmi_kcs_setup);#endifMODULE_LICENSE("GPL");

⌨️ 快捷键说明

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