Linux驱动开发基础

最近看了《Linux设备驱动详解这本书》,简单总结Linux设备驱动开发的一些基础知识。

2.1.Linux设备驱动程序入口函数

module_init(xxx_init);
module_exit(xxx_exit);

module_init和module_exit是两个宏,module_init是驱动程序的入口函数,相当于我们应用程序的main函数,module_exit是清理函数。

这两个宏展开函数分别在insmod的时候和rmmod的时候调用,并且insmod和rmmod只识别这两个特殊的函数。

2.设备号

设备号分为主设备号和次设备号。
主设备号:表示设备对应的驱动程序。因此,主设备号不应该冲突,最好使用alloc_chardev_region而不是register_chardev_region来指定主设备号。
次设备号:由内核使用,用于正确确定设备文件所指的设备。

在内核中,用dev_t表示设备编号,包括主设备号和次设备号。

/* <linux/kdev_t.h> */
#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))

要获得主设备号和次设备号:

MAJOR(dev_t dev); //返回unsigned int
MINOR(dev_t dev); //返回unsigned int

如果要生成dev_t:
MKDEV(int major, int minor);

3.三大结构体

3.1文件操作结构体 struct file_operations

文件操作结构体是驱动程序中最重要的结构体之一,文件操作结构体用来实现核心的系统调用,使应用程序可以通过open/read/write…等系统调用才操作和控制我们的驱动程序。反正,我们的驱动程序也是依托这些函数指针的具体实现来为应用程序服务的。

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 *);
    ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    int (*readdir) (struct file *, void *, filldir_t);
    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 *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, int datasync);
    int (*aio_fsync) (struct kiocb *, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_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);
    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);
};

说明一下owner,owner是一个指向拥有这个结构的驱动模块的指针.这个成员可以在对他的操作时,阻止模块被卸载。它一般被简单初始化为一个宏THIS_MODULE, 一个在<linux/module.h> 中定义的宏.

3.2文件结构体 struct file

file结构体代表一个打开文件(不仅限于设备,系统中所有打开文件,都有一个对应的file结构体)。它由系统调用open创建,由系统调用close销毁。主要标记了,打开模式(只读、读写)、阻塞或非阻塞,等等。对应文件描述符,一个文件描述符,就有一个struct file结构体。

3.3 inode结构体 struct inode

内核用inode结构体在内部表示文件,与struct file不同的是,inode在内核中只有一份。一个文件被打开多次,那么会有多个struct file指向这个struct inode。

Linux驱动开发基础

原文地址:https://blog.51cto.com/14207158/2521988

为您推荐

发表评论

电子邮件地址不会被公开。 必填项已用*标注