1. 程式人生 > >嵌入式核心及驅動開發之學習筆記(二) 實現應用控制驅動

嵌入式核心及驅動開發之學習筆記(二) 實現應用控制驅動

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-------