4412 字符类设备的设备号
生活随笔
收集整理的這篇文章主要介紹了
4412 字符类设备的设备号
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
一、靜態(tài)申請(qǐng)字符類設(shè)備號(hào)
- 字符類設(shè)備函數(shù)在文件"include/linux/fs.h"中
- 內(nèi)核提供了三個(gè)函數(shù)來注冊(cè)一組字符設(shè)備編號(hào),這三個(gè)函數(shù)分別是
- register_chrdev_region()
- alloc_chrdev_region()
- register_chrdev()
- register_chrdev_region()是提前知道設(shè)備的主次設(shè)備號(hào),再去申請(qǐng)?jiān)O(shè)備號(hào)
- alloc_chrdev_region()是動(dòng)態(tài)分配主次設(shè)備號(hào)
- register_chrdev() 是老版本的設(shè)備號(hào)注冊(cè)方式,只分配主設(shè)備號(hào)。從設(shè)備號(hào)在mknod的時(shí)候指定。
?
- 宏定義MKDEV的頭文件"include/linux/kdev.h"
- 在kdev_t.h頭文件中有一個(gè)系列設(shè)備號(hào)處理的宏命令,用于處理各種設(shè)備號(hào)相關(guān)的數(shù)據(jù)。本期視頻只介紹MKDEV,后面使用了其他宏定義再介紹
- include/linux/cdev.h
- cdev類型是字符設(shè)備描述的結(jié)構(gòu)
- 其次的設(shè)備號(hào)必須用"dev_t"類型來描述,高12位為主設(shè)備號(hào),低20位為此設(shè)備號(hào)
?
編寫編譯運(yùn)行
- 將視頻"16_驅(qū)動(dòng)模塊傳參數(shù)"中的文件"module_param.c"改成為"request_cdev_num.c",靜態(tài)生成設(shè)備號(hào)
- 編寫,編譯
- 加載運(yùn)行
- 使用命令"cat /proc/devices"查看已經(jīng)被注冊(cè)的主設(shè)備,設(shè)備號(hào)9沒有被注冊(cè)
- insmod /mnt/udisk/request_cdev_num.ko numdev_major=9 numdev_minor=0
- 使用命令"cat /proc/devices"查看,設(shè)備號(hào)9被注冊(cè)為scdev
- rmmod request_cdev_num numdev_major=9 numdev_minor=0
測(cè)試結(jié)果:
[root@iTOP-4412]# insmod request_cdev_num.ko numdev_major=9 numdev_minor=0 [ 135.652085] numdev_major is 9! [ 135.653710] numdev_minor is 0! [ 135.656810] Hello World enter! [root@iTOP-4412]# cat /proc/devices Character devices:1 mem4 ttyS5 /dev/tty5 /dev/console5 /dev/ptmx9 scdev10 misc13 input21 sg29 fb81 video4linux89 i2c 108 ppp 116 alsa 128 ptm 136 pts 153 rc522_test 166 ttyACM 180 usb 188 ttyUSB 189 usb_device 204 ttySAC 216 rfcomm 243 ump 244 mali 249 mt3326-gps 250 roccat 251 BaseRemoteCtl 252 media 253 ttyGS 254 rtcBlock devices:1 ramdisk 259 blkext7 loop8 sd65 sd66 sd67 sd68 sd69 sd70 sd71 sd 128 sd 129 sd 130 sd 131 sd 132 sd 133 sd 134 sd 135 sd 179 mmc 254 device-mapper [root@iTOP-4412]# rmmod request_cdev_num numdev_major=9 numdev_minor=0 [ 152.245805] Hello World exit! [root@iTOP-4412]# cat /proc/devices Character devices:1 mem4 ttyS5 /dev/tty5 /dev/console5 /dev/ptmx10 misc13 input21 sg29 fb81 video4linux89 i2c 108 ppp 116 alsa 128 ptm 136 pts 153 rc522_test 166 ttyACM 180 usb 188 ttyUSB 189 usb_device 204 ttySAC 216 rfcomm 243 ump 244 mali 249 mt3326-gps 250 roccat 251 BaseRemoteCtl 252 media 253 ttyGS 254 rtcBlock devices:1 ramdisk 259 blkext7 loop8 sd65 sd66 sd67 sd68 sd69 sd70 sd71 sd 128 sd 129 sd 130 sd 131 sd 132 sd 133 sd 134 sd 135 sd 179 mmc 254 device-mapper [root@iTOP-4412] 測(cè)試結(jié)果?
二、動(dòng)態(tài)申請(qǐng)字符類設(shè)備號(hào)
- 字符設(shè)備函數(shù)在文件"include/linux/fs.h"中
- alloc_chrdev_region()是動(dòng)態(tài)分配主次設(shè)備號(hào)
- 宏定義MAJOR提取dev_t數(shù)據(jù)中的主設(shè)備號(hào)
編寫編譯運(yùn)行
- 將視頻"17"中的文件"request_cdev_num.c改寫為"request_ascdev_num.c"動(dòng)態(tài)生成字符設(shè)備號(hào)
- 編寫,編譯
- 加載運(yùn)行
- 使用命令"cat /proc/device"查看
- 動(dòng)態(tài)加載模塊之后再查看設(shè)備號(hào)
?修改后的代碼:
#include <linux/init.h> #include <linux/module.h>/* define module_param module_param_array header file */ #include <linux/moduleparam.h> /* define perm's head file*/ #include <linux/stat.h> /* char device register head file */ #include <linux/fs.h> /* MKDEV change device ID type */ #include <linux/kdev_t.h> /* define char device struct */ #include <linux/cdev.h>#define DEVICE_NAME "scdev" #define DEVICE_MINOR_NUM 2 #define DEV_MAJOR 0 #define DEV_MINOR 0MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET");int numdev_major = DEV_MAJOR; int numdev_minor = DEV_MINOR;/* input major device ID */ module_param(numdev_major, int, S_IRUSR); /* input minor device ID */ module_param(numdev_minor, int, S_IRUSR);static int hello_init(void) {int ret;dev_t num_dev;printk(KERN_EMERG "numdev_major is %d!\n", numdev_major);printk(KERN_EMERG "numdev_minor is %d!\n", numdev_minor);if(numdev_major) {num_dev = MKDEV(numdev_major, numdev_minor);ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);} else {ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);numdev_major = MAJOR(num_dev);printk(KERN_EMERG "register req major number is %d\n", numdev_major);}if(ret < 0) {printk(KERN_EMERG "register_chrdev_region req %d is failed\n", numdev_major);unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);return ret;}printk(KERN_EMERG "Hello World enter!\n");return 0; }static void hello_exit(void) {dev_t num_dev = MKDEV(numdev_major, numdev_minor);unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);printk(KERN_EMERG "Hello World exit!\n"); }module_init(hello_init); module_exit(hello_exit); alloc_chrdev_region代碼測(cè)試運(yùn)行后:
[root@iTOP-4412]# insmod request_ascdev_num.ko [ 1335.710205] numdev_major is 0! [ 1335.711817] numdev_minor is 0! [ 1335.714861] register req major number is 248 [ 1335.727258] Hello World enter! [root@iTOP-4412]# cat /proc/ 1/ 670/ bus/ mfc/ 11907/ 714/ cgroups misc 12924/ 726/ cmdline modules 12925/ 731/ consoles mounts 12926/ 734/ cpu/ net/ 16/ 744/ cpuinfo pagetypeinfo 2/ 745/ crypto panic_info_dump 3/ 763/ devices partitions 339/ 767/ diskstats sched_debug 341/ 838/ driver/ scsi/ 343/ 866/ execdomains self/ 354/ 892/ fb softirqs 365/ 894/ filesystems stat 376/ 896/ fs/ sys/ 429/ 898/ interrupts sysrq-trigger 445/ 900/ iomem sysvipc/ 455/ 911/ ioports timer_list 456/ 918/ irq/ tty/ 5/ 919/ kallsyms uid_stat/ 508/ 9192/ key-users uptime 522/ 940/ kmsg version 528/ 943/ kpagecount vmallocinfo 6/ 956/ kpageflags vmstat 6437/ 994/ loadavg wakelocks 657/ asound/ locks zoneinfo 662/ buddyinfo meminfo [root@iTOP-4412]# cat /proc/devices Character devices:1 mem4 ttyS5 /dev/tty5 /dev/console5 /dev/ptmx10 misc13 input21 sg29 fb81 video4linux89 i2c 108 ppp 116 alsa 128 ptm 136 pts 153 rc522_test 166 ttyACM 180 usb 188 ttyUSB 189 usb_device 204 ttySAC 216 rfcomm 243 ump 244 mali 248 scdev 249 mt3326-gps 250 roccat 251 BaseRemoteCtl 252 media 253 ttyGS 254 rtc 測(cè)試?
三、注冊(cè)字符類設(shè)備
- 分配內(nèi)存空間函數(shù)kmalloc
- 分配連續(xù)的虛擬地址,用于小內(nèi)存分配。在include/linux/slab.h文件中
- 參數(shù)1:申請(qǐng)的內(nèi)存大小(最大128K)
- 參數(shù)2:GFP_KERNEL,代表優(yōu)先權(quán),內(nèi)存不夠可以延遲分配
- 清空內(nèi)存空間的數(shù)據(jù)函數(shù)memset
- 可以清空內(nèi)存空間,也就是全部寫為0
- 參數(shù)1:內(nèi)存地址
- 參數(shù)2:0
- 參數(shù)3:內(nèi)存長(zhǎng)度
- 字符設(shè)備初始化函數(shù)cdev_init
- 在頭文件include/linux/cdev.h中
- 參數(shù)1:cdev字符設(shè)備文件結(jié)構(gòu)體
- 參數(shù)2:file_operations結(jié)構(gòu)體
- 注冊(cè)設(shè)備本質(zhì)是向linux設(shè)備文件中添加數(shù)據(jù),這些數(shù)據(jù)需要初始化
- 字符設(shè)備注冊(cè)函數(shù)cdev_add
- 在頭文件include/linux/cdev.h中
- 參數(shù)1:cdev字符設(shè)備文件結(jié)構(gòu)體
- 參數(shù)2:設(shè)備號(hào)
- 參數(shù)3:設(shè)備范圍大小
- 向系統(tǒng)注冊(cè)設(shè)備,也就是向linux系統(tǒng)添加數(shù)據(jù)
- 卸載設(shè)備函數(shù)cdev_del
- 參數(shù)1:cdev結(jié)構(gòu)體
- 移除字符設(shè)備
- 將"18_動(dòng)態(tài)申請(qǐng)字符類設(shè)備號(hào)"中的文件"request_ascdev_num.c"改寫為"register_cdev.c"
- 編譯
- 測(cè)試
- 通過加載模塊后的打印信息,可以觀察到驅(qū)動(dòng)加載的過程以及注冊(cè)設(shè)備的反饋信息
?代碼:
#include <linux/init.h> #include <linux/module.h>/* define module_param module_param_array header file */ #include <linux/moduleparam.h> /* define perm's head file*/ #include <linux/stat.h> /* char device register head file */ #include <linux/fs.h> /* MKDEV change device ID type */ #include <linux/kdev_t.h> /* define char device struct */ #include <linux/cdev.h> /* define memroy sapce */ #include <linux/slab.h>#define DEVICE_NAME "scdev" #define DEVICE_MINOR_NUM 2 #define DEV_MAJOR 0 #define DEV_MINOR 0 #define REGDEV_SIZE 3000MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET");int numdev_major = DEV_MAJOR; int numdev_minor = DEV_MINOR;/* input major device ID */ module_param(numdev_major, int, S_IRUSR); /* input minor device ID */ module_param(numdev_minor, int, S_IRUSR);struct reg_dev {char *data;unsigned long size;struct cdev cdev; }; struct reg_dev *my_devices;struct file_operations my_fops = {.owner = THIS_MODULE, };static void reg_init_cdev(struct reg_dev *dev, int index) {int err;int devno = MKDEV(numdev_major, numdev_minor+index);cdev_init(&dev->cdev, &my_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &my_fops;err = cdev_add(&dev->cdev, devno, 1);if(err) {printk(KERN_EMERG "cdev_add %d is fail! %d\n", index, err);} else {printk(KERN_EMERG "cdev_add %d is success!\n", index);} }static int hello_init(void) {int ret, i;dev_t num_dev;printk(KERN_EMERG "numdev_major is %d!\n", numdev_major);printk(KERN_EMERG "numdev_minor is %d!\n", numdev_minor);if(numdev_major) {num_dev = MKDEV(numdev_major, numdev_minor);ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);} else {ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);numdev_major = MAJOR(num_dev);printk(KERN_EMERG "register req major number is %d\n", numdev_major);}if(ret < 0) {printk(KERN_EMERG "register_chrdev_region req %d is failed\n", numdev_major);unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);return ret;}my_devices = kmalloc(DEVICE_MINOR_NUM*sizeof(struct reg_dev), GFP_KERNEL);if(!my_devices) {ret = -ENOMEM;printk(KERN_EMERG "kamlloc fialed!\n");goto fail;}memset(my_devices, 0, DEVICE_MINOR_NUM*sizeof(struct reg_dev));for(i=0;i<DEVICE_MINOR_NUM;i++) {my_devices[i].data = kmalloc(REGDEV_SIZE, GFP_KERNEL);memset(my_devices[i].data, 0, REGDEV_SIZE); /* data address */reg_init_cdev(&my_devices[i], i);}printk(KERN_EMERG "Hello World enter!\n");return 0;fail:unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);return ret; }static void hello_exit(void) {int i;dev_t num_dev = MKDEV(numdev_major, numdev_minor);printk(KERN_EMERG "Hello World exit!\n");for(i=0;i<DEVICE_MINOR_NUM;i++) {cdev_del(&my_devices[i].cdev);}unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM); }module_init(hello_init); module_exit(hello_exit); 代碼測(cè)試結(jié)果:
[root@iTOP-4412]# insmod register_cdev.ko [ 1065.781646] numdev_major is 0! [ 1065.783265] numdev_minor is 0! [ 1065.786377] register req major number is 248 [ 1065.790637] cdev_add 0 is success! [ 1065.793943] cdev_add 1 is success! [ 1065.797392] Hello World enter! [root@iTOP-4412]# rmmod register_cdev [ 1082.904729] Hello World exit 測(cè)試結(jié)果?
四、生成字符類設(shè)備節(jié)點(diǎn)
前面介紹設(shè)備中的模型:bus,device,driver,都是有比較明顯確定的定義。bus代表總線,device代表實(shí)際的設(shè)備和接口,driver代表驅(qū)動(dòng)。
class是設(shè)備類,它是一個(gè)抽象的概念,沒有對(duì)應(yīng)的實(shí)體。它是提供給用戶接口相似的一類設(shè)備的集合。常見的輸入子系統(tǒng)input、usb、串口tty‘塊設(shè)備block等。
- 函數(shù)class_create創(chuàng)建class類文件
- 參數(shù)1:一般是THIS_MODULE
- 參數(shù)2:設(shè)備名稱
- 創(chuàng)建一個(gè)設(shè)備類,用于設(shè)備節(jié)點(diǎn)文件的創(chuàng)建
- 返回一個(gè)class結(jié)構(gòu)體變量
- class結(jié)構(gòu)體變量
- class是設(shè)備驅(qū)動(dòng)模型中通用的設(shè)備結(jié)構(gòu)
- 在頭文件include/linux/device.h的280行
- 老版本:創(chuàng)建設(shè)備class函數(shù)class_device_create
- 頭文件include/linux/device.h中
- 參數(shù)1:class結(jié)構(gòu)體變量
- 參數(shù)2:父設(shè)備NULL
- 參數(shù)3:dev_t設(shè)備號(hào)
- 參數(shù)4:數(shù)據(jù)NULL
- 參數(shù)5:設(shè)備節(jié)點(diǎn)名稱
- 釋放設(shè)備class函數(shù)class_destroy
- 參數(shù)1:myclass
- 創(chuàng)建設(shè)備節(jié)點(diǎn)函數(shù)device_create
- 頭文件include/linux/device.h中
- 參數(shù)1:設(shè)備誒所屬于的類
- 參數(shù)2:設(shè)備的浮設(shè)備,NULL
- 參數(shù)3:設(shè)備號(hào)
- 參數(shù)4:設(shè)備數(shù)據(jù),NULL
- 參數(shù)5:設(shè)備名稱
- 摧毀設(shè)備節(jié)點(diǎn)函數(shù)device_destroy
- 參數(shù)1:設(shè)備所屬于的類
- 參數(shù)2:設(shè)備號(hào)
- 釋放內(nèi)存函數(shù)kfree
- 參數(shù)1:數(shù)據(jù)指針
?編寫編譯運(yùn)行測(cè)試
- 將"19注冊(cè)字符類設(shè)備"中的"register_cdev.c"文件為"create_cnode.c"
- 編譯
- 加載模塊"create_cnode.ko"
- 使用命令"ls /sys/class/"可以查看到生成的class
- 使用命令"ls /dev"可以查看到生成的兩個(gè)設(shè)備節(jié)點(diǎn)
- 加載模塊的時(shí)候還可以使用命令生成設(shè)備節(jié)點(diǎn)命令,列如
- mknod dev/test0 c 249 0
- mknod dev/test1 c 249 1
?運(yùn)行代碼:
#include <linux/init.h> #include <linux/module.h>/* define module_param module_param_array header file */ #include <linux/moduleparam.h> /* define perm's head file*/ #include <linux/stat.h> /* char device register head file */ #include <linux/fs.h> /* MKDEV change device ID type */ #include <linux/kdev_t.h> /* define char device struct */ #include <linux/cdev.h> /* define memroy sapce */ #include <linux/slab.h>/* include device_create class file */ #include <linux/device.h>#define DEVICE_NAME "chardevnode" #define DEVICE_MINOR_NUM 2 #define DEV_MAJOR 0 #define DEV_MINOR 0 #define REGDEV_SIZE 3000MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET");int numdev_major = DEV_MAJOR; int numdev_minor = DEV_MINOR;/* input major device ID */ module_param(numdev_major, int, S_IRUSR); /* input minor device ID */ module_param(numdev_minor, int, S_IRUSR);static struct class *my_class;struct reg_dev {char *data;unsigned long size;struct cdev cdev; }; struct reg_dev *my_devices;struct file_operations my_fops = {.owner = THIS_MODULE, };static void reg_init_cdev(struct reg_dev *dev, int index) {int err;int devno = MKDEV(numdev_major, numdev_minor+index);cdev_init(&dev->cdev, &my_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &my_fops;err = cdev_add(&dev->cdev, devno, 1);if(err) {printk(KERN_EMERG "cdev_add %d is fail! %d\n", index, err);} else {printk(KERN_EMERG "cdev_add %d is success!\n", (numdev_minor+index));} }static int hello_init(void) {int ret, i;dev_t num_dev;printk(KERN_EMERG "numdev_major is %d!\n", numdev_major);printk(KERN_EMERG "numdev_minor is %d!\n", numdev_minor);if(numdev_major) {num_dev = MKDEV(numdev_major, numdev_minor);ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);} else {ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);numdev_major = MAJOR(num_dev);printk(KERN_EMERG "register req major number is %d\n", numdev_major);}if(ret < 0) {printk(KERN_EMERG "register_chrdev_region req %d is failed\n", numdev_major);unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);return ret;}my_class = class_create(THIS_MODULE, DEVICE_NAME);my_devices = kmalloc(DEVICE_MINOR_NUM*sizeof(struct reg_dev), GFP_KERNEL);if(!my_devices) {ret = -ENOMEM;printk(KERN_EMERG "kmalloc fialed!\n");goto fail;}memset(my_devices, 0, DEVICE_MINOR_NUM*sizeof(struct reg_dev));for(i=0;i<DEVICE_MINOR_NUM;i++) {my_devices[i].data = kmalloc(REGDEV_SIZE, GFP_KERNEL);memset(my_devices[i].data, 0, REGDEV_SIZE); /* data address *//* register device to system */reg_init_cdev(&my_devices[i], i);/* create device node */device_create(my_class, NULL, MKDEV(numdev_major, numdev_minor+i), "NULL", DEVICE_NAME"%d", i);}printk(KERN_EMERG "Hello World enter!\n");return 0;fail:unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);return ret; }static void hello_exit(void) {int i;dev_t num_dev = MKDEV(numdev_major, numdev_minor);printk(KERN_EMERG "Hello World exit!\n");for(i=0;i<DEVICE_MINOR_NUM;i++) {cdev_del(&my_devices[i].cdev);/* release memory*/device_destroy(my_class, MKDEV(numdev_major, numdev_minor+i));}/* release my class*/class_destroy(my_class);/* release kfre */kfree(my_devices);unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM); }module_init(hello_init); module_exit(hello_exit); class_create測(cè)試結(jié)果:
[root@iTOP-4412]# insmod create_cnode.ko [12828.419006] numdev_major is 0! [12828.420699] numdev_minor is 0! [12828.423674] register req major number is 248 [12828.429116] cdev_add 0 is success! [12828.432882] cdev_add 1 is success! [12828.436403] Hello World enter![root@iTOP-4412]# cat /proc/devices Character devices:1 mem4 ttyS5 /dev/tty5 /dev/console5 /dev/ptmx10 misc13 input21 sg29 fb81 video4linux89 i2c 108 ppp 116 alsa 128 ptm 136 pts 153 rc522_test 166 ttyACM 180 usb 188 ttyUSB 189 usb_device 204 ttySAC 216 rfcomm 243 ump 244 mali 248 chardevnode 249 mt3326-gps 250 roccat 251 BaseRemoteCtl 252 media 253 ttyGS 254 rtc[root@iTOP-4412]# rmmod create_cnode [12439.491484] Hello World exit! 測(cè)試結(jié)果?
五、字符驅(qū)動(dòng)
- file_operations中的函數(shù)比較多,選取用的比較多的函數(shù)簡(jiǎn)單介紹,后面的驅(qū)動(dòng)教程中調(diào)用了對(duì)應(yīng)的函數(shù),再詳細(xì)介紹
- int (*open)(struct inode *, struct file *)
- 打開函數(shù)
- int (*release)(struct inode *, struct file *)
- 釋放close函數(shù)
- long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long)
- io控制函數(shù)
- ssize_t (*read)(struct file *, char __user *, size_t, loff_t *)
- 讀函數(shù)
- ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *)
- 寫函數(shù)
- loff_t (*llseek)(struct file *, loff_t, int)
- 定位函數(shù)
- 如果需要不同的設(shè)備節(jié)點(diǎn)有不同的功能,只需要在注冊(cè)設(shè)備的時(shí)候添加不同的file_operations結(jié)構(gòu)體即可
- 編寫編譯運(yùn)行測(cè)試
- 將驅(qū)動(dòng)視頻教程20中的"create_cnode.c"改為“char_driver.c”
- 修改編譯文件Makefile
- 將驅(qū)動(dòng)視頻教程09中"invoke_hello.c"改為"invoke_char_driver.c",編譯應(yīng)用命令如下
- arm-none-linux-gnueabi-gcc -o invoke_char_driver invoke_char_driver.c -static
?編寫代碼:
#include <linux/init.h> #include <linux/module.h>/* define module_param module_param_array header file */ #include <linux/moduleparam.h> /* define perm's head file*/ #include <linux/stat.h> /* char device register head file */ #include <linux/fs.h> /* MKDEV change device ID type */ #include <linux/kdev_t.h> /* define char device struct */ #include <linux/cdev.h> /* define memroy sapce */ #include <linux/slab.h>/* include device_create class file */ #include <linux/device.h>#define DEVICE_NAME "chardevnode" #define DEVICE_MINOR_NUM 2 #define DEV_MAJOR 0 #define DEV_MINOR 0 #define REGDEV_SIZE 3000MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET");int numdev_major = DEV_MAJOR; int numdev_minor = DEV_MINOR;/* input major device ID */ module_param(numdev_major, int, S_IRUSR); /* input minor device ID */ module_param(numdev_minor, int, S_IRUSR);static struct class *my_class;struct reg_dev {char *data;unsigned long size;struct cdev cdev; }; struct reg_dev *my_devices;/* open */ static int chardevnode_open(struct inode *inode, struct file *file) {printk(KERN_EMERG "chardevnode open is success!\n");return 0; }/* close */ static int chardevnode_release(struct inode *indoe, struct file *file) {printk(KERN_EMERG "chardevnode release is success!\n");return 0; }/* io control */ static long chardevnode_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {printk(KERN_EMERG "chardevnode release is success!cmd is %d,arg is %d\n", cmd, arg);return 0; }/* read */ static ssize_t chardevnode_read(struct file *file, char __user *buf, size_t size, loff_t *f_ops) {return 0; }/* write */ static ssize_t chardevnode_write(struct file *file, const char __user *buf, size_t size, loff_t *ops) {return 0; }/* lseek */ static loff_t chardevnode_llseek(struct file *file, loff_t offset, int whence) {return 0; }struct file_operations my_fops = {.owner = THIS_MODULE,.open = chardevnode_open,.release = chardevnode_release,.unlocked_ioctl = chardevnode_ioctl,.read = chardevnode_read,.write = chardevnode_write,.llseek = chardevnode_llseek, };static void reg_init_cdev(struct reg_dev *dev, int index) {int err;int devno = MKDEV(numdev_major, numdev_minor+index);cdev_init(&dev->cdev, &my_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &my_fops;err = cdev_add(&dev->cdev, devno, 1);if(err) {printk(KERN_EMERG "cdev_add %d is fail! %d\n", index, err);} else {printk(KERN_EMERG "cdev_add %d is success!\n", (numdev_minor+index));} }static int hello_init(void) {int ret, i;dev_t num_dev;printk(KERN_EMERG "numdev_major is %d!\n", numdev_major);printk(KERN_EMERG "numdev_minor is %d!\n", numdev_minor);if(numdev_major) {num_dev = MKDEV(numdev_major, numdev_minor);ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);} else {ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);numdev_major = MAJOR(num_dev);printk(KERN_EMERG "register req major number is %d\n", numdev_major);}if(ret < 0) {printk(KERN_EMERG "register_chrdev_region req %d is failed\n", numdev_major);unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);return ret;}my_class = class_create(THIS_MODULE, DEVICE_NAME);my_devices = kmalloc(DEVICE_MINOR_NUM*sizeof(struct reg_dev), GFP_KERNEL);if(!my_devices) {ret = -ENOMEM;printk(KERN_EMERG "kmalloc fialed!\n");goto fail;}memset(my_devices, 0, DEVICE_MINOR_NUM*sizeof(struct reg_dev));for(i=0;i<DEVICE_MINOR_NUM;i++) {my_devices[i].data = kmalloc(REGDEV_SIZE, GFP_KERNEL);memset(my_devices[i].data, 0, REGDEV_SIZE); /* data address *//* register device to system */reg_init_cdev(&my_devices[i], i);/* create device node */device_create(my_class, NULL, MKDEV(numdev_major, numdev_minor+i), "NULL", DEVICE_NAME"%d", i);}printk(KERN_EMERG "Hello World enter!\n");return 0;fail:unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);return ret; }static void hello_exit(void) {int i;dev_t num_dev = MKDEV(numdev_major, numdev_minor);printk(KERN_EMERG "Hello World exit!\n");for(i=0;i<DEVICE_MINOR_NUM;i++) {cdev_del(&my_devices[i].cdev);/* release memory*/device_destroy(my_class, MKDEV(numdev_major, numdev_minor+i));}/* release my class*/class_destroy(my_class);/* release kfre */kfree(my_devices);unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM); }module_init(hello_init); module_exit(hello_exit); 代碼測(cè)試結(jié)果:
[root@iTOP-4412]# insmod char_driver.ko [ 2135.474056] numdev_major is 0! [ 2135.475744] numdev_minor is 0! [ 2135.478724] register req major number is 248 [ 2135.484220] cdev_add 0 is success! [ 2135.487909] cdev_add 1 is success! [ 2135.500246] Hello World enter! [root@iTOP-4412]# ./invok_char [ 2174.171640] chardevnode open is success! [ 2174.174452] chardevnode release is success!cmd is 1,arg is 6 [ 2174.179828] chardevnode open is success! [ 2174.183737] chardevnode release is success!cmd is 1,arg is 6 [ 2174.189346] chardevnode release is success! [ 2174.193511] chardevnode release is success! APP open /dev/chardevnode0 success APP open /dev/chardevnode0 success [root@iTOP-4412]# rmmod char_driver [ 2199.758801] Hello World exit! 測(cè)試結(jié)果?
六、字符類GPIOS,LED驅(qū)動(dòng)編寫
- 將"21_字符驅(qū)動(dòng)"中的文件“char_driver.c”改為“char_driver_leds.c”,添加gpio的初始化和操作函數(shù),卸載模塊的時(shí)候釋放GPIO,將宏定義部分添加到頭文件中,簡(jiǎn)單修改Makefile文件
- 將“21_字符驅(qū)動(dòng)”中的文件"incoke_char_driver.c"改為文件"invoke_char_gpios.c",并使用main參數(shù)傳參數(shù)操作gpio
- 應(yīng)用編譯命令
- arm-none-linux-gnueabi-gcc -o invoke_char_gpios invoke_char_gpios.c -static
- 操作命令
- 類似"./invoke_char_gpios 0 1",參數(shù)1為命令,參數(shù)2為GPIO
字符驅(qū)動(dòng)程序:
#include <linux/init.h> #include <linux/module.h>/* define module_param module_param_array header file */ #include <linux/moduleparam.h> /* define perm's head file*/ #include <linux/stat.h> /* char device register head file */ #include <linux/fs.h> /* MKDEV change device ID type */ #include <linux/kdev_t.h> /* define char device struct */ #include <linux/cdev.h> /* define memroy sapce */ #include <linux/slab.h>/* include device_create class file */ #include <linux/device.h>#include <linux/gpio.h> #include <plat/gpio-cfg.h> #include <mach/gpio.h> #include <mach/gpio-exynos4.h>#define DEVICE_NAME "chardevnode" #define DEVICE_MINOR_NUM 2 #define DEV_MAJOR 0 #define DEV_MINOR 0 #define REGDEV_SIZE 3000MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET");int numdev_major = DEV_MAJOR; int numdev_minor = DEV_MINOR;/* input major device ID */ module_param(numdev_major, int, S_IRUSR); /* input minor device ID */ module_param(numdev_minor, int, S_IRUSR);static struct class *my_class;struct reg_dev {char *data;unsigned long size;struct cdev cdev; }; struct reg_dev *my_devices;/* open */ static int chardevnode_open(struct inode *inode, struct file *file) {printk(KERN_EMERG "chardevnode open is success!\n");return 0; }/* close */ static int chardevnode_release(struct inode *indoe, struct file *file) {printk(KERN_EMERG "chardevnode release is success!\n");return 0; }/* io control */ static long chardevnode_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {printk(KERN_EMERG "chardevnode release is success!cmd is %d,arg is %d\n", cmd, arg);if(cmd >1 || arg> 1) {printk(KERN_EMERG "cmd and arg is 0 or 1");return 0;}switch(arg) {case 0:gpio_set_value(EXYNOS4_GPL2(0), cmd);break;case 1:gpio_set_value(EXYNOS4_GPK1(1), cmd);break;default:printk(KERN_EMERG "cmd and arg is 0 or 1");break;}return 0; }/* read */ static ssize_t chardevnode_read(struct file *file, char __user *buf, size_t size, loff_t *f_ops) {return 0; }/* write */ static ssize_t chardevnode_write(struct file *file, const char __user *buf, size_t size, loff_t *ops) {return 0; }/* lseek */ static loff_t chardevnode_llseek(struct file *file, loff_t offset, int whence) {return 0; }struct file_operations my_fops = {.owner = THIS_MODULE,.open = chardevnode_open,.release = chardevnode_release,.unlocked_ioctl = chardevnode_ioctl,.read = chardevnode_read,.write = chardevnode_write,.llseek = chardevnode_llseek, };/* GPL2_0 */ static int led1_init(void) {int ret;printk(KERN_EMERG "Gpio led 1 init\n");ret = gpio_request(EXYNOS4_GPL2(0), "LEDS");if(ret < 0) {printk(KERN_EMERG "gpio_request EXYNOS4_GPL2(0) failed\n");return ret;}s3c_gpio_cfgpin(EXYNOS4_GPL2(0), S3C_GPIO_OUTPUT);gpio_set_value(EXYNOS4_GPL2(0), 0);return 0; }/* GPK1_1 */ static int led2_init(void) {int ret;printk(KERN_EMERG "GPIO led 2 init\n");ret = gpio_request(EXYNOS4_GPK1(1), "LEDS2");if(ret < 0) {printk(KERN_EMERG "gpio_request EXYNOS4_GPK1(1) fialed\n");return ret;}s3c_gpio_cfgpin(EXYNOS4_GPK1(1), S3C_GPIO_OUTPUT);gpio_set_value(EXYNOS4_GPK1(1), 0);return 0; }static void reg_init_cdev(struct reg_dev *dev, int index) {int err;int devno = MKDEV(numdev_major, numdev_minor+index);cdev_init(&dev->cdev, &my_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &my_fops;err = cdev_add(&dev->cdev, devno, 1);if(err) {printk(KERN_EMERG "cdev_add %d is fail! %d\n", index, err);} else {printk(KERN_EMERG "cdev_add %d is success!\n", (numdev_minor+index));} }static int hello_init(void) {int ret, i;dev_t num_dev;printk(KERN_EMERG "numdev_major is %d!\n", numdev_major);printk(KERN_EMERG "numdev_minor is %d!\n", numdev_minor);if(numdev_major) {num_dev = MKDEV(numdev_major, numdev_minor);ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);} else {ret = alloc_chrdev_region(&num_dev, numdev_minor, DEVICE_MINOR_NUM, DEVICE_NAME);numdev_major = MAJOR(num_dev);printk(KERN_EMERG "register req major number is %d\n", numdev_major);}if(ret < 0) {printk(KERN_EMERG "register_chrdev_region req %d is failed\n", numdev_major);unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);return ret;}my_class = class_create(THIS_MODULE, DEVICE_NAME); my_devices = kmalloc(DEVICE_MINOR_NUM*sizeof(struct reg_dev), GFP_KERNEL);if(!my_devices) {ret = -ENOMEM;printk(KERN_EMERG "kmalloc fialed!\n");goto fail;}memset(my_devices, 0, DEVICE_MINOR_NUM*sizeof(struct reg_dev));for(i=0;i<DEVICE_MINOR_NUM;i++) {my_devices[i].data = kmalloc(REGDEV_SIZE, GFP_KERNEL); memset(my_devices[i].data, 0, REGDEV_SIZE); /* data address *//* register device to system */reg_init_cdev(&my_devices[i], i);/* create device node */device_create(my_class, NULL, MKDEV(numdev_major, numdev_minor+i), "NULL", DEVICE_NAME"%d", i);}led1_init();led2_init();printk(KERN_EMERG "Hello World enter!\n");return 0;fail:unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM);return ret; }static void hello_exit(void) {int i;dev_t num_dev = MKDEV(numdev_major, numdev_minor);printk(KERN_EMERG "Hello World exit!\n");for(i=0;i<DEVICE_MINOR_NUM;i++) {cdev_del(&my_devices[i].cdev);/* release memory*/device_destroy(my_class, MKDEV(numdev_major, numdev_minor+i));}/* release my class*/class_destroy(my_class);/* release kfre */kfree(my_devices);unregister_chrdev_region(num_dev, DEVICE_MINOR_NUM); }module_init(hello_init); module_exit(hello_exit); char_driver_leds.c然后是應(yīng)用程序:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <stdlib.h>int main(int argc, char *argv[]) {int fd0, fd1;char *hello_node0 = "/dev/chardevnode0";char *hello_node1 = "/dev/chardevnode1";if(argc > 2) {printf("please input cmd and arg\n");}/* O_RDWR只讀打開, O_NDELAY非阻塞方式 */fd0 = open(hello_node0, O_RDWR|O_NDELAY);if(fd0 < 0) {printf("APP open %s failed\n", hello_node0);exit(EXIT_FAILURE);} else {printf("APP open %s success\n", hello_node0);ioctl(fd0, atoi(argv[1]), atoi(argv[2]));}/* O_RDWR只讀打開, O_NDELAY非阻塞方式 */ /*fd1 = open(hello_node0, O_RDWR|O_NDELAY);if(fd1 < 0) {printf("APP open %s failed\n", hello_node0);exit(EXIT_FAILURE);} else {printf("APP open %s success\n", hello_node0);ioctl(fd1, 1, 6);} */close(fd0);close(fd1); } invoke_char_driver.c然后是makefile:
TARGET_NAME = char_driver_leds APP_NAME = invoke_char_gpios obj-m += $(TARGET_NAME).oKDIR := /home/topeet/chen/kernel-3.0/iTop4412_Kernel_3.0PWD ?= $(shell pwd)all:appmake -C $(KDIR) M=$(PWD) modulesapp:$(APP_NAME)arm-none-linux-gnueabi-gcc $(APP_NAME).c -o $(APP_NAME) -staticclean:rm -rf *.o *.ko *.mod.c *.symvers *.order *.cmd .$(TARGET_NAME)* $(APP_NAME) Makefile測(cè)試結(jié)果:
[root@iTOP-4412]# insmod char_driver_leds.ko [ 420.107938] numdev_major is 0! [ 420.109549] numdev_minor is 0! [ 420.112677] register req major number is 248 [ 420.125765] cdev_add 0 is success! [ 420.137424] cdev_add 1 is success! [ 420.148881] Gpio led 1 init [ 420.150342] gpio_request EXYNOS4_GPL2(0) failed [ 420.154743] GPIO led 2 init [ 420.165167] Hello World enter! [root@iTOP-4412]# ./invoke_char_gpios 1 0 please input cmd [ 431.050669] chardevnode open is success! [ 431.054691] chardevnode release is success!cmd is 1,arg is 0 [ 431.060238] chardevnode release is success! and arg APP open /dev/chardevnode0 success [root@iTOP-4412]# ./invoke_char_gpios 1 1 please input cmd [ 435.289936] chardevnode open is success! [ 435.294047] chardevnode release is success!cmd is 1,arg is 1 [ 435.299498] chardevnode release is success! and arg APP open /dev/chardevnode0 success [root@iTOP-4412]# ./invoke_char_gpios 0 0 please input cmd [ 440.595232] chardevnode open is success! [ 440.599237] chardevnode release is success!cmd is 0,arg is 0 and arg APP open /dev/chardevnode0 success [ 440.609648] chardevnode release is success! [root@iTOP-4412]# ./invoke_char_gpios 0 1 please input cmd [ 443.313565] chardevnode open is success! [ 443.317679] chardevnode release is success!cmd is 0,arg is 1 [ 443.323129] chardevnode release is success! and arg APP open /dev/chardevnode0 success[root@iTOP-4412]# rmmod char_driver_leds [ 468.722834] Hello World exit! 測(cè)試結(jié)果?
不知道為什么要設(shè)兩個(gè)驅(qū)動(dòng)設(shè)備,按我的寫法應(yīng)該,這兩個(gè)驅(qū)動(dòng)設(shè)備沒什么區(qū)別。
轉(zhuǎn)載于:https://www.cnblogs.com/ch122633/p/9459904.html
總結(jié)
以上是生活随笔為你收集整理的4412 字符类设备的设备号的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: recyclerview 加载fragm
- 下一篇: java writeint_Java D