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

📄 sis5595.c

📁 2440下的I2C驱动源代码 看了才知道一个驱动可以写的这么结构化!
💻 C
📖 第 1 页 / 共 2 页
字号:
	}		switch (nr) {	case 0:		reg = (reg & 0xcf) | (data->fan_div[nr] << 4);		break;	case 1:		reg = (reg & 0x3f) | (data->fan_div[nr] << 6);		break;	}	sis5595_write_value(client, SIS5595_REG_FANDIV, reg);	data->fan_min[nr] =		FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr]));	sis5595_write_value(client, SIS5595_REG_FAN_MIN(nr), data->fan_min[nr]);	up(&data->update_lock);	return count;}#define show_fan_offset(offset)						\static ssize_t show_fan_##offset (struct device *dev, char *buf)	\{									\	return show_fan(dev, buf, offset - 1);			\}									\static ssize_t show_fan_##offset##_min (struct device *dev, char *buf)	\{									\	return show_fan_min(dev, buf, offset - 1);			\}									\static ssize_t show_fan_##offset##_div (struct device *dev, char *buf)	\{									\	return show_fan_div(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 DEVICE_ATTR(fan##offset##_input, S_IRUGO, show_fan_##offset, NULL);\static DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR,		\		show_fan_##offset##_min, set_fan_##offset##_min);show_fan_offset(1);show_fan_offset(2);static ssize_t set_fan_1_div(struct device *dev, const char *buf,		size_t count){	return set_fan_div(dev, buf, count, 0) ;}static ssize_t set_fan_2_div(struct device *dev, const char *buf,		size_t count){	return set_fan_div(dev, buf, count, 1) ;}static DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR,		show_fan_1_div, set_fan_1_div);static DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR,		show_fan_2_div, set_fan_2_div);/* Alarms */static ssize_t show_alarms(struct device *dev, char *buf){	struct sis5595_data *data = sis5595_update_device(dev);	return sprintf(buf, "%d\n", data->alarms);}static DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); /* This is called when the module is loaded */static int sis5595_attach_adapter(struct i2c_adapter *adapter){	if (!(adapter->class & I2C_CLASS_HWMON))		return 0;	return i2c_detect(adapter, &addr_data, sis5595_detect);}int sis5595_detect(struct i2c_adapter *adapter, int address, int kind){	int err = 0;	int i;	struct i2c_client *new_client;	struct sis5595_data *data;	char val;	u16 a;	/* Make sure we are probing the ISA bus!!  */	if (!i2c_is_isa_adapter(adapter))		goto exit;	if (force_addr)		address = force_addr & ~(SIS5595_EXTENT - 1);	/* Reserve the ISA region */	if (!request_region(address, SIS5595_EXTENT, sis5595_driver.name)) {		err = -EBUSY;		goto exit;	}	if (force_addr) {		dev_warn(&adapter->dev, "forcing ISA address 0x%04X\n", address);		if (PCIBIOS_SUCCESSFUL !=		    pci_write_config_word(s_bridge, SIS5595_BASE_REG, address))			goto exit_release;		if (PCIBIOS_SUCCESSFUL !=		    pci_read_config_word(s_bridge, SIS5595_BASE_REG, &a))			goto exit_release;		if ((a & ~(SIS5595_EXTENT - 1)) != address)			/* doesn't work for some chips? */			goto exit_release;	}	if (PCIBIOS_SUCCESSFUL !=	    pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val)) {		goto exit_release;	}	if ((val & 0x80) == 0) {		if (PCIBIOS_SUCCESSFUL !=		    pci_write_config_byte(s_bridge, SIS5595_ENABLE_REG,					  val | 0x80))			goto exit_release;		if (PCIBIOS_SUCCESSFUL !=		    pci_read_config_byte(s_bridge, SIS5595_ENABLE_REG, &val))			goto exit_release;		if ((val & 0x80) == 0) 			/* doesn't work for some chips! */			goto exit_release;	}	if (!(data = kmalloc(sizeof(struct sis5595_data), GFP_KERNEL))) {		err = -ENOMEM;		goto exit_release;	}	memset(data, 0, sizeof(struct sis5595_data));	new_client = &data->client;	new_client->addr = address;	init_MUTEX(&data->lock);	i2c_set_clientdata(new_client, data);	new_client->adapter = adapter;	new_client->driver = &sis5595_driver;	new_client->flags = 0;	/* Check revision and pin registers to determine whether 4 or 5 voltages */	pci_read_config_byte(s_bridge, SIS5595_REVISION_REG, &(data->revision));	/* 4 voltages, 1 temp */	data->maxins = 3;	if (data->revision >= REV2MIN) {		pci_read_config_byte(s_bridge, SIS5595_PIN_REG, &val);		if (!(val & 0x80))			/* 5 voltages, no temps */			data->maxins = 4;	}		/* Fill in the remaining client fields and put it into the global list */	strlcpy(new_client->name, "sis5595", I2C_NAME_SIZE);	data->valid = 0;	init_MUTEX(&data->update_lock);	/* Tell the I2C layer a new client has arrived */	if ((err = i2c_attach_client(new_client)))		goto exit_free;		/* Initialize the SIS5595 chip */	sis5595_init_client(new_client);	/* A few vars need to be filled upon startup */	for (i = 0; i < 2; i++) {		data->fan_min[i] = sis5595_read_value(new_client,					SIS5595_REG_FAN_MIN(i));	}	/* Register sysfs hooks */	device_create_file(&new_client->dev, &dev_attr_in0_input);	device_create_file(&new_client->dev, &dev_attr_in0_min);	device_create_file(&new_client->dev, &dev_attr_in0_max);	device_create_file(&new_client->dev, &dev_attr_in1_input);	device_create_file(&new_client->dev, &dev_attr_in1_min);	device_create_file(&new_client->dev, &dev_attr_in1_max);	device_create_file(&new_client->dev, &dev_attr_in2_input);	device_create_file(&new_client->dev, &dev_attr_in2_min);	device_create_file(&new_client->dev, &dev_attr_in2_max);	device_create_file(&new_client->dev, &dev_attr_in3_input);	device_create_file(&new_client->dev, &dev_attr_in3_min);	device_create_file(&new_client->dev, &dev_attr_in3_max);	if (data->maxins == 4) {		device_create_file(&new_client->dev, &dev_attr_in4_input);		device_create_file(&new_client->dev, &dev_attr_in4_min);		device_create_file(&new_client->dev, &dev_attr_in4_max);	}	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_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_alarms);	if (data->maxins == 3) {		device_create_file(&new_client->dev, &dev_attr_temp1_input);		device_create_file(&new_client->dev, &dev_attr_temp1_max);		device_create_file(&new_client->dev, &dev_attr_temp1_max_hyst);	}	return 0;	exit_free:	kfree(data);exit_release:	release_region(address, SIS5595_EXTENT);exit:	return err;}static int sis5595_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;	}	if (i2c_is_isa_client(client))		release_region(client->addr, SIS5595_EXTENT);	kfree(i2c_get_clientdata(client));	return 0;}/* ISA access must be locked explicitly. */static int sis5595_read_value(struct i2c_client *client, u8 reg){	int res;	struct sis5595_data *data = i2c_get_clientdata(client);	down(&data->lock);	outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);	res = inb_p(client->addr + SIS5595_DATA_REG_OFFSET);	up(&data->lock);	return res;}static int sis5595_write_value(struct i2c_client *client, u8 reg, u8 value){	struct sis5595_data *data = i2c_get_clientdata(client);	down(&data->lock);	outb_p(reg, client->addr + SIS5595_ADDR_REG_OFFSET);	outb_p(value, client->addr + SIS5595_DATA_REG_OFFSET);	up(&data->lock);	return 0;}/* Called when we have found a new SIS5595. */static void sis5595_init_client(struct i2c_client *client){	u8 config = sis5595_read_value(client, SIS5595_REG_CONFIG);	if (!(config & 0x01))		sis5595_write_value(client, SIS5595_REG_CONFIG,				(config & 0xf7) | 0x01);}static struct sis5595_data *sis5595_update_device(struct device *dev){	struct i2c_client *client = to_i2c_client(dev);	struct sis5595_data *data = i2c_get_clientdata(client);	int i;	down(&data->update_lock);	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)	    || !data->valid) {		for (i = 0; i <= data->maxins; i++) {			data->in[i] =			    sis5595_read_value(client, SIS5595_REG_IN(i));			data->in_min[i] =			    sis5595_read_value(client,					       SIS5595_REG_IN_MIN(i));			data->in_max[i] =			    sis5595_read_value(client,					       SIS5595_REG_IN_MAX(i));		}		for (i = 0; i < 2; i++) {			data->fan[i] =			    sis5595_read_value(client, SIS5595_REG_FAN(i));			data->fan_min[i] =			    sis5595_read_value(client,					       SIS5595_REG_FAN_MIN(i));		}		if (data->maxins == 3) {			data->temp =			    sis5595_read_value(client, SIS5595_REG_TEMP);			data->temp_over =			    sis5595_read_value(client, SIS5595_REG_TEMP_OVER);			data->temp_hyst =			    sis5595_read_value(client, SIS5595_REG_TEMP_HYST);		}		i = sis5595_read_value(client, SIS5595_REG_FANDIV);		data->fan_div[0] = (i >> 4) & 0x03;		data->fan_div[1] = i >> 6;		data->alarms =		    sis5595_read_value(client, SIS5595_REG_ALARM1) |		    (sis5595_read_value(client, SIS5595_REG_ALARM2) << 8);		data->last_updated = jiffies;		data->valid = 1;	}	up(&data->update_lock);	return data;}static struct pci_device_id sis5595_pci_ids[] = {	{ PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },	{ 0, }};MODULE_DEVICE_TABLE(pci, sis5595_pci_ids);static int blacklist[] __devinitdata = {	PCI_DEVICE_ID_SI_540,	PCI_DEVICE_ID_SI_550,	PCI_DEVICE_ID_SI_630,	PCI_DEVICE_ID_SI_645,	PCI_DEVICE_ID_SI_730,	PCI_DEVICE_ID_SI_735,	PCI_DEVICE_ID_SI_5511, /* 5513 chip has the 0008 device but				  that ID shows up in other chips so we				  use the 5511 ID for recognition */	PCI_DEVICE_ID_SI_5597,	PCI_DEVICE_ID_SI_5598,	0 };static int __devinit sis5595_pci_probe(struct pci_dev *dev,				       const struct pci_device_id *id){	u16 val;	int *i;	int addr = 0;	for (i = blacklist; *i != 0; i++) {		struct pci_dev *dev;		dev = pci_get_device(PCI_VENDOR_ID_SI, *i, NULL);		if (dev) {			dev_err(&dev->dev, "Looked for SIS5595 but found unsupported device %.4x\n", *i);			pci_dev_put(dev);			return -ENODEV;		}	}		if (PCIBIOS_SUCCESSFUL !=	    pci_read_config_word(dev, SIS5595_BASE_REG, &val))		return -ENODEV;		addr = val & ~(SIS5595_EXTENT - 1);	if (addr == 0 && force_addr == 0) {		dev_err(&dev->dev, "Base address not set - upgrade BIOS or use force_addr=0xaddr\n");		return -ENODEV;	}	if (force_addr)		addr = force_addr;	/* so detect will get called */	if (!addr) {		dev_err(&dev->dev,"No SiS 5595 sensors found.\n");		return -ENODEV;	}	normal_isa[0] = addr;	s_bridge = pci_dev_get(dev);	if (i2c_add_driver(&sis5595_driver)) {		pci_dev_put(s_bridge);		s_bridge = NULL;	}	/* Always return failure here.  This is to allow other drivers to bind	 * to this pci device.  We don't really want to have control over the	 * pci device, we only wanted to read as few register values from it.	 */	return -ENODEV;}static struct pci_driver sis5595_pci_driver = {	.name            = "sis5595",	.id_table        = sis5595_pci_ids,	.probe           = sis5595_pci_probe,};static int __init sm_sis5595_init(void){	return pci_register_driver(&sis5595_pci_driver);}static void __exit sm_sis5595_exit(void){	pci_unregister_driver(&sis5595_pci_driver);	if (s_bridge != NULL) {		i2c_del_driver(&sis5595_driver);		pci_dev_put(s_bridge);		s_bridge = NULL;	}}MODULE_AUTHOR("Aurelien Jarno <aurelien@aurel32.net>");MODULE_DESCRIPTION("SiS 5595 Sensor device");MODULE_LICENSE("GPL");module_init(sm_sis5595_init);module_exit(sm_sis5595_exit);

⌨️ 快捷键说明

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