Home | Projects | Notes > Linux Device Drivers > Kernel APIs Used in Device Drivers
Creation
xxxxxxxxxx101/* 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.
xxxxxxxxxx91/* 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()
xxxxxxxxxx211/* fs/char_dev.c */2
3/**4 * alloc_chrdev_region() - register a range of char device numbers5 * @dev: output parameter for first assigned number6 * @baseminor: first of the requested range of minor numbers7 * @count: the number of minor numbers required8 * @name: the name of the associated device or driver9 *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}
baseminoris typically 0.
nameis 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:
xxxxxxxxxx31/* Device number creation */2dev_t device_number;3alloc_chardev_region(&device_number, 0, 7, "eeprom");Again!
eepromhere 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
xxxxxxxxxx171/* fs/char_dev.c */2
3/**4 * cdev_init() - initialize a cdev structure5 * @cdev: the structure to initialize6 * @fops: the file_operations for this device7 *8 * Initializes @cdev, remembering @fops, making it ready to add to the9 * 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}
cdevstructure is defined ininclude/linux/cdev.h:xxxxxxxxxx81struct 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_MODULEis essentially a pointer and is defined inlinux/export.has#define THIS_MODULE (&__this_module).)
ops- A pointer tofile_operationsstructure of the driver.
Usage:
xxxxxxxxxx41/* 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
cdevstructures.
cdev_add() - Add a char device to the kernel VFS
xxxxxxxxxx281/* fs/char_dev.c */2
3/**4 * cdev_add() - add a char device to the system5 * @p: the cdev structure for the device6 * @dev: the first device number for which this device is responsible7 * @count: the number of consecutive minor numbers corresponding to this8 * device9 *10 * cdev_add() adds the device represented by @p to the system, making it11 * 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()
xxxxxxxxxx421/* drivers/base/class.c */2
3/**4 * class_create - create a struct class structure5 * @owner: pointer to the module that is to "own" this struct class6 * @name: pointer to a string for the name of this class.7 * @key: the lock_class_key for this class; used by mutex lock debugging8 *9 * This is used to create a struct class pointer that can then be used10 * 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 by15 * 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:
xxxxxxxxxx21struct class *eeprom_class;2eeprom_class = class_create(THIS_MODULE, "eeprom_class");device_create()
xxxxxxxxxx381/* drivers/base/core.c */2
3/**4 * device_create - creates a device and registers it with sysfs5 * @class: pointer to the struct class that this device should be registered to6 * @parent: pointer to the parent struct device of this new device, if any7 * @devt: the dev_t for the char device to be added8 * @drvdata: the data to be added to the device for callbacks9 * @fmt: string for the device's name10 *11 * This function can be used by char device classes. A struct device12 * 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, if15 * the dev_t is not 0,0.16 * If a pointer to a parent struct device is passed in, the newly created17 * 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 this20 * 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 previously25 * 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()
xxxxxxxxxx211/* 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 with6 * @devt: the dev_t of the device that was previously registered7 *8 * This call unregisters and cleans up a device that was created with a9 * 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()
xxxxxxxxxx161/* drivers/base/class.c */2
3/**4 * class_destroy - destroys a struct class structure5 * @cls: pointer to the struct class that is to be destroyed6 *7 * Note, the pointer to be destroyed must have been created with a call8 * 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()
xxxxxxxxxx181/* fs/char_dev.c */2
3/**4 * cdev_del() - remove a cdev from the system5 * @p: the cdev structure to be removed6 *7 * cdev_del() removes @p from the system, possibly freeing the structure8 * itself.9 *10 * NOTE: This guarantees that cdev device will no longer be able to be11 * opened, however any cdevs already open will remain and their fops will12 * 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()
xxxxxxxxxx231/* fs/char_dev.c */2
3/**4 * unregister_chrdev_region() - unregister a range of device numbers5 * @from: the first in the range of numbers to unregister6 * @count: the number of device numbers to unregister7 *8 * This function will unregister a range of @count device numbers,9 * starting with @from. The caller should normally be the one who10 * 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}