Linux driver learning notes 3-character device driver instance (driver + client)

Source: Internet
Author: User
Tags dmesg
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.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.