一個Linux2.6版核心字元驅動的例子

來源:互聯網
上載者:User

轉自:http://blog.csdn.net/racehorse/archive/2007/11/14/1884038.aspx

看了《Linux裝置驅動程式》的前幾章,我結合這篇教程中給出的一個2.4版核心的字元驅動,自己編寫了一個2.6版核心的驅動程式,並且加上了詳細的注釋。這個程式很簡單,但是對初學者把握2.6版核心的字元驅動的脈絡應該有一定的協助,也可以算作我對《Linux裝置驅動程式》前幾章學習的一個小結。

#globalvar.c

#include <linux/module.h>   //模組所需的大量符號和函數定義

#include <linux/init.h>     //指定初始化和清楚函數

#include <linux/fs.h>       //檔案系統相關的函數和標頭檔

#include <linux/cdev.h>     //cdev結構的標頭檔

#include <asm/uaccess.h>    //在核心和使用者空間中移動資料的函數

MODULE_LICENSE("GPL");      //指定代碼使用的許可證

//檔案操作函數的聲明

int globalvar_open(struct inode *, struct file *);

int globalvar_release(struct inode *, struct file *);

ssize_t globalvar_read(struct file *, char *, size_t, loff_t *);

ssize_t globalvar_write(struct file *, const char *, size_t, loff_t *);

int dev_major = 50;     //指定主裝置號

int dev_minor = 0;      //指定次裝置號

struct file_operations globalvar_fops= //將檔案操作與分配的裝置號相連

{

    owner: THIS_MODULE,                 //指向擁有該模組結構的指標

    open: globalvar_open,

    release: globalvar_release,

    read: globalvar_read,

    write: globalvar_write,

};

struct globalvar_dev                //用來表示我們定義裝置的結構

{

    int global_var;                 //這個變數代表要操作的裝置

    struct cdev cdev;               //核心中表示字元裝置的結構

};

struct globalvar_dev *my_dev;       //裝置結構的指標

static void __exit globalvar_exit(void)         //結束模組時的操作

{

    dev_t devno=MKDEV(dev_major, dev_minor);    //dev_t是用來表示裝置編號的結構

    cdev_del(&my_dev->cdev);                    //從系統中移除一個字元裝置

    kfree(my_dev);                              //釋放自訂的裝置結構

    unregister_chrdev_region(devno, 1);         //登出登入的驅動程式

    printk("globalvar unregister success\n");

}

static int __init globalvar_init(void)          //初始化模組的操作

{

    int ret, err;

    dev_t devno=MKDEV(dev_major, dev_minor);



    //動態分配裝置號,次裝置號已經指定

    ret=alloc_chrdev_region(&devno, dev_minor, 1, "globalvar");

    //儲存動態分配的主裝置號

    dev_major=MAJOR(devno);

    //根據期望值分配裝置號

    //ret=register_chrdev_region(devno, 1, "globalvar");

    if(ret<0)

    {

        printk("globalvar register failure\n");

        globalvar_exit();                      //如果註冊裝置號失敗就退出系統

        return ret;

    }

    else

    {

        printk("globalvar register success\n");

    }



    //為裝置在核心空間分配空間

    my_dev=kmalloc(sizeof(struct globalvar_dev), GFP_KERNEL);

    if(!my_dev)

    {

        ret=-ENOMEM;                           //如果分配失敗返回錯誤資訊

        printk("create device failed\n");

    }

    else                                       //如果分配成功就可以完成裝置的初始化

    {

        my_dev->global_var=0;                        //裝置變數初始化為0

        cdev_init(&my_dev->cdev, &globalvar_fops);   //初始化裝置中的cdev結構

        my_dev->cdev.owner=THIS_MODULE;              //初始化cdev中的所有者欄位

        err=cdev_add(&my_dev->cdev, devno, 1);       //向核心添加這個cdev結構的資訊

        if(err<0)

            printk("add device failure\n");          //如果添加失敗列印錯誤訊息

    }

    return ret;

}



//開啟裝置檔案系統調用對應的操作

int globalvar_open(struct inode *inode, struct file *filp)

{

    struct globalvar_dev *dev;

    //根據inode結構的cdev欄位,獲得整個裝置結構的指標

    dev=container_of(inode->i_cdev, struct globalvar_dev, cdev);

    //將file結構中的private_data欄位指向已指派的裝置結構

    filp->private_data=dev;

    return 0;

}



//關閉裝置檔案系統調用對應的操作

int globalvar_release(struct inode *inode, struct file *filp)

{

    return 0;

}

//讀裝置檔案系統調用對應的操作

ssize_t globalvar_read(struct file *filp, char *buf, size_t len, loff_t *off)

{

    //擷取指向已指派資料的指標

    struct globalvar_dev *dev=filp->private_data;

    //將裝置變數值複製到使用者空間

    if(copy_to_user(buf, &dev->global_var, sizeof(int)))

    {

        return -EFAULT;

    }

    return sizeof(int);    //返回讀取資料的大小

}

//寫裝置檔案系統調用對應的操作

ssize_t globalvar_write(struct file *filp, const char *buf, size_t len, loff_t *off)

{

    //擷取指向已指派資料的指標

    struct globalvar_dev *dev=filp->private_data;

    //從使用者空間複製資料到核心中的裝置變數

    if(copy_from_user(&dev->global_var, buf, sizeof(int)))

    {

        return -EFAULT;

    }

    return sizeof(int);    //返回寫資料的大小

}

module_init(globalvar_init);        //模組被裝載時調用globalvar_init

module_exit(globalvar_exit);        //模組被卸載時調用globalvar_exit

按如下內容編寫一個Makefile檔案,然後輸入make就可以開始自動編譯了。編譯之後得到了一個名為globalvar.ko的模組檔案,這就是我們需要的裝置驅動檔案。

#Makefile

ifneq ($(KERNELRELEASE), )

    obj-m := globalvar.o

else

    KERNELDIR ?= /lib/modules/$(shell uname -r)/build

    PWD := $(shell pwd)

all:

    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules

clean:

    $(MAKE) -C $(KERNELDIR) M=$(PWD) clean

endif

接下來運行如下代碼,將驅動加入核心。

insmod globalvar.ko

此時可以用dmesg或lsmod命令檢查一下模組載入是否成功。如果沒有問題,就可以使用mknod構造一個裝置檔案:

mknod /dev/globalvar c

最後,按照下面內容編寫一個簡單的測試檔案並用gcc編譯。

#test.c

#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h>

#include <fcntl.h>

main()

{

    int fd, num;

    fd=open("/dev/globalvar", O_RDWR, S_IRUSR|S_IWUSR);     //可讀寫方式開啟裝置檔案

    if(fd!=-1)

    {

        read(fd, &num, sizeof(int));                        //讀取裝置變數

        printf("The globalvar is %d\n", num);

        printf("Please input the num written to globalvar\n");

        scanf("%d", &num);

        write(fd, &num, sizeof(int));                       //寫裝置變數

        read(fd, &num, sizeof(int));                        //再次讀取剛才寫的值

        printf("The globalvar is %d\n", num);

        close(fd);                                          //關閉裝置檔案

    }

    else

    {

        printf("Device open failure\n");

    }

}

如果前面的內容都無誤,就可以使用上面的測試程式讀寫剛才編寫的裝置檔案了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.