03.雜項裝置驅動
阿新 • • 發佈:2021-10-13
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) (structfile *, 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
這樣,一個最簡單的雜項裝置就完成了。