1. 程式人生 > >Ubuntu17.01下一次簡單的字元驅動程式設計

Ubuntu17.01下一次簡單的字元驅動程式設計

驅動程式是一類特殊的應用程式,是針對特定的硬體裝置編寫的程式,它提供了對硬體的基本操作,作業系統可以通過驅動程式來控制硬體裝置。裝置驅動程式是作業系統核心的基本組成部分。
Linux將所有的裝置都當作檔案處理,稱為裝置檔案。“/dev”目錄下存在對應的邏輯裝置節點,並且以檔案的形式存在。Linux系統下裝置檔案分為四類:字元裝置檔案、塊裝置檔案、網路裝置檔案、雜項裝置檔案。在裝置管理中,除了裝置型別,核心還要主裝置號和次裝置號來唯一標識裝置。主裝置號代表裝置的類別,次裝置號區分具體裝置。
驅動程式可以直接編譯到核心,也可以編寫成模組,在需要時調入。直接編譯到核心的優點是可以隨時呼叫,無需安裝,但是編譯到核心的話需要對核心進行重編譯,重啟系統,花費時間過長,而編寫成模組的話可以隨時對模組進行解除安裝載入,開發方便,因而此次實驗中將驅動程式編寫成模組。
核心模組中通常都需要載入和解除安裝函式來對裝置進行註冊/登出,因此設計載入/解除安裝函式:

#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

#define CHARDRIVER_MAJOR 234

static ssize_t cread(struct file *, char *, size_t, loff_t *);
static ssize_t cwrite(struct file*, const char*, size_t, loff_t*);

struct file_operations char_ops = {
    read:cread,
    write:cwrite,
 };
static
int global_var = 0; static int __init charDriver_init(void) { int ret; ret = register_chrdev(CHARDRIVER_MAJOR, "charDriver", &char_ops); if(ret<0) { printk("init failed"); return ret; } printk("init succeed"); return 0; } static void __exit charDriver_exit(void
) { int ret = 0; unregister_chrdev(CHARDRIVER_MAJOR, "charDriver"); if(ret<0) { printk("exit failed"); return; } printk("exit succeed"); } module_init(charDriver_init); module_exit(charDriver_exit); MODULE_LICENSE("GPL");

巨集module_init和module_exit用來註冊初始化/解除安裝函式,如上,charDriver_init被註冊為初始化函式,charDriver_exit
被註冊為解除安裝函式,分別在模組載入/解除安裝時被呼叫,MODULE_LICENSE宣告模組的許可協議。裝置的主裝置號被指定為234,裝置名”charDriver”。
可以看到,上面程式碼中還聲明瞭cread和cwrite兩個函式,並定義了一個struct file_operations型別的變數char_ops,關於file_operations
的定義在”include/linux/fs.h“中可以找到,其中有成員
read和write,型別為函式指標,read用來讀取裝置,write對裝置進行寫。而”read:cread,write:cwrite”指定了讀取/寫入裝置的處理函式cread和cwrite。
file_operations的定義
下面是cread和cwrite的函式定義:

static ssize_t cwrite(struct file *file, const char *buffer, size_t count, loff_t *ppos)
{
    copy_from_user(&global_var, buffer, sizeof(int));
    return sizeof(int);
}

static ssize_t cread(struct file* file, char *buffer, size_t count, loff_t*ppos)
{
    copy_to_user(buffer, &global_var, sizeof(int));
    return sizeof(int);
}

copy_to_user和copy_from_user原型在”uaccess.h”中,宣告如下:
unsigned long copy_from_user(void *to, const void *from, unsigned long n);
unsigned long copy_to_user (void * to, void * from, unsigned long len);
返回值是不能複製的位元組數。

將上面寫好的程式碼另存為檔案charDriver.c,編寫Makefile:

obj-m := charDriver.o
all:
         $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
        $(MAKE) -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

儲存到同一目錄下,執行make命令,編譯成功後目錄下會有charDriver.ko檔案執行命令;
insmod charDriver.ko,執行時需要管理員許可權,因此可能系統會提示操作被拒絕,可以用“sudo insmod charDriver.ko”提升許可權後再插入模組。
如果插入成功的話使用命令lsmod檢視已載入模組可以看到charDriver。
接下來執行“mknod /dev/charDriver c 234 0”建立裝置,裝置名為charDriver,型別為“c”即字元裝置,主裝置號234,次裝置號0。
使用“cat /proc/devices”檢視裝置可以看到“234 charDriver”一項。
檢視裝置

接下來編寫測試檔案:

#include<sys/types.h>
#include<sys/stat.h>
#include<stdio.h>
#include<fcntl.h>
#include <errno.h>

int main()
{
        int fd,num;
        //開啟"/dev/globalvar"
        fd=open("/dev/charDriver",O_RDWR,S_IRUSR|S_IWUSR);
        if(fd<0)
        {
                printf("open failed!");
        }

        if(fd>=0)
        {
            //初次讀 globalvar
            read(fd,&num,sizeof(int));
            printf("The globalvar is %d\n",num);
            //開啟"/dev/globalvar"
            fd=open("/dev/charDriver",O_RDWR,S_IRUSR|S_IWUSR);
        if(fd<0)
        {
                printf("open failed!");
        }

        if(fd>=0)
        {
                //初次讀 globalvar
                read(fd,&num,sizeof(int));
                printf("The globalvar is %d\n",num);
                //寫 globalvar
                printf("Please input the num written to globalvar\n");
                scanf("%d",&num);
                write(fd,&num,sizeof(int));
                //再次讀 globalvar
                read(fd,&num,sizeof(int));
                printf("The globalvar is %d\n",num);
                //關閉"/dev/globalvar"
                close(fd);
        }
}

編譯後執行,測試成功。

遇到的錯誤:
1、提示read:cread語句中指標不相容,錯誤提示如下圖。經查發現是因為cread函式宣告與file_operations中的read所指向的函式宣告不同,修改cread聲明後編譯成功。
這裡寫圖片描述
2、執行測試程式,開啟裝置失敗。經過網友啟發,提升許可權,使用管理員許可權執行測試程式,測試通過。原因不明。但猜測有可能是因為裝置處於核心態,因而禁止普通使用者的訪問。
這裡寫圖片描述