⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 writing-clients

📁 linux 内核源代码
💻
📖 第 1 页 / 共 2 页
字号:
This is a small guide for those who want to write kernel drivers for I2Cor SMBus devices, using Linux as the protocol host/master (not slave).To set up a driver, you need to do several things. Some are optional, andsome things can be done slightly or completely different. Use this as aguide, not as a rule book!General remarks===============Try to keep the kernel namespace as clean as possible. The best way todo 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 doit for non-exported symbols too. We will use the prefix `foo_' in thistutorial, and `FOO_' for preprocessor variables.The driver structure====================Usually, you will implement a single driver structure, and instantiateall clients from it. Remember, a driver structure contains general access routines, and should be zero-initialized except for fields with data youprovide.  A client structure holds device-specific information like thedriver model device node, and its I2C address.static struct i2c_driver foo_driver = {	.driver = {		.name	= "foo",	},	/* iff driver uses driver model ("new style") binding model: */	.probe		= foo_probe,	.remove		= foo_remove,	/* else, driver uses "legacy" binding model: */	.attach_adapter	= foo_attach_adapter,	.detach_client	= foo_detach_client,	/* these may be used regardless of the driver binding model */	.shutdown	= foo_shutdown,	/* optional */	.suspend	= foo_suspend,	/* optional */	.resume		= foo_resume,	/* optional */	.command	= foo_command,	/* optional */} The name field is the driver name, and must not contain spaces.  Itshould match the module name (if the driver can be compiled as a module),although you can use MODULE_ALIAS (passing "foo" in this example) to addanother name for the module.  If the driver name doesn't match the modulename, the module won't be automatically loaded (hotplug/coldplug).All other fields are for call-back functions which will be explained below.Extra client data=================Each client structure has a special `data' field that can point to anystructure at all.  You should use this to keep device-specific data,especially in drivers that handle multiple I2C or SMBUS devices.  Youdo not always need this, but especially for `sensors' drivers, it canbe very useful.	/* store the value */	void i2c_set_clientdata(struct i2c_client *client, void *data);	/* retrieve the value */	void *i2c_get_clientdata(struct i2c_client *client);An example structure is below.  struct foo_data {    struct i2c_client client;    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 mutex 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 needto gather information from the client, or write new information to theclient. 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 forsome 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 easilybe encapsulated.The below functions are simple examples, and should not be copiedliterally.  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);  }Probing and attaching=====================The Linux I2C stack was originally written to support access to hardwaremonitoring chips on PC motherboards, and thus it embeds some assumptionsthat are more appropriate to SMBus (and PCs) than to I2C.  One of theseassumptions is that most adapters and devices drivers support the SMBUS_QUICKprotocol to probe device presence.  Another is that devices and their driverscan be sufficiently configured using only such probe primitives.As Linux and its I2C stack became more widely used in embedded systemsand complex components such as DVB adapters, those assumptions became moreproblematic.  Drivers for I2C devices that issue interrupts need more (anddifferent) configuration information, as do drivers handling chip variantsthat can't be distinguished by protocol probing, or which need some boardspecific information to operate correctly.Accordingly, the I2C stack now has two models for associating I2C deviceswith their drivers:  the original "legacy" model, and a newer one that'sfully compatible with the Linux 2.6 driver model.  These models do not mix,since the "legacy" model requires drivers to create "i2c_client" deviceobjects after SMBus style probing, while the Linux driver model expectsdrivers to be given such device objects in their probe() routines.Standard Driver Model Binding ("New Style")-------------------------------------------System infrastructure, typically board-specific initialization code orboot firmware, reports what I2C devices exist.  For example, there may bea table, in the kernel or from the boot loader, identifying I2C devicesand linking them to board-specific configuration information about IRQsand other wiring artifacts, chip type, and so on.  That could be used tocreate i2c_client objects for each I2C device.I2C device drivers using this binding model work just like any otherkind of driver in Linux:  they provide a probe() method to bind tothose devices, and a remove() method to unbind.	static int foo_probe(struct i2c_client *client);	static int foo_remove(struct i2c_client *client);Remember that the i2c_driver does not create those client handles.  Thehandle may be used during foo_probe().  If foo_probe() reports success(zero not a negative status code) it may save the handle and use it untilfoo_remove() returns.  That binding model is used by most Linux drivers.Drivers match devices when i2c_client.driver_name and the driver name arethe same; this approach is used in several other busses that don't havedevice typing support in the hardware.  The driver and module name shouldmatch, so hotplug/coldplug mechanisms will modprobe the driver.Device Creation (Standard driver model)---------------------------------------If you know for a fact that an I2C device is connected to a given I2C bus,you can instantiate that device by simply filling an i2c_board_infostructure with the device address and driver name, and callingi2c_new_device().  This will create the device, then the driver core willtake care of finding the right driver and will call its probe() method.If a driver supports different device types, you can specify the type youwant using the type field.  You can also specify an IRQ and platform dataif needed.Sometimes you know that a device is connected to a given I2C bus, but youdon't know the exact address it uses.  This happens on TV adapters forexample, where the same driver supports dozens of slightly differentmodels, and I2C device addresses change from one model to the next.  Inthat case, you can use the i2c_new_probed_device() variant, which issimilar to i2c_new_device(), except that it takes an additional list ofpossible I2C addresses to probe.  A device is created for the firstresponsive address in the list.  If you expect more than one device to bepresent in the address range, simply call i2c_new_probed_device() thatmany times.The call to i2c_new_device() or i2c_new_probed_device() typically happensin the I2C bus driver. You may want to save the returned i2c_clientreference for later use.Device Deletion (Standard driver model)---------------------------------------Each I2C device which has been created using i2c_new_device() ori2c_new_probed_device() can be unregistered by callingi2c_unregister_device().  If you don't call it explicitly, it will becalled automatically before the underlying I2C bus itself is removed, as adevice can't survive its parent in the device driver model.Legacy Driver Binding Model---------------------------Most i2c devices can be present on several i2c addresses; for some thisis determined in hardware (by soldering some chip pins to Vcc or Ground),for others this can be changed in software (by writing to specific clientregisters). Some devices are usually on a specific address, but not always;and some are even more tricky. So you will probably need to scan severali2c addresses for your clients, and do some sort of detection to seewhether it is actually a device supported by your driver.To give the user a maximum of possibilities, some default module parametersare defined to help determine what addresses are scanned. Several macrosare defined in i2c.h to help you support them, as well as a genericdetection algorithm.You do not have to use this parameter interface; but don't try to usefunction i2c_probe() if you don't.Probing classes (Legacy model)------------------------------All parameters are given as lists of unsigned 16-bit integers. Lists areterminated 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.   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.   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 the 'normal_i2c' list only.   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. Additionally, kind-specific force lists may optionally be defined ifthe driver supports several chip kinds. They are grouped in aNULL-terminated list of pointers named forces, those first element if thegeneric force list mentioned above. Each additional list correspond to aninsmod parameter of the form force_<kind>.Fortunately, as a module writer, you just have to define the `normal_i2c' parameter. The complete declaration could look like this:  /* Scan 0x37, and 0x48 to 0x4f */  static unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4b, 0x4c,                                         0x4d, 0x4e, 0x4f, I2C_CLIENT_END };  /* Magic definition of all other variables and things */  I2C_CLIENT_INSMOD;  /* Or, if your driver supports, say, 2 kind of devices: */  I2C_CLIENT_INSMOD_2(foo, bar);If you use the multi-kind form, an enum will be defined for you:  enum chips { any_chip, foo, bar, ... }You can then (and certainly should) use it in the driver code.Note that you *have* to call the defined variable `normal_i2c',without any prefix!Attaching to an adapter (Legacy model)--------------------------------------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);  }Remember, structure `addr_data' is defined by the macros explained above,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -