Programming Linux Character Driver
Linux Character Driver
Character Device Structures
Character device driver, block device driver and network device driver as the linux kernel three major driver devices, character devices mainly complete the byte read and write operations, common applications are mouse, keyboard, etc., the structure form is shown below:
1 | struct cdev { |
- The dev_t in the cdev structure represents the 32-bit device number, 12 bits are the major device number and 20 bits are the minor device number. The major device number and minor device number can be obtained from the dev_t by macro definitions MAJOR(dev_t dev) and MINOR(dev_t dev). In addition, dev_t can be generated from the primary and secondary device numbers using the macro definition MKDEV(int major, int minor).
- The Linux kernel provides a set of functions to operate on character device structures, which can be used to manipulate the cdev structure.
1 | void cdev_init(struct cdev *, struct file_operations *); // Used to initialize the members of cdev and establish the connection between cdev and file_operation |
- Call register_chrdev_region() or alloc_chrdev_region() function to request a device number from the system, and then call cdev_add() function to register the character device with the system.
1 | int register_chrdev_region(dev_t from, unsigned count, const char *name); // Known starting device number |
- The member functions in the file_operations structure are eventually called by the kernel when the application makes Linux system calls such as open(), write(), read(), close(), etc.
- llseek() modifies the current read/write location of a file and returns the new location, returning a negative value in case of error.
- read() reads data from the device, returning the number of bytes read on success and a negative value on error. Corresponds to ssize_t read (int fd, voidbuf, size_t count) and size_t fread (voidptr, size_t size, size_t nmemb, FILE*stream) in user space applications.
- write() sends data to the device and returns the number of bytes written on success. If this function is not implemented, the user will get the -EINVAL return value when making the write() system call. Corresponds to ssize_t write (int fd, constvoidbuf, size_t count) and size_t fwrite (const voidptr, size_t size, size_t nmemb, FILE*stream) in user space applications.
- read() and write() indicate end-of-file (EOF) if they return 0.
- unlocked_ioctl() provides implementation of device-related control commands (neither read nor write operations) and returns a non-negative value to the calling program when called successfully. It is similar to the user-space application calls int fcntl (int fd, int cmd, … /arg/) and intioctl (int d, int request, …) counterparts.
- mmap() maps device memory into the virtual address space of the process. If the device driver does not implement this function, the user will get the -ENODEV return value when making the mmap() system call. This function is of particular interest for devices such as frame buffers, which are mapped into user space so that applications can access them directly without having to copy memory between the kernel and the application. It corresponds to the voidmmap (voidaddr, size_t length, int prot, int flags, int fd, off_t offset) function in user space applications.
- The functions for loading and unloading the character device driver module are as follows
- static int __init mydev_init(void)
- static void __exit mydev_exit(void)
- The application of device number and registration of cdev should be implemented in the load function of the character device driver module, while the release of device number and cancellation of cdev should be implemented in the unload function.
Character Structures Programming
Create a new dev folder and create mydev.c and the corresponding Makefile file in this directory
The mydev.c program is as follows:
1 |
|
The Makefile program is as follows:
1 | mydev.o |
Character device validation
- Enter the make command in the mydev directory
- First
dmesg -c
- Then insert the module as administrator and type insmod mydev.ko in the mydev directory
cat /proc/devices
- Enter characters into this character device to create a device node: mknod /dev/mydev c 230 0 //230 0 is the primary and secondary device number of the device you created; write the string: echo “hello world!”>/dev/mydev; check the input information: cat /dev/mydev; check the read/write situation: dmesg mydev
Test Code
Create the mydevTest.c test file with the following code:
1 |
|
Type gcc mydevTest.c a.out to generate a.out, then type . /a.out to run.
mydev: loading out-of-tree module taints kernel.
mydev: module verification failed: signature and/or required key missing - tainting kernel
are the very beginning of the Linux source code .config, which will be shown in this experiment but does not affect
If there is no CONFIG_MODULE_SIG=n statement in the Makefile file, then the hello.txt file will show
module verification failed: signature and/or required key missing - tainting kernel
i.e.: Module verification failed.
Programming Linux Character Driver
http://aslin.site/2022/03/17/Programming-Linux-Character-Driver/