writing-clients
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:31k
- This is a small guide for those who want to write kernel drivers for I2C
- or SMBus devices.
- To set up a driver, you need to do several things. Some are optional, and
- some things can be done slightly or completely different. Use this as a
- guide, not as a rule book!
- General remarks
- ===============
- Try to keep the kernel namespace as clean as possible. The best way to
- do this is to use a unique prefix for all global symbols. This is
- especially important for exported symbols, but it is a good idea to do
- it for non-exported symbols too. We will use the prefix `foo_' in this
- tutorial, and `FOO_' for preprocessor variables.
- The driver structure
- ====================
- Usually, you will implement a single driver structure, and instantiate
- all clients from it. Remember, a driver structure contains general access
- routines, a client structure specific information like the actual I2C
- address.
- struct i2c_driver foo_driver
- {
- /* name */ "Foo version 2.3 and later driver",
- /* id */ I2C_DRIVERID_FOO,
- /* flags */ I2C_DF_NOTIFY,
- /* attach_adapter */ &foo_attach_adapter,
- /* detach_client */ &foo_detach_client,
- /* command */ &foo_command, /* May be NULL */
- /* inc_use */ &foo_inc_use, /* May be NULL */
- /* dec_use */ &foo_dec_use /* May be NULL */
- }
-
- The name can be chosen freely, and may be upto 40 characters long. Please
- use something descriptive here.
- The id should be a unique ID. The range 0xf000 to 0xffff is reserved for
- local use, and you can use one of those until you start distributing the
- driver. Before you do that, contact the i2c authors to get your own ID(s).
- Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This
- means that your driver will be notified when new adapters are found.
- This is almost always what you want.
- All other fields are for call-back functions which will be explained
- below.
- Module usage count
- ==================
- If your driver can also be compiled as a module, there are moments at
- which the module can not be removed from memory. For example, when you
- are doing a lengthy transaction, or when you create a /proc directory,
- and some process has entered that directory (this last case is the
- main reason why these call-backs were introduced).
- To increase or decrease the module usage count, you can use the
- MOD_{INC,DEC}_USE_COUNT macros. They must be called from the module
- which needs to get its usage count changed; that is why each driver
- module has to implement its own callback.
- void foo_inc_use (struct i2c_client *client)
- {
- #ifdef MODULE
- MOD_INC_USE_COUNT;
- #endif
- }
- void foo_dec_use (struct i2c_client *client)
- {
- #ifdef MODULE
- MOD_DEC_USE_COUNT;
- #endif
- }
- Do not call these call-back functions directly; instead, use one of the
- following functions defined in i2c.h:
- void i2c_inc_use_client(struct i2c_client *);
- void i2c_dec_use_client(struct i2c_client *);
- You should *not* increase the module count just because a device is
- detected and a client created. This would make it impossible to remove
- an adapter driver!
- Extra client data
- =================
- The client structure has a special `data' field that can point to any
- structure at all. You can use this to keep client-specific data. You
- do not always need this, but especially for `sensors' drivers, it can
- be very useful.
- An example structure is below.
- struct foo_data {
- struct semaphore lock; /* For ISA access in `sensors' drivers. */
- int sysctl_id; /* To keep the /proc directory entry for
- `sensors' drivers. */
- enum chips type; /* To keep the chips type for `sensors' drivers. */
-
- /* Because the i2c bus is slow, it is often useful to cache the read
- information of a chip for some time (for example, 1 or 2 seconds).
- It depends of course on the device whether this is really worthwhile
- or even sensible. */
- struct semaphore update_lock; /* When we are reading lots of information,
- another process should not update the
- below information */
- char valid; /* != 0 if the following fields are valid. */
- unsigned long last_updated; /* In jiffies */
- /* Add the read information here too */
- };
- Accessing the client
- ====================
- Let's say we have a valid client structure. At some time, we will need
- to gather information from the client, or write new information to the
- client. How we will export this information to user-space is less
- important at this moment (perhaps we do not need to do this at all for
- some obscure clients). But we need generic reading and writing routines.
- I have found it useful to define foo_read and foo_write function for this.
- For some cases, it will be easier to call the i2c functions directly,
- but many chips have some kind of register-value idea that can easily
- be encapsulated. Also, some chips have both ISA and I2C interfaces, and
- it useful to abstract from this (only for `sensors' drivers).
- The below functions are simple examples, and should not be copied
- literally.
- int foo_read_value(struct i2c_client *client, u8 reg)
- {
- if (reg < 0x10) /* byte-sized register */
- return i2c_smbus_read_byte_data(client,reg);
- else /* word-sized register */
- return i2c_smbus_read_word_data(client,reg);
- }
- int foo_write_value(struct i2c_client *client, u8 reg, u16 value)
- {
- if (reg == 0x10) /* Impossible to write - driver error! */ {
- return -1;
- else if (reg < 0x10) /* byte-sized register */
- return i2c_smbus_write_byte_data(client,reg,value);
- else /* word-sized register */
- return i2c_smbus_write_word_data(client,reg,value);
- }
- For sensors code, you may have to cope with ISA registers too. Something
- like the below often works. Note the locking!
- int foo_read_value(struct i2c_client *client, u8 reg)
- {
- int res;
- if (i2c_is_isa_client(client)) {
- down(&(((struct foo_data *) (client->data)) -> lock));
- outb_p(reg,client->addr + FOO_ADDR_REG_OFFSET);
- res = inb_p(client->addr + FOO_DATA_REG_OFFSET);
- up(&(((struct foo_data *) (client->data)) -> lock));
- return res;
- } else
- return i2c_smbus_read_byte_data(client,reg);
- }
- Writing is done the same way.
- Probing and attaching
- =====================
- Most i2c devices can be present on several i2c addresses; for some this
- is determined in hardware (by soldering some chip pins to Vcc or Ground),
- for others this can be changed in software (by writing to specific client
- registers). Some devices are usually on a specific address, but not always;
- and some are even more tricky. So you will probably need to scan several
- i2c addresses for your clients, and do some sort of detection to see
- whether it is actually a device supported by your driver.
- To give the user a maximum of possibilities, some default module parameters
- are defined to help determine what addresses are scanned. Several macros
- are defined in i2c.h to help you support them, as well as a generic
- detection algorithm.
- You do not have to use this parameter interface; but don't try to use
- function i2c_probe() (or i2c_detect()) if you don't.
- NOTE: If you want to write a `sensors' driver, the interface is slightly
- different! See below.
- Probing classes (i2c)
- ---------------------
- All parameters are given as lists of unsigned 16-bit integers. Lists are
- terminated by I2C_CLIENT_END.
- The following lists are used internally:
- normal_i2c: filled in by the module writer.
- A list of I2C addresses which should normally be examined.
- normal_i2c_range: filled in by the module writer.
- A list of pairs of I2C addresses, each pair being an inclusive range of
- addresses which should normally be examined.
- probe: insmod parameter.
- A list of pairs. The first value is a bus number (-1 for any I2C bus),
- the second is the address. These addresses are also probed, as if they
- were in the 'normal' list.
- probe_range: insmod parameter.
- A list of triples. The first value is a bus number (-1 for any I2C bus),
- the second and third are addresses. These form an inclusive range of
- addresses that are also probed, as if they were in the 'normal' list.
- ignore: insmod parameter.
- A list of pairs. The first value is a bus number (-1 for any I2C bus),
- the second is the I2C address. These addresses are never probed.
- This parameter overrules 'normal' and 'probe', but not the 'force' lists.
- ignore_range: insmod parameter.
- A list of triples. The first value is a bus number (-1 for any I2C bus),
- the second and third are addresses. These form an inclusive range of
- I2C addresses that are never probed.
- This parameter overrules 'normal' and 'probe', but not the 'force' lists.
- force: insmod parameter.
- A list of pairs. The first value is a bus number (-1 for any I2C bus),
- the second is the I2C address. A device is blindly assumed to be on
- the given address, no probing is done.
- Fortunately, as a module writer, you just have to define the `normal'
- and/or `normal_range' parameters. The complete declaration could look
- like this:
- /* Scan 0x20 to 0x2f, 0x37, and 0x40 to 0x4f */
- static unsigned short normal_i2c[] = { 0x37,I2C_CLIENT_END };
- static unsigned short normal_i2c_range[] = { 0x20, 0x2f, 0x40, 0x4f,
- I2C_CLIENT_END };
- /* Magic definition of all other variables and things */
- I2C_CLIENT_INSMOD;
- Note that you *have* to call the two defined variables `normal_i2c' and
- `normal_i2c_range', without any prefix!
- Probing classes (sensors)
- -------------------------
- If you write a `sensors' driver, you use a slightly different interface.
- As well as I2C addresses, we have to cope with ISA addresses. Also, we
- use a enum of chip types. Don't forget to include `sensors.h'.
- The following lists are used internally. They are all lists of integers.
- normal_i2c: filled in by the module writer. Terminated by SENSORS_I2C_END.
- A list of I2C addresses which should normally be examined.
- normal_i2c_range: filled in by the module writer. Terminated by
- SENSORS_I2C_END
- A list of pairs of I2C addresses, each pair being an inclusive range of
- addresses which should normally be examined.
- normal_isa: filled in by the module writer. Terminated by SENSORS_ISA_END.
- A list of ISA addresses which should normally be examined.
- normal_isa_range: filled in by the module writer. Terminated by
- SENSORS_ISA_END
- A list of triples. The first two elements are ISA addresses, being an
- range of addresses which should normally be examined. The third is the
- modulo parameter: only addresses which are 0 module this value relative
- to the first address of the range are actually considered.
- probe: insmod parameter. Initialize this list with SENSORS_I2C_END values.
- A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second is the address. These
- addresses are also probed, as if they were in the 'normal' list.
- probe_range: insmod parameter. Initialize this list with SENSORS_I2C_END
- values.
- A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second and third are addresses.
- These form an inclusive range of addresses that are also probed, as
- if they were in the 'normal' list.
- ignore: insmod parameter. Initialize this list with SENSORS_I2C_END values.
- A list of pairs. The first value is a bus number (SENSORS_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second is the I2C address. These
- addresses are never probed. This parameter overrules 'normal' and
- 'probe', but not the 'force' lists.
- ignore_range: insmod parameter. Initialize this list with SENSORS_I2C_END
- values.
- A list of triples. The first value is a bus number (SENSORS_ISA_BUS for
- the ISA bus, -1 for any I2C bus), the second and third are addresses.
- These form an inclusive range of I2C addresses that are never probed.
- This parameter overrules 'normal' and 'probe', but not the 'force' lists.
- Also used is a list of pointers to sensors_force_data structures:
- force_data: insmod parameters. A list, ending with an element of which
- the force field is NULL.
- Each element contains the type of chip and a list of pairs.
- The first value is a bus number (SENSORS_ISA_BUS for the ISA bus,
- -1 for any I2C bus), the second is the address.
- These are automatically translated to insmod variables of the form
- force_foo.
- So we have a generic insmod variabled `force', and chip-specific variables
- `force_CHIPNAME'.
- Fortunately, as a module writer, you just have to define the `normal'
- and/or `normal_range' parameters, and define what chip names are used.
- The complete declaration could look like this:
- /* Scan i2c addresses 0x20 to 0x2f, 0x37, and 0x40 to 0x4f
- static unsigned short normal_i2c[] = {0x37,SENSORS_I2C_END};
- static unsigned short normal_i2c_range[] = {0x20,0x2f,0x40,0x4f,
- SENSORS_I2C_END};
- /* Scan ISA address 0x290 */
- static unsigned int normal_isa[] = {0x0290,SENSORS_ISA_END};
- static unsigned int normal_isa_range[] = {SENSORS_ISA_END};
- /* Define chips foo and bar, as well as all module parameters and things */
- SENSORS_INSMOD_2(foo,bar);
- If you have one chip, you use macro SENSORS_INSMOD_1(chip), if you have 2
- you use macro SENSORS_INSMOD_2(chip1,chip2), etc. If you do not want to
- bother with chip types, you can use SENSORS_INSMOD_0.
- A enum is automatically defined as follows:
- enum chips { any_chip, chip1, chip2, ... }
- Attaching to an adapter
- -----------------------
- Whenever a new adapter is inserted, or for all adapters if the driver is
- being registered, the callback attach_adapter() is called. Now is the
- time to determine what devices are present on the adapter, and to register
- a client for each of them.
- The attach_adapter callback is really easy: we just call the generic
- detection function. This function will scan the bus for us, using the
- information as defined in the lists explained above. If a device is
- detected at a specific address, another callback is called.
- int foo_attach_adapter(struct i2c_adapter *adapter)
- {
- return i2c_probe(adapter,&addr_data,&foo_detect_client);
- }
- For `sensors' drivers, use the i2c_detect function instead:
-
- int foo_attach_adapter(struct i2c_adapter *adapter)
- {
- return i2c_detect(adapter,&addr_data,&foo_detect_client);
- }
- Remember, structure `addr_data' is defined by the macros explained above,
- so you do not have to define it yourself.
- The i2c_probe or i2c_detect function will call the foo_detect_client
- function only for those i2c addresses that actually have a device on
- them (unless a `force' parameter was used). In addition, addresses that
- are already in use (by some other registered client) are skipped.
- The detect client function
- --------------------------
- The detect client function is called by i2c_probe or i2c_detect.
- The `kind' parameter contains 0 if this call is due to a `force'
- parameter, and 0 otherwise (for i2c_detect, it contains 0 if
- this call is due to the generic `force' parameter, and the chip type
- number if it is due to a specific `force' parameter).
- Below, some things are only needed if this is a `sensors' driver. Those
- parts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */
- markers.
- This function should only return an error (any value != 0) if there is
- some reason why no more detection should be done anymore. If the
- detection just fails for this address, return 0.
- For now, you can ignore the `flags' parameter. It is there for future use.
- /* Unique ID allocation */
- static int foo_id = 0;
- int foo_detect_client(struct i2c_adapter *adapter, int address,
- unsigned short flags, int kind)
- {
- int err = 0;
- int i;
- struct i2c_client *new_client;
- struct foo_data *data;
- const char *client_name = ""; /* For non-`sensors' drivers, put the real
- name here! */
-
- /* Let's see whether this adapter can support what we need.
- Please substitute the things you need here!
- For `sensors' drivers, add `! is_isa &&' to the if statement */
- if (!i2c_check_functionality(adapter,I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_WRITE_BYTE))
- goto ERROR0;
- /* SENSORS ONLY START */
- const char *type_name = "";
- int is_isa = i2c_is_isa_adapter(adapter);
- if (is_isa) {
- /* If this client can't be on the ISA bus at all, we can stop now
- (call `goto ERROR0'). But for kicks, we will assume it is all
- right. */
- /* Discard immediately if this ISA range is already used */
- if (check_region(address,FOO_EXTENT))
- goto ERROR0;
- /* Probe whether there is anything on this address.
- Some example code is below, but you will have to adapt this
- for your own driver */
- if (kind < 0) /* Only if no force parameter was used */ {
- /* We may need long timeouts at least for some chips. */
- #define REALLY_SLOW_IO
- i = inb_p(address + 1);
- if (inb_p(address + 2) != i)
- goto ERROR0;
- if (inb_p(address + 3) != i)
- goto ERROR0;
- if (inb_p(address + 7) != i)
- goto ERROR0;
- #undef REALLY_SLOW_IO
- /* Let's just hope nothing breaks here */
- i = inb_p(address + 5) & 0x7f;
- outb_p(~i & 0x7f,address+5);
- if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) {
- outb_p(i,address+5);
- return 0;
- }
- }
- }
- /* SENSORS ONLY END */
- /* 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 several i2c functions safely */
-
- /* Note that we reserve some space for foo_data too. If you don't
- need it, remove it. We do it here to help to lessen memory
- fragmentation. */
- if (! (new_client = kmalloc(sizeof(struct i2c_client)) +
- sizeof(struct foo_data),
- GFP_KERNEL)) {
- err = -ENOMEM;
- goto ERROR0;
- }
- /* This is tricky, but it will set the data to the right value. */
- client->data = new_client + 1;
- data = (struct foo_data *) (client->data);
- new_client->addr = address;
- new_client->data = data;
- new_client->adapter = adapter;
- new_client->driver = &foo_driver;
- new_client->flags = 0;
- /* Now, we do the remaining detection. If no `force' parameter is used. */
- /* First, the generic detection (if any), that is skipped if any force
- parameter was used. */
- if (kind < 0) {
- /* The below is of course bogus */
- if (foo_read(new_client,FOO_REG_GENERIC) != FOO_GENERIC_VALUE)
- goto ERROR1;
- }
- /* SENSORS ONLY START */
- /* Next, specific detection. This is especially important for `sensors'
- devices. */
- /* Determine the chip type. Not needed if a `force_CHIPTYPE' parameter
- was used. */
- if (kind <= 0) {
- i = foo_read(new_client,FOO_REG_CHIPTYPE);
- if (i == FOO_TYPE_1)
- kind = chip1; /* As defined in the enum */
- else if (i == FOO_TYPE_2)
- kind = chip2;
- else {
- printk("foo: Ignoring 'force' parameter for unknown chip at "
- "adapter %d, address 0x%02xn",i2c_adapter_id(adapter),address);
- goto ERROR1;
- }
- }
- /* Now set the type and chip names */
- if (kind == chip1) {
- type_name = "chip1"; /* For /proc entry */
- client_name = "CHIP 1";
- } else if (kind == chip2) {
- type_name = "chip2"; /* For /proc entry */
- client_name = "CHIP 2";
- }
-
- /* Reserve the ISA region */
- if (is_isa)
- request_region(address,FOO_EXTENT,type_name);
- /* SENSORS ONLY END */
- /* Fill in the remaining client fields. */
- strcpy(new_client->name,client_name);
- /* SENSORS ONLY BEGIN */
- data->type = kind;
- /* SENSORS ONLY END */
- new_client->id = foo_id++; /* Automatically unique */
- data->valid = 0; /* Only if you use this field */
- init_MUTEX(&data->update_lock); /* Only if you use this field */
- /* Any other initializations in data must be done here too. */
- /* Tell the i2c layer a new client has arrived */
- if ((err = i2c_attach_client(new_client)))
- goto ERROR3;
- /* SENSORS ONLY BEGIN */
- /* Register a new directory entry with module sensors. See below for
- the `template' structure. */
- if ((i = i2c_register_entry(new_client, type_name,
- foo_dir_table_template,THIS_MODULE)) < 0) {
- err = i;
- goto ERROR4;
- }
- data->sysctl_id = i;
- /* SENSORS ONLY END */
- /* This function can write default values to the client registers, if
- needed. */
- foo_init_client(new_client);
- return 0;
- /* OK, this is not exactly good programming practice, usually. But it is
- very code-efficient in this case. */
- ERROR4:
- i2c_detach_client(new_client);
- ERROR3:
- ERROR2:
- /* SENSORS ONLY START */
- if (is_isa)
- release_region(address,FOO_EXTENT);
- /* SENSORS ONLY END */
- ERROR1:
- kfree(new_client);
- ERROR0:
- return err;
- }
- Removing the client
- ===================
- The detach_client call back function is called when a client should be
- removed. It may actually fail, but only when panicking. This code is
- much simpler than the attachment code, fortunately!
- int foo_detach_client(struct i2c_client *client)
- {
- int err,i;
- /* SENSORS ONLY START */
- /* Deregister with the `i2c-proc' module. */
- i2c_deregister_entry(((struct lm78_data *)(client->data))->sysctl_id);
- /* SENSORS ONLY END */
- /* Try to detach the client from i2c space */
- if ((err = i2c_detach_client(client))) {
- printk("foo.o: Client deregistration failed, client not detached.n");
- return err;
- }
- /* SENSORS ONLY START */
- if i2c_is_isa_client(client)
- release_region(client->addr,LM78_EXTENT);
- /* SENSORS ONLY END */
- kfree(client); /* Frees client data too, if allocated at the same time */
- return 0;
- }
- Initializing the module or kernel
- =================================
- When the kernel is booted, or when your foo driver module is inserted,
- you have to do some initializing. Fortunately, just attaching (registering)
- the driver module is usually enough.
- /* Keep track of how far we got in the initialization process. If several
- things have to initialized, and we fail halfway, only those things
- have to be cleaned up! */
- static int __initdata foo_initialized = 0;
- int __init foo_init(void)
- {
- int res;
- printk("foo version %s (%s)n",FOO_VERSION,FOO_DATE);
-
- if ((res = i2c_add_driver(&foo_driver))) {
- printk("foo: Driver registration failed, module not inserted.n");
- foo_cleanup();
- return res;
- }
- foo_initialized ++;
- return 0;
- }
- int __init foo_cleanup(void)
- {
- int res;
- if (foo_initialized == 1) {
- if ((res = i2c_del_driver(&foo_driver))) {
- printk("foo: Driver registration failed, module not removed.n");
- return res;
- }
- foo_initialized --;
- }
- return 0;
- }
- #ifdef MODULE
- /* Substitute your own name and email address */
- MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl>"
- MODULE_DESCRIPTION("Driver for Barf Inc. Foo I2C devices");
- int init_module(void)
- {
- return foo_init();
- }
- int cleanup_module(void)
- {
- return foo_cleanup();
- }
- #endif /* def MODULE */
- Note that some functions are marked by `__init', and some data structures
- by `__init_data'. If this driver is compiled as part of the kernel (instead
- of as a module), those functions and structures can be removed after
- kernel booting is completed.
- Command function
- ================
- A generic ioctl-like function call back is supported. You will seldom
- need this. You may even set it to NULL.
- /* No commands defined */
- int foo_command(struct i2c_client *client, unsigned int cmd, void *arg)
- {
- return 0;
- }
- Sending and receiving
- =====================
- If you want to communicate with your device, there are several functions
- to do this. You can find all of them in i2c.h.
- If you can choose between plain i2c communication and SMBus level
- communication, please use the last. All adapters understand SMBus level
- commands, but only some of them understand plain i2c!
- Plain i2c communication
- -----------------------
- extern int i2c_master_send(struct i2c_client *,const char* ,int);
- extern int i2c_master_recv(struct i2c_client *,char* ,int);
- These routines read and write some bytes from/to a client. The client
- contains the i2c address, so you do not have to include it. The second
- parameter contains the bytes the read/write, the third the length of the
- buffer. Returned is the actual number of bytes read/written.
-
- extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
- int num);
- This sends a series of messages. Each message can be a read or write,
- and they can be mixed in any way. The transactions are combined: no
- stop bit is sent between transaction. The i2c_msg structure contains
- for each message the client address, the number of bytes of the message
- and the message data itself.
- You can read the file `i2c-protocol' for more information about the
- actual i2c protocol.
- SMBus communication
- -------------------
- extern s32 i2c_smbus_xfer (struct i2c_adapter * adapter, u16 addr,
- unsigned short flags,
- char read_write, u8 command, int size,
- union i2c_smbus_data * data);
- This is the generic SMBus function. All functions below are implemented
- in terms of it. Never use this function directly!
- extern s32 i2c_smbus_write_quick(struct i2c_client * client, u8 value);
- extern s32 i2c_smbus_read_byte(struct i2c_client * client);
- extern s32 i2c_smbus_write_byte(struct i2c_client * client, u8 value);
- extern s32 i2c_smbus_read_byte_data(struct i2c_client * client, u8 command);
- extern s32 i2c_smbus_write_byte_data(struct i2c_client * client,
- u8 command, u8 value);
- extern s32 i2c_smbus_read_word_data(struct i2c_client * client, u8 command);
- extern s32 i2c_smbus_write_word_data(struct i2c_client * client,
- u8 command, u16 value);
- extern s32 i2c_smbus_process_call(struct i2c_client * client,
- u8 command, u16 value);
- extern s32 i2c_smbus_read_block_data(struct i2c_client * client,
- u8 command, u8 *values);
- extern s32 i2c_smbus_write_block_data(struct i2c_client * client,
- u8 command, u8 length,
- u8 *values);
- All these transactions return -1 on failure. The 'write' transactions
- return 0 on success; the 'read' transactions return the read value, except
- for read_block, which returns the number of values read. The block buffers
- need not be longer than 32 bytes.
- You can read the file `smbus-protocol' for more information about the
- actual SMBus protocol.
- General purpose routines
- ========================
- Below all general purpose routines are listed, that were not mentioned
- before.
- /* This call returns a unique low identifier for each registered adapter,
- * or -1 if the adapter was not registered.
- */
- extern int i2c_adapter_id(struct i2c_adapter *adap);
- The sensors sysctl/proc interface
- =================================
- This section only applies if you write `sensors' drivers.
- Each sensors driver creates a directory in /proc/sys/dev/sensors for each
- registered client. The directory is called something like foo-i2c-4-65.
- The sensors module helps you to do this as easily as possible.
- The template
- ------------
- You will need to define a ctl_table template. This template will automatically
- be copied to a newly allocated structure and filled in where necessary when
- you call sensors_register_entry.
- First, I will give an example definition.
- static ctl_table foo_dir_table_template[] = {
- { FOO_SYSCTL_FUNC1, "func1", NULL, 0, 0644, NULL, &i2c_proc_real,
- &i2c_sysctl_real,NULL,&foo_func },
- { FOO_SYSCTL_FUNC2, "func2", NULL, 0, 0644, NULL, &i2c_proc_real,
- &i2c_sysctl_real,NULL,&foo_func },
- { FOO_SYSCTL_DATA, "data", NULL, 0, 0644, NULL, &i2c_proc_real,
- &i2c_sysctl_real,NULL,&foo_data },
- { 0 }
- };
- In the above example, three entries are defined. They can either be
- accessed through the /proc interface, in the /proc/sys/dev/sensors/*
- directories, as files named func1, func2 and data, or alternatively
- through the sysctl interface, in the appropriate table, with identifiers
- FOO_SYSCTL_FUNC1, FOO_SYSCTL_FUNC2 and FOO_SYSCTL_DATA.
- The third, sixth and ninth parameters should always be NULL, and the
- fourth should always be 0. The fifth is the mode of the /proc file;
- 0644 is safe, as the file will be owned by root:root.
- The seventh and eighth parameters should be &i2c_proc_real and
- &i2c_sysctl_real if you want to export lists of reals (scaled
- integers). You can also use your own function for them, as usual.
- Finally, the last parameter is the call-back to gather the data
- (see below) if you use the *_proc_real functions.
- Gathering the data
- ------------------
- The call back functions (foo_func and foo_data in the above example)
- can be called in several ways; the operation parameter determines
- what should be done:
- * If operation == SENSORS_PROC_REAL_INFO, you must return the
- magnitude (scaling) in nrels_mag;
- * If operation == SENSORS_PROC_REAL_READ, you must read information
- from the chip and return it in results. The number of integers
- to display should be put in nrels_mag;
- * If operation == SENSORS_PROC_REAL_WRITE, you must write the
- supplied information to the chip. nrels_mag will contain the number
- of integers, results the integers themselves.
- The *_proc_real functions will display the elements as reals for the
- /proc interface. If you set the magnitude to 2, and supply 345 for
- SENSORS_PROC_REAL_READ, it would display 3.45; and if the user would
- write 45.6 to the /proc file, it would be returned as 4560 for
- SENSORS_PROC_REAL_WRITE. A magnitude may even be negative!
- An example function:
- /* FOO_FROM_REG and FOO_TO_REG translate between scaled values and
- register values. Note the use of the read cache. */
- void foo_in(struct i2c_client *client, int operation, int ctl_name,
- int *nrels_mag, long *results)
- {
- struct foo_data *data = client->data;
- int nr = ctl_name - FOO_SYSCTL_FUNC1; /* reduce to 0 upwards */
-
- if (operation == SENSORS_PROC_REAL_INFO)
- *nrels_mag = 2;
- else if (operation == SENSORS_PROC_REAL_READ) {
- /* Update the readings cache (if necessary) */
- foo_update_client(client);
- /* Get the readings from the cache */
- results[0] = FOO_FROM_REG(data->foo_func_base[nr]);
- results[1] = FOO_FROM_REG(data->foo_func_more[nr]);
- results[2] = FOO_FROM_REG(data->foo_func_readonly[nr]);
- *nrels_mag = 2;
- } else if (operation == SENSORS_PROC_REAL_WRITE) {
- if (*nrels_mag >= 1) {
- /* Update the cache */
- data->foo_base[nr] = FOO_TO_REG(results[0]);
- /* Update the chip */
- foo_write_value(client,FOO_REG_FUNC_BASE(nr),data->foo_base[nr]);
- }
- if (*nrels_mag >= 2) {
- /* Update the cache */
- data->foo_more[nr] = FOO_TO_REG(results[1]);
- /* Update the chip */
- foo_write_value(client,FOO_REG_FUNC_MORE(nr),data->foo_more[nr]);
- }
- }
- }