[i2c] i2c-dev i2c_smbus_read_i2c_block_data update

Jean Delvare khali at linux-fr.org
Wed May 23 21:43:25 CEST 2007


On Tue, 15 May 2007 14:48:07 +0200, Jean Delvare wrote:
> On Sat, 12 May 2007 12:32:49 +0200, Jean Delvare wrote:
> > Here comes the user-space patch completing the
> > i2c_smbus_read_i2c_block_data kernel patch I sent yesterday. It finally
> > makes it possible to do I2C block reads from user-space with size less
> > than 32 bytes.
> > 
> > I'm not too sure about the python changes, I'm not even sure the
> > original code was correct and I can't test it. Mark, can you please
> > take a look and comment?
> 
> Here is an updated version that matches the kernel patch update I just
> posted. Note that "i2cdump i" would then only work with kernels >=
> 2.6.23, which is not very wise, so maybe we want to delay this change
> (after all, the new kernel patch guarantees binary compatibility) or do
> it differently, maybe falling back to the old block read if the new one
> fails? Opinions welcome.

I came up with something better. When the block read length is 32, as
was always the case before, we use the old code (6). Only when the block
read length is less than 32, we use the new code (8). This means that
the call will only fail if the kernel is old (< 2.6.23) and the length
is less than 32, i.e. if the kernel is really not able to fulfill the
request. This is the approach which gives the best binary compatibility
in both directions. I tested an old and a new i2cdump with an old and a
new kernel, all combinations work.

The only drawback is that it doesn't encourage the use of the new code.
But I guess we can't have it all. Comments anyone? Mark, your feedback
on the py-smbus changes is still needed.

Index: kernel/include/i2c-dev.h
===================================================================
--- kernel/include/i2c-dev.h	(révision 4409)
+++ kernel/include/i2c-dev.h	(copie de travail)
@@ -106,8 +106,9 @@
 #define I2C_SMBUS_WORD_DATA	    3
 #define I2C_SMBUS_PROC_CALL	    4
 #define I2C_SMBUS_BLOCK_DATA	    5
-#define I2C_SMBUS_I2C_BLOCK_DATA    6
+#define I2C_SMBUS_I2C_BLOCK_BROKEN  6
 #define I2C_SMBUS_BLOCK_PROC_CALL   7		/* SMBus 2.0 */
+#define I2C_SMBUS_I2C_BLOCK_DATA    8
 
 
 /* ----- commands for the ioctl like i2c_command call:
@@ -271,12 +272,20 @@
 }
 
 /* Returns the number of read bytes */
+/* Until kernel 2.6.22, the length is hardcoded to 32 bytes. If you
+   ask for less than 32 bytes, your code will only work with kernels
+   2.6.23 and later. */
 static inline __s32 i2c_smbus_read_i2c_block_data(int file, __u8 command,
-                                                  __u8 *values)
+                                                  __u8 length, __u8 *values)
 {
 	union i2c_smbus_data data;
 	int i;
+
+	if (length > 32)
+		length = 32;
+	data.block[0] = length;
 	if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
+	                     length == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
 	                      I2C_SMBUS_I2C_BLOCK_DATA,&data))
 		return -1;
 	else {
@@ -297,7 +306,7 @@
 		data.block[i] = values[i-1];
 	data.block[0] = length;
 	return i2c_smbus_access(file,I2C_SMBUS_WRITE,command,
-	                        I2C_SMBUS_I2C_BLOCK_DATA, &data);
+	                        I2C_SMBUS_I2C_BLOCK_BROKEN, &data);
 }
 
 /* Returns the number of read bytes */
Index: prog/dump/i2cdump.c
===================================================================
--- prog/dump/i2cdump.c	(révision 4409)
+++ prog/dump/i2cdump.c	(copie de travail)
@@ -316,7 +316,7 @@
 			} else {
 				for (res = 0; res < 256; res += i) {
 					i = i2c_smbus_read_i2c_block_data(file,
-						res, cblock + res);
+						res, 32, cblock + res);
 					if (i <= 0)
 						break;
 				}
Index: prog/py-smbus/smbusmodule.c
===================================================================
--- prog/py-smbus/smbusmodule.c	(révision 4409)
+++ prog/py-smbus/smbusmodule.c	(copie de travail)
@@ -486,22 +486,25 @@
 }
 
 PyDoc_STRVAR(SMBus_read_i2c_block_data_doc,
-	"read_i2c_block_data(addr, cmd) -> results\n\n"
+	"read_i2c_block_data(addr, cmd, len) -> results\n\n"
 	"Perform I2C Block Read transaction.\n");
 
 static PyObject *
 SMBus_read_i2c_block_data(SMBus *self, PyObject *args)
 {
-	int addr, cmd;
+	int addr, cmd, len;
 	union i2c_smbus_data data;
 
-	if (!PyArg_ParseTuple(args, "ii:read_i2c_block_data", &addr, &cmd))
+	if (!PyArg_ParseTuple(args, "iii:read_i2c_block_data", &addr, &cmd,
+			&len))
 		return NULL;
 
 	SMBus_SET_ADDR(self, addr);
 
+	data.block[0] = len;
 	/* save a bit of code by calling the access function directly */
 	if (i2c_smbus_access(self->fd, I2C_SMBUS_READ, (__u8)cmd,
+				len == 32 ? I2C_SMBUS_I2C_BLOCK_BROKEN :
 				I2C_SMBUS_I2C_BLOCK_DATA, &data)) {
 		PyErr_SetFromErrno(PyExc_IOError);
 		return NULL;
@@ -529,7 +532,7 @@
 
 	/* save a bit of code by calling the access function directly */
 	if (i2c_smbus_access(self->fd, I2C_SMBUS_WRITE, (__u8)cmd,
-				I2C_SMBUS_I2C_BLOCK_DATA, &data)) {
+				I2C_SMBUS_I2C_BLOCK_BROKEN, &data)) {
 		PyErr_SetFromErrno(PyExc_IOError);
 		return NULL;
 	}

-- 
Jean Delvare



More information about the i2c mailing list