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

📄 pc87360.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
	}	if (data->innr == 14) {		device_create_file(&new_client->dev, &dev_attr_temp4_input);		device_create_file(&new_client->dev, &dev_attr_temp5_input);		device_create_file(&new_client->dev, &dev_attr_temp6_input);		device_create_file(&new_client->dev, &dev_attr_temp4_min);		device_create_file(&new_client->dev, &dev_attr_temp5_min);		device_create_file(&new_client->dev, &dev_attr_temp6_min);		device_create_file(&new_client->dev, &dev_attr_temp4_max);		device_create_file(&new_client->dev, &dev_attr_temp5_max);		device_create_file(&new_client->dev, &dev_attr_temp6_max);		device_create_file(&new_client->dev, &dev_attr_temp4_crit);		device_create_file(&new_client->dev, &dev_attr_temp5_crit);		device_create_file(&new_client->dev, &dev_attr_temp6_crit);		device_create_file(&new_client->dev, &dev_attr_temp4_status);		device_create_file(&new_client->dev, &dev_attr_temp5_status);		device_create_file(&new_client->dev, &dev_attr_temp6_status);	}	if (data->fannr) {		if (FAN_CONFIG_MONITOR(data->fan_conf, 0)) {			device_create_file(&new_client->dev,					   &dev_attr_fan1_input);			device_create_file(&new_client->dev,					   &dev_attr_fan1_min);			device_create_file(&new_client->dev,					   &dev_attr_fan1_div);			device_create_file(&new_client->dev,					   &dev_attr_fan1_status);		}		if (FAN_CONFIG_MONITOR(data->fan_conf, 1)) {			device_create_file(&new_client->dev,					   &dev_attr_fan2_input);			device_create_file(&new_client->dev,					   &dev_attr_fan2_min);			device_create_file(&new_client->dev,					   &dev_attr_fan2_div);			device_create_file(&new_client->dev,					   &dev_attr_fan2_status);		}		if (FAN_CONFIG_CONTROL(data->fan_conf, 0))			device_create_file(&new_client->dev, &dev_attr_pwm1);		if (FAN_CONFIG_CONTROL(data->fan_conf, 1))			device_create_file(&new_client->dev, &dev_attr_pwm2);	}	if (data->fannr == 3) {		if (FAN_CONFIG_MONITOR(data->fan_conf, 2)) {			device_create_file(&new_client->dev,					   &dev_attr_fan3_input);			device_create_file(&new_client->dev,					   &dev_attr_fan3_min);			device_create_file(&new_client->dev,					   &dev_attr_fan3_div);			device_create_file(&new_client->dev,					   &dev_attr_fan3_status);		}		if (FAN_CONFIG_CONTROL(data->fan_conf, 2))			device_create_file(&new_client->dev, &dev_attr_pwm3);	}	return 0;ERROR2:	for (i = 0; i < 3; i++) {		if (data->address[i]) {			release_region(data->address[i], PC87360_EXTENT);		}	}ERROR1:	kfree(data);	return err;}static int pc87360_detach_client(struct i2c_client *client){	struct pc87360_data *data = i2c_get_clientdata(client);	int i;	if ((i = i2c_detach_client(client))) {		dev_err(&client->dev, "Client deregistration failed, "			"client not detached.\n");		return i;	}	for (i = 0; i < 3; i++) {		if (data->address[i]) {			release_region(data->address[i], PC87360_EXTENT);		}	}	kfree(data);	return 0;}/* ldi is the logical device index   bank is for voltages and temperatures only */static int pc87360_read_value(struct pc87360_data *data, u8 ldi, u8 bank,			      u8 reg){	int res;	down(&(data->lock));	if (bank != NO_BANK)		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);	res = inb_p(data->address[ldi] + reg);	up(&(data->lock));	return res;}static void pc87360_write_value(struct pc87360_data *data, u8 ldi, u8 bank,				u8 reg, u8 value){	down(&(data->lock));	if (bank != NO_BANK)		outb_p(bank, data->address[ldi] + PC87365_REG_BANK);	outb_p(value, data->address[ldi] + reg);	up(&(data->lock));}static void pc87360_init_client(struct i2c_client *client, int use_thermistors){	struct pc87360_data *data = i2c_get_clientdata(client);	int i, nr;	const u8 init_in[14] = { 2, 2, 2, 2, 2, 2, 2, 1, 1, 3, 1, 2, 2, 2 };	const u8 init_temp[3] = { 2, 2, 1 };	u8 reg;	if (init >= 2 && data->innr) {		reg = pc87360_read_value(data, LD_IN, NO_BANK,					 PC87365_REG_IN_CONVRATE);		dev_info(&client->dev, "VLM conversion set to"			 "1s period, 160us delay\n");		pc87360_write_value(data, LD_IN, NO_BANK,				    PC87365_REG_IN_CONVRATE,				    (reg & 0xC0) | 0x11);	}	nr = data->innr < 11 ? data->innr : 11;	for (i=0; i<nr; i++) {		if (init >= init_in[i]) {			/* Forcibly enable voltage channel */			reg = pc87360_read_value(data, LD_IN, i,						 PC87365_REG_IN_STATUS);			if (!(reg & 0x01)) {				dev_dbg(&client->dev, "Forcibly "					"enabling in%d\n", i);				pc87360_write_value(data, LD_IN, i,						    PC87365_REG_IN_STATUS,						    (reg & 0x68) | 0x87);			}		}	}	/* We can't blindly trust the Super-I/O space configuration bit,	   most BIOS won't set it properly */	for (i=11; i<data->innr; i++) {		reg = pc87360_read_value(data, LD_IN, i,					 PC87365_REG_TEMP_STATUS);		use_thermistors = use_thermistors || (reg & 0x01);	}	i = use_thermistors ? 2 : 0;	for (; i<data->tempnr; i++) {		if (init >= init_temp[i]) {			/* Forcibly enable temperature channel */			reg = pc87360_read_value(data, LD_TEMP, i,						 PC87365_REG_TEMP_STATUS);			if (!(reg & 0x01)) {				dev_dbg(&client->dev, "Forcibly "					"enabling temp%d\n", i+1);				pc87360_write_value(data, LD_TEMP, i,						    PC87365_REG_TEMP_STATUS,						    0xCF);			}		}	}	if (use_thermistors) {		for (i=11; i<data->innr; i++) {			if (init >= init_in[i]) {				/* The pin may already be used by thermal				   diodes */				reg = pc87360_read_value(data, LD_TEMP,				      (i-11)/2, PC87365_REG_TEMP_STATUS);				if (reg & 0x01) {					dev_dbg(&client->dev, "Skipping "						"temp%d, pin already in use "						"by temp%d\n", i-7, (i-11)/2);					continue;				}				/* Forcibly enable thermistor channel */				reg = pc87360_read_value(data, LD_IN, i,							 PC87365_REG_IN_STATUS);				if (!(reg & 0x01)) {					dev_dbg(&client->dev, "Forcibly "						"enabling temp%d\n", i-7);					pc87360_write_value(data, LD_IN, i,						PC87365_REG_TEMP_STATUS,						(reg & 0x60) | 0x8F);				}			}		}	}	if (data->innr) {		reg = pc87360_read_value(data, LD_IN, NO_BANK,					 PC87365_REG_IN_CONFIG);		if (reg & 0x01) {			dev_dbg(&client->dev, "Forcibly "				"enabling monitoring (VLM)\n");			pc87360_write_value(data, LD_IN, NO_BANK,					    PC87365_REG_IN_CONFIG,					    reg & 0xFE);		}	}	if (data->tempnr) {		reg = pc87360_read_value(data, LD_TEMP, NO_BANK,					 PC87365_REG_TEMP_CONFIG);		if (reg & 0x01) {			dev_dbg(&client->dev, "Forcibly enabling "				"monitoring (TMS)\n");			pc87360_write_value(data, LD_TEMP, NO_BANK,					    PC87365_REG_TEMP_CONFIG,					    reg & 0xFE);		}		if (init >= 2) {			/* Chip config as documented by National Semi. */			pc87360_write_value(data, LD_TEMP, 0xF, 0xA, 0x08);			/* We voluntarily omit the bank here, in case the			   sequence itself matters. It shouldn't be a problem,			   since nobody else is supposed to access the			   device at that point. */			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xB, 0x04);			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xC, 0x35);			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xD, 0x05);			pc87360_write_value(data, LD_TEMP, NO_BANK, 0xE, 0x05);		}	}}static void pc87360_autodiv(struct i2c_client *client, int nr){	struct pc87360_data *data = i2c_get_clientdata(client);	u8 old_min = data->fan_min[nr];	/* Increase clock divider if needed and possible */	if ((data->fan_status[nr] & 0x04) /* overflow flag */	 || (data->fan[nr] >= 224)) { /* next to overflow */		if ((data->fan_status[nr] & 0x60) != 0x60) {			data->fan_status[nr] += 0x20;			data->fan_min[nr] >>= 1;			data->fan[nr] >>= 1;			dev_dbg(&client->dev, "Increasing "				"clock divider to %d for fan %d\n",				FAN_DIV_FROM_REG(data->fan_status[nr]), nr+1);		}	} else {		/* Decrease clock divider if possible */		while (!(data->fan_min[nr] & 0x80) /* min "nails" divider */		 && data->fan[nr] < 85 /* bad accuracy */		 && (data->fan_status[nr] & 0x60) != 0x00) {			data->fan_status[nr] -= 0x20;			data->fan_min[nr] <<= 1;			data->fan[nr] <<= 1;			dev_dbg(&client->dev, "Decreasing "				"clock divider to %d for fan %d\n",				FAN_DIV_FROM_REG(data->fan_status[nr]),				nr+1);		}	}	/* Write new fan min if it changed */	if (old_min != data->fan_min[nr]) {		pc87360_write_value(data, LD_FAN, NO_BANK,				    PC87360_REG_FAN_MIN(nr),				    data->fan_min[nr]);	}}static struct pc87360_data *pc87360_update_device(struct device *dev){	struct i2c_client *client = to_i2c_client(dev);	struct pc87360_data *data = i2c_get_clientdata(client);	u8 i;	down(&data->update_lock);	if ((jiffies - data->last_updated > HZ * 2)	 || (jiffies < data->last_updated) || !data->valid) {		dev_dbg(&client->dev, "Data update\n");		/* Fans */		for (i = 0; i < data->fannr; i++) {			if (FAN_CONFIG_MONITOR(data->fan_conf, i)) {				data->fan_status[i] =					pc87360_read_value(data, LD_FAN,					NO_BANK, PC87360_REG_FAN_STATUS(i));				data->fan[i] = pc87360_read_value(data, LD_FAN,					       NO_BANK, PC87360_REG_FAN(i));				data->fan_min[i] = pc87360_read_value(data,						   LD_FAN, NO_BANK,						   PC87360_REG_FAN_MIN(i));				/* Change clock divider if needed */				pc87360_autodiv(client, i);				/* Clear bits and write new divider */				pc87360_write_value(data, LD_FAN, NO_BANK,						    PC87360_REG_FAN_STATUS(i),						    data->fan_status[i]);			}			if (FAN_CONFIG_CONTROL(data->fan_conf, i))				data->pwm[i] = pc87360_read_value(data, LD_FAN,					       NO_BANK, PC87360_REG_PWM(i));		}		/* Voltages */		for (i = 0; i < data->innr; i++) {			data->in_status[i] = pc87360_read_value(data, LD_IN, i,					     PC87365_REG_IN_STATUS);			/* Clear bits */			pc87360_write_value(data, LD_IN, i,					    PC87365_REG_IN_STATUS,					    data->in_status[i]);			if ((data->in_status[i] & 0x81) == 0x81) {				data->in[i] = pc87360_read_value(data, LD_IN,					      i, PC87365_REG_IN);			}			if (data->in_status[i] & 0x01) {				data->in_min[i] = pc87360_read_value(data,						  LD_IN, i,						  PC87365_REG_IN_MIN);				data->in_max[i] = pc87360_read_value(data,						  LD_IN, i,						  PC87365_REG_IN_MAX);				if (i >= 11)					data->in_crit[i-11] =						pc87360_read_value(data, LD_IN,						i, PC87365_REG_TEMP_CRIT);			}		}		if (data->innr) {			data->in_alarms = pc87360_read_value(data, LD_IN,					  NO_BANK, PC87365_REG_IN_ALARMS1)					| ((pc87360_read_value(data, LD_IN,					    NO_BANK, PC87365_REG_IN_ALARMS2)					    & 0x07) << 8);			data->vid = (data->vid_conf & 0xE0) ?				    pc87360_read_value(data, LD_IN,				    NO_BANK, PC87365_REG_VID) : 0x1F;		}		/* Temperatures */		for (i = 0; i < data->tempnr; i++) {			data->temp_status[i] = pc87360_read_value(data,					       LD_TEMP, i,					       PC87365_REG_TEMP_STATUS);			/* Clear bits */			pc87360_write_value(data, LD_TEMP, i,					    PC87365_REG_TEMP_STATUS,					    data->temp_status[i]);			if ((data->temp_status[i] & 0x81) == 0x81) {				data->temp[i] = pc87360_read_value(data,						LD_TEMP, i,						PC87365_REG_TEMP);			}			if (data->temp_status[i] & 0x01) {				data->temp_min[i] = pc87360_read_value(data,						    LD_TEMP, i,						    PC87365_REG_TEMP_MIN);				data->temp_max[i] = pc87360_read_value(data,						    LD_TEMP, i,						    PC87365_REG_TEMP_MAX);				data->temp_crit[i] = pc87360_read_value(data,						     LD_TEMP, i,						     PC87365_REG_TEMP_CRIT);			}		}		if (data->tempnr) {			data->temp_alarms = pc87360_read_value(data, LD_TEMP,					    NO_BANK, PC87365_REG_TEMP_ALARMS)					    & 0x3F;		}		data->last_updated = jiffies;		data->valid = 1;	}	up(&data->update_lock);	return data;}static int __init pc87360_init(void){	int i;	if (pc87360_find(0x2e, &devid, extra_isa)	 && pc87360_find(0x4e, &devid, extra_isa)) {		printk(KERN_WARNING "pc87360: PC8736x not detected, "		       "module not inserted.\n");		return -ENODEV;	}	/* Arbitrarily pick one of the addresses */	for (i = 0; i < 3; i++) {		if (extra_isa[i] != 0x0000) {			normal_isa[0] = extra_isa[i];			break;		}	}	if (normal_isa[0] == 0x0000) {		printk(KERN_WARNING "pc87360: No active logical device, "		       "module not inserted.\n");		return -ENODEV;	}	return i2c_add_driver(&pc87360_driver);}static void __exit pc87360_exit(void){	i2c_del_driver(&pc87360_driver);}MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");MODULE_DESCRIPTION("PC8736x hardware monitor");MODULE_LICENSE("GPL");module_init(pc87360_init);module_exit(pc87360_exit);

⌨️ 快捷键说明

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