📄 writing-clients
字号:
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. /* 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%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 */ 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 beremoved. It may actually fail, but only when panicking. This code ismuch 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; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -