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

📄 w83781d.c

📁 《linux驱动程序设计从入门到精通》一书中所有的程序代码含驱动和相应的应用程序
💻 C
📖 第 1 页 / 共 4 页
字号:
}static ssize_tstore_rt_reg(struct device *dev, const char *buf, size_t count, int nr){	struct i2c_client *client = to_i2c_client(dev);	struct w83781d_data *data = i2c_get_clientdata(client);	u32 val, i;	for (i = 0; i < count; i++) {		val = simple_strtoul(buf + count, NULL, 10);		/* fixme: no bounds checking 0-255 */		data->rt[nr - 1][i] = val & 0xff;		w83781d_write_value(client, W83781D_REG_RT_IDX, i);		w83781d_write_value(client, W83781D_REG_RT_VAL,				    data->rt[nr - 1][i]);	}	return count;}#define sysfs_rt(offset) \static ssize_t show_regs_rt_##offset (struct device *dev, char *buf) \{ \	return show_rt_reg(dev, buf, offset); \} \static ssize_t store_regs_rt_##offset (struct device *dev, const char *buf, size_t count) \{ \    return store_rt_reg(dev, buf, count, offset); \} \static DEVICE_ATTR(rt##offset, S_IRUGO | S_IWUSR, show_regs_rt_##offset, store_regs_rt_##offset);sysfs_rt(1);sysfs_rt(2);sysfs_rt(3);#define device_create_file_rt(client, offset) \do { \device_create_file(&client->dev, &dev_attr_rt##offset); \} while (0)#endif				/* ifdef W83781D_RT *//* This function is called when:     * w83781d_driver is inserted (when this module is loaded), for each       available adapter     * when a new adapter is inserted (and w83781d_driver is still present) */static intw83781d_attach_adapter(struct i2c_adapter *adapter){	if (!(adapter->class & I2C_CLASS_HWMON))		return 0;	return i2c_detect(adapter, &addr_data, w83781d_detect);}/* Assumes that adapter is of I2C, not ISA variety. * OTHERWISE DON'T CALL THIS */static intw83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind,		struct i2c_client *new_client){	int i, val1 = 0, id;	int err;	const char *client_name = "";	struct w83781d_data *data = i2c_get_clientdata(new_client);	data->lm75[0] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);	if (!(data->lm75[0])) {		err = -ENOMEM;		goto ERROR_SC_0;	}	memset(data->lm75[0], 0x00, sizeof (struct i2c_client));	id = i2c_adapter_id(adapter);	if (force_subclients[0] == id && force_subclients[1] == address) {		for (i = 2; i <= 3; i++) {			if (force_subclients[i] < 0x48 ||			    force_subclients[i] > 0x4f) {				dev_err(&new_client->dev, "Invalid subclient "					"address %d; must be 0x48-0x4f\n",					force_subclients[i]);				err = -EINVAL;				goto ERROR_SC_1;			}		}		w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR,				(force_subclients[2] & 0x07) |				((force_subclients[3] & 0x07) << 4));		data->lm75[0]->addr = force_subclients[2];	} else {		val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR);		data->lm75[0]->addr = 0x48 + (val1 & 0x07);	}	if (kind != w83783s) {		data->lm75[1] = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);		if (!(data->lm75[1])) {			err = -ENOMEM;			goto ERROR_SC_1;		}		memset(data->lm75[1], 0x0, sizeof(struct i2c_client));		if (force_subclients[0] == id &&		    force_subclients[1] == address) {			data->lm75[1]->addr = force_subclients[3];		} else {			data->lm75[1]->addr = 0x48 + ((val1 >> 4) & 0x07);		}		if (data->lm75[0]->addr == data->lm75[1]->addr) {			dev_err(&new_client->dev,			       "Duplicate addresses 0x%x for subclients.\n",			       data->lm75[0]->addr);			err = -EBUSY;			goto ERROR_SC_2;		}	}	if (kind == w83781d)		client_name = "w83781d subclient";	else if (kind == w83782d)		client_name = "w83782d subclient";	else if (kind == w83783s)		client_name = "w83783s subclient";	else if (kind == w83627hf)		client_name = "w83627hf subclient";	else if (kind == as99127f)		client_name = "as99127f subclient";	for (i = 0; i <= 1; i++) {		/* store all data in w83781d */		i2c_set_clientdata(data->lm75[i], NULL);		data->lm75[i]->adapter = adapter;		data->lm75[i]->driver = &w83781d_driver;		data->lm75[i]->flags = 0;		strlcpy(data->lm75[i]->name, client_name,			I2C_NAME_SIZE);		if ((err = i2c_attach_client(data->lm75[i]))) {			dev_err(&new_client->dev, "Subclient %d "				"registration at address 0x%x "				"failed.\n", i, data->lm75[i]->addr);			if (i == 1)				goto ERROR_SC_3;			goto ERROR_SC_2;		}		if (kind == w83783s)			break;	}	return 0;/* Undo inits in case of errors */ERROR_SC_3:	i2c_detach_client(data->lm75[0]);ERROR_SC_2:	if (NULL != data->lm75[1])		kfree(data->lm75[1]);ERROR_SC_1:	if (NULL != data->lm75[0])		kfree(data->lm75[0]);ERROR_SC_0:	return err;}static intw83781d_detect(struct i2c_adapter *adapter, int address, int kind){	int i = 0, val1 = 0, val2;	struct i2c_client *new_client;	struct w83781d_data *data;	int err;	const char *client_name = "";	int is_isa = i2c_is_isa_adapter(adapter);	enum vendor { winbond, asus } vendid;	if (!is_isa	    && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {		err = -EINVAL;		goto ERROR0;	}	/* Prevent users from forcing a kind for a bus it isn't supposed	   to possibly be on */	if (is_isa && (kind == as99127f || kind == w83783s)) {		dev_err(&adapter->dev,			"Cannot force I2C-only chip for ISA address 0x%02x.\n",			address);		err = -EINVAL;		goto ERROR0;	}	if (!is_isa && kind == w83697hf) {		dev_err(&adapter->dev,			"Cannot force ISA-only chip for I2C address 0x%02x.\n",			address);		err = -EINVAL;		goto ERROR0;	}		if (is_isa)		if (!request_region(address, W83781D_EXTENT, "w83781d")) {			err = -EBUSY;			goto ERROR0;		}	/* Probe whether there is anything available on this address. Already	   done for SMBus clients */	if (kind < 0) {		if (is_isa) {#define REALLY_SLOW_IO			/* We need the timeouts for at least some LM78-like			   chips. But only if we read 'undefined' registers. */			i = inb_p(address + 1);			if (inb_p(address + 2) != i) {				err = -ENODEV;				goto ERROR1;			}			if (inb_p(address + 3) != i) {				err = -ENODEV;				goto ERROR1;			}			if (inb_p(address + 7) != i) {				err = -ENODEV;				goto ERROR1;			}#undef REALLY_SLOW_IO			/* Let's just hope nothing breaks here */			i = inb_p(address + 5) & 0x7f;			outb_p(~i & 0x7f, address + 5);			if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {				outb_p(i, address + 5);				err = -ENODEV;				goto ERROR1;			}		}	}	/* OK. For now, we presume we have a valid client. We now create the	   client structure, even though we cannot fill it completely yet.	   But it allows us to access w83781d_{read,write}_value. */	if (!(data = kmalloc(sizeof(struct w83781d_data), GFP_KERNEL))) {		err = -ENOMEM;		goto ERROR1;	}	memset(data, 0, sizeof(struct w83781d_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 = &w83781d_driver;	new_client->flags = 0;	/* Now, we do the remaining detection. */	/* The w8378?d may be stuck in some other bank than bank 0. This may	   make reading other information impossible. Specify a force=... or	   force_*=... parameter, and the Winbond will be reset to the right	   bank. */	if (kind < 0) {		if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80){			err = -ENODEV;			goto ERROR2;		}		val1 = w83781d_read_value(new_client, W83781D_REG_BANK);		val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);		/* Check for Winbond or Asus ID if in bank 0 */		if ((!(val1 & 0x07)) &&		    (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3))		     || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12)))) {			err = -ENODEV;			goto ERROR2;		}		/* If Winbond SMBus, check address at 0x48.		   Asus doesn't support, except for as99127f rev.2 */		if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) ||				  ((val1 & 0x80) && (val2 == 0x5c)))) {			if (w83781d_read_value			    (new_client, W83781D_REG_I2C_ADDR) != address) {				err = -ENODEV;				goto ERROR2;			}		}	}	/* We have either had a force parameter, or we have already detected the	   Winbond. Put it now into bank 0 and Vendor ID High Byte */	w83781d_write_value(new_client, W83781D_REG_BANK,			    (w83781d_read_value(new_client,						W83781D_REG_BANK) & 0x78) |			    0x80);	/* Determine the chip type. */	if (kind <= 0) {		/* get vendor ID */		val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN);		if (val2 == 0x5c)			vendid = winbond;		else if (val2 == 0x12)			vendid = asus;		else {			err = -ENODEV;			goto ERROR2;		}		val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID);		if ((val1 == 0x10 || val1 == 0x11) && vendid == winbond)			kind = w83781d;		else if (val1 == 0x30 && vendid == winbond)			kind = w83782d;		else if (val1 == 0x40 && vendid == winbond && !is_isa				&& address == 0x2d)			kind = w83783s;		else if ((val1 == 0x21 || val1 == 0x90) && vendid == winbond)			kind = w83627hf;		else if (val1 == 0x31 && !is_isa && address >= 0x28)			kind = as99127f;		else if (val1 == 0x60 && vendid == winbond && is_isa)			kind = w83697hf;		else {			if (kind == 0)				dev_warn(&new_client->dev,				       "Ignoring 'force' parameter for unknown chip at"				       "adapter %d, address 0x%02x\n",				       i2c_adapter_id(adapter), address);			err = -EINVAL;			goto ERROR2;		}	}	if (kind == w83781d) {		client_name = "w83781d";	} else if (kind == w83782d) {		client_name = "w83782d";	} else if (kind == w83783s) {		client_name = "w83783s";	} else if (kind == w83627hf) {		if (val1 == 0x90)			client_name = "w83627thf";		else			client_name = "w83627hf";	} else if (kind == as99127f) {		client_name = "as99127f";	} else if (kind == w83697hf) {		client_name = "w83697hf";	}	/* Fill in the remaining client fields and put into the global list */	strlcpy(new_client->name, client_name, I2C_NAME_SIZE);	data->type = kind;	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 ERROR2;	/* attach secondary i2c lm75-like clients */	if (!is_isa) {		if ((err = w83781d_detect_subclients(adapter, address,				kind, new_client)))			goto ERROR3;	} else {		data->lm75[0] = NULL;		data->lm75[1] = NULL;	}	/* Initialize the chip */	w83781d_init_client(new_client);	/* A few vars need to be filled upon startup */	for (i = 1; i <= 3; i++) {		data->fan_min[i - 1] = w83781d_read_value(new_client,					W83781D_REG_FAN_MIN(i));	}	if (kind != w83781d && kind != as99127f)		for (i = 0; i < 4; i++)			data->pwmenable[i] = 1;	/* Register sysfs hooks */	device_create_file_in(new_client, 0);	if (kind != w83783s && kind != w83697hf)		device_create_file_in(new_client, 1);	device_create_file_in(new_client, 2);	device_create_file_in(new_client, 3);	device_create_file_in(new_client, 4);	device_create_file_in(new_client, 5);	device_create_file_in(new_client, 6);	if (kind != as99127f && kind != w83781d && kind != w83783s) {		device_create_file_in(new_client, 7);		device_create_file_in(new_client, 8);	}	device_create_file_fan(new_client, 1);	device_create_file_fan(new_client, 2);	if (kind != w83697hf)		device_create_file_fan(new_client, 3);	device_create_file_temp(new_client, 1);	device_create_file_temp(new_client, 2);	if (kind != w83783s && kind != w83697hf)		device_create_file_temp(new_client, 3);	if (kind != w83697hf)		device_create_file_vid(new_client);	if (kind != w83697hf)		device_create_file_vrm(new_client);	device_create_file_fan_div(new_client, 1);	device_create_file_fan_div(new_client, 2);	if (kind != w83697hf)		device_create_file_fan_div(new_client, 3);	device_create_file_alarms(new_client);	device_create_file_beep(new_client);	if (kind != w83781d && kind != as99127f) {		device_create_file_pwm(new_client, 1);		device_create_file_pwm(new_client, 2);		device_create_file_pwmenable(new_client, 2);	}	if (kind == w83782d && !is_isa) {

⌨️ 快捷键说明

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