嵌入式核心及驅動開發之學習筆記(二) 實現應用控制驅動
Linux系統根據驅動程式實現的模型框架將裝置驅動分成字元裝置驅動、塊裝置驅動、網路裝置驅動三大類。這裡簡單理解一下概念
- 字元裝置:裝置按位元組流處理資料,通常用的串列埠裝置、鍵盤裝置都是這種。
- 塊裝置:裝置按塊單位對資料處理,通常是儲存裝置。
- 網路裝置:顧名思義,建立在socket介面上的裝置。
字元裝置驅動框架
作為字元裝置驅動要素:
1,必須有一個裝置號,用在眾多到裝置驅動中進行區分
2,使用者必須知道裝置驅動對應到裝置節點(裝置檔案)
3,對裝置操作其實就是對檔案操作,應用空間操作open,read,write的時候,實際在驅動程式碼有對應到open, read,write
linux把所有到裝置都看成檔案,使用者對字元裝置進行操作實際上就是對驅動進行操作,實際上就是操作對應的裝置檔案!
而裝置號是核心層區別裝置的一個標識,我們通過驅動程式碼程式實現下面 應用程式到裝置驅動的控制過程。
應用層程式 --> 裝置結點 --> 裝置號 --> 裝置驅動 --> 硬體
實現一簡易的框架。首先是驅動程式的實現
當用戶裝載完驅動模組,程式會執行 chr_drv_init 這個回撥函式,向系統申請一個主裝置號(表示程式為哪一類裝置服務),建立裝置結點(產生/dev/chr2,linux系統能識別這個裝置檔案);當用戶解除安裝驅動模組後,程式執行 chr_drv_exit 這個回撥函式,將之前申請的裝置結點和裝置號回收。
結構體型別 file_operations 定義了很多對應用層的介面,這些成員變數都是函式指標。我們將這些指標指向自己定義的函式入口。再去實現我們的函式功能。
//chr_drv.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/device.h> static unsigned int dev_major = 250; static struct class *devcls; static struct device *dev; ssize_t chr_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos); ssize_t chr_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos); int chr_drv_open(struct inode *inode, struct file *filp); int chr_drv_close(struct inode *inode, struct file *filp); const struct file_operations my_fops = { .open = chr_drv_open, .read = chr_drv_read, .write = chr_drv_write, .release = chr_drv_close, }; static int __init chr_drv_init(void) { printk("-------%s-------------\n", __FUNCTION__); //向系統申請裝置號 int ret; ret = register_chrdev(dev_major, "chr_dev_test", &my_fops); if(ret == 0){ printk("register ok\n"); }else{ printk("register failed\n"); return -EINVAL; } //建立裝置結點 devcls = class_create(THIS_MODULE, "chr_cls"); dev = device_create(devcls, NULL, MKDEV(dev_major, 0), NULL, "chr2"); return 0; } static void __exit chr_drv_exit(void) { printk("-------%s-------------\n", __FUNCTION__); //銷燬這個裝置結點 device_destroy(devcls, MKDEV(dev_major, 0)); class_destroy(devcls); //釋放這個裝置號 unregister_chrdev(dev_major, "chr_dev_test"); } module_init(chr_drv_init); module_exit(chr_drv_exit); MODULE_LICENSE("GPL"); // read(fd, buf, size); ssize_t chr_drv_read(struct file *filp, char __user *buf, size_t count, loff_t *fpos) { printk("-------%s-------\n", __FUNCTION__); return 0; } ssize_t chr_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos) { printk("-------%s-------\n", __FUNCTION__); return 0; } int chr_drv_open(struct inode *inode, struct file *filp) { printk("-------%s-------\n", __FUNCTION__); return 0; } int chr_drv_close(struct inode *inode, struct file *filp) { printk("-------%s-------\n", __FUNCTION__); return 0; }
應用程式用來測試驅動程式的這些介面函式,實現對驅動的控制。
這裡open函式定位到驅動程式的chr_drv_open函式,read函式定位到驅動程式的chr_drv_read函式(參考驅動程式中my_fops結構體的初始化)。就像檔案IO函式那樣使用,只不過我們驅動程式裡對應的函沒有具體的實現,能看到一些列印資訊。
//chr_test.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd;
int value = 0;
//開啟裝置結點
fd = open("/dev/chr2", O_RDWR);
if(fd < 0)
{
perror("open");
exit(1);
}
//讀操作
read(fd, &value, 4);
while(1)
{
//寫操作
value = 0;
write(fd, &value, 4);
sleep(1);
//寫操作
value = 1;
write(fd, &value, 4);
sleep(1);
}
close(fd);
return 0;
}
Makefile檔案負責整個工程的編譯與管理
相比於之前,要多編譯了chr_test.c這個檔案,APP_NAME 指定目標檔名,CROSS_COMPILE 指定交叉編譯工具鏈。下面還要修改新增一下編譯規則
ROOTFS_DIR = /nfs/rootfs
APP_NAME = chr_test
CROSS_COMPILE = /home/linux/soft/gcc-4.6.4/bin/arm-none-linux-gnueabi-
CC = $(CROSS_COMPILE)gcc
ifeq ($(KERNELRELEASE), )
KERNEL_DIR = /mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412
CUR_DIR = $(shell pwd)
all :
make -C $(KERNEL_DIR) M=$(CUR_DIR) modules
$(CC) $(APP_NAME).c -o $(APP_NAME)
clean :
make -C $(KERNEL_DIR) M=$(CUR_DIR) clean
install:
cp -raf *.ko $(APP_NAME) $(ROOTFS_DIR)/drv_module
else
obj-m += chr_drv.o
endif
檢視實驗結果
編譯並移動檔案到nfs根目錄
[email protected]:/mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412/drivers/mydrivers/chr_drv# make
[email protected]:/mnt/hgfs/sharefolder/kernel/linux-3.14-fs4412/drivers/mydrivers/chr_drv# make install
開發板載入模組,執行應用程式
[[email protected] drv_module]# ls
chr_drv.ko chr_test chr_test.ko hello.ko math.ko
[[email protected] drv_module]# insmod chr_drv.ko
[ 3036.170000] -------chr_drv_init-------------
[ 3036.175000] register ok
[[email protected] drv_module]# ./chr_test
[ 3041.255000] -------chr_drv_open-------
[ 3041.255000] -------chr_drv_read-------
[ 3041.260000] -------chr_drv_write-------
[ 3042.265000] -------chr_drv_write-------
[ 3043.265000] -------chr_drv_write-------