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

📄 it87.c

📁 ite_8075 io source code temperature and fan speed control for linux
💻 C
📖 第 1 页 / 共 4 页
字号:
		     &dev_attr_pwm2_freq))		 || (err = device_create_file(dev,		     &dev_attr_pwm3_freq)))			goto ERROR4;	}	if (data->type == it8712 || data->type == it8716	 || data->type == it8718) {		data->vrm = vid_which_vrm();		/* VID reading from Super-I/O config space if available */		data->vid = sio_data->vid_value;		if ((err = device_create_file(dev,		     &dev_attr_vrm))		 || (err = device_create_file(dev,		     &dev_attr_cpu0_vid)))			goto ERROR4;	}	data->hwmon_dev = hwmon_device_register(dev);	if (IS_ERR(data->hwmon_dev)) {		err = PTR_ERR(data->hwmon_dev);		goto ERROR4;	}	return 0;ERROR4:	sysfs_remove_group(&dev->kobj, &it87_group);	sysfs_remove_group(&dev->kobj, &it87_group_opt);ERROR2:	platform_set_drvdata(pdev, NULL);	kfree(data);ERROR1:	release_region(res->start, IT87_EC_EXTENT);ERROR0:	return err;}static int __devexit it87_remove(struct platform_device *pdev){	struct it87_data *data = platform_get_drvdata(pdev);	hwmon_device_unregister(data->hwmon_dev);	sysfs_remove_group(&pdev->dev.kobj, &it87_group);	sysfs_remove_group(&pdev->dev.kobj, &it87_group_opt);	release_region(data->addr, IT87_EC_EXTENT);	platform_set_drvdata(pdev, NULL);	kfree(data);	return 0;}/* Must be called with data->update_lock held, except during initialization.   We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,   would slow down the IT87 access and should not be necessary. */static int it87_read_value(struct it87_data *data, u8 reg){	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);	return inb_p(data->addr + IT87_DATA_REG_OFFSET);}/* Must be called with data->update_lock held, except during initialization.   We ignore the IT87 BUSY flag at this moment - it could lead to deadlocks,   would slow down the IT87 access and should not be necessary. */static void it87_write_value(struct it87_data *data, u8 reg, u8 value){	outb_p(reg, data->addr + IT87_ADDR_REG_OFFSET);	outb_p(value, data->addr + IT87_DATA_REG_OFFSET);}/* Return 1 if and only if the PWM interface is safe to use */static int __devinit it87_check_pwm(struct device *dev){	struct it87_data *data = dev_get_drvdata(dev);	/* Some BIOSes fail to correctly configure the IT87 fans. All fans off	 * and polarity set to active low is sign that this is the case so we	 * disable pwm control to protect the user. */	int tmp = it87_read_value(data, IT87_REG_FAN_CTL);	if ((tmp & 0x87) == 0) {		if (fix_pwm_polarity) {			/* The user asks us to attempt a chip reconfiguration.			 * This means switching to active high polarity and			 * inverting all fan speed values. */			int i;			u8 pwm[3];			for (i = 0; i < 3; i++)				pwm[i] = it87_read_value(data,							 IT87_REG_PWM(i));			/* If any fan is in automatic pwm mode, the polarity			 * might be correct, as suspicious as it seems, so we			 * better don't change anything (but still disable the			 * PWM interface). */			if (!((pwm[0] | pwm[1] | pwm[2]) & 0x80)) {				dev_info(dev, "Reconfiguring PWM to "					 "active high polarity\n");				it87_write_value(data, IT87_REG_FAN_CTL,						 tmp | 0x87);				for (i = 0; i < 3; i++)					it87_write_value(data,							 IT87_REG_PWM(i),							 0x7f & ~pwm[i]);				return 1;			}			dev_info(dev, "PWM configuration is "				 "too broken to be fixed\n");		}		dev_info(dev, "Detected broken BIOS "			 "defaults, disabling PWM interface\n");		return 0;	} else if (fix_pwm_polarity) {		dev_info(dev, "PWM configuration looks "			 "sane, won't touch\n");	}	return 1;}/* Called when we have found a new IT87. */static void __devinit it87_init_device(struct platform_device *pdev){	struct it87_data *data = platform_get_drvdata(pdev);	int tmp, i;	/* initialize to sane defaults:	 * - if the chip is in manual pwm mode, this will be overwritten with	 *   the actual settings on the chip (so in this case, initialization	 *   is not needed)	 * - if in automatic or on/off mode, we could switch to manual mode,	 *   read the registers and set manual_pwm_ctl accordingly, but currently	 *   this is not implemented, so we initialize to something sane */	for (i = 0; i < 3; i++) {		data->manual_pwm_ctl[i] = 0xff;	}	/* Some chips seem to have default value 0xff for all limit	 * registers. For low voltage limits it makes no sense and triggers	 * alarms, so change to 0 instead. For high temperature limits, it	 * means -1 degree C, which surprisingly doesn't trigger an alarm,	 * but is still confusing, so change to 127 degrees C. */	for (i = 0; i < 8; i++) {		tmp = it87_read_value(data, IT87_REG_VIN_MIN(i));		if (tmp == 0xff)			it87_write_value(data, IT87_REG_VIN_MIN(i), 0);	}	for (i = 0; i < 3; i++) {		tmp = it87_read_value(data, IT87_REG_TEMP_HIGH(i));		if (tmp == 0xff)			it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);	}	/* Check if temperature channnels are reset manually or by some reason */	tmp = it87_read_value(data, IT87_REG_TEMP_ENABLE);	if ((tmp & 0x3f) == 0) {		/* Temp1,Temp3=thermistor; Temp2=thermal diode */		tmp = (tmp & 0xc0) | 0x2a;		it87_write_value(data, IT87_REG_TEMP_ENABLE, tmp);	}	data->sensor = tmp;	/* Check if voltage monitors are reset manually or by some reason */	tmp = it87_read_value(data, IT87_REG_VIN_ENABLE);	if ((tmp & 0xff) == 0) {		/* Enable all voltage monitors */		it87_write_value(data, IT87_REG_VIN_ENABLE, 0xff);	}	/* Check if tachometers are reset manually or by some reason */	data->fan_main_ctrl = it87_read_value(data, IT87_REG_FAN_MAIN_CTRL);	if ((data->fan_main_ctrl & 0x70) == 0) {		/* Enable all fan tachometers */		data->fan_main_ctrl |= 0x70;		it87_write_value(data, IT87_REG_FAN_MAIN_CTRL, data->fan_main_ctrl);	}	data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;	/* Set tachometers to 16-bit mode if needed */	if (data->type == it8716 || data->type == it8718) {		tmp = it87_read_value(data, IT87_REG_FAN_16BIT);		if (~tmp & 0x07 & data->has_fan) {			dev_dbg(&pdev->dev,				"Setting fan1-3 to 16-bit mode\n");			it87_write_value(data, IT87_REG_FAN_16BIT,					 tmp | 0x07);		}		if (tmp & (1 << 4))			data->has_fan |= (1 << 3);	/* fan4 enabled */		if (tmp & (1 << 5))			data->has_fan |= (1 << 4);	/* fan5 enabled */	}	/* Set current fan mode registers and the default settings for the	 * other mode registers */	for (i = 0; i < 3; i++) {		if (data->fan_main_ctrl & (1 << i)) {			/* pwm mode */			tmp = it87_read_value(data, IT87_REG_PWM(i));			if (tmp & 0x80) {				/* automatic pwm - not yet implemented, but				 * leave the settings made by the BIOS alone				 * until a change is requested via the sysfs				 * interface */			} else {				/* manual pwm */				data->manual_pwm_ctl[i] = PWM_FROM_REG(tmp);			}		} 	}	/* Start monitoring */	it87_write_value(data, IT87_REG_CONFIG,			 (it87_read_value(data, IT87_REG_CONFIG) & 0x36)			 | (update_vbat ? 0x41 : 0x01));}static struct it87_data *it87_update_device(struct device *dev){	struct it87_data *data = dev_get_drvdata(dev);	int i;	mutex_lock(&data->update_lock);	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)	    || !data->valid) {		if (update_vbat) {			/* Cleared after each update, so reenable.  Value		 	  returned by this read will be previous value */				it87_write_value(data, IT87_REG_CONFIG,			   it87_read_value(data, IT87_REG_CONFIG) | 0x40);		}		for (i = 0; i <= 7; i++) {			data->in[i] =			    it87_read_value(data, IT87_REG_VIN(i));			data->in_min[i] =			    it87_read_value(data, IT87_REG_VIN_MIN(i));			data->in_max[i] =			    it87_read_value(data, IT87_REG_VIN_MAX(i));		}		/* in8 (battery) has no limit registers */		data->in[8] =		    it87_read_value(data, IT87_REG_VIN(8));		for (i = 0; i < 5; i++) {			/* Skip disabled fans */			if (!(data->has_fan & (1 << i)))				continue;			data->fan_min[i] =			    it87_read_value(data, IT87_REG_FAN_MIN[i]);			data->fan[i] = it87_read_value(data,				       IT87_REG_FAN[i]);			/* Add high byte if in 16-bit mode */			if (data->type == it8716 || data->type == it8718) {				data->fan[i] |= it87_read_value(data,						IT87_REG_FANX[i]) << 8;				data->fan_min[i] |= it87_read_value(data,						IT87_REG_FANX_MIN[i]) << 8;			}		}		for (i = 0; i < 3; i++) {			data->temp[i] =			    it87_read_value(data, IT87_REG_TEMP(i));			data->temp_high[i] =			    it87_read_value(data, IT87_REG_TEMP_HIGH(i));			data->temp_low[i] =			    it87_read_value(data, IT87_REG_TEMP_LOW(i));		}		/* Newer chips don't have clock dividers */		if ((data->has_fan & 0x07) && data->type != it8716		 && data->type != it8718) {			i = it87_read_value(data, IT87_REG_FAN_DIV);			data->fan_div[0] = i & 0x07;			data->fan_div[1] = (i >> 3) & 0x07;			data->fan_div[2] = (i & 0x40) ? 3 : 1;		}		data->alarms =			it87_read_value(data, IT87_REG_ALARM1) |			(it87_read_value(data, IT87_REG_ALARM2) << 8) |			(it87_read_value(data, IT87_REG_ALARM3) << 16);		data->fan_main_ctrl = it87_read_value(data,				IT87_REG_FAN_MAIN_CTRL);		data->fan_ctl = it87_read_value(data, IT87_REG_FAN_CTL);		data->sensor = it87_read_value(data, IT87_REG_TEMP_ENABLE);		/* The 8705 does not have VID capability */		if (data->type == it8712 || data->type == it8716) {			data->vid = it87_read_value(data, IT87_REG_VID);			/* The older IT8712F revisions had only 5 VID pins,			   but we assume it is always safe to read 6 bits. */			data->vid &= 0x3f;		}		data->last_updated = jiffies;		data->valid = 1;	}	mutex_unlock(&data->update_lock);	return data;}static int __init it87_device_add(unsigned short address,				  const struct it87_sio_data *sio_data){	struct resource res = {		.start	= address + IT87_EC_OFFSET,		.end	= address + IT87_EC_OFFSET + IT87_EC_EXTENT - 1,		.name	= DRVNAME,		.flags	= IORESOURCE_IO,	};	int err;	pdev = platform_device_alloc(DRVNAME, address);	if (!pdev) {		err = -ENOMEM;		printk(KERN_ERR DRVNAME ": Device allocation failed\n");		goto exit;	}	err = platform_device_add_resources(pdev, &res, 1);	if (err) {		printk(KERN_ERR DRVNAME ": Device resource addition failed "		       "(%d)\n", err);		goto exit_device_put;	}	err = platform_device_add_data(pdev, sio_data,				       sizeof(struct it87_sio_data));	if (err) {		printk(KERN_ERR DRVNAME ": Platform data allocation failed\n");		goto exit_device_put;	}	err = platform_device_add(pdev);	if (err) {		printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",		       err);		goto exit_device_put;	}	return 0;exit_device_put:	platform_device_put(pdev);exit:	return err;}static int __init sm_it87_init(void){	int err;	unsigned short isa_address=0;	struct it87_sio_data sio_data;	err = it87_find(&isa_address, &sio_data);	if (err)		return err;	err = platform_driver_register(&it87_driver);	if (err)		return err;	err = it87_device_add(isa_address, &sio_data);	if (err){		platform_driver_unregister(&it87_driver);		return err;	}	return 0;}static void __exit sm_it87_exit(void){	platform_device_unregister(pdev);	platform_driver_unregister(&it87_driver);}MODULE_AUTHOR("Chris Gauthron, "	      "Jean Delvare <khali@linux-fr.org>" "Cark Li <cark.li@ite.com.tw>");MODULE_DESCRIPTION("IT8705F/8712F/8716F/8718F/8720F/8726F/8781F/8782F, SiS950 driver");module_param(update_vbat, bool, 0);MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");module_param(fix_pwm_polarity, bool, 0);MODULE_PARM_DESC(fix_pwm_polarity, "Force PWM polarity to active high (DANGEROUS)");MODULE_LICENSE("GPL");module_init(sm_it87_init);module_exit(sm_it87_exit);

⌨️ 快捷键说明

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