字元設備驅動程式

 


在驅動程式一開始會先讀取module_init中的devone_init初始化函式。

module_init(devone_init);

 

在初始話的函式中設置了,動態配置major number、設定file_oprations結構定義、自動建立對應的裝置檔。

static int devone_devs = 4; /* 這一個變數的設定它的數值影響下面會建立多少個設備 */

static int devone_init(void)

{

        dev_t dev = MKDEV(devone_major, 0);

        int alloc_ret = 0;

        int major;

        int cdev_err = 0;

        struct class_device *class_dev = NULL;

       

#ifdef DEBUG_demo

    printk("Before dynamic allocate major=%d minor=%d alloc_ret=%d\n",MAJOR(dev),MINOR(dev),alloc_ret);

#endif

 

        alloc_ret = alloc_chrdev_region(&dev, 0, devone_devs, "devone");   /* 動態配置major number */

       

#ifdef DEBUG_demo

    printk("After dynamic allocate major=%d minor=%d alloc_ret=%d\n",MAJOR(dev),MINOR(dev),alloc_ret);

#endif

 

        if (alloc_ret)

                goto error;       /* 如果動態配置發生錯誤則跳至error */

        devone_major = major = MAJOR(dev);    /* 獲得major number */

       

#ifdef DEBUG_demo 

        printk("Dynamic allocate successful ! Get  devone_major = major = MAJOR(dev) = %d\n",major);

#endif

 

    /* 設定file_oprations結構定義 */ 

        cdev_init(&devone_cdev, &devone_fops);

        devone_cdev.owner = THIS_MODULE;

        devone_cdev.ops = &devone_fops;

        cdev_err = cdev_add(&devone_cdev, MKDEV(devone_major, devone_minor), devone_devs);

        if (cdev_err)

                goto error;

 

        /* register class */

        devone_class = class_create(THIS_MODULE, "devone");

        if (IS_ERR(devone_class)) {

                goto error;

        }

       

        /* 掛載模組時自動建立對應的裝置檔devone0 ~ devone2... */

        for(devone_minor=0;devone_minor<devone_devs;devone_minor++)

        {

        devone_dev[devone_minor] = MKDEV(devone_major, devone_minor);

        class_dev = class_device_create(

                                        devone_class,

                                        NULL,

                                        devone_dev[devone_minor],

                                        NULL,

                                        "devone%d",

                                        devone_minor);

        }

 

        printk(KERN_ALERT "devone driver(major %d) installed.\n", major);

 

        return 0;

 

error:

        if (cdev_err == 0)

                cdev_del(&devone_cdev);

 

        if (alloc_ret == 0)

                unregister_chrdev_region(dev, devone_devs);

 

        return -1;

}

 

File_operations結構定義,其中設定了openreleasewriteread…

struct file_operations devone_fops = {

    .open = devone_open,

        .release = devone_close,

        .write = devone_write,

        .read = devone_read,

};

 

在此file_oprations中還設定了Handler切換

static int devone_open(struct inode *inode, struct file *file)

{

        printk("%s: major %d minor %d (pid %d)\n", __func__,

                        imajor(inode),

                        iminor(inode),

                        current->pid

                        );

   /* 透過minor number去做切換Handler選擇 */

   switch (iminor(inode)) {

                case 0:

                        file->f_op = &zero_fops;

                        break;

 

                case 1:

                        file->f_op = &one_fops;

                        break;

 

                default:

                        return 0;

        }

 

    /* 設定當檔案有開啟時,才實行上面所做過的選擇。 */

        if (file->f_op && file->f_op->open)

                return file->f_op->open(inode, file);

        return 0;

}

 

另外所設定的file_opreations也跟上面一樣都有openreleasewriteread

struct file_operations zero_fops = {

        .open = zero_open,

        .release = zero_close,

        .read = zero_read,

        .write = zero_write,

};

 

struct file_operations one_fops = {

        .open = one_open,

        .release = one_close,

        .read = one_read,

        .write = one_write,

};

 

當卸載sample模組時,會先讀取module_exitdevone_exit函式。

module_exit(devone_exit);

在裡面做,刪除裝置、刪除class、及註銷之前註冊的裝置。

static void devone_exit(void)

{

        dev_t dev = MKDEV(devone_major, 0);

        int i;

 

        /* unregister class */

        for(i=0;i<devone_devs;i++)

    {

        class_device_destroy(devone_class, devone_dev[i]);  /* 刪除裝置 */

        class_destroy(devone_class);   /* 刪除先前登記的 class */

        }

 

        cdev_del(&devone_cdev);

        unregister_chrdev_region(dev, devone_devs);

 

        printk(KERN_ALERT "devone driver removed.\n");

 

}


實際測試

 

當插入移除模組時,可以在下面這裏看到之前設定printfk()顯示設定的資訊。

# insmod sample.ko

# rmmod sample

# dmesg | tail

[47692.501184] Before dynamic allocate major=0 minor=0 alloc_ret=0

[47692.501397] After dynamic allocate major=253 minor=0 alloc_ret=0

[47692.501416] Dynamic allocate successful ! Get  devone_major = major = MAJOR(dev) = 253

[47692.502622] devone driver(major 253) installed.

[47698.980427] devone driver removed.

 

執行下面這行指令,可以看到自動建立的設備

# ls /dev/devone*

/dev/devone0  /dev/devone1  /dev/devone2  /dev/devone3

 

編譯 ;執行simple.c範例

#include <stdlib.h>

#include <string.h>

#include <sys/time.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <errno.h>

 

#define DEVFILE "/dev/devone0"

 

int open_file(void)

{

        int fd;

       

        printf("Start open fd\n");

        fd = open(DEVFILE, O_RDWR);

        printf("Open fd finish\n");

        if (fd == -1) {

        printf("open event\n");

                perror("open");

        }

        return (fd);

}

 

void close_file(int fd)

{

        if (close(fd) != 0) {

        printf("close event\n");

                perror("close");

        }

}

 

 

int main(void)

{

        int fd;

       

        printf("Call open function\n");

        fd = open_file();

        printf("fd :%d\n",fd);

        sleep(1);

        printf("Call close function\n");

        close_file(fd);

 

 

        return 0;

}

 

由於已經自動建立了設備,所以執行完這個程式之後出現了下面的結果,可以看出驅動程式在讀取設備時是沒問題的。

結果:

Call open function

Start open fd

Open fd finish

fd :3

Call close function

 

也可以利用cat來檢視設備。

# cat /dev/devone0

# cat /dev/devone1

# cat /dev/devone2

# dmesg | tail

[48378.554835] devone_open: major 253 minor 0 (pid 18368)

[48378.554845] zero_open: major 253 minor 0 (pid 18368)

[48378.554987] zero_read called

[48378.555009] zero_close: major 253 minor 0 (pid 18368)

[48381.676440] devone_open: major 253 minor 1 (pid 18369)

[48381.676541] one_open: major 253 minor 1 (pid 18369)

[48381.676602] one_read called

[48381.676681] one_close: major 253 minor 1 (pid 18369)

[48384.888112] devone_open: major 253 minor 2 (pid 18370)

[48384.889202] devone_read called

[48384.889618] devone_close: major 253 minor 2 (pid 18370)

 

我的原始檔

資料來源:

博碩 Linux Device Driver Programming

設備驅動程式講義     by 明新科技大學 曾宏立 老師

arrow
arrow
    全站熱搜

    flykof 發表在 痞客邦 留言(1) 人氣()