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

📄 envctrl.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
 * Return: None. */static void envctrl_init_adc(struct i2c_child_t *pchild, int node){	char chnls_desc[CHANNEL_DESC_SZ];	int i = 0, len;	char *pos = chnls_desc;	/* Firmware describe channels into a stream separated by a '\0'. */	len = prom_getproperty(node, "channels-description", chnls_desc,			       CHANNEL_DESC_SZ);	chnls_desc[CHANNEL_DESC_SZ - 1] = '\0';	while (len > 0) {		int l = strlen(pos) + 1;		envctrl_set_mon(pchild, pos, i++);		len -= l;		pos += l;	}	/* Get optional properties. */        len = prom_getproperty(node, "warning-temp", (char *)&warning_temperature,			       sizeof(warning_temperature));        len = prom_getproperty(node, "shutdown-temp", (char *)&shutdown_temperature,			       sizeof(shutdown_temperature));}/* Function Description: Initialize child device monitoring fan status. * Return: None. */static void envctrl_init_fanstat(struct i2c_child_t *pchild){	int i;	/* Go through all channels and set up the mask. */	for (i = 0; i < pchild->total_chnls; i++)		pchild->fan_mask |= chnls_mask[(pchild->chnl_array[i]).chnl_no];	/* We only need to know if this child has fan status monitored.	 * We don't care which channels since we have the mask already.	 */	pchild->mon_type[0] = ENVCTRL_FANSTAT_MON;}/* Function Description: Initialize child device for global addressing line. * Return: None. */static void envctrl_init_globaladdr(struct i2c_child_t *pchild){	int i;	/* Voltage/PowerSupply monitoring is piggybacked 	 * with Global Address on CompactPCI.  See comments	 * within envctrl_i2c_globaladdr for bit assignments.	 *	 * The mask is created here by assigning mask bits to each	 * bit position that represents PCF8584_VOLTAGE_TYPE data.	 * Channel numbers are not consecutive within the globaladdr	 * node (why?), so we use the actual counter value as chnls_mask	 * index instead of the chnl_array[x].chnl_no value.	 *	 * NOTE: This loop could be replaced with a constant representing	 * a mask of bits 5&6 (ENVCTRL_GLOBALADDR_PSTAT_MASK).	 */	for (i = 0; i < pchild->total_chnls; i++) {		if (PCF8584_VOLTAGE_TYPE == pchild->chnl_array[i].type) {			pchild->voltage_mask |= chnls_mask[i];		}	}	/* We only need to know if this child has global addressing 	 * line monitored.  We don't care which channels since we know 	 * the mask already (ENVCTRL_GLOBALADDR_ADDR_MASK).	 */	pchild->mon_type[0] = ENVCTRL_GLOBALADDR_MON;}/* Initialize child device monitoring voltage status. */static void envctrl_init_voltage_status(struct i2c_child_t *pchild){	int i;	/* Go through all channels and set up the mask. */	for (i = 0; i < pchild->total_chnls; i++)		pchild->voltage_mask |= chnls_mask[(pchild->chnl_array[i]).chnl_no];	/* We only need to know if this child has voltage status monitored.	 * We don't care which channels since we have the mask already.	 */	pchild->mon_type[0] = ENVCTRL_VOLTAGESTAT_MON;}/* Function Description: Initialize i2c child device. * Return: None. */static void envctrl_init_i2c_child(struct linux_ebus_child *edev_child,				   struct i2c_child_t *pchild){	int node, len, i, tbls_size = 0;	node = edev_child->prom_node;	/* Get device address. */	len = prom_getproperty(node, "reg",			       (char *) &(pchild->addr),			       sizeof(pchild->addr));	/* Get tables property.  Read firmware temperature tables. */	len = prom_getproperty(node, "translation",			       (char *) pchild->tblprop_array,			       (PCF8584_MAX_CHANNELS *				sizeof(struct pcf8584_tblprop)));	if (len > 0) {                pchild->total_tbls = len / sizeof(struct pcf8584_tblprop);		for (i = 0; i < pchild->total_tbls; i++) {			if ((pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset) > tbls_size) {				tbls_size = pchild->tblprop_array[i].size + pchild->tblprop_array[i].offset;			}		}                pchild->tables = kmalloc(tbls_size, GFP_KERNEL);		if (pchild->tables == NULL){			printk("envctrl: Failed to allocate table.\n");			return;		}                len = prom_getproperty(node, "tables",				       (char *) pchild->tables, tbls_size);                if (len <= 0) {			printk("envctrl: Failed to get table.\n");			return;		}	}	/* SPARCengine ASM Reference Manual (ref. SMI doc 805-7581-04)	 * sections 2.5, 3.5, 4.5 state node 0x70 for CP1400/1500 is	 * "For Factory Use Only."	 *	 * We ignore the node on these platforms by assigning the	 * 'NULL' monitor type.	 */	if (ENVCTRL_CPCI_IGNORED_NODE == pchild->addr) {		int len;		char prop[56];		len = prom_getproperty(prom_root_node, "name", prop, sizeof(prop));		if (0 < len && (0 == strncmp(prop, "SUNW,UltraSPARC-IIi-cEngine", len)))		{			for (len = 0; len < PCF8584_MAX_CHANNELS; ++len) {				pchild->mon_type[len] = ENVCTRL_NOMON;			}			return;		}	}	/* Get the monitor channels. */	len = prom_getproperty(node, "channels-in-use",			       (char *) pchild->chnl_array,			       (PCF8584_MAX_CHANNELS *				sizeof(struct pcf8584_channel)));	pchild->total_chnls = len / sizeof(struct pcf8584_channel);	for (i = 0; i < pchild->total_chnls; i++) {		switch (pchild->chnl_array[i].type) {		case PCF8584_TEMP_TYPE:			envctrl_init_adc(pchild, node);			break;		case PCF8584_GLOBALADDR_TYPE:			envctrl_init_globaladdr(pchild);			i = pchild->total_chnls;			break;		case PCF8584_FANSTAT_TYPE:			envctrl_init_fanstat(pchild);			i = pchild->total_chnls;			break;		case PCF8584_VOLTAGE_TYPE:			if (pchild->i2ctype == I2C_ADC) {				envctrl_init_adc(pchild,node);			} else {				envctrl_init_voltage_status(pchild);			}			i = pchild->total_chnls;			break;		default:			break;		};	}}/* Function Description: Search the child device list for a device. * Return : The i2c child if found. NULL otherwise. */static struct i2c_child_t *envctrl_get_i2c_child(unsigned char mon_type){	int i, j;	for (i = 0; i < ENVCTRL_MAX_CPU*2; i++) {		for (j = 0; j < PCF8584_MAX_CHANNELS; j++) {			if (i2c_childlist[i].mon_type[j] == mon_type) {				return (struct i2c_child_t *)(&(i2c_childlist[i]));			}		}	}	return NULL;}static void envctrl_do_shutdown(void){	static int inprog = 0;	static char *envp[] = {			"HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };	char *argv[] = { 		"/sbin/shutdown", "-h", "now", NULL };		if (inprog != 0)		return;	inprog = 1;	printk(KERN_CRIT "kenvctrld: WARNING: Shutting down the system now.\n");	if (0 > execve("/sbin/shutdown", argv, envp)) {		printk(KERN_CRIT "kenvctrld: WARNING: system shutdown failed!\n"); 		inprog = 0;  /* unlikely to succeed, but we could try again */	}}static struct task_struct *kenvctrld_task;static int kenvctrld(void *__unused){	int poll_interval;	int whichcpu;	char tempbuf[10];	struct i2c_child_t *cputemp;	if (NULL == (cputemp = envctrl_get_i2c_child(ENVCTRL_CPUTEMP_MON))) {		printk(KERN_ERR 		       "envctrl: kenvctrld unable to monitor CPU temp-- exiting\n");		return -ENODEV;	}	poll_interval = 5000; /* TODO env_mon_interval */	printk(KERN_INFO "envctrl: %s starting...\n", current->comm);	for (;;) {		msleep_interruptible(poll_interval);		if (kthread_should_stop())			break;				for (whichcpu = 0; whichcpu < ENVCTRL_MAX_CPU; ++whichcpu) {			if (0 < envctrl_read_cpu_info(whichcpu, cputemp,						      ENVCTRL_CPUTEMP_MON,						      tempbuf)) {				if (tempbuf[0] >= shutdown_temperature) {					printk(KERN_CRIT 						"%s: WARNING: CPU%i temperature %i C meets or exceeds "\						"shutdown threshold %i C\n", 						current->comm, whichcpu, 						tempbuf[0], shutdown_temperature);					envctrl_do_shutdown();				}			}		}	}	printk(KERN_INFO "envctrl: %s exiting...\n", current->comm);	return 0;}static int __init envctrl_init(void){	struct linux_ebus *ebus = NULL;	struct linux_ebus_device *edev = NULL;	struct linux_ebus_child *edev_child = NULL;	int err, i = 0;	for_each_ebus(ebus) {		for_each_ebusdev(edev, ebus) {			if (!strcmp(edev->prom_name, "bbc")) {				/* If we find a boot-bus controller node,				 * then this envctrl driver is not for us.				 */				return -ENODEV;			}		}	}	/* Traverse through ebus and ebus device list for i2c device and	 * adc and gpio nodes.	 */	for_each_ebus(ebus) {		for_each_ebusdev(edev, ebus) {			if (!strcmp(edev->prom_name, "i2c")) {				i2c = ioremap(edev->resource[0].start, 0x2);				for_each_edevchild(edev, edev_child) {					if (!strcmp("gpio", edev_child->prom_name)) {						i2c_childlist[i].i2ctype = I2C_GPIO;						envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));					}					if (!strcmp("adc", edev_child->prom_name)) {						i2c_childlist[i].i2ctype = I2C_ADC;						envctrl_init_i2c_child(edev_child, &(i2c_childlist[i++]));					}				}				goto done;			}		}	}done:	if (!edev) {		printk("envctrl: I2C device not found.\n");		return -ENODEV;	}	/* Set device address. */	writeb(CONTROL_PIN, i2c + PCF8584_CSR);	writeb(PCF8584_ADDRESS, i2c + PCF8584_DATA);	/* Set system clock and SCL frequencies. */ 	writeb(CONTROL_PIN | CONTROL_ES1, i2c + PCF8584_CSR);	writeb(CLK_4_43 | BUS_CLK_90, i2c + PCF8584_DATA);	/* Enable serial interface. */	writeb(CONTROL_PIN | CONTROL_ES0 | CONTROL_ACK, i2c + PCF8584_CSR);	udelay(200);	/* Register the device as a minor miscellaneous device. */	err = misc_register(&envctrl_dev);	if (err) {		printk("envctrl: Unable to get misc minor %d\n",		       envctrl_dev.minor);		goto out_iounmap;	}	/* Note above traversal routine post-incremented 'i' to accommodate 	 * a next child device, so we decrement before reverse-traversal of	 * child devices.	 */	printk("envctrl: initialized ");	for (--i; i >= 0; --i) {		printk("[%s 0x%lx]%s", 			(I2C_ADC == i2c_childlist[i].i2ctype) ? ("adc") : 			((I2C_GPIO == i2c_childlist[i].i2ctype) ? ("gpio") : ("unknown")), 			i2c_childlist[i].addr, (0 == i) ? ("\n") : (" "));	}	kenvctrld_task = kthread_run(kenvctrld, NULL, "kenvctrld");	if (IS_ERR(kenvctrld_task)) {		err = PTR_ERR(kenvctrld_task);		goto out_deregister;	}	return 0;out_deregister:	misc_deregister(&envctrl_dev);out_iounmap:	iounmap(i2c);	for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)		kfree(i2c_childlist[i].tables);	return err;}static void __exit envctrl_cleanup(void){	int i;	kthread_stop(kenvctrld_task);	iounmap(i2c);	misc_deregister(&envctrl_dev);	for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++)		kfree(i2c_childlist[i].tables);}module_init(envctrl_init);module_exit(envctrl_cleanup);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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