Character-driven programming model:
1. Device Description Structure Cdev
1.1 structure definition
1.2 Device number
1.3 Device Operation Set
In the Linux system, the types of devices are very diverse, such as: Character devices, block devices, network interface devices, USB devices, PCI devices, platform equipment, hybrid devices ..., and the device type is different, it also means that the corresponding driver model is different, which led to the need to master a lot of driver model. Then it is not possible to extract some common rules from these many drive models, which is the key to our ability to learn the Linux drive.
View the device number can be seen by viewing the device number in the/dev directory
Secondary device number
Operation of the device number:
Assignment of the device number:
Logoff of the device number:
Regardless of the method used to assign the device number, you should use the Unregister_chrdev_region function to release the device numbers when the driver exits.
Set of operating functions:
Set of operating functions:
2. Character device driver Model
Describe the allocation of structs:
Cdev variables can be defined using both static and dynamic methods.
Static assignment: struct Cdev mdev;
Dynamic assignment: struct Cdev *pdev = Cdev_alloc ();
Describe the initialization of the structure:
To describe the registration of a struct:
The registration of the character device is done using the Cdev_add function, the function prototype:
Cdev_add (struct Cdev *p, dev_t Dev, unsigned count)
Parameters:
P: Character device structure to be added to the kernel
Dev: Device number
Count: Number of devices for this type of device
The rest is to complete the initialization according to the corresponding chip manual.
To implement device operations:
Device Operation prototype:
Turn on the device in response to the open system call
Int (*open) (struct inode *, struct file *)
Turn off the device in response to the close system call
Int (*release) (struct inode *, struct file *)
Relocate read-write pointers in response to Lseek system calls
loff_t (*llseek) (struct file*, loff_t, int)
Read the data from the device in response to the read system call
ssize_t (*read) (struct file*, char __user *, size_t, Lofft *)
Writes data to the device in response to a write system call
ssize_t (*write) (struct file*, char __user *, size_t, Lofft *)
struct file: In a Linux system, each open file is associated with a struct file in the kernel, which is created when the kernel is opened and released after the file is closed.
Important Members:
loff_t F_pos/* file read/write pointer */
struct File_operations *f_op/* The action for reading the file */
struct Inode
Each file that exists in the file system is associated with an inode structure, which is primarily used to record the physical information of a file. Therefore, it differs from the file structure that represents open files. When a file is not opened, it is not associated with the file structure, but it is associated with an inode structure.
Important members: dev_t I_RDEV/* Device number */
Device Operation---Open
The open device method is used by the driver to perform initialization preparation for subsequent operations, and in most drivers, open completes the following tasks:
1> marking the secondary device number
2.> Boot Device
Device Operation---Release
The release method works just as opposed to open. This device method is sometimes called close, and it is used to turn off the device
Device Operation---Read
Device Operation---Write
Finally, the driver is logged out: When we unload the driver from the kernel, we need to make the Cdev_del function to complete the character device logoff.
3. Example driven analysis
Here's a sample code to drive a well-written character:
MEMDEV.C file
#include <linux/module.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/cdev.h > #include <asm/uaccess.h>int dev1_registers[5];int dev2_registers[5];struct cdev Cdev; dev_t devno;/* File Open function */int mem_open (struct inode *inode, struct file *filp) {/* Get secondary device number */int num = MINOR (inode-> ; i_rdev); if (num==0) filp->private_data = dev1_registers; else if (num = = 1) filp->private_data = dev2_registers; else Return-enodev; Invalid secondary device number return 0; }/* file Release function */int 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) {unsigned long p = *ppos; unsigned int count = size; int ret = 0; int *register_addr = filp->private_data; /* Obtain the device's register base address */* To determine if the read position is valid */if (P >= 5*sizeof (int)) return 0; if (Count > 5*sizeof (int)-P) Count = 5*sizeof (int)-p; /* Read data to User space */if (Copy_to_user (buf, RegiSter_addr+p, Count)) {ret =-efault; } else {*ppos + = count; ret = count; } return ret;} /* Write function */static ssize_t mem_write (struct file *filp, const char __user *buf, size_t size, loff_t *ppos) {unsigned long p = *ppos; unsigned int count = size; int ret = 0; int *register_addr = filp->private_data; /* Get the device's register address */* parse and get valid write length */if (P >= 5*sizeof (int)) return 0; if (Count > 5*sizeof (int)-P) Count = 5*sizeof (int)-p; /* Write data from user space */if (Copy_from_user (Register_addr + p, buf, count)) ret =-efault; else {*ppos + = count; ret = count; } return ret;} /* Seek file Locator function */static loff_t mem_llseek (struct file *filp, loff_t offset, int whence) {loff_t newpos; Switch (whence) {case seek_set:newpos = offset; Break Case Seek_cur:newpos = Filp->f_pos + offset; Break Case seek_end:newpos = 5*sizeof (int)-1 + offset; Break Default:return-einval; } if ((newpos<0) | | (newpos>5*sizeof (int))) Return-einval; Filp->f_pos = Newpos; return newpos;} /* File operation struct */static const struct file_operations mem_fops ={. Llseek = Mem_llseek,. Read = Mem_read,. Write = Mem_write, . open = Mem_open,. Release = mem_release,};/* device driver module load function */static int memdev_init (void) {/* Initialize CDEV structure */Cdev_init (&CD EV, &MEM_FOPS); /* Register character device */alloc_chrdev_region (&DEVNO, 0, 2, "Memdev"); Cdev_add (&cdev, Devno, 2);} /* Module unload function */static void memdev_exit (void) {Cdev_del (&cdev); /* Unregister device */Unregister_chrdev_region (DEVNO, 2); /* Release device number */}module_license ("GPL"); Module_init (Memdev_init); Module_exit (Memdev_exit);
Makefile file
Obj-m: = Memdev.okdir: =/home/s5-driver/lesson7/linux-tiny6410/all:make-c $ (kdir) m=$ (PWD) modules cross_compile= Arm-linux-arch=armclean:rm-f *.ko *.o *.mod.o *.mod.c *.symvers *.bak *.order
Compile the driver module and sync to the Development Board via the root file system of the NFS mounted Dev board
Installing the driver module Insmod Memdev.ko
Create a character device file: (because the application is using the device file to drive communication with the corresponding device, the instructions above)
Character device files and character device drivers are also linked by the main device number!
Cat/proc/device can see the main device number and device driver name!
From the above can be seen device driver Memdev corresponding device driver number is 252
Below to create a character device file with Mknod
Mdmdev0 the name of the device file (as long as it does not repeat with other names)
C stands for the creation of a character device file
252 is the device driver above the corresponding main device number 0 represents the secondary device number, here is a non-negative on the line
Application to access character device drivers via character device files: (here is the virtual character device file, as can be seen through the memdev.c above)
Read-memdev.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>int main () { int FD = 0;int DST = 0;/* to open the device file */FD = open ("/dev/memdev0", O_RDWR);/* Write Data */read (FD, &DST, sizeof (int));p rintf ("DST is% D\n ", DST);/* close Device */close (FD); return 0;}
Write-memdev.c
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>int main () { int fd = 0;int src = 2013;/* Open the device file */FD = open ("/dev/memdev0", O_RDWR);/* Write Data */write (FD, &SRC, sizeof (int));/* Turn off the device */ Close (FD); return 0;}
Cross-compiling, use static compilation here! Because some library boards have not been ported to the past!
For example, if you do not use the-static option to compile WRITE-MEM.C, running the application on the Development Board will appear
Here you can see that this app is running with libc.so.6 this dynamic link library! Then go to the Development Board of the system on the Lib directory down to see if there is no this library.
Empty, nothing, so there are two ways to solve this problem, one is to copy the library to the Lib directory, one way is to compile the time with the-static option to choose the static compilation of the method of compiling the program!
This is how the entire character device driver and application are linked together as well as the entire character driven device model introduction over!
Character Device driver Model