Linux LED驅動原始碼簡析

Quartz010發表於2016-10-17

驅動的載入與解除安裝函式

驅動載入服務函式

int major;
static int first_drv_init(void)
{
    major = register_chrdev(0, "first_drv", 
    &first_drv_fops); 
    // 註冊驅動,其中第一個引數為0,則表示採用系統動態分配的主裝置號
    //第二個引數是其註冊的裝置名
    //第三個很重要的引數,就是我們配置驅動函式的結構
    //(具體見上一篇對該函式的解析)

    firstdrv_class = class_create(THIS_MODULE, 
    "firstdrv");
    //建立一個驅動類
    firstdrv_class_dev = 
    class_device_create(firstdrv_class, NULL, 
    MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */
    //用於自動的在系統的目錄下建立一個字元裝置的節點
    gpfcon = (volatile unsigned long 
    *)ioremap(0x56000050, 16);
    //通過記憶體對映到真實地址
    gpfdat = gpfcon + 1;
    //配置GPIO為輸出

    return 0;

}

驅動解除安裝服務函式

static void first_drv_exit(void)
{
    unregister_chrdev(major, "first_drv");
    //告訴核心,解除安裝該驅動
    //major是程式的主裝置號
    class_device_unregister(firstdrv_class_dev);
    class_destroy(firstdrv_class);
    //這兩句用於刪除在檔案系統中建立的節點

    iounmap(gpfcon);
    //取消GPIO的對映
}

最後別忘了,把這兩個函式註冊進去

module_init(first_drv_init);
module_exit(first_drv_exit);

重要的結構體

static struct file_operations first_drv_fops = {
    .owner  =   THIS_MODULE,    
    /* 這是一個巨集,推向編譯模組時自動建立的__this_module變數 */
    //說是與神祕高階特性有關,不懂,先這麼寫       
    .open   =   first_drv_open,     
    .ioctl  =   first_drv_ioctl,       
};

用來儲存驅動核心模組提供的對裝置進行各種操作的函式的指標。該結構體的每個域都對應著驅動核心模組用來處理某個被請求的事務的函式的地址

驅動函式

open()函式

static int first_drv_open(struct inode *inode, struct 
file *file)
{
    printk("first_drv_open\n");
    /* 配置GPF4,5,6為輸出 */
    ......
    return 0;
}

ioctl()函式

這個函式比較重要,用於應用程式到驅動程式的引數傳遞

int ioctl(int fd, ind cmd, …);
//最多可以傳遞三個引數 

static int first_dev_ioctl(struct inode *inode, 
struct file *file, int cmd, int arg)
{
    printk("first_drv_ioctl\n");
    ......
}

證書

因為Linux遵循GNU/GPL ,所以要在核心做出宣告
(要不,核心會傲嬌…)

MODULE_LICENSE("GPL");

就此,一個簡單的led的驅動程式就是分析完了,下面開始說說,驅動是如何被使用的。

在應用層,和硬體層之間的中間層,就是驅動所在的位置那麼我們的驅動程式,一定是要通過應用程式呼叫的

驅動測試程式

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

int main(int argc, char **argv)
{
    int fd;

    fd = open("/dev/xyz", O_RDWR);
    if (fd < 0) {
        printf("can't open!\n");
    }
    ...
    ioctl(fd, strtol(argv[2]));
    return 0;
}

一套驅動就算完成了,
長路漫漫,這這只是最簡單的第一步

相關文章