Monday, 1 December 2014

I2C devices on BBB

Enable the I2C devices on the BeagleBone Black

On the BeagleBone Black, it's not all of the /dev/i2c-* devices that are enabled by default. The other i2c devices must be enabled before they can be used.

To enable the I2c-1 on the BeagleBone Black Rev A, B and C:
  1. Rev A/B: Open the file /media/BEAGLEBONE/uEnv.txt in an editor (vim/nano)
  2. Rec C: Open the file /boot/uboot/uEnv.txt in an editor (vim/nano)
  3. Add the key "capemgr.enable_partno="
  4. Add the ports you want to enable, comma separated (BB-I2C0, BB-I2C1, etc)
  5. Reboot
An example line looks like this:

root@beaglebone:/dev# cat /media/BEAGLEBONE/uEnv.txt
optargs=quiet drm.debug=7 capemgr.enable_partno=BB-I2C1


After reboot, the device is present in the device list:
root@beaglebone:/dev# ls -l /dev/i2c*
crw-rw---- 1 root tty     249, 0 Jan  1 01:18 /dev/ttyO0
crw-rw---- 1 root dialout 249, 4 Jan  1 01:18 /dev/ttyO4

Note: The I2C devices do not map one-to-one with the devices in /dev/. I.e. I2C-1 does not necessarily map to /dev/i2c-1, it could just as well be one of the other devs, e.g. /dev/i2c-2.

Testing the I2C devices


You can use the standard Linux i2c tools to test your i2c setup:

List all the enabled devices:
root@beaglebone:/dev# i2cdetect -l
i2c-0   i2c             OMAP I2C adapter                        I2C adapter
i2c-1   i2c             OMAP I2C adapter                        I2C adapter
Scan all addresses on one device:
root@beaglebone:/dev# i2cdetect -r 0
WARNING! This program can confuse your I2C bus, cause data loss and worse!
I will probe file /dev/i2c-0 using read byte commands.
I will probe address range 0x03-0x77.
Continue? [Y/n] Y
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: UU -- -- -- -- -- -- --
Write one byte to a device and an address:

i2cset -y 2 0x77 0xf4 0x34

Read one byte from a device and an address:

i2cdump -y 2 0x77


JavaScript / Node.js

In JavaScript / Node.js you can use the package "i2c" or the latest version of "bonescript" that includes the same package.
 - npm install i2c
 - npm install bonescript

I've had some problems with crashes in the i2c module (segmentation faults).

If you just need to read and write single bytes, you can also do this using normal file system (open /dev/i2c-1 for read+write) and set the device address using the "ioctl" module:
 - npm install ioctl

The code sequence:
1. Open /dev/i2c-1 for read+write
2. Use ioctl to set slave address: ioctl(fileHandle, I2C_SLAVE, address)

(I2C_SLAVE = 0x0703 )
Reference: 
http://beaglebone.cameon.net/home/i2c-devices






Documentation of I2c on 

Usually, i2c devices are controlled by a kernel driver. But it is also
possible to access all devices on an adapter from userspace, through
the /dev interface. You need to load module i2c-dev for this.

Each registered i2c adapter gets a number, counting from 0. You can
examine /sys/class/i2c-dev/ to see what number corresponds to which adapter.
Alternatively, you can run "i2cdetect -l" to obtain a formated list of all
i2c adapters present on your system at a given time. i2cdetect is part of
the i2c-tools package.

I2C device files are character device files with major device number 89
and a minor device number corresponding to the number assigned as 
explained above. They should be called "i2c-%d" (i2c-0, i2c-1, ..., 
i2c-10, ...). All 256 minor device numbers are reserved for i2c.


C example
=========

So let's say you want to access an i2c adapter from a C program. The
first thing to do is "#include <linux/i2c-dev.h>". Please note that
there are two files named "i2c-dev.h" out there, one is distributed
with the Linux kernel and is meant to be included from kernel
driver code, the other one is distributed with i2c-tools and is
meant to be included from user-space programs. You obviously want
the second one here.

Now, you have to decide which adapter you want to access. You should
inspect /sys/class/i2c-dev/ or run "i2cdetect -l" to decide this.
Adapter numbers are assigned somewhat dynamically, so you can not
assume much about them. They can even change from one boot to the next.

Next thing, open the device file, as follows:

  int file;
  int adapter_nr = 2; /* probably dynamically determined */
  char filename[20];
  
  snprintf(filename, 19, "/dev/i2c-%d", adapter_nr);
  file = open(filename, O_RDWR);
  if (file < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

When you have opened the device, you must specify with what device
address you want to communicate:

  int addr = 0x40; /* The I2C address */

  if (ioctl(file, I2C_SLAVE, addr) < 0) {
    /* ERROR HANDLING; you can check errno to see what went wrong */
    exit(1);
  }

Well, you are all set up now. You can now use SMBus commands or plain
I2C to communicate with your device. SMBus commands are preferred if
the device supports them. Both are illustrated below.

  __u8 reg = 0x10; /* Device register to access */
  __s32 res;
  char buf[10];

  /* Using SMBus commands */
  res = i2c_smbus_read_word_data(file, reg);
  if (res < 0) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* res contains the read word */
  }

  /* Using I2C Write, equivalent of 
     i2c_smbus_write_word_data(file, reg, 0x6543) */
  buf[0] = reg;
  buf[1] = 0x43;
  buf[2] = 0x65;
  if (write(file, buf, 3) != 3) {
    /* ERROR HANDLING: i2c transaction failed */
  }

  /* Using I2C Read, equivalent of i2c_smbus_read_byte(file) */
  if (read(file, buf, 1) != 1) {
    /* ERROR HANDLING: i2c transaction failed */
  } else {
    /* buf[0] contains the read byte */
  }

Note that only a subset of the I2C and SMBus protocols can be achieved by
the means of read() and write() calls. In particular, so-called combined
transactions (mixing read and write messages in the same transaction)
aren't supported. For this reason, this interface is almost never used by
user-space programs.

IMPORTANT: because of the use of inline functions, you *have* to use
'-O' or some variation when you compile your program!


Full interface description
==========================

The following IOCTLs are defined:

ioctl(file, I2C_SLAVE, long addr)
  Change slave address. The address is passed in the 7 lower bits of the
  argument (except for 10 bit addresses, passed in the 10 lower bits in this
  case).

ioctl(file, I2C_TENBIT, long select)
  Selects ten bit addresses if select not equals 0, selects normal 7 bit
  addresses if select equals 0. Default 0.  This request is only valid
  if the adapter has I2C_FUNC_10BIT_ADDR.

ioctl(file, I2C_PEC, long select)
  Selects SMBus PEC (packet error checking) generation and verification
  if select not equals 0, disables if select equals 0. Default 0.
  Used only for SMBus transactions.  This request only has an effect if the
  the adapter has I2C_FUNC_SMBUS_PEC; it is still safe if not, it just
  doesn't have any effect.

ioctl(file, I2C_FUNCS, unsigned long *funcs)
  Gets the adapter functionality and puts it in *funcs.

ioctl(file, I2C_RDWR, struct i2c_rdwr_ioctl_data *msgset)
  Do combined read/write transaction without stop in between.
  Only valid if the adapter has I2C_FUNC_I2C.  The argument is
  a pointer to a

  struct i2c_rdwr_ioctl_data {
      struct i2c_msg *msgs;  /* ptr to array of simple messages */
      int nmsgs;             /* number of messages to exchange */
  }

  The msgs[] themselves contain further pointers into data buffers.
  The function will write or read data to or from that buffers depending
  on whether the I2C_M_RD flag is set in a particular message or not.
  The slave address and whether to use ten bit address mode has to be
  set in each message, overriding the values set with the above ioctl's.

ioctl(file, I2C_SMBUS, struct i2c_smbus_ioctl_data *args)
  Not meant to be called  directly; instead, use the access functions
  below.

You can do plain i2c transactions by using read(2) and write(2) calls.
You do not need to pass the address byte; instead, set it through
ioctl I2C_SLAVE before you try to access the device.

You can do SMBus level transactions (see documentation file smbus-protocol 
for details) through the following functions:
  __s32 i2c_smbus_write_quick(int file, __u8 value);
  __s32 i2c_smbus_read_byte(int file);
  __s32 i2c_smbus_write_byte(int file, __u8 value);
  __s32 i2c_smbus_read_byte_data(int file, __u8 command);
  __s32 i2c_smbus_write_byte_data(int file, __u8 command, __u8 value);
  __s32 i2c_smbus_read_word_data(int file, __u8 command);
  __s32 i2c_smbus_write_word_data(int file, __u8 command, __u16 value);
  __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value);
  __s32 i2c_smbus_read_block_data(int file, __u8 command, __u8 *values);
  __s32 i2c_smbus_write_block_data(int file, __u8 command, __u8 length, 
                                   __u8 *values);
All these transactions return -1 on failure; you can read errno to see
what happened. The 'write' transactions return 0 on success; the
'read' transactions return the read value, except for read_block, which
returns the number of values read. The block buffers need not be longer
than 32 bytes.

The above functions are all inline functions, that resolve to calls to
the i2c_smbus_access function, that on its turn calls a specific ioctl
with the data in a specific format. Read the source code if you
want to know what happens behind the screens.


Implementation details
======================

For the interested, here's the code flow which happens inside the kernel
when you use the /dev interface to I2C:

1* Your program opens /dev/i2c-N and calls ioctl() on it, as described in
section "C example" above.

2* These open() and ioctl() calls are handled by the i2c-dev kernel
driver: see i2c-dev.c:i2cdev_open() and i2c-dev.c:i2cdev_ioctl(),
respectively. You can think of i2c-dev as a generic I2C chip driver
that can be programmed from user-space.

3* Some ioctl() calls are for administrative tasks and are handled by
i2c-dev directly. Examples include I2C_SLAVE (set the address of the
device you want to access) and I2C_PEC (enable or disable SMBus error
checking on future transactions.)

4* Other ioctl() calls are converted to in-kernel function calls by
i2c-dev. Examples include I2C_FUNCS, which queries the I2C adapter
functionality using i2c.h:i2c_get_functionality(), and I2C_SMBUS, which
performs an SMBus transaction using i2c-core.c:i2c_smbus_xfer().

The i2c-dev driver is responsible for checking all the parameters that
come from user-space for validity. After this point, there is no
difference between these calls that came from user-space through i2c-dev
and calls that would have been performed by kernel I2C chip drivers
directly. This means that I2C bus drivers don't need to implement
anything special to support access from user-space.

5* These i2c-core.c/i2c.h functions are wrappers to the actual
implementation of your I2C bus driver. Each adapter must declare
callback functions implementing these standard calls.
i2c.h:i2c_get_functionality() calls i2c_adapter.algo->functionality(),
while i2c-core.c:i2c_smbus_xfer() calls either
adapter.algo->smbus_xfer() if it is implemented, or if not,
i2c-core.c:i2c_smbus_xfer_emulated() which in turn calls
i2c_adapter.algo->master_xfer().

After your I2C bus driver has processed these requests, execution runs
up the call chain, with almost no processing done, except by i2c-dev to
package the returned data, if any, in suitable format for the ioctl.
 
 
 
EEPROM I2C 
 
/*
  2     Copyright (C) 1998, 1999  Frodo Looijaard <frodol@dds.nl> and
  3                                Philip Edelbrock <phil@netroedge.com>
  4     Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
  5     Copyright (C) 2003 IBM Corp.
  6     Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
  7 
  8     This program is free software; you can redistribute it and/or modify
  9     it under the terms of the GNU General Public License as published by
 10     the Free Software Foundation; either version 2 of the License, or
 11     (at your option) any later version.
 12 
 13     This program is distributed in the hope that it will be useful,
 14     but WITHOUT ANY WARRANTY; without even the implied warranty of
 15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 16     GNU General Public License for more details.
 17 
 18     You should have received a copy of the GNU General Public License
 19     along with this program; if not, write to the Free Software
 20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 21 */
 22 
 23 #include <linux/kernel.h>
 24 #include <linux/init.h>
 25 #include <linux/module.h>
 26 #include <linux/slab.h>
 27 #include <linux/jiffies.h>
 28 #include <linux/i2c.h>
 29 #include <linux/mutex.h>
 30 
 31 /* Addresses to scan */
 32 static const unsigned short normal_i2c[] = { 0x50, 0x51, 0x52, 0x53, 0x54,
 33                                         0x55, 0x56, 0x57, I2C_CLIENT_END };
 34 
 35 /* Insmod parameters */
 36 I2C_CLIENT_INSMOD_1(eeprom);
 37 
 38 
 39 /* Size of EEPROM in bytes */
 40 #define EEPROM_SIZE             256
 41 
 42 /* possible types of eeprom devices */
 43 enum eeprom_nature {
 44         UNKNOWN,
 45         VAIO,
 46 };
 47 
 48 /* Each client has this additional data */
 49 struct eeprom_data {
 50         struct mutex update_lock;
 51         u8 valid;                       /* bitfield, bit!=0 if slice is valid */
 52         unsigned long last_updated[8];  /* In jiffies, 8 slices */
 53         u8 data[EEPROM_SIZE];           /* Register values */
 54         enum eeprom_nature nature;
 55 };
 56 
 57 
 58 static void eeprom_update_client(struct i2c_client *client, u8 slice)
 59 {
 60         struct eeprom_data *data = i2c_get_clientdata(client);
 61         int i;
 62 
 63         mutex_lock(&data->update_lock);
 64 
 65         if (!(data->valid & (1 << slice)) ||
 66             time_after(jiffies, data->last_updated[slice] + 300 * HZ)) {
 67                 dev_dbg(&client->dev, "Starting eeprom update, slice %u\n", slice);
 68 
 69                 if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
 70                         for (i = slice << 5; i < (slice + 1) << 5; i += 32)
 71                                 if (i2c_smbus_read_i2c_block_data(client, i,
 72                                                         32, data->data + i)
 73                                                         != 32)
 74                                         goto exit;
 75                 } else {
 76                         for (i = slice << 5; i < (slice + 1) << 5; i += 2) {
 77                                 int word = i2c_smbus_read_word_data(client, i);
 78                                 if (word < 0)
 79                                         goto exit;
 80                                 data->data[i] = word & 0xff;
 81                                 data->data[i + 1] = word >> 8;
 82                         }
 83                 }
 84                 data->last_updated[slice] = jiffies;
 85                 data->valid |= (1 << slice);
 86         }
 87 exit:
 88         mutex_unlock(&data->update_lock);
 89 }
 90 
 91 static ssize_t eeprom_read(struct kobject *kobj, struct bin_attribute *bin_attr,
 92                            char *buf, loff_t off, size_t count)
 93 {
 94         struct i2c_client *client = to_i2c_client(container_of(kobj, struct device, kobj));
 95         struct eeprom_data *data = i2c_get_clientdata(client);
 96         u8 slice;
 97 
 98         if (off > EEPROM_SIZE)
 99                 return 0;
100         if (off + count > EEPROM_SIZE)
101                 count = EEPROM_SIZE - off;
102 
103         /* Only refresh slices which contain requested bytes */
104         for (slice = off >> 5; slice <= (off + count - 1) >> 5; slice++)
105                 eeprom_update_client(client, slice);
106 
107         /* Hide Vaio private settings to regular users:
108            - BIOS passwords: bytes 0x00 to 0x0f
109            - UUID: bytes 0x10 to 0x1f
110            - Serial number: 0xc0 to 0xdf */
111         if (data->nature == VAIO && !capable(CAP_SYS_ADMIN)) {
112                 int i;
113 
114                 for (i = 0; i < count; i++) {
115                         if ((off + i <= 0x1f) ||
116                             (off + i >= 0xc0 && off + i <= 0xdf))
117                                 buf[i] = 0;
118                         else
119                                 buf[i] = data->data[off + i];
120                 }
121         } else {
122                 memcpy(buf, &data->data[off], count);
123         }
124 
125         return count;
126 }
127 
128 static struct bin_attribute eeprom_attr = {
129         .attr = {
130                 .name = "eeprom",
131                 .mode = S_IRUGO,
132         },
133         .size = EEPROM_SIZE,
134         .read = eeprom_read,
135 };
136 
137 /* Return 0 if detection is successful, -ENODEV otherwise */
138 static int eeprom_detect(struct i2c_client *client, int kind,
139                          struct i2c_board_info *info)
140 {
141         struct i2c_adapter *adapter = client->adapter;
142 
143         /* EDID EEPROMs are often 24C00 EEPROMs, which answer to all
144            addresses 0x50-0x57, but we only care about 0x50. So decline
145            attaching to addresses >= 0x51 on DDC buses */
146         if (!(adapter->class & I2C_CLASS_SPD) && client->addr >= 0x51)
147                 return -ENODEV;
148 
149         /* There are four ways we can read the EEPROM data:
150            (1) I2C block reads (faster, but unsupported by most adapters)
151            (2) Word reads (128% overhead)
152            (3) Consecutive byte reads (88% overhead, unsafe)
153            (4) Regular byte data reads (265% overhead)
154            The third and fourth methods are not implemented by this driver
155            because all known adapters support one of the first two. */
156         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)
157          && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK))
158                 return -ENODEV;
159 
160         strlcpy(info->type, "eeprom", I2C_NAME_SIZE);
161 
162         return 0;
163 }
164 
165 static int eeprom_probe(struct i2c_client *client,
166                         const struct i2c_device_id *id)
167 {
168         struct i2c_adapter *adapter = client->adapter;
169         struct eeprom_data *data;
170         int err;
171 
172         if (!(data = kzalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
173                 err = -ENOMEM;
174                 goto exit;
175         }
176 
177         memset(data->data, 0xff, EEPROM_SIZE);
178         i2c_set_clientdata(client, data);
179         mutex_init(&data->update_lock);
180         data->nature = UNKNOWN;
181 
182         /* Detect the Vaio nature of EEPROMs.
183            We use the "PCG-" or "VGN-" prefix as the signature. */
184         if (client->addr == 0x57
185          && i2c_check_functionality(adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
186                 char name[4];
187 
188                 name[0] = i2c_smbus_read_byte_data(client, 0x80);
189                 name[1] = i2c_smbus_read_byte_data(client, 0x81);
190                 name[2] = i2c_smbus_read_byte_data(client, 0x82);
191                 name[3] = i2c_smbus_read_byte_data(client, 0x83);
192 
193                 if (!memcmp(name, "PCG-", 4) || !memcmp(name, "VGN-", 4)) {
194                         dev_info(&client->dev, "Vaio EEPROM detected, "
195                                  "enabling privacy protection\n");
196                         data->nature = VAIO;
197                 }
198         }
199 
200         /* create the sysfs eeprom file */
201         err = sysfs_create_bin_file(&client->dev.kobj, &eeprom_attr);
202         if (err)
203                 goto exit_kfree;
204 
205         return 0;
206 
207 exit_kfree:
208         kfree(data);
209 exit:
210         return err;
211 }
212 
213 static int eeprom_remove(struct i2c_client *client)
214 {
215         sysfs_remove_bin_file(&client->dev.kobj, &eeprom_attr);
216         kfree(i2c_get_clientdata(client));
217 
218         return 0;
219 }
220 
221 static const struct i2c_device_id eeprom_id[] = {
222         { "eeprom", 0 },
223         { }
224 };
225 
226 static struct i2c_driver eeprom_driver = {
227         .driver = {
228                 .name   = "eeprom",
229         },
230         .probe          = eeprom_probe,
231         .remove         = eeprom_remove,
232         .id_table       = eeprom_id,
233 
234         .class          = I2C_CLASS_DDC | I2C_CLASS_SPD,
235         .detect         = eeprom_detect,
236         .address_data   = &addr_data,
237 };
238 
239 static int __init eeprom_init(void)
240 {
241         return i2c_add_driver(&eeprom_driver);
242 }
243 
244 static void __exit eeprom_exit(void)
245 {
246         i2c_del_driver(&eeprom_driver);
247 }
248 
249 
250 MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
251                 "Philip Edelbrock <phil@netroedge.com> and "
252                 "Greg Kroah-Hartman <greg@kroah.com>");
253 MODULE_DESCRIPTION("I2C EEPROM driver");
254 MODULE_LICENSE("GPL");
255 
256 module_init(eeprom_init);
257 module_exit(eeprom_exit);
258  


Saturday, 29 November 2014

Porting Embbeded OS(Part1)

In this part we would be understanding all the basics of kernel which are required
-What if you’re looking for the right place to add some custom support for your new embedded project? How do you know which files are important for your architecture?



                                                                                                                      
-There are various source of kernel available(www.kernel.org)

Top-Level Source Directory
arch/                                              kernel/                           drivers/                                       
block/                                            lib/                                  ipc/
crypto/                                          mm/                                samples/
Documentation/                          net/                                 virt/
firmware/                                      scripts/
fs/                                                  security/                                  
include/                                        sound/
init/                                                usr/


-/arch contain more than 20 unique processor architecture.
-two important build targets are found in the top-level kernel source tree after
a successful build: System.map and the kernel proper, vmlinux

Compiling the Kernel










Tuesday, 25 November 2014

Linux Device Model


Device model is one of most integral and least looked part of kernel. Since during normal kernel development, most aspects of device model are either left untouched or are taken for granted.
With this article, I have made an honest attempt to decode everything that lies beneath.
The motive is to help reader understand the philosophy and working of LDM (Linux Device Model)
The initial motivation for the device model was this final point: providing an accurate device tree to facilitate power management.

To implement device-level power management in the kernel, you need to build a tree representing the device topology in the system: for example, what drive connects to what controller, and what device connects to what bus. When powering down, the kernel must power down the lower (leaf) nodes of the tree before the higher nodes. For example, before a USB controller is powered down, all the USB peripherals connected to that controller had to be powered down.

A unified device model was added in Linux kernel to provide a single mechanism for representing devices and describing their topology in the system. Such a system provides several benefits:
  • Minimization of code duplication
  • A mechanism for providing common facilities, such as reference counting
  • Capability to determine all the devices in the system, view their status and power state, see to what bus they are attached, and which driver is responsible for them
  • The capability to generate a complete and valid tree of the entire device structure of the system, including all buses and interconnections
  • The capability to link devices to their drivers and vice versa
  • Categorize devices by their kind (“classes”), such as input device, without the need to understand the physical device topology
  • Power Management - The capability to walk the tree of devices from the leaves up to the root, powering down devices in the correct order
The device model brings with it a whole new vocabulary to describe its data structures. A quick overview of some device model terms appears below; much of this stuff will be looked at in detail later on.

device

A physical or virtual object which attaches to a (possibly virtual) bus.
driver

A software entity which may probe for and be bound to devices, and which can perform certain management functions.
bus

A device which serves as an attachment point for other devices.
class

A particular type of device which can be expected to perform in certain ways. Classes might include disks, partitions, serial ports, etc.
subsystem

A top-level view of the system's structure. Subsystems used in the kernel include devices (a hierarchical view of all devices on the system), bus (a bus-oriented view), class(devices by class), net (the networking subsystem), and others. The best way to think of a subsystem, perhaps, is as a particular view into the device model data structure rather than a physical component of the system. The same objects (devices, usually) show up in most subsystems, but they are organized differently.

The fundamental task of the device model is to maintain a set of internal data structures which reflect the architecture and state of the underlying system. The device model works by tracking system configuration changes (hardware and software) and maintaining a complex "web woven by a spider on drugs" data structure to represent it all.
In order to understand device model, it is of utmost importance to first understand the low lying structures and their relationship with each other. Interface to the sysfs virtual file system is out of scope of this article. Without going deep in the details, here is what you should know about them.

Kobjects

At the heart of the device model is the kobject, short for kernel object, which is represented
by struct kobject and defined in <linux/kobject.h>. It provides basic facilities, such as reference counting, a name, and a parent pointer, enabling the creation of a hierarchy of objects.

Even though, in most of cases, you will never have to manipulate a kobject directly, it is hard to dig very deeply into the driver model without encountering them. Kobjects are usually embedded in other structures. Some of the important fields are:
struct kobject
|-- name (string)
|-- parent (kobject’s parent)
|-- ktype ( type associated with a kobject)
|-- kset (group of kobjects all of which are embedded in structures of the same type)
|-- sd (points to a sysfs_dirent structure that represents this kobject in sysfs.)
|-- kref (provides reference counting)

It is the glue that holds much of the device model and its sysfs interface together.

For initialization and setup of kobjects, following functions exist:
        void kobject_init(struct kobject *kobj);

Kobject users must, at a minimum, set the name of the kobject; this is the name that will be used in sysfs entries
        kobject_set_name(struct kobject *kobj, "The name");

Following functions manage the reference counts of kobjects :
        struct kobject *kobject_get(struct kobject *kobj);
        void kobject_put(struct kobject *kobj);

 To create sysfs entries

    int kobject_add(struct kobject *kobj);
         void kobject_del(struct kobject *kobj);

There is a kobject_register() function, which is really just the combination of the calls to kobject_init() and kobject_add(). Similarly, kobject_unregister() will call kobject_del(), then call kobject_put() to release the initial reference created with kobject_register() (or really kobject_init()).

Ktypes

Kobjects are associated with a specific type, called a ktype, short for kernel object type.
Ktypes are represented by struct kobj_type and defined in <linux/kobject.h>

struct kobj_type
|-- release (pointer points to the deconstructor)
|-- sysfs_ops (describes the behavior of sysfs files on read and write)
|-- default_attrs (default attributes associated with this kobject)

Ktypes have the simple job of describing default behavior for a family of kobjects.

Instead of each kobject defining its own behavior, the behavior is stored in a ktype, and
kobjects of the same “type” point at the same ktype structure, thus sharing the same
behavior.

Every kobject needs to have an associated kobj_type structure and every kobject must have a release() method, and the kobject must persist (in a consistent state) until that method is called. If these constraints are not met, the code is flawed.

Ksets

Ksets, short for kernel object sets, are aggregate collections of kobjects. Ksets work as the
base container class for a set of kernel objects, collecting related kobjects, such as “all block devices,” together in a single place.

The kset pointer points at a kobject’s associated kset. ksets are represented by the kset
structure, which is declared in <linux/kobject.h>

struct kset
|-- list (linked list of all kobjects in this kset)
|-- kobj (kobject representing the base class for this set)
|-- uevent_ops (describes the hotplug behavior of kobjects in this kset)

Ksets group related kernel objects together, whereas ktypes enable kernel objects (functionally related or not) to share common operations.

The distinction is kept to allow kobjects of identical ktypes to be grouped into different ksets.

A kset serves these functions:
  • It serves as a bag containing a group of identical objects. A kset can be used by the kernel to track "all block devices" or "all PCI device drivers."
  • A kset is the directory-level glue that holds the device model (and sysfs) together. Every kset contains a kobject which can be set up to be the parent of other kobjects; in this way the device model hierarchy is constructed.
  • Ksets can support the "hotplugging" of kobjects and influence how hotplug events are reported to user space.
For initialization and setup of ksets, following functions exist:
    void kset_init(struct kset *kset);
          int kset_add(struct kset *kset);
         int kset_register(struct kset *kset);
    void kset_unregister(struct kset *kset);

Following functions manage the reference counts of ksets :

    struct kset *kset_get(struct kset *kset);
         void kset_put(struct kset *kset);

A kset, too, has a name, which is stored in the embedded kobject whose name is set by:

    kobject_set_name(my_set->kobj, "The name");

Having understood low lying structures and before we start digging inside the kernel code, let’s look at some of other important structures and functions which are building blocks of device model.

Device Model Core

Some of the important structures defined by the device model core are given below.

  • struct bus_type
  • struct device
  • struct device_driver
  • struct class
The struct bus_type is used to represent buses like PCI, USB, I2C, etc. The struct device is used to represent devices like an Intel AC97 audio controller, an Intel PRO/100 ethernet controller, a PS/2 mouse etc. The struct device_driver is used to represent kernel drivers that can handle specific devices. The struct class is used to represent a class of devices like sound, input, graphics, etc. no matter how they are connected to the system.

The device model core, among other things, defines functions to register and unregister instances of the above structures. These functions are listed below.

  • bus_register()
  • bus_unregister()
  • device_register()
  • device_unregister()
  • driver_register()
  • driver_unregister()
  • class_register()
  • class_unregister()

Generic Bus Drivers

For each bus supported by the kernel there is a generic bus driver. The generic bus driver allocates a struct bus_type and registers it with the kernel's list of bus types. The registration is done using bus_register().
The important fields of the struct bus_type structure are shown below.

struct bus_type       
|-- name (string)
|-- p (subsys_private)
     |-- klist_devices (klist)
     |-- klist_drivers (klist)
     |-- drivers_kset
     |-- devices_kset
|-- match (fp)

  • The name member provides a human readable representation of the bus type, example: platform, pci, usb etc.
  • The klist_drivers member is a list of drivers that can handle devices on that bus. This list is updated by the driver_register() which is called when a driver initializes itself.
  • The klist_devices member is a list of devices in the system that reside on this particular type of bus. This list is updated by device_register() which is called when the bus is scanned for devices by the bus controller driver (during initialization or when a gadget is hot plugged.)
  • When a new gadget is plugged into the system, the bus controller driver detects the device and calls device_register() the list of drivers associated with the bus is iterated over to find out if there are any drivers that can handle the device. The match function provided in the bus_type structure is used to check if a given driver can handle a given device.
  • When a driver module is inserted into the kernel and the driver calls driver_register(), the list of devices associated with the bus is iterated over to find out if there are any devices that the driver can handle. The match function is used for this purpose.
When a match is found, the device is associated with the device driver. The process of associating a device with a device driver is called binding.

Given below is a sample of bus_type instantiation for the platform bus, taken from drivers/base/platform.c.

struct bus_type platform_bus_type = {
          .name           = "platform",
          .dev_attrs      = platform_dev_attrs,
          .match          = platform_match,
          .uevent         = platform_uevent,
          .pm              = &platform_dev_pm_ops,
};

Apart from defining a bus_type, the generic bus driver defines a bus specific driver structure and a bus specific device structure. These structures extend the generic struct device_driver and struct device provided by the device model core, by adding bus specific members.

The generic bus driver provides helper functions to register and unregister device drivers that can handle devices on that bus. These helper functions wrap the generic functions provided by the device model core.

Bus Controller Drivers

For a specific bus type there could be many different controllers provided by different vendors. Each of these controllers needs a corresponding bus controller driver. The role of a bus controller driver in maintenance of the device model, is similar to that of any other device driver in that, it registers itself with driver_register(). But apart from registering itself, it also detects devices on the bus it is controlling and registers the devices on the bus usingdevice_register().

The bus controller driver is responsible for instantiating and registering instances of struct device with the device model core. Some of the important members of struct device are given below.

struct device
|-- init_name (string)
|-- bus (bus_type)
|-- parent (device)
|-- driver (device_driver)

  • The init_name member is a unique name for the device within a bus type.
  • The bus member is a pointer to the bus_type to which this device belongs to.
  • When a device is registered by the bus controller driver, the parent member is pointed to the bus controller device so as to build the physical device tree.
  • When a binding occurs and a driver is found that can handle the device, the driver member is pointed to the corresponding device driver.
Device Drivers

Every device driver registers itself with the bus_type using driver_register(). After which the device model core tries to bind it with a device. When a device is detected (registered) that can be handled by a particular driver, theprobe member of the driver is called to instantiate the driver for that particular device.

Each device driver is responsible for instantiating and registering an instance of struct device_driver with the device model core. The important members of struct device_driver is given below.

struct device_driver
|-- bus (bus_type)
|-- probe (fp)
|-- remove (fp)
|-- p (driver_private)

  • The bus member is a pointer to the bus_type to which the device driver is registered.
  • The probe member is a callback function which is called for each device detected that is supported by the driver. The driver should instantiate itself for each device and initialize the device as well.
  • The remove member is a callback function is called to unbind the driver from the device. This happens when the device is physically removed, when the driver is unloaded, or when the system is shutdown.
Class Drivers

Most users of a system are not bothered about how devices are connected in a system, but what type of devices are connected in the system. A class driver instantiates a struct class for the class of devices it represents and registers it with the device model core using class_register(). Each device driver is responsible for adding its device to the appropriate class.
The important members of struct class is given below.

struct class
|-- name (string)
|-- p (subsys_private)
name is the human readable name given to the instance of struct class like graphics, sound, etc.

Now it is time to see how things are being done inside kernel.


During kernel startup, driver_init() is the function call which initializes driver model. It is defined in drivers/base/init.c

This in-turn calls the driver model init functions to initialize their subsystems:
devices_init():

Defined in driver/base/core.c, this function does following initializations:

  • create a struct kset “devices_kset “ dynamically and add it to sysfs (/sys/devices) using function kset_create_and_add().
  • create a struct kobject “dev_kobj dynamically and register it with sysfs (/sys/dev) using function kobject_create_and_add()
  • creates struct kobject “sysfs_dev_block_kobj  and sysfs_dev_char_kobj dynamically with parent as “dev_kobj” and register it with sysfs (/sys/dev/block, /sys/dev/char respectively) using function kobject_create_and_add()

Important point to note here is while creating sysfs_dev_block_kobj  and sysfs_dev_char_kobj kobjects, parent kobject used is “dev_kobj” and thus, sysfs entries are created within “/sys/dev”.

buses_init():

Defined in driver/base/bus.c, this function does following initializations:
  • create a struct kset “bus_kset dynamically and register it with sysfs (/sys/bus) using function kset_create_and_add()
  • create a struct kset “system_kset dynamically with parent as “devices_kset->kobj” and register it with sysfs (/sys/devices/system) using function kset_create_and_add()
classes_init():

Defined in driver/base/class.c, this function does following initialization:

  • create a struct kset “class_kset dynamically and register it with sysfs (/sys/class) using function kset_create_and_add()

platform_bus_init():

Defined in driver/base/platform.c, this function does following initialization:
device_register():

Defined in driver/base/core.c, this function does following initialization:
    • register “platform” bus device with system using function device_register().
device_initialize():
      • initialize “device” structure
          • set dev->kobj.kset = devices_kset
          • initialize dev->kobj with ktype = devices_ktype
device_add():
      • add “platform” device to device hierarchy (/sys/device/platform)


bus_add_device()
        • add device to bus’s list of devices

bus_probe_device()
        • probe for a driver for new device if bus allows it

device_attach()
        • try to attach device to a driver by walking the list of drivers that the bus has and call driver_probe_device() for each pair.
bus_register():

Defined in driver/base/bus.c, this function does following initialization:
    • register a driver-core subsystem and then register the children subsystems it has
        • allocate memory to struct subsys_private *priv
                                    priv-> subsys.kobj.kset = bus_kset;
priv->subsys.kobj.ktype = &bus_ktype;
priv->drivers_autoprobe = 1;
priv->devices_kset = kset_create_and_add("devices", NULL,
                                                           &priv->subsys.kobj);
priv->drivers_kset = kset_create_and_add("drivers", NULL,
                                                                             &priv->subsys.kobj);
        • Thus we have following directories:
/sys/bus/platform/devices
/sys/bus/platform/drivers

Now you understand why it is referred to as complex "web woven by a spider on drugs" data structure to represent it all.

After driver_init(), kernel is ready with solid base of device model. From now onwards, all you have to do is simply call device and driver register functions and everything will be hooked to the right place right where it belongs. Since we took platform bus as an example, we will quickly look what happens when a platform device and a (corresponding) platform driver are registered.

Let’s take example of simple uart8250 device as reference

static struct platform_device uart8250_device = {
          .name                    = "serial8250",
          .id                          = PLAT8250_DEV_PLATFORM,
          .dev                       = {
                   .platform_data         = uart8250_data,
          },
};

The important members of struct platform_device are given below.

struct platform_device
|-- name (string)
|-- id (device instance number, or else "-1" to indicate there's only one)
|-- dev (struct device)
     |-- platform_data
static int __init uart8250_init(void)
{
          return platform_device_register(&uart8250_device);
}


platform_device_register():

Defined in driver/base/platform.c, this function does following initialization:
    platform_device_add():
    • add a platform device to device hierarchy
    • struct platform_device *pdev
                    pdev->dev.parent = &platform_bus;
pdev->dev.bus = &platform_bus_type;
    • add platform device “pdev->name” to device hierarchy (/sys/device/platform/ serial8250) by calling function device_add().


Once we have serial8250 platform device added, corresponding platform driver will be registered.

static struct platform_driver serial8250_isa_driver = {
          .probe           = serial8250_probe,
          .remove        = __devexit_p(serial8250_remove),
          .suspend       = serial8250_suspend,
          .resume        = serial8250_resume,
          .driver          = {
                   .name = "serial8250",
                   .owner = THIS_MODULE,
          },
};

The important members of struct platform_driver are given below.

struct platform_driver
|-- probe (function pointer)
|-- remove (function pointer)
|-- driver (struct device driver)
static int __init serial8250_init(void)
{
    int ret;
   
    ret = platform_driver_register(&serial8250_isa_driver);
    
}

platform_driver_register():

Defined in driver/base/platform.c, this function does following initialization:
  • set bus type of driver pointed by struct platform_driver *drv
drv->driver.bus = &platform_bus_type;
  • register driver with bus by calling driver_register().

        driver_find():
    • locate driver on a bus by its name
    • Call kset_find_obj() to iterate over list of drivers on a bus to find driver by name
        bus_add_drivers():
    • Add a driver to the bus
    • allocate memory to struct driver_private *priv
struct bus_type *bus;
bus = bus_get(drv->bus);
priv->driver = drv;
drv->p = priv;
priv->kobj.kset = bus->p->drivers_kset;
kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, "%s", drv->name);

(/sys/devices/platform/serial8250/driver/serial8250)
    • try to bind driver to devices by calling driver_attach()
      • this in turn calls driver_probe_device() which calls really_probe() function which is defined in drivers/base/dd.c
      • really_probe() adds driver in sysfs and calls probe() function of your platform device driver (serial8250_probe):
ret = drv->probe(dev);

 With all this information at your dispense, I leave you to explore the world of device model.
 
 Reference:
http://linuxburps.blogspot.in/