I2C (Inter-Integrated Circuit) driver

This example is a driver for an I2C bus controller. The I2C bus is simply a 2-wire bus, and the hardware is extremely cheap to implement. The bus supports up to 127 devices on the bus, and each device can handle 256 commands. When devices want to read or write information to or from another device, they must first be set up as a master to own the bus. Then the device sends out the device address and command register number. The slave then acts upon the command received.

You think a resource manager wouldn't apply in this case. All read() and write() operations require a device address and command register. You could use devctl(), but a resource manager again provides a cleaner interface.

With a resource manager, each device would live under its own directory, and each register would have a filename:


An important thing to note is that each filename (127 devices * 256 registers = 32512 filenames) doesn't really need to exist. Each device would be created live, as it's required. Therefore, each open() is actually an O_CREAT.

To prevent any problems caused by a high number of possibly existing files, you could make an ls command of the /dev/i2c1 directory return nothing. Alternatively, you could make ls list the filenames that have been opened at least once. At this point, it's important to clarify that the existence of the filenames is totally handled by the resource manager; the OS itself isn't used in that process. So it isn't a problem if filenames respond to open() requests, but not to ls.

One element is left to solve: the I2C bus has a concept of a baud rate. There are already C functions to set up baud rates, and you can make it work via the stty command from the shell.

People using the driver don't have to worry about libraries or include files because there are none. The resource manager, at no cost, allows each command register to be accessed via the shell, or for that matter, though SAMBA from a Linux or Windows machine. Access via the shell makes debugging so easy—there's no need to write custom test tools, and it's unbelievably flexible, not to mention the support for separate permissions for each and every command register of every device.

One more thing: this code could be clearer:

fd = open ( "/dev/i2c1/34/45" );
read( fd, &variable, sizeof( variable ) );

It would be much better to have this instead:

fd = open ( "/dev/i2c1/flash/page_number" );
read( fd, &page_number, sizeof( page_number ) );
close (fd );

Of course, you could use #define directives to show meaningful information, but an even better solution is to create a configuration file that the driver could read to create an alias. The configuration file looks like this:


The field inside the square brackets defines the device address and name. The data that follows specifies each register of that device. The main advantages to this approach are:

These predefined devices would always show via the ls command.