When we program the character device, we need to do some common preparations, get the device number, the registration of the device file operation function, the initialization of the file information, the kernel representation of the file, the registration to the kernel, and so on.
Access to the character device is done through the device name within the file system, usually in the/dev directory.
Use the first character of each line of Ls-l to identify the file type, and C is the character device driver file. B is the block device driver file.
The kernel uses primary and secondary device numbers to manage devices.
The main device number represents the corresponding driver (although Linux allows multiple drivers to share the main device number, but most of the devices are one driver for the main device number), and the secondary device number represents the specific device number.
Using the Ls-l command, the two columns of data that appear behind the user group are the primary and secondary device numbers.
Dev_t:<linux/types.h> a 32-bit number, 12 bits represents the main device number, and 20 bits represents the secondary device number.
In order to avoid conflict, we cannot directly define the primary and secondary device number, we should use the function to obtain the primary and secondary device number.
<linux/kdev_t.h>
MAJOR (dev_t dev);//Get the main device number
MINOR (dev_t dev);//Get the secondary device number
MKDEV (int major,int minor);//convert primary and secondary device number to dev_t type
<linux/fs.h>
int register_chrdev_region (dev_t from,unsigned int Count,char * name);//Get device number
Parameter: From: The device number of the main device number has been known
Count: The number of consecutive device numbers requested, if the General Assembly and the next main device number overlap, but as long as the allocation is passed, it can be used normally.
Name: The type of the device.
Return value: Successfully returned 0, failed to return the failure code. If it is negative, the number range for the request is not available.
int alloc_chrdev_region (dev_t *dev,unsigned int firstminor,unsigned int Count,char *name);//Get main device number
Parameters: Dev: Used for output, saved to the first number assigned after a successful call
Firstminor: To use the first secondary device number used, typically 0
Count: The number of consecutive device numbers requested, if the General Assembly and the next main device number overlap, but as long as the allocation is passed, it can be used normally.
Name: The type of the device.
Return value: Successfully returned 0, failed to return failure code.
void Unregister_chrdev_region (dev_t first,unsigned int count);//Release device number
Parameter: First: A number of the released device number
Count: Number of device numbers that need to be freed.
Usually called in the purge function.
The main device number is used to view in the/proc/devices file
Detailed device number usage in the/sys/dev directory
The character device operates using the file operation method
<linux/fs.h>
File_operations: Structure, the kernel is open to the driver of an interface, through the structure of the device can read and write operations and read and write operations to connect the drive.
struct File_operations {
The struct module *owner;//has a pointer to the module
loff_t (*llseek) (struct file *, loff_t, int);//change read/write location
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);//Read data
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//Write Data
ssize_t (*aio_read) (struct KIOCB *, const struct IOVEC *, unsigned long, loff_t);//asynchronous Read
ssize_t (*aio_write) (struct KIOCB *, const struct IOVEC *, unsigned long, loff_t);//Asynchronous Write
Int (*readdir) (struct file *, void *, filldir_t);//Read Directory
The/*poll method is the back-end of 3 system calls: Poll, Epoll, and select are used as queries against one or more file descriptors for read or write blocking. The poll method should return a bitmask indicating whether non-blocking reads or writes are possible, and, possibly, providing kernel information to make the calling process sleep until I/O becomes possible. If a driver's poll method is NULL, the device is assumed to be non-blocking readable and writable. */
unsigned int (*poll) (struct file *, struct poll_table_struct *);
Long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
Long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
Int (*mmap) (struct file *, struct vm_area_struct *);//request to map device memory to the address space of the process
Int (*open) (struct inode *, struct file *);//Open operation
Int (*flush) (struct file *, fl_owner_t ID);//Refresh
Int (*release) (struct inode *, struct file *);//Release
Int (*fsync) (struct file *, int datasync),//fsync system call backend, user calls to refresh any data that hangs
Int (*aio_fsync) (struct KIOCB *, int datasync);//Asynchronous version
Int (*fasync) (int, struct file *, int);//This operation is used to notify the device of the change of its Fasync flag, asynchronous
Int (*lock) (struct file *, int, struct file_lock *);//Lock
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area) (struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
Int (*check_flags) (int);//Check flag
Int (*flock) (struct file *, int, struct file_lock *);
ssize_t (*splice_write) (struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
ssize_t (*splice_read) (struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
Int (*setlease) (struct file *, long, struct file_lock * *);
Long (*fallocate) (struct file *file, int mode, loff_t offset,loff_t len);
};
Interface Docking:
struct File_operations op = {
. Owner = This_module,
. Read = Test_read,
. write = Test_write,
};
File structure: Some information about open files
Inode struct: Represents a file
dev_t I_rdev: The inode structure that represents the device file that contains the true device number
struct Cdev *i_cdev: internal build of the kernel that represents the character device, which contains pointers to struct CDEV structures when indoe points to a character device file
unsigned int iminor (struct inode *inode);//Get secondary device number from Indoe
unsigned int imajor (struct inode *inode);//Get main device number from Indoe
<linux/cedv.h>
CEDV structure: Represents a character device
struct Cdev *my_cdev = Cdev_alloc ();//Application space
Cdev->owner = this_module;//Owner
Registering interface functions
struct File_operations *fops;
Cdev_init (My_cdev,fops);
int Cdev_add (struct cdev *p, dev_t Dev, unsigned count);
Tell the kernel that the structure of the information, after the addition of the device can be used, so it is necessary to initialize everything after the completion of operation
Parameters: Cdev structure pointer holding information
Dev Device number
Count: Number of devices, typically 1
Return value: 0 successful, error returned error code
void Cdev_del (struct cdev *p);//removal of the character device from the system
Character Device driver programming (i)