Home | Projects | Notes > Linux Device Drivers > Kernel APIs Used in Device Drivers
Creation
xxxxxxxxxx
101/* 1. Dynamically Register a Range of Char Device Numbers */
2alloc_chrdev_region();
3
4/* 2. Create and Register Char Device to VFS */
5cdev_init();
6cdev_add();
7
8/* 3. Create device files */
9class_create();
10class_destroy();
When a module is loaded, these creation services must be executed and the driver must be ready to accept system calls from the user space program. So, it would make sense for this part to be taken care of by the module initialization function.
Deletion
Deletion process is the reverse of that of the creations.
xxxxxxxxxx
91/* 1. Delete device files */
2class_destroy();
3device_destory();
4
5/* 2. Delete the registration */
6cdev_del();
7
8/* 3. Delete device number */
9unregister_chrdev_region();
Taken care of by the module cleanup function.
Kernel functions and data structures | Kernel header file |
---|---|
alloc_chrdev_region() unregister_chardev_region() | include/linux/fs.h |
cdev_init() cdev_add() cdev_del() | include/linux/cdev.h |
device_create() class_create() device_destroy() class_destroy() | include/linux/device.h |
copy_to_user() copty_from_user() | include/linux/uaccess.h |
VFS structure definitions | include/linux/fs.h |
alloc_chrdev_region()
xxxxxxxxxx
211/* fs/char_dev.c */
2
3/**
4 * alloc_chrdev_region() - register a range of char device numbers
5 * @dev: output parameter for first assigned number
6 * @baseminor: first of the requested range of minor numbers
7 * @count: the number of minor numbers required
8 * @name: the name of the associated device or driver
9 *
10 * Allocates a range of char device numbers. The major number will be chosen dynamically,
11 * and returned (along with the first minor number) in @dev. Returns zero or a negative error code.
12 */
13int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
14{
15 struct char_device_struct *cd;
16 cd = __register_chrdev_region(0, baseminor, count, name);
17 if (IS_ERR(cd))
18 return PTR_ERR(cd);
19 *dev = MKDEV(cd->major, cd->baseminor);
20 return 0;
21}
baseminor
is typically 0.
name
is NOT the device file name. It is a pointer to a string that represents the name or identifier of the character device region being allocated. This name is typically used for identification or debugging purposes and is not directly related to the functionality of the device.
Usage:
xxxxxxxxxx
31/* Device number creation */
2dev_t device_number;
3alloc_chardev_region(&device_number, 0, 7, "eeprom");
Again!
eeprom
here is not the name of a device file. It is just an identifier that indicates the range of device numbers.
cdev_init()
- Initialize a cdev
structure
xxxxxxxxxx
171/* fs/char_dev.c */
2
3/**
4 * cdev_init() - initialize a cdev structure
5 * @cdev: the structure to initialize
6 * @fops: the file_operations for this device
7 *
8 * Initializes @cdev, remembering @fops, making it ready to add to the
9 * system with cdev_add().
10 */
11void cdev_init(struct cdev *cdev, const struct file_operations *fops)
12{
13 memset(cdev, 0, sizeof *cdev);
14 INIT_LIST_HEAD(&cdev->list);
15 kobject_init(&cdev->kobj, &ktype_cdev_default);
16 cdev->ops = fops;
17}
cdev
structure is defined ininclude/linux/cdev.h
:xxxxxxxxxx
81struct cdev {
2struct kobject kobj;
3struct module *owner;
4const struct file_operations *ops;
5struct list_head list;
6dev_t dev;
7unsigned int count;
8} __randomize_layout;
ownder
- A pointer to the module that owns this structure; it should usually be initialized toTHIS_MODULE
. This field is used to prevent the module from being unloaded while the structure is in use. (THIS_MODULE
is essentially a pointer and is defined inlinux/export.h
as#define THIS_MODULE (&__this_module)
.)
ops
- A pointer tofile_operations
structure of the driver.
Usage:
xxxxxxxxxx
41/* Initialize file ops structure with driver's system call implementation methods */
2struct file_operations eeprom_fops;
3struct cdev eeprom_cdev;
4cedv_init(&eeprom_cdev, &eeprom_fops);
If you are dealing with 10 devices, then you may have to create 10
cdev
structures.
cdev_add()
- Add a char device to the kernel VFS
xxxxxxxxxx
281/* fs/char_dev.c */
2
3/**
4 * cdev_add() - add a char device to the system
5 * @p: the cdev structure for the device
6 * @dev: the first device number for which this device is responsible
7 * @count: the number of consecutive minor numbers corresponding to this
8 * device
9 *
10 * cdev_add() adds the device represented by @p to the system, making it
11 * live immediately. A negative error code is returned on failure.
12 */
13int cdev_add(struct cdev *p, dev_t dev, unsigned count)
14{
15 int error;
16
17 p->dev = dev;
18 p->count = count;
19
20 error = kobj_map(cdev_map, dev, count, NULL,
21 exact_match, exact_lock, p);
22 if (error)
23 return error;
24
25 kobject_get(p->kobj.parent);
26
27 return 0;
28}
Dynamic device file creation in Linux
Behind the scenes
In Linux, you can create a device file dynamically (on demand), i.e., you don't need to manually create device files under /dev
directory to access your hardware.
User-level program such as udevd
can populate /dev
directory with device files dynamically. (udevd
is a user level daemon which runs in the background and scans for uevents
generated by the kernel. By analyzing the uevents
, udevd
populates /dev
directory with device files.)
udev
program listens to the uevents
generated by hot plug events or kernel modules. When udev
receives the uevents
, it scans the subdirectories of /sys/class
looking for the dev
files to create device files.
For each such dev
file, which represents a combination of major and minor number for a device, the udev
program creates a corresponding device in /dev
directory.
udev
Relies on device information exported to user space through sysfs
.
uevents
are generated when device driver uses kernel APIs to trigger the dynamic creation of device files or when a hot pluggable device such as a USB peripheral is plugged into the system.
All a device driver needs to do, for udev
to work properly with it, is to ensure that any major and minor numbers assigned to a device controlled by the driver are exported to user space through sysfs
.
The driver exports all the information regarding the device such as device file name, major, minor number to sysfs
by calling the function device_create
.
udev
looks for a file called dev
in the /sys/class/
tree of sysfs
, to determine what the major and minor number is assigned to a specific device.
class_create()
xxxxxxxxxx
421/* drivers/base/class.c */
2
3/**
4 * class_create - create a struct class structure
5 * @owner: pointer to the module that is to "own" this struct class
6 * @name: pointer to a string for the name of this class.
7 * @key: the lock_class_key for this class; used by mutex lock debugging
8 *
9 * This is used to create a struct class pointer that can then be used
10 * in calls to device_create().
11 *
12 * Returns &struct class pointer on success, or ERR_PTR() on error.
13 *
14 * Note, the pointer created here is to be destroyed when finished by
15 * making a call to class_destroy().
16 */
17struct class *__class_create(struct module *owner, const char *name, struct lock_class_key *key)
18{
19 struct class *cls;
20 int retval;
21
22 cls = kzalloc(sizeof(*cls), GFP_KERNEL);
23 if (!cls) {
24 retval = -ENOMEM;
25 goto error;
26 }
27
28 cls->name = name;
29 cls->owner = owner;
30 cls->class_release = class_create_release;
31
32 retval = __class_register(cls, key);
33 if (retval)
34 goto error;
35
36 return cls;
37
38error:
39 kfree(cls);
40 return ERR_PTR(retval);
41}
42EXPORT_SYMBOL_GPL(__class_create);
Usage:
xxxxxxxxxx
21struct class *eeprom_class;
2eeprom_class = class_create(THIS_MODULE, "eeprom_class");
device_create()
xxxxxxxxxx
381/* drivers/base/core.c */
2
3/**
4 * device_create - creates a device and registers it with sysfs
5 * @class: pointer to the struct class that this device should be registered to
6 * @parent: pointer to the parent struct device of this new device, if any
7 * @devt: the dev_t for the char device to be added
8 * @drvdata: the data to be added to the device for callbacks
9 * @fmt: string for the device's name
10 *
11 * This function can be used by char device classes. A struct device
12 * will be created in sysfs, registered to the specified class.
13 *
14 * A "dev" file will be created, showing the dev_t for the device, if
15 * the dev_t is not 0,0.
16 * If a pointer to a parent struct device is passed in, the newly created
17 * struct device will be a child of that device in sysfs.
18 * The pointer to the struct device will be returned from the call.
19 * Any further sysfs files that might be required can be created using this
20 * pointer.
21 *
22 * Returns &struct device pointer on success, or ERR_PTR() on error.
23 *
24 * Note: the struct class passed to this function must have previously
25 * been created with a call to class_create().
26 */
27struct device *device_create(struct class *class, struct device *parent,
28 dev_t devt, void *drvdata, const char *fmt, ...)
29{
30 va_list vargs;
31 struct device *dev;
32
33 va_start(vargs, fmt);
34 dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
35 va_end(vargs);
36 return dev;
37}
38EXPORT_SYMBOL_GPL(device_create);
device_destroy()
xxxxxxxxxx
211/* drivers/base/core.c */
2
3/**
4 * device_destroy - removes a device that was created with device_create()
5 * @class: pointer to the struct class that this device was registered with
6 * @devt: the dev_t of the device that was previously registered
7 *
8 * This call unregisters and cleans up a device that was created with a
9 * call to device_create().
10 */
11void device_destroy(struct class *class, dev_t devt)
12{
13 struct device *dev;
14
15 dev = class_find_device(class, NULL, &devt, __match_devt);
16 if (dev) {
17 put_device(dev);
18 device_unregister(dev);
19 }
20}
21EXPORT_SYMBOL_GPL(device_destroy);
class_destroy()
xxxxxxxxxx
161/* drivers/base/class.c */
2
3/**
4 * class_destroy - destroys a struct class structure
5 * @cls: pointer to the struct class that is to be destroyed
6 *
7 * Note, the pointer to be destroyed must have been created with a call
8 * to class_create().
9 */
10void class_destroy(struct class *cls)
11{
12 if ((cls == NULL) || (IS_ERR(cls)))
13 return;
14
15 class_unregister(cls);
16}
cdev
Registration from the Kernel VFScdev_del()
xxxxxxxxxx
181/* fs/char_dev.c */
2
3/**
4 * cdev_del() - remove a cdev from the system
5 * @p: the cdev structure to be removed
6 *
7 * cdev_del() removes @p from the system, possibly freeing the structure
8 * itself.
9 *
10 * NOTE: This guarantees that cdev device will no longer be able to be
11 * opened, however any cdevs already open will remain and their fops will
12 * still be callable even after cdev_del returns.
13 */
14void cdev_del(struct cdev *p)
15{
16 cdev_unmap(p->dev, p->count);
17 kobject_put(&p->kobj);
18}
unregister_chrdev_region()
xxxxxxxxxx
231/* fs/char_dev.c */
2
3/**
4 * unregister_chrdev_region() - unregister a range of device numbers
5 * @from: the first in the range of numbers to unregister
6 * @count: the number of device numbers to unregister
7 *
8 * This function will unregister a range of @count device numbers,
9 * starting with @from. The caller should normally be the one who
10 * allocated those numbers in the first place...
11 */
12void unregister_chrdev_region(dev_t from, unsigned count)
13{
14 dev_t to = from + count;
15 dev_t n, next;
16
17 for (n = from; n < to; n = next) {
18 next = MKDEV(MAJOR(n)+1, 0);
19 if (next > to)
20 next = to;
21 kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
22 }
23}