目錄·:
1、概述
2、設備號、設備節點
3、字符設備驅動框架
4、申請設備號
5、創建設備節點
6、實現文件IO接口--fops
7、應用程序控制驅動
8、驅動程序控制外設
1、概述:
linux中一切皆文件,設備也如此,並且以操作文件即文件IO的方式訪問設備。
應用程序只能通過庫函數中的系統調用來操作硬件,對於每個系統調用,驅動程序中都會有一個與之對應的函數,對於字符設備驅動,這些函數集中在file_operations結構體中。當應用程序使用系統調用read、write等函數訪問設備時,最終會調用到file_opeartions中的成員,當然一開始fops中的只是一大堆函數指針的調用接口,具體的函數就需要我們在驅動中實現,實現對應操作函數后,與fops一對接,應用程序最終就能對硬件進行控制了。
那么問題來了,當應用程序使用系統調用訪問設備時,linux系統怎么知道調用哪一個驅動的fops中的成員呢?
2、設備號、設備節點
設備號和驅動相關聯
設備號是一個ID,設備節點就是驅動文件
字符設備和塊設備是獨立的,雖然設備號可能相同,但卻是不同的設備
3、字符設備驅動框架
作為字符設備驅動要素: 1,必須有一個設備號,用在眾多到設備驅動中進行區分 2,用戶必須知道設備驅動對應到設備節點(設備文件) linux把所有到設備都看成文件 crw-r----- 1 root root 13, 64 Mar 28 20:14 event0 crw-r----- 1 root root 13, 65 Mar 28 20:14 event1 crw-r----- 1 root root 13, 66 Mar 28 20:14 event2 3,對設備操作其實就是對文件操作,應用空間操作open,read,write的時候 實際在驅動代碼有對應到open, read,write
4、申請設備號
// 1、注冊獲取設備號 // 2、初始化設備 // 3、操作設備 file_operations – open release read write ioctl… // 4、兩個宏定義 module_init module_exit // 5、注冊設備號 register_chrdev_region // 6、cdev_init 初始化字符設備 // 7、cdev_add 添加字符設備到系統
1)向系統申請主設備號
int register_chrdev(unsigned int major, const char * name, const struct file_operations * fops) //參數: //1、major:主設備號 // 設備號(32bit–dev_t)==主設備號(高12bit) + 次設備號(低20bit) // 主設備號:表示一類設備—(如:camera) // 次設備號: 表示一類設備中某一個—(如:前置camera/后置camera) // 0 -->動態分配 ; 250 --> 給定整數,靜態指定 //2、name: 描述設備信息,可自定義 // 在目錄/proc/devices列舉出了所有的已經注冊的設備 //3、fops: 文件操作對象 // 提供open, read,write //返回值:成功-0,失敗-負數
2)釋放設備號
void unregister_chrdev(unsigned int major, const char * name)
3)例:主設備號的申請

1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/fs.h> 4 5 //靜態指定 6 static int dev_major = 250; 7 8 const struct file_operations my_fops = {}; 9 10 static int __init chr_drv_init(void) 11 { 12 //申請設備號 13 int ret; 14 ret = register_chrdev(dev_major, "chr_dev", &my_fops); 15 if(ret == 0) 16 { 17 printk("register success!\n"); 18 } 19 else 20 { 21 printk("register failed!\n"); 22 return -EFAULT; 23 } 24 return 0; 25 } 26 27 static void __exit chr_drv_exit(void) 28 { 29 //釋放設備號資源 30 unregister_chrdev(dev_major, "chr_dev"); 31 } 32 33 module_init(chr_drv_init); 34 module_exit(chr_drv_exit); 35 36 MODULE_LICENSE("GPL");
加載驅動前:
加載驅動后:
5、創建設備節點
1)手動創建
·· 缺點/dev/
目錄中文件都是在內存中,斷電后/dev/
文件就會消失
mknod /dev/設備名 類型 主設備號 次設備號 (主設備號要和驅動中申請的主設備號保持一致) 比如: mknod /dev/chr0 c 250 0
eg: [root@farsight drv_module]# ls /dev/chr0 -l crw-r--r-- 1 0 0 250, 0 Jan 1 00:33 /dev/chr0
2)自動創建
通過udev/mdev機制
struct class *class_create(owner, name)//創建一個類 //參數: //1、owner:THIS_MODULE //2、name :字符串名字,自定義 //返回: // 返回一個class指針
創建一個設備文件:
//創建一個設備文件 struct device *device_create(struct class * class, struct device * parent, dev_t devt, void * drvdata, const char * fmt,...) //參數: //1、class結構體,class_create調用之后的返回值 //2、表示父親,一般直接填NULL //3、設備號類型 dev_t //4、私有數據,一般直接填NULL //5/6、表示可變參數,字符串,表示設備節點名字 設備號類型:dev_t devt #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) //獲取主設備號 #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) //獲取次設備號 #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) //生成設備號
銷毀設備文件:
void device_destroy(devcls, MKDEV(dev_major, 0)); //參數: //1、class結構體,class_create調用之后到返回值 //2、設備號類型 dev_t void class_destroy(devcls); //參數:class結構體,class_create調用之后到返回值
3)示例:

1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/fs.h> 4 #include <linux/device.h> 5 6 /* 7 設備號給定方式有兩種: 8 1,動態--參數1直接填0 9 2,靜態--指定一個整數,250 10 */ 11 static unsigned int dev_major = 250; 12 static unsigned int dev_minor = 0; 13 static struct class *devcls; 14 static struct device *dev; 15 16 const struct file_operations my_fops = { 17 18 }; 19 20 static int __init chr_dev_init(void) 21 { 22 //裝載一般都是申請設備號資源 23 //申請設備號 24 int ret; 25 26 ret = register_chrdev(dev_major, "chr_dev_test", &my_fops); 27 if(ret == 0){ 28 printk("register ok\n"); 29 } 30 else{ 31 printk("register failed\n"); 32 return -EINVAL; 33 } 34 35 //自動創建設備節點 36 devcls = class_create(THIS_MODULE, "chr_cls"); 37 dev = device_create(devcls,NULL,MKDEV(dev_major,dev_minor),NULL,"chr2"); 38 39 return 0; 40 } 41 42 static void __exit chr_dev_exit(void) 43 { 44 //卸載一般都是釋放資源 45 46 //銷毀節點和類 47 device_destroy(devcls,MKDEV(dev_major,dev_minor)); 48 class_destroy(devcls); 49 //釋放設備號 50 unregister_chrdev(dev_major, "chr_dev_test"); 51 } 52 53 module_init 54 (chr_dev_init); 55 module_exit(chr_dev_exit); 56 MODULE_LICENSE("GPL");
7、實現文件IO接口--fops
1)驅動中實現文件io操作接口:struct file_operations
1 struct file_operations { 2 struct module *owner; 3 loff_t (*llseek) (struct file *, loff_t, int); 4 ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); 5 ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); 6 ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t); 7 ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t); 8 int (*iterate) (struct file *, struct dir_context *); 9 unsigned int (*poll) (struct file *, struct poll_table_struct *); 10 long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); 11 long (*compat_ioctl) (struct file *, unsigned int, unsigned long); 12 int (*mmap) (struct file *, struct vm_area_struct *); 13 int (*open) (struct inode *, struct file *); 14 .... 16 long (*fallocate)(struct file *file, int mode, loff_t offset, loff_t len); 17 int (*show_fdinfo)(struct seq_file *m, struct file *f); 18 }; //函數指針的集合,其實就是接口,我們寫驅動到時候需要去實現 19 20 const struct file_operations my_fops = { 21 .open = chr_drv_open, 22 .read = chr_drv_read, 23 .write = chr_drv_write, 24 .release = chr_drv_close, 25 };
示例:

1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/fs.h> 4 #include <linux/device.h> 5 6 /* 7 設備號給定方式有兩種: 8 1,動態--參數1直接填0 9 2,靜態--指定一個整數,250 10 */ 11 static unsigned int dev_major = 250; 12 static unsigned int dev_minor = 0; 13 static struct class *devcls; 14 static struct device *dev; 15 16 ssize_t chr_drv_write (struct file *filp, char __user *buf, size_t count, loff_t *fpos) 17 { 18 printk("---------write %s-------------\n",__FUNCTION__); 19 20 return 0; 21 } 22 23 ssize_t chr_drv_read (struct file *filp, const char __user *buf, size_t count, loff_t *fops) 24 { 25 printk("---------read %s-------------\n",__FUNCTION__); 26 27 return 0; 28 } 29 30 int chr_drv_open (struct inode *inode, struct file *filp) 31 { 32 printk("---------open %s-------------\n",__FUNCTION__); 33 34 return 0; 35 } 36 37 int chr_drv_close (struct inode *inode, struct file *filp) 38 { 39 printk("---------close %s-------------\n",__FUNCTION__); 40 41 return 0; 42 } 43 44 45 46 const struct file_operations my_fops = { 47 .open = chr_drv_open, 48 .read = chr_drv_read, 49 .write = chr_drv_write, 50 .release = chr_drv_close 51 }; 52 53 static int __init chr_dev_init(void) 54 { 55 //裝載一般都是申請設備號資源 56 //申請設備號 57 int ret; 58 59 ret = register_chrdev(dev_major, "chr_dev_test", &my_fops); 60 if(ret == 0){ 61 printk("register ok\n"); 62 } 63 else{ 64 printk("register failed\n"); 65 return -EINVAL; 66 } 67 68 //自動創建設備節點 69 devcls = class_create(THIS_MODULE, "chr_cls"); 70 dev = device_create(devcls,NULL,MKDEV(dev_major,dev_minor),NULL,"chr2"); 71 72 return 0; 73 } 74 75 static void __exit chr_dev_exit(void) 76 { 77 //卸載一般都是釋放資源 78 79 //銷毀節點和類 80 device_destroy(devcls,MKDEV(dev_major,dev_minor)); 81 class_destroy(devcls); 82 //釋放設備號 83 unregister_chrdev(dev_major, "chr_dev_test"); 84 } 85 86 module_init 87 (chr_dev_init); 88 module_exit(chr_dev_exit); 89 MODULE_LICENSE("GPL");
實現了底層的fops成員函數,再實現應用程序的調用
2)應用程序調用文件IO控制驅動 :open、read...

1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/fs.h> 4 #include <linux/device.h> 5 6 /* 7 設備號給定方式有兩種: 8 1,動態--參數1直接填0 9 2,靜態--指定一個整數,250 10 */ 11 static unsigned int dev_major = 250; 12 static unsigned int dev_minor = 0; 13 static struct class *devcls; 14 static struct device *dev; 15 16 ssize_t chr_drv_write (struct file *filp, char __user *buf, size_t count, loff_t *fpos) 17 { 18 printk("---------write %s-------------\n",__FUNCTION__); 19 20 return 0; 21 } 22 23 ssize_t chr_drv_read (struct file *filp, const char __user *buf, size_t count, loff_t *fops) 24 { 25 printk("---------read %s-------------\n",__FUNCTION__); 26 27 return 0; 28 } 29 30 int chr_drv_open (struct inode *inode, struct file *filp) 31 { 32 printk("---------open %s-------------\n",__FUNCTION__); 33 34 return 0; 35 } 36 37 int chr_drv_close (struct inode *inode, struct file *filp) 38 { 39 printk("---------close %s-------------\n",__FUNCTION__); 40 41 return 0; 42 } 43 44 45 46 const struct file_operations my_fops = { 47 .open = chr_drv_open, 48 .read = chr_drv_read, 49 .write = chr_drv_write, 50 .release = chr_drv_close 51 }; 52 53 static int __init chr_dev_init(void) 54 { 55 //裝載一般都是申請設備號資源 56 //申請設備號 57 int ret; 58 59 ret = register_chrdev(dev_major, "chr_dev_test", &my_fops); 60 if(ret == 0){ 61 printk("register ok\n"); 62 } 63 else{ 64 printk("register failed\n"); 65 return -EINVAL; 66 } 67 68 //自動創建設備節點 69 devcls = class_create(THIS_MODULE, "chr_cls"); 70 dev = device_create(devcls,NULL,MKDEV(dev_major,dev_minor),NULL,"chr2"); 71 72 return 0; 73 } 74 75 static void __exit chr_dev_exit(void) 76 { 77 //卸載一般都是釋放資源 78 79 //銷毀節點和類 80 device_destroy(devcls,MKDEV(dev_major,dev_minor)); 81 class_destroy(devcls); 82 //釋放設備號 83 unregister_chrdev(dev_major, "chr_dev_test"); 84 } 85 86 module_init 87 (chr_dev_init); 88 module_exit(chr_dev_exit); 89 MODULE_LICENSE("GPL");

1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 9 int main(int argc, char * argv [ ]) 10 { 11 //調用驅動 12 int fd; 13 int value = 0; //buf 14 15 fd = open("/dev/chr2", O_RDWR); 16 if(fd < 0) 17 { 18 perror("open"); 19 exit(1); 20 } 21 22 read(fd, &value, 4); 23 24 write(fd, &value, 4); 25 26 close(fd); 27 28 return 0; 29 }

1 ROOTFS_DIR = /home/linux/source/rootfs#根文件系統路徑 2 3 APP_NAME = chr_test 4 5 CROSS_COMPILE = /home/linux/toolchains/gcc-4.6.4/bin/arm-none-linux-gnueabi- 6 CC = $(CROSS_COMPILE)gcc 7 8 ifeq ($(KERNELRELEASE),) 9 10 KERNEL_DIR = /home/linux/kernel/linux-3.14-fs4412 #編譯過的內核源碼的路徑 11 CUR_DIR = $(shell pwd) #當前路徑 12 13 all: 14 make -C $(KERNEL_DIR) M=$(CUR_DIR) modules #把當前路徑編成modules 15 $CC $(APP_NAME).c -o $(APP_NAME) 16 @#make -C 進入到內核路徑 17 @#M 指定當前路徑(模塊位置) 18 19 clean: 20 make -C $(KERNEL_DIR) M=$(CUR_DIR) clean 21 22 install: 23 sudo cp -raf *.ko $(APP_NAME) $(ROOTFS_DIR)/drv_module #把當前的所有.ko文件考到根文件系統的drv_module目錄 24 25 else 26 27 obj-m += chr_drv1.o #指定內核要把哪個文件編譯成ko 28 29 endif
測試結果;
7、應用程序控制驅動
應用程序要控制驅動,就涉及用戶空間與內核空間的數據交互,如何實現?通過以下函數:
1)copy_to_user
1 //將數據從內核空間拷貝到用戶空間,一般是在驅動中chr_drv_read()用 2 int copy_to_user(void __user * to, const void * from, unsigned long n) 3 //參數: 4 //1:應用驅動中的一個buffer 5 //2:內核空間到一個buffer 6 //3:個數 7 //返回值:大於0,表示出錯,剩下多少個沒有拷貝成功等於0,表示正確
2)copy_from_user
1 //將數據從用戶空間拷貝到內核空間,一般是在驅動中chr_drv_write()用 2 int copy_from_user(void * to, const void __user * from, unsigned long n) 3 //參數: 4 //1:內核驅動中的一個buffer 5 //2:應用空間到一個buffer 6 //3:個數
示例:

1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/fs.h> 4 #include <linux/device.h> 5 #include <asm/uaccess.h> 6 7 8 /* 9 設備號給定方式有兩種: 10 1,動態--參數1直接填0 11 2,靜態--指定一個整數,250 12 */ 13 static unsigned int dev_major = 250; 14 static unsigned int dev_minor = 0; 15 static struct class *devcls; 16 static struct device *dev; 17 18 static int kernal_val = 555; 19 20 // 用戶空間向內核空間傳數據 21 ssize_t chr_drv_write (struct file *filp, char __user *buf, size_t count, loff_t *fpos) 22 { 23 printk("---------write %s-------------\n",__FUNCTION__); 24 25 int ret; 26 int value; //從用戶空間獲取到的數據存在value中 27 ret = copy_from_user(&value, buf, count); 28 if(ret > 0) 29 { 30 printk("copy_from_user"); 31 return -EFAULT; 32 } 33 34 printk("__KERNEL__: value = %d\n", value); 35 36 return 0; 37 } 38 39 // read(fd, buf, size) 用戶空間獲取內核空間的數據 40 ssize_t chr_drv_read (struct file *filp, const char __user *buf, size_t count, loff_t *fops) 41 { 42 printk("---------read %s-------------\n",__FUNCTION__); 43 44 int ret; 45 ret = copy_to_user(buf, &kernal_val, count); 46 if(ret > 0) 47 { 48 printk("copy_to_user"); 49 return -EFAULT; 50 } 51 52 return 0; 53 } 54 55 int chr_drv_open (struct inode *inode, struct file *filp) 56 { 57 printk("---------open %s-------------\n",__FUNCTION__); 58 59 return 0; 60 } 61 62 int chr_drv_close (struct inode *inode, struct file *filp) 63 { 64 printk("---------close %s-------------\n",__FUNCTION__); 65 66 return 0; 67 } 68 69 70 71 const struct file_operations my_fops = { 72 .open = chr_drv_open, 73 .read = chr_drv_read, 74 .write = chr_drv_write, 75 .release = chr_drv_close 76 }; 77 78 static int __init chr_dev_init(void) 79 { 80 //裝載一般都是申請設備號資源 81 //申請設備號 82 int ret; 83 84 ret = register_chrdev(dev_major, "chr_dev_test", &my_fops); 85 if(ret == 0){ 86 printk("register ok\n"); 87 } 88 else{ 89 printk("register failed\n"); 90 return -EINVAL; 91 } 92 93 //自動創建設備節點 94 devcls = class_create(THIS_MODULE, "chr_cls"); 95 dev = device_create(devcls,NULL,MKDEV(dev_major,dev_minor),NULL,"chr2"); 96 97 return 0; 98 } 99 100 static void __exit chr_dev_exit(void) 101 { 102 //卸載一般都是釋放資源 103 104 //銷毀節點和類 105 device_destroy(devcls,MKDEV(dev_major,dev_minor)); 106 class_destroy(devcls); 107 //釋放設備號 108 unregister_chrdev(dev_major, "chr_dev_test"); 109 } 110 111 module_init 112 (chr_dev_init); 113 module_exit(chr_dev_exit); 114 MODULE_LICENSE("GPL");

1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 9 10 int main(int argc, char * argv [ ]) 11 { 12 //調用驅動 13 int fd; 14 int value = 0; //buf 15 16 fd = open("/dev/chr2", O_RDWR); 17 if(fd < 0) 18 { 19 perror("open"); 20 exit(1); 21 } 22 23 read(fd, &value, 4); //應用程序從內核獲取4字節數據存放在value中 24 printf("__USER__: value = %d\n", value); //打印獲取的值 25 sleep(1); //sleep1秒,防止串口打印信息不完整 26 27 //重新給value賦值,傳給內核 28 value = 666; 29 write(fd, &value, 4); 30 31 32 close(fd); 33 34 return 0; 35 }
測試:
8、驅動程序控制外設
之前我們了解了應用程序如何與內核空間進行數據交互,那么內核驅動與外設間的控制是怎么樣的?
寫過裸機程序的都知道,可以通過修改外設對應的控制寄存器來控制外設,即向寄存器的地址寫入數據,這個地址就是物理地址,且物理地址是已知的,有硬件設計決定。
在內核中,同樣也是操作地址控制外設,但是內核中的地址,是經過MMU映射后的虛擬地址,而且CPU通常並沒有為這些已知的外設I/O內存資源的物理地址預定義虛擬地址范圍,驅動程序並不能直接通過物理地址訪問I/O內存資源,而必須將它們映射到核心虛地址空間內,然后才能根據映射所得到的核心虛地址范圍,通過訪內指令訪問這些I/O內存資源。Linux在io.h頭文件中聲明了函數ioremap(),用來將I/O內存資源的物理地址映射到核心虛地址空間中
ioremap的函數如下:
1 //映射虛擬地址 2 void *ioremap(cookie, size) 3 //參數: 4 //1、cookie:物理地址 5 //2、size:長度(連續映射一定長度的地址空間) 6 //返回值:虛擬地址
解除映射:
1 //去映射--解除映射 2 void iounmap(void __iomem *addr) 3 //參數:映射后的虛擬地址
實例:通過驅動控制LED燈
LED —— GPX2_7 —— GPX2CON —— 0x11000C40
GPX2DAT—— 0x11000C44
將0x11000c40映射為虛擬地址

1 #include <linux/init.h> 2 #include <linux/module.h> 3 #include <linux/fs.h> 4 #include <linux/device.h> 5 #include <asm/uaccess.h> 6 #include <asm/io.h> 7 8 //物理地址 9 #define GPX2CON 0x11000C40 10 #define GPX2_SIZE 8 11 12 //存放虛擬地址的指針 13 volatile unsigned long *gpx2conf; 14 volatile unsigned long *gpx2dat; 15 16 static unsigned int dev_major = 250; 17 static unsigned int dev_minor = 0; 18 static struct class *devcls; 19 static struct device *dev; 20 21 static int kernal_val = 555; 22 23 // 用戶空間向內核空間傳數據 24 ssize_t chr_drv_write (struct file *filp, char __user *buf, size_t count, loff_t *fpos) 25 { 26 27 int ret; 28 int value; //從用戶空間獲取到的數據存在value中 29 ret = copy_from_user(&value, buf, count); 30 if(ret > 0) 31 { 32 printk("copy_from_user"); 33 return -EFAULT; 34 } 35 36 if(value) //根據用戶傳遞的值決定燈的亮滅 37 { 38 *gpx2dat |= (0x1<<7); 39 }else 40 { 41 *gpx2dat &= ~(0x1<<7); 42 } 43 44 return 0; 45 } 46 47 // read(fd, buf, size) 用戶空間獲取內核空間的數據 48 ssize_t chr_drv_read (struct file *filp, const char __user *buf, size_t count, loff_t *fops) 49 { 50 printk("---------read %s-------------\n",__FUNCTION__); 51 52 int ret; 53 ret = copy_to_user(buf, &kernal_val, count); 54 if(ret > 0) 55 { 56 printk("copy_to_user"); 57 return -EFAULT; 58 } 59 60 return 0; 61 } 62 63 int chr_drv_open (struct inode *inode, struct file *filp) 64 { 65 printk("---------open %s-------------\n",__FUNCTION__); 66 67 return 0; 68 } 69 70 int chr_drv_close (struct inode *inode, struct file *filp) 71 { 72 printk("---------close %s-------------\n",__FUNCTION__); 73 74 return 0; 75 } 76 77 78 79 const struct file_operations my_fops = { 80 .open = chr_drv_open, 81 .read = chr_drv_read, 82 .write = chr_drv_write, 83 .release = chr_drv_close, 84 }; 85 86 static int __init chr_dev_init(void) 87 { 88 //裝載一般都是申請設備號資源 89 //申請設備號 90 int ret; 91 92 ret = register_chrdev(dev_major, "chr_dev_test", &my_fops); 93 if(ret == 0){ 94 printk("register ok\n"); 95 } 96 else{ 97 printk("register failed\n"); 98 return -EINVAL; 99 } 100 101 //自動創建設備節點 102 devcls = class_create(THIS_MODULE, "chr_cls"); 103 dev = device_create(devcls,NULL,MKDEV(dev_major,dev_minor),NULL,"chr2"); 104 105 //對地址進行映射 106 gpx2conf = ioremap(GPX2CON, GPX2_SIZE); //映射兩個寄存器 107 gpx2dat = gpx2conf + 1; 108 109 printk("After ioremap : gpx2conf = 0x%p, gpx2dat = 0x%p\n",gpx2conf,gpx2dat); 110 111 //配置GPIO為輸出功能 112 *gpx2conf &= ~(0xf << 28); 113 *gpx2conf |= (0x1 << 28); 114 115 return 0; 116 } 117 118 static void __exit chr_dev_exit(void) 119 { 120 //卸載一般都是釋放資源 121 iounmap(gpx2conf); 122 123 //銷毀節點和類 124 device_destroy(devcls,MKDEV(dev_major,dev_minor)); 125 class_destroy(devcls); 126 //釋放設備號 127 unregister_chrdev(dev_major, "chr_dev_test"); 128 } 129 130 module_init 131 (chr_dev_init); 132 module_exit(chr_dev_exit); 133 MODULE_LICENSE("GPL");

1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <unistd.h> 5 #include <sys/types.h> 6 #include <sys/stat.h> 7 #include <fcntl.h> 8 9 10 int main(int argc, char * argv [ ]) 11 { 12 //調用驅動 13 int fd; 14 int value = 0; //buf 15 16 fd = open("/dev/chr2", O_RDWR); 17 if(fd < 0) 18 { 19 perror("open"); 20 exit(1); 21 } 22 23 read(fd, &value, 4); //應用程序從內核獲取4字節數據存放在value中 24 printf("__USER__: value = %d\n", value); //打印獲取的值 25 sleep(1); //sleep1秒,防止串口打印信息不完整 26 27 //應用程序控制燈 28 while(1) 29 { 30 value = 0; 31 write(fd, &value, 4); 32 sleep(1); 33 34 value = 1; 35 write(fd, &value, 4); 36 sleep(1); 37 } 38 39 40 close(fd); 41 42 return 0; 43 }
測試:
執行app后,可以看到LED等以一秒的間隔亮滅