Memdev device driver source code
Memdev. h. Custom header file ************************************ **************************************** ** # ifndef _ memdev_h _ # DEFINE _ memdev_h _ # ifndef memdev_major # define memdev_major 254/* default mem primary device Number */# endif # ifndef primary # define limit 2 /* number of devices */# endif # ifndef memdev_size # define memdev_size 4096 // size of memory allocated # endif/* mem device description struct */struct mem_dev {char * data; // The initial address unsigned Long size of the allocated memory; // memory size}; # endif/* _ memdev_h _*/
Memdev. c. A complete character driver ********************************* **************************************** * ***** # 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 "memdev. H "static mem_major = memdev_major; Module_param (mem_major, Int, s_irugo); struct mem_dev * mem_devp;/* Device struct pointer */struct cdev;/* file open function */INT mem_open (struct inode * inode, struct file * filp) {struct mem_dev * dev;/* get the device Number */INT num = minor (inode-> I _rdev ); // inode-> I _rdev contains the actual device number if (Num> = memdev_nr_devs) Return-enodev; Dev = & mem_devp [num]; /* assign the device description structure pointer to the file Private Data Pointer */filp-> private_data = dev; // use this member to point to the allocated data return 0 ;} /* file release function */I NT mem_release (struct inode * inode, struct file * filp) {return 0;}/* read function */static ssize_t mem_read (struct file * filp, char _ User * Buf, size_t size, loff_t * PPOs) // Buf cache, size Read File Size, PPOs current read/write location {unsigned long P = * PPOs; // P indicates the current read/write position unsigned int COUNT = size; // the size of one read int ret = 0; struct mem_dev * Dev = filp-> private_data; /* get the device struct pointer * // * determine whether the read location is valid */If (P> = memdev_size) // determine whether the read location exceeds the value of returned 0; If (count> Memdev_size-p) Count = memdev_size-P; // if the value of count is greater than the readable range, the read range is reduced. /* Read data to user space */If (copy_to_user (BUF, (void *) (Dev-> Data + p), count) // return Buf, read location, read count {ret =-efault;} else {* PPOs + = count; // Move the current position of the file back to ret = count; // returns the actual number of bytes read printk (kern_info "read % d bytes (s) from % d \ n", Count, P);} return ret; // return the actual number of bytes read to determine whether the read is successful}/* write function */static ssize_t mem_write (struct file * filp, const char _ User * Buf, size_t size, loff_t * PPOs) // write is similar to read. For more information, see read {unsigned long P = * PPOs; unsigned int COUNT = size; int ret = 0; struct mem_dev * Dev = filp-> private_data; /* get the device struct pointer * // * analyze and obtain valid write lengths */If (P> = memdev_size) return 0; If (count> memdev_size-P) count = memdev_size-P;/* write data from user space */If (copy_from_user (Dev-> Data + P, Buf, count) ret =-efault; else {* PPOs + = count; ret = count; printk (kern_info "written % d bytes (s) from % d \ n", Count, P);} return ret ;} /* seek text Location function */static loff_t mem_llseek (struct file * filp, loff_t offset, int whence) // Changes the current read/write position in the file, and the new position is (positive) the returned value must be located again in the test program. Whence is set to seek_set {loff_t newpos here; Switch (whence) {Case 0:/* seek_set */newpos = offset; // locate break from the file header; Case 1:/* seek_cur */newpos = filp-> f_pos + offset; // locate break from the file center; Case 2: /* seek_end */newpos = memdev_size-1 + offset; // start from the end of the file. Because the position starts from 0, 1 break is required. DEFA Ult:/* can't happen */Return-einval;} If (newpos <0) | (newpos> memdev_size) Return-einval; filp-> f_pos = newpos; // return the current file location return newpos;}/* file operation struct */static const struct file_operations mem_fops = {. owner = this_module ,. llseek = mem_llseek ,. read = mem_read ,. write = mem_write ,. open = mem_open ,. release = mem_release,};/* Device Driver Module Loading Function */static int memdev_init (void) // initialization module {int result; int I; Dev_t devno = mkdev (mem_major, 0); // mkdev converts the master and secondary device numbers into dev_t data, the mem_major parameter is set to 254/* apply for the device ID statically */If (mem_major)/memdev in the header file. the value of H is 254. Therefore, in this example, the master device number 254 result = register_chrdev_region (devno, 2, "memdev") is allocated statically. // devno is the master device number. Two consecutive devices are requested, the device name is "memdev" else/* dynamically allocates the device Number */{result = alloc_chrdev_region (& devno, 0, 2, "memdev"); // & devno is used as an output parameter, the device number starts from 0 and applies for two devices. The device name is "memdev" mem_major = major (devno); // gets the dynamically assigned master device number.} If (result <0) // If the returned result is 0, the application is successful, and the negative value of the backend is failed. Return result;/* initialize the cdev structure */cdev_init (& cdev, & mem_fops); // initialize the cdev structure and bind the cdev and mem_fops struct to the cdev. owner = this_module; // The reference count of the driver. This is used when the driver is in use. When you use the inmod command again, a warning message is displayed, prompting cdev. ops = & mem_fops;/* register a character device */cdev_add (& cdev, mkdev (mem_major, 0), memdev_nr_devs); // memdev_nr_devs = 2, allocate 2 devices/* allocate memory for the device description structure */mem_devp = kmalloc (memdev_nr_devs * sizeof (struct mem_dev), gfp_kernel ); // The kmalloc function returns a virtual address (linear address ). if (! Mem_devp)/* application failed */{result =-enomem; goto fail_malloc;} memset (mem_devp, 0, sizeof (struct mem_dev )); // initialize the newly applied memory/* allocate memory to the device */for (I = 0; I <memdev_nr_devs; I ++) {mem_devp [I]. size = memdev_size; // # define memdev_size 4096 mem_devp [I]. data = kmalloc (memdev_size, gfp_kernel); // allocate memory to two devices: memset (mem_devp [I]. data, 0, memdev_size); // initialize the newly allocated memory} return 0; fail_malloc: unregister_chrdev_region (devno, 1); // if the application fails, log out of the device and return result ;} /* module unmount function */static void memdev_exit (void) {cdev_del (& cdev);/* log out of the device */kfree (mem_devp ); /* release the device struct memory */unregister_chrdev_region (mkdev (mem_major, 0), 2);/* release the device Number */} module_author ("David xie "); module_license ("GPL"); module_init (memdev_init); module_exit (memdev_exit );
Test. C testing program ************************************* **************************************** ** # include <stdio. h> int main () {file * fp0 = NULL; char Buf [4096];/* initialize Buf */strcpy (BUF, "mem is Char Dev! "); Printf (" Buf: % s \ n ", Buf);/* Open the device file */fp0 = fopen ("/dev/memdev0 ", "R +"); If (fp0 = NULL) {printf ("Open memdev0 error! \ N "); Return-1;}/* Write Device */fwrite (BUF, sizeof (BUF), 1, fp0 ); /* relocate the file location (think about the consequences of not having this command) */fseek (fp0, 0, seek_set); // call mem_llseek () to locate, move the file pointer back to the starting position to facilitate reading/* clearing Buf */strcpy (BUF, "Buf is null! "); // Overwrite the previous value to prevent printf (" Buf: % s \ n ", Buf) from being judged when the data cannot be read ); /* read the device */fread (BUF, sizeof (BUF), 1, fp0);/* test result */printf ("Buf: % s \ n", Buf ); return 0 ;}