sensors-detect and 2.6.0-test3

Greg KH greg at kroah.com
Sat Aug 23 18:15:56 CEST 2003


On Thu, Aug 21, 2003 at 06:02:53PM +0200, Geert Uytterhoeven wrote:
> On Thu, 21 Aug 2003, Greg KH wrote:
> > On Thu, Aug 21, 2003 at 11:34:32AM +0200, Geert Uytterhoeven wrote:
> > > On Tue, 19 Aug 2003, Greg KH wrote:
> > > > On Sun, Aug 17, 2003 at 08:32:44PM +0200, Geert Uytterhoeven wrote:
> > > > > I'm porting i2c-hydra (which I wrote many years ago) to 2.6.0-test3 and am
> > > > > trying to test it. I want to probe for all i2c devices on my i2c bus, but
> > > > > sensors-detect doesn't work because /proc/bus/i2c is not there.
> > > > 
> > > > sensors-detect does not work on 2.6, sorry.  You have to poke around in
> > > > the sysfs tree by hand right now after loading the drivers by hand :)
> > > > 
> > > > > How do I probe for all i2c devices in 2.6.0-test3? Thanks!
> > > > 
> > > > I just load all of the drivers and see what happens :)
> > > 
> > > Hmm... And all I have on the i2c bus is the SPD EEPROMs on my SDRAM DIMMs.
> > > AFAIK there's no kernel `driver' for these?
> > 
> > There's one in my bk tree, but it's not "correct" and I haven't taken
> > the time to fix it up in order to get it into shape for submission to
> > the main kernel.
> > 
> > If you want, I can send a patch so you can test with.
> 
> Please do so, thanks!

Oops, forgot to send this out, sorry for the delay.

Here's a patch against 2.6.0-test3.  It should work just fine against
2.6.0-test4 too.  Let me know if you have any problems.

thanks,

greg k-h


diff -Nru a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
--- a/drivers/i2c/chips/Kconfig	Fri Aug 22 13:30:06 2003
+++ b/drivers/i2c/chips/Kconfig	Fri Aug 22 13:30:06 2003
@@ -22,6 +22,20 @@
 	  in the lm_sensors package, which you can download at 
 	  http://www.lm-sensors.nu
 
+config SENSORS_EEPROM
+	tristate "  EEPROM (DIMM) reader"
+	depends on I2C
+	help
+	  If you say yes here you get read-only access to the EEPROM data
+	  available on modern memory DIMMs, and which could theoretically
+	  also be available on other devices. This can also be built as a
+	  module which can be inserted and removed while the kernel is
+	  running.
+
+	  You will also need the latest user-space utilties: you can find them
+	  in the lm_sensors package, which you can download at
+	  http://www.lm-sensors.nu
+
 config SENSORS_IT87
 	tristate "  National Semiconductors IT87 and compatibles"
 	depends on I2C && EXPERIMENTAL
diff -Nru a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
--- a/drivers/i2c/chips/Makefile	Fri Aug 22 13:30:57 2003
+++ b/drivers/i2c/chips/Makefile	Fri Aug 22 13:30:57 2003
@@ -11,3 +11,8 @@
 obj-$(CONFIG_SENSORS_LM78)	+= lm78.o
 obj-$(CONFIG_SENSORS_LM85)	+= lm85.o
 obj-$(CONFIG_SENSORS_VIA686A)	+= via686a.o
+
+
+
+obj-$(CONFIG_SENSORS_EEPROM)	+= eeprom.o
+obj-$(CONFIG_SENSORS_SMBUS_ARP)	+= smbus-arp.o
diff -Nru a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/chips/eeprom.c	Fri Aug 22 13:30:58 2003
@@ -0,0 +1,310 @@
+/*
+    eeprom.c - Part of lm_sensors, Linux kernel modules for hardware
+               monitoring
+    Copyright (c) 1998, 1999  Frodo Looijaard <frodol at dds.nl> and
+    Philip Edelbrock <phil at netroedge.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/i2c-sensor.h>
+#include <linux/init.h>
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+static unsigned short normal_i2c_range[] = { 0x50, 0x57, I2C_CLIENT_END };
+static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };
+static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };
+
+/* Insmod parameters */
+SENSORS_INSMOD_1(eeprom);
+
+static int checksum = 0;
+MODULE_PARM(checksum, "i");
+MODULE_PARM_DESC(checksum, "Only accept eeproms whose checksum is correct");
+
+
+/* EEPROM registers */
+#define EEPROM_REG_CHECKSUM	0x3f
+
+/* EEPROM memory types: */
+#define ONE_K			1
+#define TWO_K			2
+#define FOUR_K			3
+#define EIGHT_K			4
+#define SIXTEEN_K		5
+
+/* Size of EEPROM in bytes */
+#define EEPROM_SIZE		256
+
+/* Each client has this additional data */
+struct eeprom_data {
+//	int sysctl_id;
+	struct semaphore update_lock;
+	char valid;			/* !=0 if following fields are valid */
+	unsigned long last_updated;	/* In jiffies */
+	u8 data[EEPROM_SIZE];		/* Register values */
+};
+
+
+static int eeprom_attach_adapter(struct i2c_adapter *adapter);
+static int eeprom_detect(struct i2c_adapter *adapter, int address, int kind);
+static int eeprom_detach_client(struct i2c_client *client);
+
+static void eeprom_update_client(struct i2c_client *client);
+
+
+/* This is the driver that will be inserted */
+static struct i2c_driver eeprom_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "eeprom",
+	.id		= I2C_DRIVERID_EEPROM,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= eeprom_attach_adapter,
+	.detach_client	= eeprom_detach_client,
+};
+
+static int eeprom_id = 0;
+
+static ssize_t show_eeprom(struct device *dev, char *buf, int base)
+{
+	struct i2c_client *client;
+	struct eeprom_data *data;
+	char *buffer;
+	int i;
+
+	client = to_i2c_client(dev);
+	data = i2c_get_clientdata(client);
+	buffer = buf;
+
+	eeprom_update_client(client);
+	for (i = 0; i < 15; ++i)
+		buf += sprintf(buf, "%d ", data->data[i + base]);
+	buf += sprintf(buf, "%d\n", data->data[15 + base]);
+	return (buf - buffer);
+}
+#define show_eeprom_offset(offset)			\
+static ssize_t						\
+show_eeprom_##offset (struct device *dev, char *buf)	\
+{							\
+	return show_eeprom(dev, buf, 0x##offset);	\
+}							\
+static DEVICE_ATTR(eeprom_##offset, S_IRUGO, show_eeprom_##offset, NULL)
+show_eeprom_offset(00);
+show_eeprom_offset(10);
+show_eeprom_offset(20);
+show_eeprom_offset(30);
+show_eeprom_offset(40);
+show_eeprom_offset(50);
+show_eeprom_offset(60);
+show_eeprom_offset(70);
+show_eeprom_offset(80);
+show_eeprom_offset(90);
+show_eeprom_offset(a0);
+show_eeprom_offset(b0);
+show_eeprom_offset(c0);
+show_eeprom_offset(d0);
+show_eeprom_offset(e0);
+show_eeprom_offset(f0);
+
+static int eeprom_attach_adapter(struct i2c_adapter *adapter)
+{
+	return i2c_detect(adapter, &addr_data, eeprom_detect);
+}
+
+/* This function is called by i2c_detect */
+int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	int i, cs;
+	struct i2c_client *new_client;
+	struct eeprom_data *data;
+	int err = 0;
+	const char *type_name, *client_name;
+
+	/* Make sure we aren't probing the ISA bus!! This is just a safety check
+	   at this moment; i2c_detect really won't call us. */
+#ifdef DEBUG
+	if (i2c_is_isa_adapter(adapter)) {
+		dev_dbg(&adapter->dev, " eeprom_detect called for an ISA bus adapter?!?\n");
+		return 0;
+	}
+#endif
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+		goto ERROR0;
+
+	/* 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 eeprom_{read,write}_value. */
+	if (!(new_client = kmalloc(sizeof(struct i2c_client) +
+				   sizeof(struct eeprom_data),
+				   GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto ERROR0;
+	}
+	memset(new_client, 0x00, sizeof(struct i2c_client) +
+				 sizeof(struct eeprom_data));
+
+	data = (struct eeprom_data *) (new_client + 1);
+	memset(data, 0xff, EEPROM_SIZE);
+	i2c_set_clientdata(new_client, data);
+	new_client->addr = address;
+	new_client->adapter = adapter;
+	new_client->driver = &eeprom_driver;
+	new_client->flags = 0;
+
+	/* Now, we do the remaining detection. It is not there, unless you force
+	   the checksum to work out. */
+	if (checksum) {
+		/* prevent 24RF08 corruption */
+		i2c_smbus_write_quick(new_client, 0);
+		cs = 0;
+		for (i = 0; i <= 0x3e; i++)
+			cs += i2c_smbus_read_byte_data(new_client, i);
+		cs &= 0xff;
+		if (i2c_smbus_read_byte_data (new_client, EEPROM_REG_CHECKSUM) != cs)
+			goto ERROR1;
+	}
+
+	/* Determine the chip type - only one kind supported! */
+	if (kind <= 0)
+		kind = eeprom;
+
+	if (kind == eeprom) {
+		type_name = "eeprom";
+		client_name = "EEPROM chip";
+	} else {
+		dev_dbg(&adap->dev, "Internal error: unknown kind (%d)?!?", kind);
+		goto ERROR1;
+	}
+
+	/* Fill in the remaining client fields and put it into the global list */
+	strncpy(new_client->name, client_name, DEVICE_NAME_SIZE);
+
+	new_client->id = eeprom_id++;
+	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 ERROR3;
+
+	device_create_file(&new_client->dev, &dev_attr_eeprom_00);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_10);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_20);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_30);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_40);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_50);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_60);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_70);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_80);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_90);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_a0);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_b0);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_c0);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_d0);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_e0);
+	device_create_file(&new_client->dev, &dev_attr_eeprom_f0);
+
+//	/* Register a new directory entry with module sensors */
+//	if ((i = i2c_register_entry(new_client, type_name, eeprom_dir_table_template)) < 0) {
+//		err = i;
+//		goto ERROR4;
+//	}
+//	data->sysctl_id = i;
+
+	return 0;
+
+//ERROR4:
+//	i2c_detach_client(new_client);
+ERROR3:
+ERROR1:
+	kfree(new_client);
+ERROR0:
+	return err;
+}
+
+static int eeprom_detach_client(struct i2c_client *client)
+{
+	int err;
+
+//	i2c_deregister_entry(((struct eeprom_data *) (i2c_get_clientdata(client)))->sysctl_id);
+
+	if ((err = i2c_detach_client(client))) {
+		printk
+		    ("eeprom.o: Client deregistration failed, client not detached.\n");
+		return err;
+	}
+
+	kfree(client);
+
+	return 0;
+}
+
+static void eeprom_update_client(struct i2c_client *client)
+{
+	struct eeprom_data *data = i2c_get_clientdata(client);
+	int i, j;
+
+	down(&data->update_lock);
+
+	if ((jiffies - data->last_updated > 300 * HZ) |
+	    (jiffies < data->last_updated) || !data->valid) {
+		dev_dbg(&client->dev, "Starting eeprom update\n");
+
+		if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
+			for (i=0; i<EEPROM_SIZE; i+=I2C_SMBUS_I2C_BLOCK_MAX)
+				if (i2c_smbus_read_i2c_block_data(client, i, data->data + i) != I2C_SMBUS_I2C_BLOCK_MAX)
+					goto DONE;
+		} else {
+			if (i2c_smbus_write_byte(client, 0)) {
+				dev_dbg(&client->dev, "eeprom read start has failed!\n");
+				goto DONE;
+			}
+			for (i = 0; i < EEPROM_SIZE; i++) {
+				j = i2c_smbus_read_byte(client);
+				if (j < 0)
+					goto DONE;
+				data->data[i] = (u8) j;
+			}
+		}
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+DONE:
+	up(&data->update_lock);
+}
+
+static int __init sm_eeprom_init(void)
+{
+	return i2c_add_driver(&eeprom_driver);
+}
+
+static void __exit sm_eeprom_exit(void)
+{
+	i2c_del_driver(&eeprom_driver);
+}
+
+
+MODULE_AUTHOR ("Frodo Looijaard <frodol at dds.nl> and "
+		"Philip Edelbrock <phil at netroedge.com>");
+MODULE_DESCRIPTION("EEPROM driver");
+MODULE_LICENSE("GPL");
+
+module_init(sm_eeprom_init);
+module_exit(sm_eeprom_exit);



More information about the lm-sensors mailing list