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

📄 smsc47m1.c

📁 h内核
💻 C
📖 第 1 页 / 共 2 页
字号:
}									\static ssize_t get_fan##offset##_min (struct device *dev, char *buf)	\{									\	return get_fan_min(dev, buf, offset - 1);			\}									\static ssize_t set_fan##offset##_min (struct device *dev,		\		const char *buf, size_t count)				\{									\	return set_fan_min(dev, buf, count, offset - 1);		\}									\static ssize_t get_fan##offset##_div (struct device *dev, char *buf)	\{									\	return get_fan_div(dev, buf, offset - 1);			\}									\static ssize_t set_fan##offset##_div (struct device *dev,		\		const char *buf, size_t count)				\{									\	return set_fan_div(dev, buf, count, offset - 1);		\}									\static ssize_t get_pwm##offset (struct device *dev, char *buf)		\{									\	return get_pwm(dev, buf, offset - 1);				\}									\static ssize_t set_pwm##offset (struct device *dev,			\		const char *buf, size_t count)				\{									\	return set_pwm(dev, buf, count, offset - 1);			\}									\static ssize_t get_pwm##offset##_en (struct device *dev, char *buf)	\{									\	return get_pwm_en(dev, buf, offset - 1);			\}									\static ssize_t set_pwm##offset##_en (struct device *dev,		\		const char *buf, size_t count)				\{									\	return set_pwm_en(dev, buf, count, offset - 1);			\}									\static DEVICE_ATTR(fan##offset##_input, S_IRUGO, get_fan##offset,	\		NULL);							\static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\		get_fan##offset##_min, set_fan##offset##_min);		\static DEVICE_ATTR(fan##offset##_div, S_IRUGO | S_IWUSR,		\		get_fan##offset##_div, set_fan##offset##_div);		\static DEVICE_ATTR(pwm##offset, S_IRUGO | S_IWUSR,			\		get_pwm##offset, set_pwm##offset);			\static DEVICE_ATTR(pwm##offset##_enable, S_IRUGO | S_IWUSR,		\		get_pwm##offset##_en, set_pwm##offset##_en);fan_present(1);fan_present(2);static DEVICE_ATTR(alarms, S_IRUGO, get_alarms, NULL);static int smsc47m1_attach_adapter(struct i2c_adapter *adapter){	if (!(adapter->class & I2C_CLASS_HWMON))		return 0;	return i2c_detect(adapter, &addr_data, smsc47m1_detect);}static int smsc47m1_find(int *address){	u8 val;	superio_enter();	val = superio_inb(SUPERIO_REG_DEVID);	/*	 * SMSC LPC47M10x/LPC47M13x (device id 0x59), LPC47M14x (device id	 * 0x5F) and LPC47B27x (device id 0x51) have fan control.	 * The LPC47M15x and LPC47M192 chips "with hardware monitoring block"	 * can do much more besides (device id 0x60, unsupported).	 */	if (val == 0x51)		printk(KERN_INFO "smsc47m1: Found SMSC47B27x\n");	else if (val == 0x59)		printk(KERN_INFO "smsc47m1: Found SMSC47M10x/SMSC47M13x\n");	else if (val == 0x5F)		printk(KERN_INFO "smsc47m1: Found SMSC47M14x\n");	else {		superio_exit();		return -ENODEV;	}	superio_select();	*address = (superio_inb(SUPERIO_REG_BASE) << 8)		 |  superio_inb(SUPERIO_REG_BASE + 1);	val = superio_inb(SUPERIO_REG_ACT);	if (*address == 0 || (val & 0x01) == 0) {		printk(KERN_INFO "smsc47m1: Device is disabled, will not use\n");		superio_exit();		return -ENODEV;	}	superio_exit();	return 0;}static int smsc47m1_detect(struct i2c_adapter *adapter, int address, int kind){	struct i2c_client *new_client;	struct smsc47m1_data *data;	int err = 0;	int fan1, fan2, pwm1, pwm2;	if (!i2c_is_isa_adapter(adapter)) {		return 0;	}	if (!request_region(address, SMSC_EXTENT, smsc47m1_driver.name)) {		dev_err(&adapter->dev, "Region 0x%x already in use!\n", address);		return -EBUSY;	}	if (!(data = kmalloc(sizeof(struct smsc47m1_data), GFP_KERNEL))) {		err = -ENOMEM;		goto error_release;	}	memset(data, 0x00, sizeof(struct smsc47m1_data));	new_client = &data->client;	i2c_set_clientdata(new_client, data);	new_client->addr = address;	init_MUTEX(&data->lock);	new_client->adapter = adapter;	new_client->driver = &smsc47m1_driver;	new_client->flags = 0;	strlcpy(new_client->name, "smsc47m1", I2C_NAME_SIZE);	new_client->id = smsc47m1_id++;	init_MUTEX(&data->update_lock);	/* If no function is properly configured, there's no point in	   actually registering the chip. */	fan1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(0)) & 0x05)	       == 0x05;	fan2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_TPIN(1)) & 0x05)	       == 0x05;	pwm1 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(0)) & 0x05)	       == 0x04;	pwm2 = (smsc47m1_read_value(new_client, SMSC47M1_REG_PPIN(1)) & 0x05)	       == 0x04;	if (!(fan1 || fan2 || pwm1 || pwm2)) {		dev_warn(&new_client->dev, "Device is not configured, will not use\n");		err = -ENODEV;		goto error_free;	}	if ((err = i2c_attach_client(new_client)))		goto error_free;	/* Some values (fan min, clock dividers, pwm registers) may be	   needed before any update is triggered, so we better read them	   at least once here. We don't usually do it that way, but in	   this particular case, manually reading 5 registers out of 8	   doesn't make much sense and we're better using the existing	   function. */	smsc47m1_update_device(&new_client->dev, 1);	if (fan1) {		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);	} else		dev_dbg(&new_client->dev, "Fan 1 not enabled by hardware, "			"skipping\n");	if (fan2) {		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);	} else		dev_dbg(&new_client->dev, "Fan 2 not enabled by hardware, "			"skipping\n");	if (pwm1) {		device_create_file(&new_client->dev, &dev_attr_pwm1);		device_create_file(&new_client->dev, &dev_attr_pwm1_enable);	} else		dev_dbg(&new_client->dev, "PWM 1 not enabled by hardware, "			"skipping\n");	if (pwm2) {		device_create_file(&new_client->dev, &dev_attr_pwm2);		device_create_file(&new_client->dev, &dev_attr_pwm2_enable);	} else		dev_dbg(&new_client->dev, "PWM 2 not enabled by hardware, "			"skipping\n");	device_create_file(&new_client->dev, &dev_attr_alarms);	return 0;error_free:	kfree(new_client);error_release:	release_region(address, SMSC_EXTENT);	return err;}static int smsc47m1_detach_client(struct i2c_client *client){	int err;	if ((err = i2c_detach_client(client))) {		dev_err(&client->dev, "Client deregistration failed, "			"client not detached.\n");		return err;	}	release_region(client->addr, SMSC_EXTENT);	kfree(i2c_get_clientdata(client));	return 0;}static int smsc47m1_read_value(struct i2c_client *client, u8 reg){	int res;	down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);	res = inb_p(client->addr + reg);	up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);	return res;}static void smsc47m1_write_value(struct i2c_client *client, u8 reg, u8 value){	down(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);	outb_p(value, client->addr + reg);	up(&((struct smsc47m1_data *) i2c_get_clientdata(client))->lock);}static struct smsc47m1_data *smsc47m1_update_device(struct device *dev,		int init){ 	struct i2c_client *client = to_i2c_client(dev);	struct smsc47m1_data *data = i2c_get_clientdata(client);	down(&data->update_lock);	if ((jiffies - data->last_updated > HZ + HZ / 2) ||	    (jiffies < data->last_updated) || init) {		int i;		for (i = 0; i < 2; i++) {			data->fan[i] = smsc47m1_read_value(client,				       SMSC47M1_REG_FAN(i));			data->fan_preload[i] = smsc47m1_read_value(client,					       SMSC47M1_REG_FAN_PRELOAD(i));			data->pwm[i] = smsc47m1_read_value(client,				       SMSC47M1_REG_PWM(i));		}		i = smsc47m1_read_value(client, SMSC47M1_REG_FANDIV);		data->fan_div[0] = (i >> 4) & 0x03;		data->fan_div[1] = i >> 6;		data->alarms = smsc47m1_read_value(client,			       SMSC47M1_REG_ALARM) >> 6;		/* Clear alarms if needed */		if (data->alarms)			smsc47m1_write_value(client, SMSC47M1_REG_ALARM, 0xC0);		data->last_updated = jiffies;	}	up(&data->update_lock);	return data;}static int __init sm_smsc47m1_init(void){	if (smsc47m1_find(normal_isa)) {		return -ENODEV;	}	return i2c_add_driver(&smsc47m1_driver);}static void __exit sm_smsc47m1_exit(void){	i2c_del_driver(&smsc47m1_driver);}MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>");MODULE_DESCRIPTION("SMSC LPC47M1xx fan sensors driver");MODULE_LICENSE("GPL");module_init(sm_smsc47m1_init);module_exit(sm_smsc47m1_exit);

⌨️ 快捷键说明

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