1. 程式人生 > 其它 >03.雜項裝置驅動

03.雜項裝置驅動

Linux三大裝置驅動

字元裝置:IO的傳輸過程是以字元為單位的,沒有緩衝。比如I2C,SPI都是字元裝置。

塊裝置:IO的傳輸過程是以塊為單位的。跟儲存相關的,都屬於塊裝置,比如TF卡。

網路裝置:與前倆個不一樣,是以socket套接字來訪問的。

雜項裝置(misc device)

1、 本小節講述的雜項裝置是屬於字元裝置的一種。可以自動生成裝置節點。

  我們的系統中有許多雜項裝置,可以輸入cat /proc/misc來檢視。

2、雜項裝置除了比字元裝置程式碼簡單,還有什麼區別?

  雜項裝置的主裝置號是相同的,均為10,次裝置號是不同的。主裝置號相同就可以節省核心的資源。

3、主裝置號和次裝置號是什麼?

  裝置號包括主裝置號和次裝置號,主裝置號在Linux系統裡是唯一的,次裝置號不一定唯一。

  裝置號是計算機識別裝置的一種方式,主裝置號相同的就被視作為同一類裝置。

  主裝置號可以比作成電話號碼的區號,比如北京的區號是010.

  次裝置號可以比作電話號碼。

  主裝置號可以通過命令cat /proc/devices來檢視。

4、雜項裝置的描述

  定義在核心原始碼路徑:include/linux/miscdevice.h

struct miscdevice  {
    int minor;//次裝置號
    const char *name;//裝置節點名字
    const struct file_operations *fops;//
檔案操作集 struct list_head list; struct device *parent; struct device *this_device; const char *nodename; mode_t mode; };

  include/linux/fs.h講述了檔案操作集的結構體定義

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 *, loff_t, loff_t, 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); };

  裡面的一個結構體成員都要對應一個呼叫。

extern int misc_register(struct miscdevice * misc);//註冊雜項裝置
extern int misc_deregister(struct miscdevice *misc);//登出雜項裝置

5、註冊雜項裝置的流程

  (1)填充miscdevice這個結構體。

  (2)填充file_operations這個結構體。

  (3)註冊雜項裝置並生成裝置節點。

雜項設備註冊實踐

按照5中講述的註冊雜項裝置的流程實現程式碼misc.c

 1 #include <linux/init.h>   
 2 #include <linux/module.h>
 3 #include <linux/miscdevice.h>
 4 #include <linux/fs.h>
 5 
 6 stuct file_operations misc_fops = {
 7     .owner = THIS_MODULE
 8 };
 9 
10 struct miscdevice misc_dev = {
11     ./minor = MISC_DYNAMIC_MINOR,//此巨集定義表示自動分配次裝置號
12     .name = "hello_misc",//裝置名
13     .fops = &misc_fops//檔案操作集
14     
15 };
16 static int misc_init(void)
17 {
18     int ret;
19     ret = misc_register(&misc_dev);
20     if(ret < 0)
21     {
22         printk("misc register is error\n");
23     }
24     
25     printk("misc register is succeed\n");
26     return 0;
27 }
28 
29 
30 static int misc_exit(void)
31 {
32     misc_deregister(&misc_dev);
33     printk("misc bye bye\n"); 
34     return 0;
35 }  
36 
37 module_init(hello_init);//模組入口
38 module_exit(hello_exit);//模組出口
39 
40 MODULE_LICENSE("GPL");

使用如下的Makefile,編譯成模組

obj-m +=helloworld.o #obj-m表示把驅動編譯成模組,生成的中間檔名字為helloworld.o

KDIR:=/home/topeet/topeet/imx6ull/linux-imx-rel_imx_4.1.15_2.1.0_ga #指定核心路徑

PWD?=$(shell pwd) #獲取當前目錄變數

all:
    make -C $(KDIR) M=$(PWD) modules #make進入到核心原始碼路徑因為編譯需要這個環境,把當前路徑程式碼編譯成模組

當然不要忘記指定核心的環境變數和交叉編譯配置

export CROSS_COMPILE=XXX
export ARCH=arm

編譯成功後,載入模組到板子上

insmod misc.ko

檢視現象,/dev/路徑下有hello_misc

這樣,一個最簡單的雜項裝置就完成了。