1. 程式人生 > 其它 >(2)字元裝置驅動基本框架

(2)字元裝置驅動基本框架

技術標籤:Linux

  • 參考正點原子視訊,做記錄以及簡單使用。

首先建立如下所示資料夾及檔案,檔案的內容如下三個所示。。。

/************************chrdevbase.c*****************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>

#define MAJOR_NUMBER 200
const char* CHR_NAME = "chr_test";


static int chrtest_open(struct inode *inode,struct file *filp)
{
    printk("chrtest_open !!!!\n");
    return 0;
}
//filp:要開啟的裝置檔案(檔案描述符)
//buf:返回給使用者空間的資料緩衝區
//cnt:要讀取的資料長度
//offt:相對於檔案首地址的偏移
//return:返回讀取到的位元組數
static ssize_t chrtest_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    printk("chrtest_read !!!!\n");
    return 0;
}

static ssize_t chrtest_write(struct file *filp,const char __user *buf, size_t cnt, loff_t *offt)
{
    printk("chrtest_write !!!!\n");
    return 0;
}

static int chrtest_release(struct inode *inode, struct file *filp)
{
    printk("chrtest_release !!!!\n");
    return 0;
}

static struct file_operations test_fops = { //例項化一個函式結構體
    .owner = THIS_MODULE,
    .open = chrtest_open,
    .read = chrtest_read,
    .write = chrtest_write,
    .release = chrtest_release,
};

int xxx_init(void) //模組入口函式
{
    int retvalue = 0;

    retvalue = register_chrdev(MAJOR_NUMBER, CHR_NAME, &test_fops); //設備註冊
    if(retvalue < 0){
        printk("register failed!!!!\n");  //printf 執行在使用者態,printk 執行在核心態。
    }
    else{
        printk("register success!!!!\n");
    }



    return 0;
}
 
void xxx_exit(void) //模組退出函式
{
    unregister_chrdev(200, CHR_NAME); //設備註銷
}
 

module_init(xxx_init);  
module_exit(xxx_exit);  

MODULE_LICENSE("Dual BSD/GPL");
/************************Makefile*************************/
KERNELDIR := /usr/src/linux-headers-$(shell uname -r) #核心原始碼目錄
CURRENT_PATH := $(shell pwd)  #shell指令碼執行pwd,得知當前位置
obj-m := chrdevbase.o #生成檔名

build: kernel_modules
 
 
kernel_modules:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules #表明編譯生成的是.ko模組檔案
 
clean:
	$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean #刪除生成檔案
/*********************chrdevApp.c*************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main(int argc, char* argv[])
{
    int ret = 0;
    char* filename;
    char readbuf[10];
    char writebuf[50];

    int fd = 0;
    filename = argv[1];

    //open(開啟的檔名,讀寫許可權);
    fd = open(filename,O_RDWR);  //返回檔案描述符  O_RDWR表示讀寫模式
    if(fd < 0){ //檔案開啟錯誤,返回<0
        printf("canot open file %s \r\n", filename);
        return -1;
    }
    else{
        printf(" open file %s sucess \r\n", filename);
    }

    ret = read (fd, readbuf, 50); //從open()開啟的fd檔案讀50個位元組
    if(ret < 0){
        printf("read file %s error !!!\n", filename);
    }
    else{
        printf("read file %s success !!!\n", filename);
    }

    ret = write(fd,writebuf, 50);//將writebuf中的50個位元組寫到fd對應的檔案中
    if(ret < 0){
        printf("read file %s error !!!\n", filename);
    }
    else{
        printf("read file %s success !!!\n", filename);    
    }

    ret = close(fd);//關閉開啟的fd檔案
    if(ret < 0){
        printf("close file %s error !!!\n", filename);
    }
    else{
        printf("close file %s success !!!\n", filename);    
    }                                                                         
}

https://mp.csdn.net/editor/html/113354613配合此連結的第一張圖起理解以下的4點)

  1. 首先第一個檔案chrdevbase.c, 此檔案通過make編譯生成chrdevbase.ko檔案,然後通過sudo insmod chrdevbase.ko載入模組,然後用lsmod即可看到載入了的chrdevbase模組,這個時候代表模組已經載入到核心空間,驅動載入成功。。可用dmesg看到在chrdevbase.c中列印的register success!!!!。然後用cat /proc/device即可看到一個名為200 chr_test的chardev裝置。
  2. 第二個檔案chrdevAPP.c,此檔案通過gcc chrdevApp.c -o chrdevApp生成可執行檔案chrdevApp。然後在手動建立一個裝置節點mknod /dev/chrdevbase c 200 0,(c:字元裝置 200:主裝置號 0:副裝置號)此時通過ls /dev/chrdevbase -l即可檢視裝置節點chrdevbase檔案。然後通過sudo ./chrdevApp /dev/chrdevbase代表執行chrdevApp,輸入引數/dev/chrdevbase.
  3. 執行之後,可看到列印的chrdevApp中的內容,表明對檔案的open file success等操作成功。而在用dmesg即可看到列印了chrtest_open等。。這表明chrdevbaseAPP 使用 read 函式從 chrdevbase 裝置讀取資料,因此chrdevbase_read 函式就會執行並列印chrtest_read。。。
  4. 按照圖來理解:使用者空間的程式呼叫open函式對chrdevbase裝置檔案進行操作,系統呼叫到核心,核心根據手動建立的裝置節點來找到chrdevbase裝置驅動程式,然後驅動程式根據我們在chrdevbase.c寫的read的函式來執行具體的操作。以上即為字元裝置從應用程式到驅動程式的基本框架。。