The Driver Model Core, Part I
The main i2c bus subsystem needs to be declared in the kernel and registered with the driver core. To accomplish this, the following code was added to drivers/i2c/i2c-core.c:
static int i2c_device_match(struct device *dev,
struct device_driver *drv)
{
return 1;
}
struct bus_type i2c_bus_type = {
.name = "i2c",
.match = i2c_device_match,
};
The name field says what the bus should be called, and the match field points to our match function. Right now, the match function is left alone, always returning 1 whenever the driver core wants to try to match a driver with a device. This logic will be modified at a later time.
Then, in the i2c core startup code, the i2c_bus_type is registered with a call to:
bus_register(&i2c_bus_type);
When the i2c core is shut down, a call is added to unregister this bus:
bus_unregister(&i2c_bus_type);When the above code runs, the following tree is created in sysfs:
$ tree /sys/bus/i2c/ /sys/bus/i2c/ |-- devices '-- driversWhen the i2c core is removed from the system, the above directories are removed. This is all that is needed to create the i2c bus.
An i2c bus by itself is pretty boring. Now, the i2c bus adapter drivers need to be modified to register themselves with this bus. To do this, a struct device variable is added to the struct i2c_adapter structure:
struct i2c_adapter {
.....
struct device dev;
};
A to_i2c_adapter() macro is defined as:
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)This macro is used by the i2c core to get a pointer to a real i2c_adapter structure whenever the driver core passes it a pointer to a struct device.
The struct device in the i2c_adapter is a whole variable declared within the structure, not merely a pointer. This is done so when the driver core passes a pointer to a struct device, the i2c code can use the to_i2c_adapter() macro to get a pointer to the real i2c_adapter structure.
The individual struct i2c_driver variables are declared in the different i2c bus drivers. For example, in the i2c-piix4.c driver, there is a variable called piix4_adapter of type struct i2c_driver. This variable is passed to the i2c core in the i2c_add_adapter() function, when a PIIX4 adapter is seen by the i2c-piix4 driver.
In the i2c-piix4.c driver, before i2c_add_adapter() is called, a pointer to the parent device of the PIIX4 adapter needs to be saved within the i2c_driver structure. This is done with a single line of code:
piix4_adapter.dev.parent = &dev->dev;
dev is a pointer to the struct pci_dev that is passed to the i2c-piix4 driver's PCI probe function; the PIIX4 is a PCI-based device.
To link the i2c_driver variable to the sysfs tree, the following lines of code are added to the i2c_add_adapter() function:
/* add the adapter to the driver core. * The parent pointer should already * have been set up. */ sprintf(adap->dev.bus_id, "i2c-%d", i); strcpy(adap->dev.name, "i2c controller"); device_register(&adap->dev);
With this code, when the PIIX4 device is detected by the driver, an i2c bus tree is created and linked to the controlling PCI device:
$ tree /sys/devices/pci0/00:07.3/i2c-0 /sys/devices/pci0/00:07.3/i2c-0 |-- name `-- powerWhen the i2c-piix4 driver is unloaded, the i2c_del_adapter() function is called. The following line of code is added to clean up the i2c bus device:
/* clean up the sysfs representation */ device_unregister(&adap->dev);
The i2c bus has a number of different drivers that control access to a wide range of i2c devices that live on the i2c bus. These drivers are declared with a struct i2c_driver structure. Within this structure, a struct device_driver variable is added to allow these drivers to be registered with the driver core:
struct i2c_driver {
.....
struct device_driver driver;
};
And, a to_i2c_driver() macro is defined as:
#define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)An i2c driver registers itself with the i2c core in a call to i2c_add_driver(). To add driver core support for i2c drivers, the following lines of code are added to this function:
/* add the driver to the list of
*i2c drivers in the driver core */
driver->driver.name = driver->name;
driver->driver.bus = &i2c_bus_type;
driver->driver.probe = i2c_device_probe;
driver->driver.remove = i2c_device_remove;
retval = driver_register(&driver->driver);
if (retval)
return retval;
This sets up the driver core structure to have the same name as the
driver and a bus type of i2c_bus_type; the probe and remove
functions are set to local i2c functions. For now, these functions
are declared as:
int i2c_device_probe(struct device *dev)
{
return -ENODEV;
}
int i2c_device_remove(struct device *dev)
{
return 0;
}
because no i2c device support has been added yet. These functions
will be called when an i2c device is added or removed from the
driver core, but that will be described in the next column.
When the i2c_add_driver() is called, the driver is registered with the i2c_bus_type, and it shows up in sysfs as:
$ tree /sys/bus/i2c/
/sys/bus/i2c/
|-- devices
`-- drivers
|-- EEPROM READER
`-- W83781D sensors
To remove an i2c driver from the system, the i2c_del_driver() function is called. In order to remove the i2c driver from the driver core that was registered with the call to driver_register, the following line of code is added to this function:
driver_unregister(&driver->driver);
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Sponsored by AMD
Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6
Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.
Learn more about catching the bad guy in this free white paper.
Sponsored by DLT Solutions
| Designing Electronics with Linux | May 22, 2013 |
| Dynamic DNS—an Object Lesson in Problem Solving | May 21, 2013 |
| Using Salt Stack and Vagrant for Drupal Development | May 20, 2013 |
| Making Linux and Android Get Along (It's Not as Hard as It Sounds) | May 16, 2013 |
| Drupal Is a Framework: Why Everyone Needs to Understand This | May 15, 2013 |
| Home, My Backup Data Center | May 13, 2013 |
- RSS Feeds
- Dynamic DNS—an Object Lesson in Problem Solving
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Designing Electronics with Linux
- Using Salt Stack and Vagrant for Drupal Development
- New Products
- A Topic for Discussion - Open Source Feature-Richness?
- Drupal Is a Framework: Why Everyone Needs to Understand This
- Validate an E-Mail Address with PHP, the Right Way
- What's the tweeting protocol?




8 hours 31 min ago
12 hours 58 min ago
16 hours 34 min ago
17 hours 6 min ago
19 hours 30 min ago
19 hours 33 min ago
19 hours 34 min ago
23 hours 59 min ago
1 day 1 hour ago
1 day 7 hours ago