Linux Platform驅動模型(三) _platform+cdev

来源:http://www.cnblogs.com/xiaojiang1025/archive/2017/02/06/6369065.html
-Advertisement-
Play Games

平臺匯流排是一種實現設備信息與驅動方法相分離的方法,利用這種方法,我們可以寫出一個更像樣一點的字元設備驅動,即使用cdev作為介面,平臺匯流排作為分離方式: xjkeydrv_init():模塊載入函數 └──platform_driver_register()將驅動對象模塊註冊到平臺匯流排 └──pla ...


平臺匯流排是一種實現設備信息與驅動方法相分離的方法,利用這種方法,我們可以寫出一個更像樣一點的字元設備驅動,即使用cdev作為介面,平臺匯流排作為分離方式:

xjkeydrv_init():模塊載入函數
└──platform_driver_register()將驅動對象模塊註冊到平臺匯流排
        └──platform_driver.probe()探測函數,提取相應的信息
                └──xjkey_init():初始化cdev對象,創建設備文件等關於cdev介面創建的工作
                        └──cdev_init():將cdev結構與fops綁定到一起,在fops實現操作介面與控制硬體的邏輯

static struct class *cls = NULL;

static int major = 0;
static int minor = 0;
const  int count = 1;

#define DEVNAME "xjkey"

static struct cdev *xjkeyp = NULL;

static unsigned long irqflags;
static int irq;

static atomic_t tv;

#if 0
/{
    key@26{
        compatible = "xj4412,key";
        interrupt-parent = <&gpx1>;
        interrupts = <2 2>;
    };
};
#endif

static irqreturn_t handler_t(int irq, void *dev_id)
{
    printk(KERN_INFO "%s : %s : %d\n", __FILE__, __func__, __LINE__);
    return IRQ_HANDLED;
}

//打開設備
static int xjkey_open(struct inode *inode, struct file *filp)
{
    //get major and minor from inode
    printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
        imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);

    if(!atomic_dec_and_test(&tv)){
        atomic_inc(&tv);
        return -EBUSY;
    }

    return request_irq(irq, handler_t, irqflags, DEVNAME, NULL);
}

//關閉設備
static int xjkey_release(struct inode *inode, struct file *filp)
{
    //get major and minor from irqflagsinode
    printk(KERN_INFO "(major=%d, minor=%d), %s : %s : %d\n",
        imajor(inode), iminor(inode), __FILE__, __func__, __LINE__);

    free_irq(irq, NULL);

    atomic_inc(&tv);
    return 0;
}

static struct file_operations fops = {
    .owner  = THIS_MODULE,
    .open   = xjkey_open,
    .release= xjkey_release,
};

static int xjkey_init(void)
{
    dev_t devnum;
    int ret, i;

    struct device *devp = NULL;

    //get command and pid
    printk(KERN_INFO "(%s:pid=%d), %s : %s : %d\n",
        current->comm, current->pid, __FILE__, __func__, __LINE__);

    //1. alloc cdev objxjkey_init
    xjkeyp = cdev_alloc();
    if(NULL == xjkeyp){
        return -ENOMEM;
    }

    //2. init cdev obj
    cdev_init(xjkeyp, &fops);

    ret = alloc_chrdev_region(&devnum, minor, count, DEVNAME);
    if(ret){
        goto ERR_STEP;
    }
    major = MAJOR(devnum);

    //3. register cdev obj
    ret = cdev_add(xjkeyp, devnum, count);
    if(ret){
        goto ERR_STEP1;
    }

    cls = class_create(THIS_MODULE, DEVNAME);
    if(IS_ERR(cls)){
        ret = PTR_ERR(cls);
        goto ERR_STEP1;
    }

    for(i = minor; i < (count+minor); i++){
        devp = device_create(cls, NULL, MKDEV(major, i), NULL, "%s%d", DEVNAME, i);
        if(IS_ERR(devp)){
            ret = PTR_ERR(devp);
            goto ERR_STEP2;
        }
    }

    // init atomic_t
    atomic_set(&tv, 1);

    //get command and pid
    printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - ok.\n",
        current->comm, current->pid, __FILE__, __func__, __LINE__);
    return 0;

ERR_STEP2:
    for(--i; i >= minor; i--){
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);

ERR_STEP1:
    unregister_chrdev_region(devnum, count);

ERR_STEP:
    cdev_del(xjkeyp);

    //get command and pid
    printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - fail.\n",
        current->comm, current->pid, __FILE__, __func__, __LINE__);
    return ret;
}

static void xjkey_exit(void)
{
    int i;
    //get command and pid
    printk(KERN_INFO "(%s:pid=%d), %s : %s : %d - leave.\n",
        current->comm, current->pid, __FILE__, __func__, __LINE__);

    for(i=minor; i < (count+minor); i++){
        device_destroy(cls, MKDEV(major, i));
    }
    class_destroy(cls);

    unregister_chrdev_region(MKDEV(major, minor), count);
    cdev_del(xjkeyp);
}

static int xjkey_probe(struct platform_device *pdev)
{
    struct resource *irq_res;
    irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    if(irq_res){
        irq = irq_res->start;
        irqflags = irq_res->flags & IRQF_TRIGGER_MASK;
    }else{
        printk(KERN_INFO "No 0 irq\n");
        return -EINVAL;     
    }

    return xjkey_init();
}

static int xjkey_remove(struct platform_device *pdev)
{
    printk(KERN_INFO "%s : %s : %d - leave.\n", __FILE__, __func__, __LINE__);
    xjkey_exit();
    return 0;
}

struct of_device_id of_tbl[] = {
    {.compatible = "xj4412,key",},
    {},
};
MODULE_DEVICE_TABLE(of, of_tbl);


//1. alloc obj
static struct platform_driver xjkeydrv = {
    .probe  = xjkey_probe,
    .remove = xjkey_remove,

    .driver = {
        .name = DEVNAME,
        .of_match_table = of_tbl,
    },
};

//3. register obj
module_platform_driver(xjkeydrv);

MODULE_LICENSE("GPL");




您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  •  ...
  • 部署環境:VM虛擬機 操作系統:CentOS-6.8-x64 IP地址:192.168.31.91Mysql資料庫版本:5.6.34 Cmake軟體包版本:3.5.2Nginx軟體包版本:1.10.2 PHP軟體包版本:5.6.30 依賴軟體包版本:libiconv-1.14.tar.gz 免費開源 ...
  • 本文主要介紹瞭如何在Linux環境下,在QT中如何引用Shark machine learning library的方法。 ...
  • 為了方便與UCOS對比,順序按照UCOS那篇編寫。 0、一些移植、系統相關 1、框架寫法(個人習慣相關) 1-1、main 函數里創建一個開始任務 1-2、開始任務里,創建我們要運行的多個任務 2、任務創建、掛起、刪除 2-0、相關配置 2-1、任務創建(動態) 2-2、任務掛起 2-3、任務解掛 ...
  • 方法及其簡單,只需要兩步即可: 1、第一步: 打開終端,輸入sudo su命令。 –此處的密碼為普通用戶的密碼,也就是開機時輸入的密碼。 2、第二步: 直接sudo passwd root就重置了roor密碼了。 此時輸入新的密碼即可,個人建議密碼最好字母加數字相結合。 ...
  • 安裝inotify [root@server ~]# mkdir -p /home/oldboy/tools 安裝inotify-tools-3.14.tar.gz [root@server tools]# ls -l /proc/sys/fs/inotify/ #出現下麵三個表示支持inotify... ...
  • 硬碟分區 常識 主分區:最多只能有4個 擴展分區:用於突破主分區最多4個的限制 *最多只能有1個 *主分區+擴展分區最多有4個 *不能寫入數據,只能包含邏輯分區 邏輯分區 格式化:實際是寫入文件系統,文件系統有: Window: FAT16:最大支持2G分區 FAT32:單文件不超過4G,支持16T ...
  • "Linux設備樹語法詳解" 一文中介紹了設備樹的語法,這裡主要介紹內核中提供的操作設備樹的API,這些API通常都在 "include/of.h" 中聲明。 device_node 內核中用下麵的這個結構描述設備樹中的一個節點,後面的API都需要一個device_node對象作為參數傳入。 str ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...