]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add wrapper support for I2C_SMBUS ioctls. Patch from
authorJulian Seward <jseward@acm.org>
Thu, 5 Feb 2015 15:52:46 +0000 (15:52 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 5 Feb 2015 15:52:46 +0000 (15:52 +0000)
super.firetwister@gmail.com.  Fixes #342603.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@14908

coregrind/m_syswrap/syswrap-linux.c
include/vki/vki-linux.h

index 9603512ac011fc90fb02d132307f3e2898d40775..16df0756f2b1cde395db8545703e7c96cd4027c1 100644 (file)
@@ -6790,6 +6790,58 @@ PRE(sys_ioctl)
           }
       }
       break;
+   case VKI_I2C_SMBUS:
+       if ( ARG3 ) {
+            struct vki_i2c_smbus_ioctl_data *vkis
+               = (struct vki_i2c_smbus_ioctl_data *) ARG3;
+            PRE_MEM_READ("ioctl(VKI_I2C_SMBUS).i2c_smbus_ioctl_data.read_write",
+                         (Addr)&vkis->read_write, sizeof(vkis->read_write));
+            PRE_MEM_READ("ioctl(VKI_I2C_SMBUS).i2c_smbus_ioctl_data.size",
+                         (Addr)&vkis->size, sizeof(vkis->size));
+            PRE_MEM_READ("ioctl(VKI_I2C_SMBUS).i2c_smbus_ioctl_data.command",
+                         (Addr)&vkis->command, sizeof(vkis->command));
+            /* i2c_smbus_write_quick hides its value in read_write, so
+               this variable can hava a different meaning */
+            /* to make matters worse i2c_smbus_write_byte stores its
+               value in command */
+            if ( ! (((vkis->size == VKI_I2C_SMBUS_QUICK) 
+                     && (vkis->command == VKI_I2C_SMBUS_QUICK)) ||
+                 ((vkis->size == VKI_I2C_SMBUS_BYTE)
+                  && (vkis->read_write == VKI_I2C_SMBUS_WRITE))))  {
+                    /* the rest uses the byte array to store the data,
+                       some the first byte for size */
+                    UInt size;
+                    switch(vkis->size) {
+                        case VKI_I2C_SMBUS_BYTE_DATA:
+                            size = 1;
+                            break;
+                        case VKI_I2C_SMBUS_WORD_DATA:
+                        case VKI_I2C_SMBUS_PROC_CALL:
+                            size = 2;
+                            break;
+                        case VKI_I2C_SMBUS_BLOCK_DATA:
+                        case VKI_I2C_SMBUS_I2C_BLOCK_BROKEN:
+                        case VKI_I2C_SMBUS_BLOCK_PROC_CALL:
+                        case VKI_I2C_SMBUS_I2C_BLOCK_DATA:
+                            size = vkis->data->block[0];
+                            break;
+                        default:
+                            size = 0;
+                    }
+
+                    if ((vkis->read_write == VKI_I2C_SMBUS_READ)
+                        || (vkis->size == VKI_I2C_SMBUS_PROC_CALL)
+                        || (vkis->size == VKI_I2C_SMBUS_BLOCK_PROC_CALL))
+                        PRE_MEM_WRITE("ioctl(VKI_I2C_SMBUS)"
+                                      ".i2c_smbus_ioctl_data.data",
+                                      (Addr)&vkis->data->block[0], size);
+                    else
+                        PRE_MEM_READ("ioctl(VKI_I2C_SMBUS)."
+                                     "i2c_smbus_ioctl_data.data",
+                                     (Addr)&vkis->data->block[0], size);
+            }
+       }
+       break;
 
       /* Wireless extensions ioctls */
    case VKI_SIOCSIWCOMMIT:
@@ -9225,6 +9277,43 @@ POST(sys_ioctl)
           }
       }
       break;
+   case VKI_I2C_SMBUS:
+       if ( ARG3 ) {
+            struct vki_i2c_smbus_ioctl_data *vkis
+               = (struct vki_i2c_smbus_ioctl_data *) ARG3;
+            /* i2c_smbus_write_quick hides its value in read_write, so
+               this variable can hava a different meaning */
+            /* to make matters worse i2c_smbus_write_byte stores its
+               value in command */
+            if ((vkis->read_write == VKI_I2C_SMBUS_READ)
+                || (vkis->size == VKI_I2C_SMBUS_PROC_CALL)
+                || (vkis->size == VKI_I2C_SMBUS_BLOCK_PROC_CALL)) {
+                if ( ! ((vkis->size == VKI_I2C_SMBUS_QUICK) 
+                        && (vkis->command == VKI_I2C_SMBUS_QUICK))) {
+                    UInt size;
+                    switch(vkis->size) {
+                        case VKI_I2C_SMBUS_BYTE:
+                        case VKI_I2C_SMBUS_BYTE_DATA:
+                            size = 1;
+                            break;
+                        case VKI_I2C_SMBUS_WORD_DATA:
+                        case VKI_I2C_SMBUS_PROC_CALL:
+                            size = 2;
+                            break;
+                        case VKI_I2C_SMBUS_BLOCK_DATA:
+                        case VKI_I2C_SMBUS_I2C_BLOCK_BROKEN:
+                        case VKI_I2C_SMBUS_BLOCK_PROC_CALL:
+                        case VKI_I2C_SMBUS_I2C_BLOCK_DATA:
+                            size = vkis->data->block[0];
+                            break;
+                        default:
+                            size = 0;
+                    }
+                    POST_MEM_WRITE((Addr)&vkis->data->block[0], size);
+                }
+            }
+       }
+       break;
 
       /* Wireless extensions ioctls */
    case VKI_SIOCSIWCOMMIT:
index 76e539e206b256ba009882fe6172f5fbb7e996e1..b7b3bab8887224d61e28dc068c53ace838122661 100644 (file)
@@ -2598,16 +2598,48 @@ struct vki_usbdevfs_setuppacket {
 // From linux-2.6.20.1/include/linux/i2c.h
 //----------------------------------------------------------------------
 
-#define VKI_I2C_SLAVE          0x0703  /* Change slave address                 */
-                                       /* Attn.: Slave address is 7 or 10 bits */
-#define VKI_I2C_SLAVE_FORCE    0x0706  /* Change slave address                 */
-                                       /* Attn.: Slave address is 7 or 10 bits */
-                                       /* This changes the address, even if it */
-                                       /* is already taken!                    */
-#define VKI_I2C_TENBIT         0x0704  /* 0 for 7 bit addrs, != 0 for 10 bit   */
-#define VKI_I2C_FUNCS          0x0705  /* Get the adapter functionality */
-#define VKI_I2C_RDWR           0x0707  /* Combined R/W transfer (one STOP only) */
-#define VKI_I2C_PEC            0x0708  /* != 0 for SMBus PEC                   */
+#define VKI_I2C_SMBUS_QUICK             0
+#define VKI_I2C_SMBUS_BYTE              1
+#define VKI_I2C_SMBUS_BYTE_DATA         2
+#define VKI_I2C_SMBUS_WORD_DATA         3
+#define VKI_I2C_SMBUS_PROC_CALL         4
+#define VKI_I2C_SMBUS_BLOCK_DATA        5
+#define VKI_I2C_SMBUS_I2C_BLOCK_BROKEN  6
+#define VKI_I2C_SMBUS_BLOCK_PROC_CALL   7           /* SMBus 2.0 */
+#define VKI_I2C_SMBUS_I2C_BLOCK_DATA    8
+
+/* smbus_access read or write markers */
+#define VKI_I2C_SMBUS_READ  1
+#define VKI_I2C_SMBUS_WRITE 0
+
+#define VKI_I2C_SLAVE        0x0703  /* Change slave address                 */
+                                     /* Attn.: Slave address is 7 or 10 bits */
+#define VKI_I2C_SLAVE_FORCE  0x0706  /* Change slave address                 */
+                                     /* Attn.: Slave address is 7 or 10 bits */
+                                     /* This changes the address, even if it */
+                                     /* is already taken!                    */
+#define VKI_I2C_TENBIT       0x0704  /* 0 for 7 bit addrs, != 0 for 10 bit   */
+#define VKI_I2C_FUNCS        0x0705  /* Get the adapter functionality */
+#define VKI_I2C_RDWR         0x0707  /* Combined R/W transfer (one STOP only) */
+#define VKI_I2C_PEC          0x0708  /* != 0 for SMBus PEC                   */
+#define VKI_I2C_SMBUS        0x0720  /* SMBus transfer */
+
+#define VKI_I2C_SMBUS_BLOCK_MAX  32  /* As specified in SMBus standard */
+union vki_i2c_smbus_data {
+        __vki_u8 byte;
+        __vki_u16 word;
+        __vki_u8 block[VKI_I2C_SMBUS_BLOCK_MAX + 2];
+                 /* block[0] is used for length */
+                 /* and one more for PEC */
+};
+
+/* This is the structure as used in the I2C_SMBUS ioctl call */
+struct vki_i2c_smbus_ioctl_data {
+        __vki_u8 read_write;
+        __vki_u8 command;
+        __vki_u32 size;
+        union vki_i2c_smbus_data __user *data;
+};
 
 struct vki_i2c_msg {
        __vki_u16 addr;         /* slave address                        */