Linux Device Driver Development - Everything You Need To Start With Device Driver Development For Linux Kernel 已经读到141页
4 Writing Character Device Drivers
linux一切文件的思想,每一个在系统注册了的设备都有一个对应的文件在 /dev 里,把硬件暴露在用户空间,对这个文件的操作会重定位到文件代表的设备的驱动
ll /dev
c开头的就是字符设备,character devices are slow and transfer data to or from user applications sequentially byte by byte; include serial ports and input devices (keyboards, mouses, touchpads, video devices, and so on).
b开头的是块设备, block devices are fast, since they are accessed quite frequently and transfer data in blocks. Such devices are essentially storage devices (hard drives, CD-ROMs, solid-state drives, and so on).
The major number either identifies the type of device or can be bound to a driver. The minor number either identifies a device locally to the driver or devices of the same type;第五列和第六列的数字,前一个是设备种类编号称主号major,比如179代表disk,后一个是特定设备类型的设备编号 叫 minor
Character device data structure introduction
include /linux/cdev.h
struct cdev {
struct kobject kobj;
struct module *owner;
const struct file_operations *ops;
dev_t dev;
[...]
};
kobj: This is the underlying kernel object for this character device object, used to enforce the Linux device model. We will discuss this in Chapter 14, Introduction to the Linux Device Model.
owner: This should be set with the THIS_MODULE macro.
ops: This is the set of file operations associated with this character device. 该字符设备支持的文件操作
dev: This is the character device identifier.
An introduction to device file operations
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *, fl_owner_t id);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, loff_t, loff_t, int datasync);
int (*flock) (struct file *, int, struct file_lock *);
[...]
}; # /linux/ fs.h ;
• struct module *owner: This is a mandatory field that should point to the module owning this structure. It is used for proper reference counting. Most of the time, it is set to THIS_MODULE, a macro defined in .
• loff_t (*llseek) (struct file *, loff_t, int);: This method is used to move the current cursor position in the file given as the first parameter. On a successful move, the function must return the new position, or else a negative value must be returned. If this method is not implemented, then every seek performed on this file will succeed by modifying the position counter in the file structure (file->f_pos), except the seek relative to end-of-file, which will fail.
• ssize_t (*read) (struct file *, char *, size_t, loff_t *);: The role of this function is to retrieve data from the device. Since the return value is a "signed size" type, this function must return either the number (positive) of bytes successfully read, or else return an appropriate negative code on error. If this function is not implemented, then any read() system call on the device file will fail, returning with -EINVAL (an "invalid argument").
• ssize_t (*write) (struct file *, const char *, size_t, loff_t *);: The role of this function is to send data to the device. Like the read() function, it must return a positive number, which, in this case, represents the number of bytes that have been written successfully, or else return an appropriately negative code on error. In the same way, if it is not implemented in the driver, then the write() system call attempt will fail with -EINVAL.
• int (*flush) (struct file *, fl_owner_t id);: This operation is invoked when the file structure is being released. Like open, release can be NULL.
• unsigned int (*poll) (struct file *, struct poll_table_ struct *);: This file operation must return a bitmask describing the status of the device. It is the kernel backend for both poll() and select() system calls, both used to query whether the device is writable, readable, or in some special state. Any caller of this method will block until the device enters the requested state. If this file operation is not implemented, then the device is always assumed to be readable, writable, and in no special state.
• int (*mmap) (struct file *, struct vm_area_struct *);: This is used to request part or all of the device memory to be mapped to a process address space. If this file operation is not implemented, then any attempt to invoke the mmap() system call on the device file will fail, returning -ENODEV.
• int (*open) (struct inode *, struct file *); This file operation is the backend of the open() system call, which, if not implemented (if NULL), will result in the success of any attempt to open the device and the driver won't be notified of the operation.
• int (*release) (struct inode *, struct file *);: This is invoked when the file is being released, in response to the close() system call. Like open, release is not mandatory and can be NULL.
• int (*fsync) (struct file *, loff_t, loff_t, int datasync);: This operation is the backend of the fsync() system call, whose purpose is to flush any pending data. If it is not implemented, any call to fsync() on the device file will fail, returning -EINVAL.
• long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);: This is the backend of the ioctl system call, whose purpose is to extend the commands that can be sent to the device (such as formatting a track of a floppy disk, which is neither reading nor writing). The commands defined by this function will extend a set of predefined commands that are already recognized by the kernel without referring to this file operation. Thus, for any command that is not defined (either because this function is not implemented or because it does not support the specified command), the system call will return -ENOTTY, to say "No such ioctl for device". Any non-negative value returned by this function is passed back to the calling program to indicate successful completion.
File representation in the kernel
inode refers to a file on the disk #struct inode * 指向disk中的文件
struct file structure associated with a file descriptor within a process #struct file * 指向进程中打开的文件描述符
Creating a device node
Device identification
include/linux/kdev_t.h
a 32-bit unsigned integer in which the major is represented by the first 12 bits, and the minor is coded on the 20 remaining bits.
#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) #accepts a minor and a major number and returns a dev_t type identifier,
Registration and deregistration of character device numbers
int register_chrdev_region(dev_t first, unsigned int count, char *name); #知道主号major ,静态注册
This method returns 0 on success, or a negative error code when it fails. The first parameter is the identifier you must have built using the major number and the first minor of the desired range. You can use the MKDEV(maj, min) macro to achieve that. count is the number of consecutive device minors required, and name should be the name of the associated device or driver
int alloc_chrdev_region( dev_t *dev, unsigned int firstminor, unsigned int count, char *name); #由系统分配 major ,跟 firstminor 生成 dev。推荐使用
This method returns 0 on success, or a negative error code on failure. dev is the only output parameter. It represents the first number (built using the allocated major and the first minor requested) that the kernel assigned. firstminor is the first of the requested range of minor numbers, count is the number of consecutive minors you need, and name should be the name of the associated device or driver.
Initializing and registering a character device on the system
initialize the character device and add it to the system using cdev_init() and cdev_add(), respectively:
void cdev_init(struct cdev *cdev, const struct file_operations *fops); #初始化字符设备
int cdev_add (struct cdev * p, dev_t dev, unsigned count); #把字符设备加入系统中
In cdev_init(), cdev is the structure to initialize, and fops the file_operations instance for this device, making it ready to add to the system. In cdev_add(), p is the cdev structure for the device, dev is the first device number for which this device is responsible (obtained dynamically), and count is the number of consecutive minor numbers corresponding to this device. When it succeeds, cdev_add() returns 0, or else it returns a negative error code.
删除字符设备:
void cdev_del(struct cdev *);
cdev add之后 /dev 并不会出现 使用下面的device_create创建 node:
struct device * device_create(struct class *class, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...)
class 创建后将出现在 /sys/class ;
Implementing file operations 实现文件操作
unsigned long copy_from_user(void *to, const void __user *from, unsigned long n)
unsigned long copy_to_user(void __user *to, const void *from, unsigned long n)
__user point to the user space (untrusted) memory;Each of these returns the number of bytes that could not be copied, if any, while they return 0 on success. Note that these routines may sleep as they run in a user context and do not need to be invoked in an atomic context.
Implementing the open file operation
int (*open) (struct inode *inode, struct file *filp);
Per-device data
Implementing the release file operation
free所有 open 里面占用的资源
Implementing the write file operation
ssize_t(*write)(struct file *filp, const char __user *buf, size_t count, loff_t *pos);
Implementing the read file operation
ssize_t (*read) (struct file *filp, char __user *buf, size_t count, loff_t *pos);
Implementing the llseek file operation
loff_t(*llseek) (struct file *filp, loff_t offset, int whence);
The poll method
unsigned int (*poll) (struct file *, struct poll_table_struct *);
The kernel function at the heart of this method implementation is poll_wait(), defined in <linux/poll.h> , which is the header you must include in the driver code. It has the following declaration:
void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
The ioctl method
long ioctl(struct file *f, unsigned int cmd, unsigned long arg);
_IO(MAGIC, SEQ_NO)
_IOR(MAGIC, SEQ_NO, TYPE)
_IOW(MAGIC, SEQ_NO, TYPE)
_IORW(MAGIC, SEQ_NO, TYPE)
This is well documented in Documentation/ioctl/ioctl-decoding.txt in the kernel sources, and existing IOCTL commands are listed in Documentation/ioctl/ ioctl-number.txt, a good place to start when you need to create your own IOCTL commands.
Generating an IOCTL number (a command)
标签:字符,struct,17,int,unsigned,dev,2023.7,file,device From: https://www.cnblogs.com/yangdinshan/p/17561539.html