📄 writing-clients
字号:
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 variable `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 2you use macro SENSORS_INSMOD_2(chip1,chip2), etc. If you do not want tobother 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 isbeing registered, the callback attach_adapter() is called. Now is thetime to determine what devices are present on the adapter, and to registera client for each of them.The attach_adapter callback is really easy: we just call the genericdetection function. This function will scan the bus for us, using theinformation as defined in the lists explained above. If a device isdetected 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_clientfunction only for those i2c addresses that actually have a device onthem (unless a `force' parameter was used). In addition, addresses thatare 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 -1 otherwise (for i2c_detect, it contains 0 ifthis call is due to the generic `force' parameter, and the chip typenumber if it is due to a specific `force' parameter).Below, some things are only needed if this is a `sensors' driver. Thoseparts are between /* SENSORS ONLY START */ and /* SENSORS ONLY END */markers. This function should only return an error (any value != 0) if there issome reason why no more detection should be done anymore. If thedetection just fails for this address, return 0.For now, you can ignore the `flags' parameter. It is there for future use. 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 */ if (!(data = kzalloc(sizeof(struct foo_data), GFP_KERNEL))) { err = -ENOMEM; goto ERROR0; } new_client = &data->client; 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%02x\n",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 */ 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(data); ERROR0: return err; }Removing the client===================The detach_client call back function is called when a client should beremoved. It may actually fail, but only when panicking. This code ismuch simpler than the attachment code, fortunately!
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -