1-驅(qū)動

驅(qū)動:
  • 必做實驗一磅轻、二珍逸、四、五聋溜、十一
十天:
  • 模塊谆膳、字符設(shè)備框架以及接口、led驅(qū)動
  • platform總線 原子操作 自旋鎖 信號量 IO模型
外設(shè)驅(qū)動:按鍵驅(qū)動撮躁、蜂鳴器驅(qū)動漱病、ADC、I2C把曼、輸入子系統(tǒng)
學(xué)習(xí)驅(qū)動時需要的基礎(chǔ):
  • 1杨帽、驅(qū)動接口的理解 %50
  • 2、操作系統(tǒng)內(nèi)核機制 %30
  • 3嗤军、硬件 %20
第一天的重點內(nèi)容:模塊注盈、字符設(shè)備框架
什么是驅(qū)動?
  • driver駕駛員.在內(nèi)核中提供的一系列接口來操作硬件
現(xiàn)有內(nèi)核中我們通常以模塊的方式寫驅(qū)動叙赚。
  • 1老客、什么是模塊 內(nèi)核中可以隨時添加和刪除的一部分代碼
  • 2、為什么要用模塊 使用靈活方便震叮、可以規(guī)避版權(quán)
  • 3胧砰、模塊和應(yīng)用程序什么區(qū)別?
應(yīng)用程序 模塊
運行空間 用戶空間 內(nèi)核空間
入口 main 加載函數(shù)
調(diào)用的接口 c庫或者系統(tǒng)調(diào)用 內(nèi)核函數(shù)
釋放空間 自動釋放 必須手動釋放
  • 系統(tǒng)調(diào)用的源代碼處于內(nèi)核空間苇瓣,但是千萬不要說系統(tǒng)調(diào)用是內(nèi)核函數(shù)

  • 了解:內(nèi)核中可以使用模塊的部分包括——驅(qū)動尉间、文件系統(tǒng)、網(wǎng)絡(luò)協(xié)議棧

如何去操作一個驅(qū)動模塊?
模塊的三要素:
  • 規(guī)避版權(quán)的宏
  • 加載函數(shù)
  • 卸載函數(shù)
  • 如何規(guī)避版權(quán)?MODULE_LICENSE("GPL") 規(guī)避GPL版權(quán)哲嘲。如果不使用這個宏也可以編譯和執(zhí)行贪薪,但是內(nèi)核會抱怨(你玷污了內(nèi)核)。
加載函數(shù):
  • 1眠副、自定義加載函數(shù)
  • int 函數(shù)名(void) 建議函數(shù)名以_init結(jié)尾
  • 這種情況下如果要想被內(nèi)核調(diào)用還需要使用一個內(nèi)核提供的接口:module_init();
vim -t module_init 選擇5
297 #define module_init(initfn)                 \
298     static inline initcall_t __inittest(void)       \
299     { return initfn; }                  \
300     int init_module(void) __attribute__((alias(#initfn)));

135 typedef int (*initcall_t)(void); <==> typedef int (*)(void) initcall_t

int init_module(void) __attribute__((alias(#initfn)));給默認加載函數(shù)取別名為initfn
module_init(initfn);告訴系統(tǒng)內(nèi)核我們的自定義的模塊入口為initfn

vim -t module_init 選擇4
266 #define module_init(x)  __initcall(x);

212 #define __initcall(fn) device_initcall(fn)

207 #define device_initcall(fn)     __define_initcall(fn, 6)

176 #define __define_initcall(fn, id) \
177     static initcall_t __initcall_##fn##id __used \
178     __attribute__((__section__(".initcall" #id ".init"))) = fn

假設(shè)module_init(hello_init) <==> static initcall_t __initcall_hello_init6 __used __attribute__((__section__(.initcall6.init))) = hello_init
最終的結(jié)果的作用是通過initcall_t類型定義了一個變量__initcall_hello_init6 __used __attribute__((__section__(.initcall6.init))),同時這個變量被賦值為hello_init
上面的變量最終編譯后會被放到.initcall6.init這個代碼分段中古掏。
進入到arch/arm/kernel/vmlinux.lds來尋找上面的分段
內(nèi)核在什么時候調(diào)用module_init();?
  • a、init/main.c中的start_kernel();
  • ==> rest_init();
  • ==>kernel_init
  • ==> kernel_init_freeable()
  • ==> do_basic_setup();
  • ==>do_initcalls()
for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1;level++)  
725 static initcall_t *initcall_levels[] __initdata = {
726     __initcall0_start,
727     __initcall1_start,
728     __initcall2_start,
729     __initcall3_start,
730     __initcall4_start,
731     __initcall5_start,
732     __initcall6_start, 這個符號就是我們的加載函數(shù)所在分段的起始地址
733     __initcall7_start,
734     __initcall_end,
735
    };
  • b侦啸、默認加載函數(shù)

    • int init_module(void)
  • 2、卸載函數(shù)

    • 自定義的卸載函數(shù) void 函數(shù)名(void) 建議函數(shù)名以_exit結(jié)尾
  • 調(diào)用module_exit(自定義卸載函數(shù)名)來告訴內(nèi)核我們自定的函數(shù)是模塊的出口

  • 默認的卸載函數(shù) void cleanup_module(void)

  • 注意:在內(nèi)核中形參為void不能省略

  • 自己寫一個模塊程序熟悉流程丧枪。

  • make tags 產(chǎn)生tags文件用于我們查看內(nèi)核中的函數(shù)或者宏

    • 1光涂、自定義模塊的入口函數(shù)
    • 2、自定義模塊的出口函數(shù)
    • 3拧烦、告訴內(nèi)核我們的入口和出口是哪些自定義函數(shù) module_init module_exit
    • 4忘闻、規(guī)避版權(quán) MODULE_LICENSE
驅(qū)動程序的編譯:
  • 1、直接將驅(qū)動程序放到內(nèi)核中指定的文件夾中恋博,將驅(qū)動的二進制內(nèi)容添加到uImage文件中
    操作流程:寫好一個驅(qū)動程序齐佳,拷貝到drivers/char目錄下
    • 修改drivers/char/Kconfig,添加:
    • config HELLO
    • tristate "my first driver hello"
  • 修改drivers/char/Makefile,在最后一行添加obj-$(CONFIG_HELLO) += hello.o
  • 回到頂層目錄執(zhí)行make menuconfig,找到my first driver hello這個選項债沮,選中為*
  • make uImage
  • cp arch/arm/boot/uImage /tftpboot然后啟動開發(fā)板炼吴,如果驅(qū)動加載成功會在串口終端上看見hello init success
2、如果直接將驅(qū)動編譯到uImage文件中疫衩,無論這個驅(qū)動使用不使用都會占用內(nèi)存空間硅蹦,所以為了節(jié)省空間我們通常選擇編譯成模塊
  • 編譯成模塊又分成兩種方法:
  • 第一種:內(nèi)部編譯
    • a、將驅(qū)動hello.c放在drivers/char目錄下
    • b闷煤、修改Kconfig文件
      • config HELLO
      • tristate "my first driver hello"
  • c童芹、修改drivers/char/Makefile,在最后一行添加obj-$(CONFIG_HELLO) += hello.o
  • d鲤拿、回到頂層目錄make menuconfig 將我們添加的選項選為M
  • e假褪、在頂層目錄執(zhí)行make modules 默認在drivers/char目錄下生成一個hello.ko的文件(這個文件模塊文件)
  • f、拷貝到rootfs目錄下,然后去掛載開發(fā)板
  • g近顷、在開發(fā)板上執(zhí)行insmod hello.ko
模塊文件名:hello.ko
  • 模塊名:hello
  • 模塊的命令:
    • insmod 模塊文件名 作用為模塊文件在內(nèi)核中分配空間

    • 例子:insmod hello.ko

    • 查看驅(qū)動的打印信息:dmesg如果執(zhí)行成功會打印hello init success

    • rmmod 模塊名 作用是將模塊從內(nèi)核中釋放掉

    • dmesg 會打印hello exit success

    • 例如:rmmod hello

  • 第二種:外部編譯(比較常用的方式生音,但這種方式比較難理解)
  • 我們的驅(qū)動程序不需要拷貝到內(nèi)核源碼目錄下,任意存放就可以
  • 要想寫一個外部編譯的Makefile先了解一個文件:/lib/modules/3.5.0-23-generic/build,這個文件是一個軟連接文件幕庐。
  • 通過軟連接build查看到它的源路徑為/usr/src/linux-headers-3.5.0-23-generic,這文件夾相當(dāng)于是內(nèi)核源碼的頂層目錄久锥。
  • 在/usr/src/linux-headers-3.5.0-23-generic目錄下有一個Makefile文件,
  • 文件的1181行有一句話1181 # make M=dir modules 在編譯模塊時需要用M=模塊的絕對路徑,其中M不能變
$(shell uname -r) 這里的shell是Makefile的一個函數(shù)异剥,作用就是在Makefile調(diào)用shell命令
uname -r 顯示當(dāng)前操作系統(tǒng)的內(nèi)核版本
驗證過程:
sudo dmesg -c 清除內(nèi)核緩存區(qū)中的信息
sudo insmod hello.ko
dmesg

sudo rmmod hello
dmesg
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末瑟由,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌歹苦,老刑警劉巖青伤,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異殴瘦,居然都是意外死亡狠角,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門蚪腋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丰歌,“玉大人,你說我怎么就攤上這事屉凯×⑻” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵悠砚,是天一觀的道長晓勇。 經(jīng)常有香客問我,道長灌旧,這世上最難降的妖魔是什么绑咱? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮枢泰,結(jié)果婚禮上描融,老公的妹妹穿的比我還像新娘。我一直安慰自己宗苍,他們只是感情好稼稿,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著讳窟,像睡著了一般让歼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上丽啡,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天谋右,我揣著相機與錄音,去河邊找鬼补箍。 笑死改执,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的坑雅。 我是一名探鬼主播辈挂,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼裹粤!你這毒婦竟也來了终蒂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拇泣,沒想到半個月后噪叙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡霉翔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年睁蕾,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片债朵。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡子眶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出序芦,到底是詐尸還是另有隱情壹店,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布芝加,位于F島的核電站,受9級特大地震影響射窒,放射性物質(zhì)發(fā)生泄漏藏杖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一脉顿、第九天 我趴在偏房一處隱蔽的房頂上張望蝌麸。 院中可真熱鬧,春花似錦艾疟、人聲如沸来吩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽弟疆。三九已至,卻和暖如春盗冷,著一層夾襖步出監(jiān)牢的瞬間怠苔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工仪糖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留柑司,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓锅劝,卻偏偏與公主長得像攒驰,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子故爵,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容