[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