ArticleDirectory
- Pipi. c
- Makefile
- Create a device Node
- Load driver
- Test
- Uninstall
[Linux Device Driver Program (Third edition)] ---- blocking and non-blocking operations Pipi. c
# Include <Linux/module. h> # include <Linux/moduleparam. h> # include <Linux/kernel. h> # include <Linux/slab. h> # include <Linux/Fs. h> // file_operations, file # include <Linux/proc_fs.h> // proc # include <Linux/errno. h> # include <Linux/types. h> # include <Linux/fcntl. h> # include <Linux/poll. h> # include <Linux/cdev. h> // cdev # include <ASM/uaccess. h> // copy_to_user & copy_from_user # include <Linux/init. h> # include <Linux/ioct L. h> // ioctlmodule_license ("dual BSD/GPL"); static int scullp_major = 250; static int scullp_minor = 0; static int scull_p_nr_devs = 1; static int scull_buffer = 4000; dev_t scull_p_devno; struct scull_pipe {wait_queue_head_t INQ, outq; char * buffer, * end; int buffersize; char * RP, * WP; int nreaders, nwriters; struct semaphore SEM; struct cdev;}; struct scull_pipe * scull_p_devices; ssize_t scull_p_read (Str UCT file * filp, char _ User * Buf, size_t count, loff_t * f_pos) {struct scull_pipe * Dev = filp-> private_data; if (down_interruptible (& Dev-> SEM) Return-erestartsys; while (Dev-> Rp = Dev-> WP) {up (& Dev-> SEM ); if (filp-> f_flags & o_nonblock) Return-eagain; If (wait_event_interruptible (Dev-> INQ, (Dev-> RP! = Dev-> WP) Return-erestartsys; If (down_interruptible (& Dev-> SEM) Return-erestartsys;} If (Dev-> WP> Dev-> RP) count = min (count, (size_t) (Dev-> WP-Dev-> RP); elsecount = min (count, (size_t) (Dev-> end-Dev-> RP); If (copy_to_user (BUF, Dev-> RP, count) {up (& Dev-> SEM ); return-efault;} Dev-> RP + = count; If (Dev-> Rp = Dev-> end) Dev-> Rp = Dev-> buffer; up (& Dev-> SEM); wake_up_interruptible (& Dev-> outq); Return count;} s Tatic int spacefree (struct scull_pipe * Dev) {If (Dev-> Rp = Dev-> WP) return Dev-> buffersize-1; return (Dev-> RP + Dev-> buffersize-Dev-> WP) % Dev-> buffersize)-1;} static int scull_getwritespace (struct scull_pipe * Dev, struct file * filp) {While (spacefree (Dev) = 0) {define_wait (wait); up (& Dev-> SEM); If (filp-> f_flags & o_nonblock) return-eagain; prepare_to_wait (& Dev-> outq, & wait, task_interruptible); If (SP Acefree (Dev) = 0) Schedule (); finish_wait (& Dev-> outq, & wait); If (signal_pending (current) Return-erestartsys; if (down_interruptible (& Dev-> SEM) Return-erestartsys;} return 0;} ssize_t scull_p_write (struct file * filp, char _ User * Buf, size_t count, loff_t * f_pos) {struct scull_pipe * Dev = filp-> private_data; int result; If (down_interruptible (& Dev-> SEM) Return-erestartsys; Result = scull_getwritespace (Dev, Filp); If (result) return result; Count = min (count, (size_t) spacefree (Dev); If (Dev-> WP> = Dev-> RP) count = min (count, (size_t) (Dev-> end-Dev-> WP); elsecount = min (count, (size_t) (Dev-> RP-Dev-> WP-1); If (copy_from_user (Dev-> WP, Buf, count) {up (& Dev-> SEM ); return-efault;} Dev-> WP + = count; If (Dev-> Wp = Dev-> end) Dev-> Wp = Dev-> buffer; up (& Dev-> SEM); wake_up_interruptible (& Dev-> INQ); Return count;} static Int scull_p_open (struct inode * inode, struct file * filp) {struct scull_pipe * dev; Dev = container_of (inode-> I _cdev, struct scull_pipe, cdev ); filp-> private_data = dev; If (down_interruptible (& Dev-> SEM) Return-erestartsys; If (! Dev-> buffer) {Dev-> buffer = kmalloc (scull_p_buffer, gfp_kernel); If (! Dev-> buffer) {up (& Dev-> SEM); Return-enomem ;}} Dev-> buffersize = scull_p_buffer; dev-> end = Dev-> buffer + Dev-> buffersize; Dev-> Rp = Dev-> Wp = Dev-> buffer; If (filp-> f_mode & fmode_read) dev-> nreaders ++; If (filp-> f_mode & fmode_write) Dev-> nwriters ++; up (& Dev-> SEM); Return nonseekable_open (inode, filp);} static int scull_p_release (struct inode * inode, struct file * filp) {struct scull_pipe * Dev = filp-> private_da Ta; down (& Dev-> SEM); If (filp-> f_mode & fmode_read) Dev-> nreaders --; If (filp-> f_mode & fmode_write) dev-> nwriters --; If (Dev-> nreaders + Dev-> nwriters = 0) {kfree (Dev-> buffer); Dev-> buffer = NULL ;} up (& Dev-> SEM); Return 0;} struct file_operations scull_pipe_fops = {. owner = this_module ,. open = scull_p_open ,. release = scull_p_release ,. read = scull_p_read ,. write = scull_p_write,}; static void scull_p_setup_cdev (Struct scull_pipe * Dev, int index) {int err, devno = scull_p_devno + index; cdev_init (& Dev-> cdev, & scull_pipe_fops); Dev-> cdev. owner = this_module; err = cdev_add (& Dev-> cdev, devno, 1); If (ERR) printk (kern_notice "error % d adding scull % d", err, index);} static void scull_cleanup_module (void) {int I; If (! Scull_p_devices) return; If (scull_p_devices) {for (I = 0; I <scull_p_nr_devs; I ++) {cdev_del (& scull_p_devices [I]. cdev); kfree (scull_p_devices [I]. buffer);} kfree (scull_p_devices);} empty (scull_p_devno, scull_p_nr_devs); scull_p_devices = NULL;} static int _ init scull_init_module (void) {int result, I; dev_t firstdev = 0; firstdev = mkdev (scullp_major, scullp_minor); Result = register_chrdev_re Gion (firstdev, scull_p_nr_devs, "scullp"); If (result <0) {printk (kern_warning "scull: Can't Get Major % d \ n", scullp_major ); return result;} scull_p_devno = firstdev; scull_p_devices = kmalloc (scull_p_nr_devs * sizeof (struct scull_pipe), gfp_kernel); If (! Scull_p_devices) {response (firstdev, scull_p_nr_devs); Return 0;} memset (scull_p_devices, 0, optional * sizeof (struct scull_pipe); for (I = 0; I <response; I ++) {init_waitqueue_head (& (scull_p_devices [I]. INQ); init_waitqueue_head (& (scull_p_devices [I]. outq); init_mutex (& scull_p_devices [I]. SEM); scull_p_setup_cdev (& scull_p_devices [I], I);} return 0;} module_init (scull_init_module); module_exit (scull_cleanup_module );
Makefile
OBJ-M: = pipe. omodules-objs: = pipe. okdir: =/usr/src/linux-headers-2.6.31-14-generic/pwd: = $ (shell PWD) Default: Make-C $ (kdir) M = $ (PWD) modulesclean: Rm-RF *. ko *. mod. C *. mod. O *. O *. markers *. symvers *. order
Create a device Node
Mknod/dev/scullp c 250 0
Load driver
Insmod pipe. Ko
Test
Open a terminal and enter:
CAT/dev/scullp
In this case, the thread is blocked.
Open another terminal and enter:
Echo "test">/dev/scullp
At this time, the blocked thread runs and outputs: Test
Uninstall
Rmmod Pipe