[i2c] [PATCH] i2c-stub: Support multiple chips

Mark M. Hoffman mhoffman at lightlink.com
Tue Oct 9 14:18:08 CEST 2007


Hi Jean:

* Jean Delvare <khali at linux-fr.org> [2007-09-18 20:28:40 +0200]:
> Add support for multiple chips to i2c-stub. I've changed the memory
> allocation scheme from static to dynamic, so that we don't waste too
> much memory.
> 
> Signed-off-by: Jean Delvare <khali at linux-fr.org>
> Cc: Mark M. Hoffman <mhoffman at lightlink.com>

Acked-by: Mark M. Hoffman <mhoffman at lightlink.com>

> ---
>  Documentation/i2c/i2c-stub    |   18 ++++-----
>  drivers/i2c/busses/i2c-stub.c |   78 +++++++++++++++++++++++++++++------------
>  2 files changed, 64 insertions(+), 32 deletions(-)
> 
> --- linux-2.6.23-rc6.orig/drivers/i2c/busses/i2c-stub.c	2007-02-04 19:44:54.000000000 +0100
> +++ linux-2.6.23-rc6/drivers/i2c/busses/i2c-stub.c	2007-09-18 20:23:57.000000000 +0200
> @@ -27,21 +27,37 @@
>  #include <linux/errno.h>
>  #include <linux/i2c.h>
>  
> -static unsigned short chip_addr;
> -module_param(chip_addr, ushort, S_IRUGO);
> -MODULE_PARM_DESC(chip_addr, "Chip address (between 0x03 and 0x77)\n");
> -
> -static u8  stub_pointer;
> -static u8  stub_bytes[256];
> -static u16 stub_words[256];
> +#define MAX_CHIPS 10
> +
> +static unsigned short chip_addr[MAX_CHIPS];
> +module_param_array(chip_addr, ushort, NULL, S_IRUGO);
> +MODULE_PARM_DESC(chip_addr,
> +		 "Chip addresses (up to 10, between 0x03 and 0x77)\n");
> +
> +struct stub_chip {
> +	u8 pointer;
> +	u8 bytes[256];
> +	u16 words[256];
> +};
> +
> +static struct stub_chip *stub_chips;
>  
>  /* Return -1 on error. */
>  static s32 stub_xfer(struct i2c_adapter * adap, u16 addr, unsigned short flags,
>  	char read_write, u8 command, int size, union i2c_smbus_data * data)
>  {
>  	s32 ret;
> +	int i;
> +	struct stub_chip *chip = NULL;
>  
> -	if (addr != chip_addr)
> +	/* Search for the right chip */
> +	for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
> +		if (addr == chip_addr[i]) {
> +			chip = stub_chips + i;
> +			break;
> +		}
> +	}
> +	if (!chip)
>  		return -ENODEV;
>  
>  	switch (size) {
> @@ -53,12 +69,12 @@ static s32 stub_xfer(struct i2c_adapter 
>  
>  	case I2C_SMBUS_BYTE:
>  		if (read_write == I2C_SMBUS_WRITE) {
> -			stub_pointer = command;
> +			chip->pointer = command;
>  			dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
>  					"wrote 0x%02x.\n",
>  					addr, command);
>  		} else {
> -			data->byte = stub_bytes[stub_pointer++];
> +			data->byte = chip->bytes[chip->pointer++];
>  			dev_dbg(&adap->dev, "smbus byte - addr 0x%02x, "
>  					"read  0x%02x.\n",
>  					addr, data->byte);
> @@ -69,29 +85,29 @@ static s32 stub_xfer(struct i2c_adapter 
>  
>  	case I2C_SMBUS_BYTE_DATA:
>  		if (read_write == I2C_SMBUS_WRITE) {
> -			stub_bytes[command] = data->byte;
> +			chip->bytes[command] = data->byte;
>  			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
>  					"wrote 0x%02x at 0x%02x.\n",
>  					addr, data->byte, command);
>  		} else {
> -			data->byte = stub_bytes[command];
> +			data->byte = chip->bytes[command];
>  			dev_dbg(&adap->dev, "smbus byte data - addr 0x%02x, "
>  					"read  0x%02x at 0x%02x.\n",
>  					addr, data->byte, command);
>  		}
> -		stub_pointer = command + 1;
> +		chip->pointer = command + 1;
>  
>  		ret = 0;
>  		break;
>  
>  	case I2C_SMBUS_WORD_DATA:
>  		if (read_write == I2C_SMBUS_WRITE) {
> -			stub_words[command] = data->word;
> +			chip->words[command] = data->word;
>  			dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
>  					"wrote 0x%04x at 0x%02x.\n",
>  					addr, data->word, command);
>  		} else {
> -			data->word = stub_words[command];
> +			data->word = chip->words[command];
>  			dev_dbg(&adap->dev, "smbus word data - addr 0x%02x, "
>  					"read  0x%04x at 0x%02x.\n",
>  					addr, data->word, command);
> @@ -129,23 +145,41 @@ static struct i2c_adapter stub_adapter =
>  
>  static int __init i2c_stub_init(void)
>  {
> -	if (!chip_addr) {
> +	int i, ret;
> +
> +	if (!chip_addr[0]) {
>  		printk(KERN_ERR "i2c-stub: Please specify a chip address\n");
>  		return -ENODEV;
>  	}
> -	if (chip_addr < 0x03 || chip_addr > 0x77) {
> -		printk(KERN_ERR "i2c-stub: Invalid chip address 0x%02x\n",
> -		       chip_addr);
> -		return -EINVAL;
> +
> +	for (i = 0; i < MAX_CHIPS && chip_addr[i]; i++) {
> +		if (chip_addr[i] < 0x03 || chip_addr[i] > 0x77) {
> +			printk(KERN_ERR "i2c-stub: Invalid chip address "
> +			       "0x%02x\n", chip_addr[i]);
> +			return -EINVAL;
> +		}
> +
> +		printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n",
> +		       chip_addr[i]);
>  	}
>  
> -	printk(KERN_INFO "i2c-stub: Virtual chip at 0x%02x\n", chip_addr);
> -	return i2c_add_adapter(&stub_adapter);
> +	/* Allocate memory for all chips at once */
> +	stub_chips = kzalloc(i * sizeof(struct stub_chip), GFP_KERNEL);
> +	if (!stub_chips) {
> +		printk(KERN_ERR "i2c-stub: Out of memory\n");
> +		return -ENOMEM;
> +	}
> +
> +	ret = i2c_add_adapter(&stub_adapter);
> +	if (ret)
> +		kfree(stub_chips);
> +	return ret;
>  }
>  
>  static void __exit i2c_stub_exit(void)
>  {
>  	i2c_del_adapter(&stub_adapter);
> +	kfree(stub_chips);
>  }
>  
>  MODULE_AUTHOR("Mark M. Hoffman <mhoffman at lightlink.com>");
> --- linux-2.6.23-rc6.orig/Documentation/i2c/i2c-stub	2007-02-04 19:44:54.000000000 +0100
> +++ linux-2.6.23-rc6/Documentation/i2c/i2c-stub	2007-09-18 19:56:25.000000000 +0200
> @@ -6,13 +6,14 @@ This module is a very simple fake I2C/SM
>  types of SMBus commands: write quick, (r/w) byte, (r/w) byte data, and
>  (r/w) word data.
>  
> -You need to provide a chip address as a module parameter when loading
> -this driver, which will then only react to SMBus commands to this address.
> +You need to provide chip addresses as a module parameter when loading this
> +driver, which will then only react to SMBus commands to these addresses.
>  
>  No hardware is needed nor associated with this module.  It will accept write
> -quick commands to one address; it will respond to the other commands (also
> -to one address) by reading from or writing to an array in memory.  It will
> -also spam the kernel logs for every command it handles.
> +quick commands to the specified addresses; it will respond to the other
> +commands (also to the specified addresses) by reading from or writing to
> +arrays in memory.  It will also spam the kernel logs for every command it
> +handles.
>  
>  A pointer register with auto-increment is implemented for all byte
>  operations.  This allows for continuous byte reads like those supported by
> @@ -26,8 +27,8 @@ The typical use-case is like this:
>  
>  PARAMETERS:
>  
> -int chip_addr:
> -	The SMBus address to emulate a chip at.
> +int chip_addr[10]:
> +	The SMBus addresses to emulate chips at.
>  
>  CAVEATS:
>  
> @@ -41,9 +42,6 @@ If the hardware for your driver has bank
>  chips) this module will not work well - although it could be extended to
>  support that pretty easily.
>  
> -Only one chip address is supported - although this module could be
> -extended to support more.
> -
>  If you spam it hard enough, printk can be lossy.  This module really wants
>  something like relayfs.

Regards,

-- 
Mark M. Hoffman
mhoffman at lightlink.com




More information about the i2c mailing list