1. 程式人生 > >驅動框架入門——以LED為例

驅動框架入門——以LED為例

一、什麼是驅動框架?

1、驅動是誰寫的?

(1)驅動開發工程師;

(2)核心維護者;

2、驅動程式設計協作要求

(1)介面標準化;

(2)核心開發者應該儘量降低驅動開發者難度;

3、到底什麼是驅動框架?

(1)驅動框架

  • 核心中驅動部分維護者,針對每個種類(比如LED、LCD、蜂鳴器等等)的裝置,都設計有一套成熟的、標準的、典型的驅動實現;
  • 它是把不同廠家的同類硬體驅動中相同的部分抽出來自己實現好,再把不同部分留出介面給具體的驅動開發工程師來實現。
  • 降低了難度,也標準化。

(2)核心維護者在核心中設計了一些(統一管控系統資源的)體系

  • 這些體系讓核心能夠(對資源在各個驅動之間的使用)統一協調和分配,保證整個核心的穩定健康執行。
  • 譬如系統中所有的GPIO就屬於系統資源,每個驅動模組如果要使用某個GPIO就要先呼叫特殊的介面先申請,申請到後使用,使用完後要釋放。
  • 又譬如中斷號也是一種資源,驅動在使用前也必須去申請。
  • 這體系也是驅動框架的組成部分。

(3)一些特定的介面函式、一些特定的資料結構,這些是驅動框架的直接表現。

二、核心驅動框架中LED的基本情況

1、相關檔案

(1)drivers/leds目錄

  • 這個目錄就是驅動框架規定的LED這種硬體的驅動應該待的地方。

(2)drivers/leds目錄下有led-class.c和led-core.c

  • 這兩個檔案加起來屬於LED驅動框架的第一部分,這兩個檔案是核心開發者提供的,他們描述的是核心中所有廠家的不同LED硬體的相同部分的邏輯。

(3)此目錄下有leds-xxxx.c

  • 這個檔案是LED驅動框架的第2部分,是由不同廠商的驅動工程師編寫新增的;
  • 廠商驅動工程師結合自己公司的硬體的不同情況來對LED進行操作,使用第一部分提供的介面來和驅動框架進行互動,最終實現驅動的功能。

2、九鼎移植的核心中led驅動

  • 九鼎實際未使用核心推薦的led驅動框架;
  • drivers/char/led/x210-led.c;

3、案例分析驅動框架的使用

(1)以leds-s3c24xx.c為例。

  • leds-s3c24xx.c中通過呼叫led_classdev_register來完成LED驅動的註冊,而led_classdev_register是在drivers/leds/led-class.c中定義的。
  • 所以其實SoC廠商的驅動工程師是呼叫核心開發者在驅動框架中提供的介面來實現自己的驅動的。

(2)驅動框架的關鍵點

  • 核心開發者提供了什麼?
  • 驅動開發者要完成什麼?

4、典型的驅動開發行業現狀

(1)核心開發者對驅動框架進行開發和維護、升級,對應led-class.c和led-core.c;

(2)SoC廠商的驅動工程師對裝置驅動原始碼進行編寫、除錯,提供參考版本,對應leds-s3c24xx.c;(全志、三星、華為等晶片廠商)

(3)做產品的廠商的驅動工程師以SoC廠商提供的驅動原始碼為基礎,來做移植和除錯;

三、.初步分析led驅動框架原始碼

1、涉及到的檔案

  • led-core.c;(一些巨集與標頭檔案包含而已)
  • led-class.c;

(1)分析發現,LED驅動框架中,核心開發者實現的部分主要是led-class.c;

(2)led-class.c其實就是一個核心模組(明顯的特徵是,有安裝和解除安裝函式)

  • 那麼對led-class.c的分析應該從下往上,遵從對模組的基本分析方法。

(3)為什麼LED驅動框架中,核心開發者實現的部分,要實現成一個模組?

  • 因為核心開發者希望這個驅動框架是可以被裝載/解除安裝的。
  • 這樣當核心使用者不需要這個驅動框架時可以完全去掉,需要時可以隨時加上。

(4)led_init在/sys/class目錄下建立“leds”這個類名;led_exit銷燬“leds”這個類名。

2、subsys_initcall

(1)subsys_initcall是一個巨集,定義在Linux/init.h中。

  • 這個巨集的功能是:將其宣告的函式放到一個特定的段:.initcall4.init。

(2)分析module_init巨集,可以看出它將函式放到了.initcall6.init段中。

  • module_init
  •       __initcall
  •             device_initcall
  •                  __define_initcall("6",fn,6)

(3)核心在啟動過程中,需要按照順序執行很多事情。核心如何實現按照先後順序去做很多初始化操作?

  • 核心的解決方案就是將核心啟動時要呼叫的所有函式歸類,然後每個類按照一定的次序去呼叫執行。
  • 這些分類名就叫.initcalln.init,n的值從1到8。
  • 核心開發者在編寫核心程式碼時只要將函式設定合適的級別,連結的時候,這些函式就會被放入特定的段,核心啟動時再按照(核心連結指令碼中指定的)段順序去依次執行各個段即可。核心連結指令碼(編譯之後才有)在arch/arm/kernel/vmlinux.lds中。

(4)經過分析可以看出,subsys_initcall和module_init的作用是一樣的,只不過前者所宣告的函式要比後者在核心啟動時的執行順序更早。

3、led_class_attrs

(1)什麼是attribute?

  • 對應將來/sys/class/leds/目錄裡的內容,一般是檔案和資料夾。
  • 這些檔案其實就是sysfs開放給應用層的一些操作介面(非常類似於/dev/目錄下的那些裝置檔案,對這些裝置檔案的操作API,對應file_operations裡面的函式)。

(2)attribute有什麼用?

  • 讓應用程式可以通過/sys/class/leds/目錄下面的屬性檔案來操作驅動進而操作硬體裝置。

(3)attribute其實是另一條驅動實現的路線(不再有c_dev相關的函式操作),有區別於之前講的file_operations那條線。

4、led_classdev_register設備註冊函式

  • led_classdev_register函式建立一個屬於leds這個類的一個裝置,其實就是去註冊一個裝置。
  • 這個函式是led驅動框架中,核心開發者提供給SoC廠家驅動開發者的一個註冊驅動的介面。
  • 當使用led驅動框架去編寫驅動的時候,這個led_classdev_register函式的作用類似於之前使用file_operations方式去註冊字元裝置驅動時的register_chrdev函式。
  • 之前使用file_operations方式時,在sys/class目錄下建立一個類,然後再建立屬於這個類的一個裝置。

5、led_classdev結構體

  • 在leds.h檔案中

四、在核心中新增或去除某個驅動

1、去除九鼎移植的LED驅動

(1)九鼎移植的驅動(在應用層的介面)在/sys/devices/platform/x210-led/目錄下,有led1、led2、led3、led4四個裝置檔案,各自管理一個led。

  • echo 1 > led1可以點亮其中的led1;

(2)要去掉九鼎自己移植的led驅動,要在make menucofig中去掉選擇項,然後重新make得到zImage,然後重啟時啟動這個新的zImage即可。

  • 新的核心啟動後,如果/sys/devices/platform/目錄下已經沒有了x210-led這個目錄,就說明我們去掉這個驅動成功了。

(3)為什麼make menuconfig就能去掉這個驅動?

  • 理解make menuconfig的功能。

2、新增led驅動框架支援

當前核心中沒有LED驅動框架,要去新增它。(/sys/class目錄下沒有此類,因此要去新增此類)

  • 主要是menuconfig的操作。

3、sysfs中的內容分析

4、後續展望:完成leds-x210.c

五、基於驅動框架寫led驅動1

1、分析

(1)參考哪裡?  drivers/leds/leds-s3c24xx.c檔案

(2)關鍵點?led_classdev_register函式

2、動手寫led驅動模組

程式碼如下

注意設備註冊函式、設備註銷函式

  1. #include <linux/module.h>     // module_init  module_exit  
  2. #include <linux/init.h>           // __init   __exit  
  3. #include <linux/fs.h>  
  4. #include <linux/leds.h>  
  5. #include <mach/regs-gpio.h>  
  6. #include <mach/gpio-bank.h>  
  7. #include <linux/io.h>  
  8. #include <linux/ioport.h>  
  9. #define GPJ0CON     S5PV210_GPJ0CON  
  10. #define GPJ0DAT     S5PV210_GPJ0DAT  
  11. static struct led_classdev mydev;           // 定義結構體變數  
  12. // 這個函式就是要去完成具體的硬體讀寫任務的  
  13. static void s5pv210_led_set(struct led_classdev *led_cdev,enum led_brightness value)  
  14. {  
  15.     printk(KERN_INFO "s5pv210_led_set\n");  
  16.     // 在這裡根據使用者設定的值來操作硬體  
  17.     // 使用者設定的值就是value  
  18.     if (value == LED_OFF)  
  19.     {  
  20.         // 使用者給了個0,希望LED滅  
  21.         writel(0x11111111, GPJ0CON);  
  22.         writel(((1<<3) | (1<<4) | (1<<5)), GPJ0DAT);  
  23.     }  
  24.     else  
  25.     {  
  26.         // 使用者給的是非0,希望LED亮  
  27.         writel(0x11111111, GPJ0CON);  
  28.         writel(((0<<3) | (0<<4) | (0<<5)), GPJ0DAT);  
  29.     }  
  30. }  
  31. static int __init s5pv210_led_init(void)  
  32. {  
  33.     // 使用者insmod安裝驅動模組時會呼叫該函式  
  34.     // 該函式的主要任務就是去使用led驅動框架提供的設備註冊函式來註冊一個裝置  
  35.     int ret = -1;  
  36.     mydev.name = "myled";//裝置的名字  
  37.     mydev.brightness = 255;   
  38.     mydev.brightness_set = s5pv210_led_set;  
  39.     ret = led_classdev_register(NULL, &mydev);  
  40.     if (ret < 0) {  
  41.         printk(KERN_ERR "led_classdev_register failed\n");  
  42.         return ret;  
  43.     }  
  44.     return 0;  
  45. }  
  46. static void __exit s5pv210_led_exit(void)  
  47. {  
  48.     led_classdev_unregister(&mydev);  
  49. }  
  50. module_init(s5pv210_led_init);  
  51. module_exit(s5pv210_led_exit);  
  52. // MODULE_xxx這種巨集作用是用來新增模組描述資訊  
  53. MODULE_LICENSE("GPL");                          // 描述模組的許可證  
  54. MODULE_AUTHOR("aston <[email protected]>");       // 描述模組的作者  
  55. MODULE_DESCRIPTION("s5pv210 led driver");       // 描述模組的介紹資訊  
  56. MODULE_ALIAS("s5pv210_led");                    // 描述模組的別名資訊  

六、基於驅動框架寫led驅動2

1、程式碼實踐

(1)除錯

(2)分析

  • 我們寫的驅動確實工作了,被載入了,/sys/class/leds/目錄下確實多出來了一個表示裝置的資料夾。
  • 資料夾裡面有相應的操控led硬體的2個屬性brightness和max_brightness。
  • led-class.c中brightness方法有一個show方法和store方法,這兩個方法對應使用者在/sys/class/leds/myled/brightness目錄下直接去讀寫這個檔案時實際執行的程式碼。
  • 當我們show brightness時,實際就會執行led_brightness_show函式。
  • 當我們echo 1 > brightness時,實際就會執行led_brightness_store函式。

(3)show方法實際要做的就是讀取LED硬體資訊,然後把硬體資訊返回

  • 因此show方法和store方法會去操控硬體;
  • 但是led-class.c檔案又屬於驅動框架中的檔案,它本身無法直接讀取具體硬體,因此在show和store方法中使用函式指標的方式呼叫了struct led_classdev結構體中的相應的讀取/寫入硬體資訊的方法。

(4)struct led_classdev結構體中的實際用來讀寫硬體資訊的函式,就是我們自己寫的驅動檔案leds-s5pv210.c中要提供的。

2、新增硬體操作

七、基於驅動框架寫led驅動3

1、在驅動中將4個LED分開

(1)好處

  • 驅動層實現對各個LED裝置的獨立訪問,並嚮應用層展示出4個操作介面led1、led2、led3、led4,這樣應用層可以完全按照自己的需要對LED進行控制。
  • 驅動的設計理念:不要對最終需求功能進行假定(不能假定使用者進行什麼操作,比如是幾個led一起操作還是一個操作而已?),而應該只是直接的對硬體的操作。
  • 有一個概念就是:機制和策略的問題。在硬體操作上驅動只應該提供機制(具體實現)而不是策略(方法、主意、解決方案)。策略由應用程式來做。

(2)如何實現

  1. #include <linux/module.h>     // module_init  module_exit  
  2. #include <linux/init.h>           // __init   __exit  
  3. #include <linux/fs.h>  
  4. #include <linux/leds.h>  
  5. #include <mach/regs-gpio.h>  
  6. #include <mach/gpio-bank.h>  
  7. #include <linux/io.h>  
  8. #include <linux/ioport.h>  
  9. #define GPJ0CON     S5PV210_GPJ0CON  
  10. #define GPJ0DAT     S5PV210_GPJ0DAT  
  11. static struct led_classdev mydev1;          // 定義結構體變數  
  12. static struct led_classdev mydev2;          // 定義結構體變數  
  13. static struct led_classdev mydev3;          // 定義結構體變數  
  14. // 這個函式就是要去完成具體的硬體讀寫任務的  
  15. static void s5pv210_led1_set(struct led_classdev *led_cdev,  
  16.                 enum led_brightness value)  
  17. {  
  18.     printk(KERN_INFO "s5pv210_led1_set\n");  
  19.     writel(0x11111111, GPJ0CON);  
  20.     // 在這裡根據使用者設定的值來操作硬體  
  21.     // 使用者設定的值就是value  
  22.     

    相關推薦

    驅動框架入門——LED

    一、什麼是驅動框架?1、驅動是誰寫的?(1)驅動開發工程師;(2)核心維護者;2、驅動程式設計協作要求(1)介面標準化;(2)核心開發者應該儘量降低驅動開發者難度;3、到底什麼是驅動框架?(1)驅動框架核心中驅動部分維護者,針對每個種類(比如LED、LCD、蜂鳴器等等)的裝置

    《5.linux驅動開發-第4部分-5.4.驅動框架入門LED

    《5.linux驅動開發-第4部分-5.4.驅動框架入門之LED》 第一部分、章節目錄 5.4.1.何謂驅動框架 5.4.2.核心驅動框架中LED的基本情況 5.4.3.初步分析led驅動框架原始碼1 5.4.4.初步分析led驅動框架原始碼2 5.4.5.在核心中新增或去除某個驅動 5

    GPIO的配置程式(LED

    基於普中的STM32開發板原理圖: void LED_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; //定義GPIO配置的結構體 __HAL_RCC_GPIOC_CLK_ENABLE(

    Linux內核調用I2C驅動_MPU6050

    匹配 獲取 inux error: sdn git alt 說明 時鐘 Linux內核調用I2C驅動_以MPU6050為例 0. 導語 最近一段時間都在惡補數據結構和C++,加上導師的事情比較多,Linux內核驅動的學習進程總是被阻礙、不過,十一假期終於沒有人打擾,有這個奢

    python 爬蟲 如何通過scrapy框架簡單爬取網站資訊--51job

    Scrapy框架三大優點: Scrapy框架是用純Python實現一個為了爬取網站資料、提取結構性資料而編寫的應用框架,用途非常廣泛。 框架的力量,使用者只需要定製開發幾個模組就可以輕鬆的實現一個爬蟲,用來抓取網頁內容以及各種圖片,非常之方便。 Scrapy

    ThinkPhp ,理解 PHP 框架的入口

    2018-12-29 19:55 以 ThinkPhp 為例,理解 PHP 框架的入口 以 ThinkPhp 為例,理解 PHP 框架的入口。 ThinkPhp 是用 PHP 語言寫的,它所影響到的範圍是 PHP 內部,ThinkPhp 必須先被載入起來,它才能工作,所以整體思路是獲得入口的載入機會,然後

    linux驅動由淺入深系列:塊裝置驅動之三(塊裝置驅動結構分析,mmc

    linux驅動由淺入深系列:塊裝置驅動之一(高通eMMC分割槽例項)前一篇文章介紹了塊裝置驅動在linux框架張的位置關係,本文來分析一下驅動本身。塊裝置驅動的模型還是基本基於字元裝置驅動的,可以簡單理解為塊裝置僅僅增加了操作緩衝區,對使用者操作請求進行佇列重排。因此只在有了

    【轉】怎麼在Linux上安裝印表機驅動Ubuntu

    通常來說,你不需要手動在Linux上安裝硬體驅動。系統會自動檢測計算機硬體,然後自動為你安裝驅動。但是,對於印表機,情況就不一樣了。事實上,Linux是通過CUPS(Common Unix Printing System)處理列印服務。Apple是CUPS的主要開發者,M

    AJAX入門學習-2:基於JS的AJAX實現(Django)

    data from 博客 password als ont 提交數據 open type 小生博客:http://xsboke.blog.51cto.com 如果有疑問,請點擊此處,然後發表評論交流,作者會及時回復。 ----

    原創:PHP利用session,實現用戶登錄後回到點擊的頁面(本文TP

    con gop query php代碼 自帶 ttr strpos 手機 roo 1、以下內容純屬原創,請謹慎選擇: ①目的:用戶登錄超時,session過期,點擊後跳轉到登錄頁,登錄成功再跳轉到鼠標點擊的頁面。 ②流程:用戶登錄---session過期---點擊跳

    IOS 刪除git中的submodules sourceTree

    wan .wang neapp img module 技術分享 net 子目錄 git 1、首先刪除submodule的條目 選中要刪除的子目錄 右鍵刪除,刪除之後, 該子模塊消失。 然後查看 .gitmodules 發現刪除了裏面的 [submodule "Iphon

    MySQL——修改root密碼的4種方法(windows)

    ron 情況 登錄 使用 方法 命令 ont demo root密碼 MySQL——修改root密碼的4種方法(以windows為例) 來自:http://www.jb51.net/article/39454.htm 本文以windows為例為大家詳細介紹下MySQL

    (轉)開放window是服務器端口——8080

    win 做了 tcp and setting 範圍 -- .com 右上角 本文記錄兩個內容: 1.win7下打開端口 2.服務器(2003或者其他老版的系統以2003為例) 測試端口時 可用telnet 命令 偵聽端口:C:\Documents and Setti

    『TensorFlow』GAN的神經網絡類範式

    default 方法 paper ear 類屬性 lin 簡單 貪婪 base 1、導入包: import os import time import math from glob import glob from PIL import Image import tens

    循環語句總結(代碼C#

    bre else col 運行 循環條件 span 表達式 條件 ons 1. while循環 代碼格式: while(循環條件) { //循環體 } 流程圖: 解讀: 如果循環條件為真,則執行循環體執行完循環體後,再判斷條件是否為真如果為真,再執行循環體然後

    高斯消元poj1222

    tin 組成 sub ac代碼 題目 iostream tdi pre 變亮 【題目鏈接】   http://poj.org/problem?id=1222 【題目大意】  5*6的一個由燈組成的方陣 操作一個燈 周圍的上下左右四個燈會發生相應變化 即由滅變亮 由亮變滅 問

    通過JDBC進行簡單的增刪改查(MySQL

    mage ron end main exce javax xtend 探索 rman 通過JDBC進行簡單的增刪改查(以MySQL為例) 目錄 前言:什麽是JDBC 一、準備工作(一):MySQL安裝配置和基礎學習 二、準備工作(二):下載數據庫對應的jar包並

    自定義shell終端提示符及顏色 (Centos

    工作目錄 con bashrc func global 目錄 藍色 顯示 inux Linux修改Shell命令提示符及顏色 1. Linux登錄過程中加載配置文件順序: /etc/profile → /etc/profile.d/*.sh → ~/.bash_pro

    11)代碼重用思想(遊戲

    class 我想 就是 cas == 點擊 ~~ 重用 body 1)情況說明:      假如 我想在我的遊戲上 顯示以惡搞菜單 然後這個菜單 顯示1和2           要是我用鼠標點擊1 ,就可以玩 貪吃蛇遊戲           要是我用鼠標點擊

    用redis實現悲觀鎖(後端語言php

    號碼 blank mys 時間 先來 ng-click print -m 兩種 1479 鎖機制 通常使用的鎖分為樂觀鎖,悲觀鎖這兩種,簡單介紹下這兩種鎖,作為本文的背景知識,對這類知識已經有足夠了解的同學可以跳過這部分。 樂觀鎖 先來看下百度百科上的解釋