Character Device Driver instance
With the foundation of the previous section, I will learn how to compile a character device driver and test it on the client to verify whether the character device driver has been created successfully.
1. Character Device Driver
The following is the driver source code of the character device.
Borytest. c
# Include <Linux/module. h> # include <Linux/types. h> # include <Linux/Fs. h> # include <Linux/errno. h> # include <Linux/mm. h> # include <Linux/sched. h> # include <Linux/init. h> # include <Linux/cdev. h> # include <ASM/Io. h> # include <ASM/system. h> # include <ASM/uaccess. h> # include <Linux/Timer. h> # include <ASM/atomic. h> # include <Linux/slab. h> # define bory_major 255/* default Bory master device Number */static int bory_major = bory_major; struct Bory_dev/* Device number struct */{struct cdev; atomic_t counter; struct timer_list s_timer ;}; struct bory_dev * bory_devp; /* Device struct pointer */static void bory_timer_handle (unsigned long Arg)/* timer processing function */{printk (kern_notice "====== bory_timer_handle "); mod_timer (& bory_devp-> s_timer, jiffies + Hz); atomic_inc (& bory_devp-> counter); printk (kern_err "Current jiffies is % LD \ n", jiffies );} int bory_open (struct inode * inode, struc T file * filp)/* file opening function */{printk (kern_notice "======= bory_open"); init_timer (& bory_devp-> s_timer ); functions-> s_timer.function = & amp; compute; bory_devp-> memory = jiffies + Hz; add_timer (& bory_devp-> s_timer);/* register the timer */atomic_set, 0); Return 0;} int bory_release (struct inode * inode, struct file * filp) /* file release */{printk (kern_notice "======== bory_release"); del_timer (& Bory _ Devp-> s_timer); Return 0;} static ssize_t bory_read (struct file * filp, char _ User * Buf, size_t count, loff_t * PPOs) {printk (kern_notice "======== bory_read"); int counter; counter = atomic_read (& bory_devp-> counter); If (put_user (counter, (int *) BUF) {return-efault;} else {return sizeof (unsigned INT) ;}/ * file operation struct */static const struct file_operations bory_fops = {. owner = this_module ,. open = bory_open ,. rele ASE = bory_release ,. read = bory_read,};/* initialize and register cdev */static void bory_setup_cdev (struct bory_dev * Dev, int index) {printk (kern_notice "======= bory_setup_cdev 1"); int err, devno = mkdev (bory_major, index ); printk (kern_notice "======= bory_setup_cdev 2"); cdev_init (& Dev-> cdev, & bory_fops ); printk (kern_notice "======= bory_setup_cdev 3"); Dev-> cdev. owner = this_module; Dev-> cdev. ops = & bory_fops; printk (Kern_notice "======= bory_setup_cdev 4"); err = cdev_add (& Dev-> cdev, devno, 1 ); printk (kern_notice "======= bory_setup_cdev 5"); If (ERR) {printk (kern_notice "error % d add Bory % d", err, index) ;}} int bory_init (void) {printk (kern_notice "======= bory_init"); int ret; dev_t devno = mkdev (bory_major, 0 ); /* apply for the device Number */If (bory_major) {printk (kern_notice "======= bory_init 1"); ret = register_chrdev_region (devno, 1, "Bory");} else {printk (kern_notice "======= bory_init 2"); ret = alloc_chrdev_region (& devno, "Bory"); bory_major = major (devno);} If (Ret <0) {printk (kern_notice "======= bory_init 3 "); return ret;}/* dynamically apply for device struct memory */bory_devp = kmalloc (sizeof (struct bory_dev), gfp_kernel); If (! Bory_devp)/* application failed */{ret =-enomem; printk (kern_notice "error add Bory"); goto fail_malloc;} memset (bory_devp, 0, sizeof (struct bory_dev); printk (kern_notice "======= bory_init 3"); bory_setup_cdev (bory_devp, 0 ); printk (kern_notice "======= bory_init 4"); Return 0; fail_malloc: unregister_chrdev_region (devno, 1);} void bory_exit (void) /* uninstall the module */{printk (kern_notice "End Bory"); cdev_del (& bory_devp-> cdev);/* log out of cdev */kfree (bory_devp ); /* release the device struct memory */unregister_chrdev_region (mkdev (bory_major, 0), 1); // release the device number} module_author ("Bory "); module_license ("dual BSD/GPL"); module_param (bory_major, Int, s_irugo); module_init (bory_init); module_exit (bory_exit );
Below is the MAKEFILE file
ifneq ($(KERNELRELEASE),)obj-m := borytest.oelseKERNELDIR ?= /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)default:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesendif
Then, run make in the directory to check the file.
bory@borya:~/driver/timertest2$ lsborytest.c borytest.mod.c borytest.o Makefile~ Module.symversborytest.ko borytest.mod.o Makefile modules.order
Load borytest. Ko
bory@borya:~/driver/timertest2$ sudo insmod ./borytest.ko
Run the dmesg command to view the printed log information.
bory@borya:~/driver/timertest2$ dmesg | tail -10[26341.765552] End second[26586.476212] ======== bory_init [26586.476216] ======== bory_init 1[26586.476219] ======== bory_init 3[26586.476220] ======== bory_setup_cdev 1[26586.476221] ======== bory_setup_cdev 2[26586.476223] ======== bory_setup_cdev 3[26586.476224] ======== bory_setup_cdev 4[26586.476227] ======== bory_setup_cdev 5[26586.476228] ======== bory_init 4
At this time, you can also run the lsmod command to check whether the above character device has been loaded successfully.
bory@borya:~/driver/timertest2$ lsmod | head -5Module Size Used byborytest 12714 0 hello 12448 0 nls_utf8 12493 1 isofs 39549 1
2. Client Test Program
Now, the driver of the character device has been completed. The following is a client test program.
Test. c
# Include <stdio. h> # include <unistd. h> # include <fcntl. h> int main (void) {int FD, I; int data; FD = open ("/sys/module/borytest", o_rdonly ); /* Open the/dev/second device file */If (FD <0) {printf ("Open/dev/borytest error \ n ");} else {printf ("Open/dev/borytest success \ n");} Close (FD );}
Compile with command gcc-O test. O testc
bory@borya:~/driver/test$ gcc -o test.o test.cbory@borya:~/driver/test$ ./test.o open /dev/borytest success
The printed result indicates that the character device is successfully enabled!
3. Error Handling
When loading the character device driver, the error "device or resource busy" may occur. This is probably because the device number you have defined has been used and needs to be modified.
#define BORY_MAJOR 255
.
How can I check whether the character device number is used? Use the following command
bory@borya:~/driver/test$ cat /proc/devices Character devices:255 bory 1 mem 4 /dev/vc/0 4 tty 4 ttyS 5 /dev/tty 5 /dev/console 5 /dev/ptmx 5 ttyprintk 6 lp 7 vcs 10 misc 13 input 21 sg 29 fb 99 ppdev108 ppp116 alsa128 ptm136 pts180 usb189 usb_device216 rfcomm226 drm251 hidraw252 usbmon253 bsg254 rtcBlock devices: 1 ramdisk259 blkext 7 loop 8 sd 9 md 11 sr 65 sd 66 sd 67 sd 68 sd 69 sd 70 sd 71 sd128 sd129 sd130 sd131 sd132 sd133 sd134 sd135 sd253 device-mapper254 mdp
As you can see, there are
255 bory
If you write a letter to the device driver next time, you cannot use the 255 device number.