《《字元装置驱动程式》PPT课件》由会员分享,可在线阅读,更多相关《《字元装置驱动程式》PPT课件(53页珍藏版)》请在金锄头文库上搜索。
1、Chap 3-字元裝置驅動程式OutlineIntroduction3.1 scull的設計藍圖3.2 主編號與次編號3.3 檔案架構3.4 file 結構3.5 open 與 release3.6 Scull 的記憶體用法規劃3.7 相競狀況3.8 read 與 write3.9 try scull3.10 devfs 檔案系統3.11 回溯相容性3.12 速查參考3-Introduction本章目標:寫出一個完整的字元裝置驅動程式(char device driver)-簡稱char driver終極目標:寫出一個模組化的char driver範例:scull-( Simple Chara
2、cter Utility for Loading Localities )scull的作用是“讓使用者可把一塊記憶區當成字元裝置來使用”scull所驅動的目標裝置是一塊記憶區不需依賴任何“特殊”硬體只要有linux平台就可以編譯與執行未提供任何實用功能,只展示核心與char driver之間軟體介面定義驅動程式要提供哪些功能給user-sapce的程式可循序存取(字元裝置) or 可隨機存取(區塊裝置)模擬單一裝置(ex:一機多體 or 多個同類裝置)Scull所模擬出的每一種裝置,分別由不同類型的模組予以實現(相同的mechanism差別在於policy的不同)scull0scull3四個由
3、記憶區所構成的裝置,兼具“共通” “持續”scullpipe0scullpipe3四個FIFO裝置( blocking與nonblocking )Scullsingle一次只容許一個被行程存取Scullpriv允許每個終端機都有權開啟一次,分屬不同行程Sculluid允許開始多次,限同一使用者。(回傳錯誤碼)Scullwuid允許開始多次,限同一使用者。(推延,等待)主編號(major number)(0255)代表裝置所配合的驅動程式當核心收到open()系統呼叫時,就是依據“主編號”來選擇驅動程式次編號(minor number)(0255)驅動程式以次編號來辨認同類裝置的個體核心本身用不
4、到,只有驅動程式自己才知道次編號的意義當使用者要存取字元裝置時,必須透過檔案系統裡的“代表名稱”特殊檔(special file) 、裝置檔(device file) 、 檔案系統樹的節點(node),集中在/dev/目錄下。裝置類型:“c”代表char driver的特殊檔“b”代表block driver的裝置檔 ls al /dev/ |lessbrw-rw- 1 root disk 66, 72 Apr 11 2002 sdak8brw-rw- 1 root disk 66, 73 Apr 11 2002 sdak9crw-r-r- 1 root root 253, 1 Mar 1 2
5、2:58 scull1crw-r-r- 1 root root 253, 2 Mar 1 22:58 scull2crw-r-r- 1 root root 253, 3 Mar 1 22:58 scull3brw-rw- 1 root disk 8, 0 Apr 11 2002 sdacrw-rw- 1 root uucp 154, 18 Apr 11 2002 ttySR18裝置類型裝置類型主編號主編號次編號次編號代表名稱代表名稱檔案系統製作裝置節點的命令是mknod,必須有特權身分(root)才能使用此工具。至少需要四個引數 mknod /dev/ant c 252 0像任何儲存在磁碟上的
6、普通檔案一樣,mknod所產生的裝置節點會被保存下來,除非刻意刪除它們。用一般的rm命令即可辦到 rm /dev/ant大部份常見的裝置幾乎都有固定的主編號,可在核心源碼樹的Documentation/devices.txt檔案內找到一份“裝置-主編號”對照表。“實驗性或自家使用”的主編號:6063 、 120127、240.254“隨機索取主編號”呼叫register_chrdev()定義在extern int register_chrdev(unsigned int, const char *, struct file_operations *);extern int unregister
7、_chrdev(unsigned int, const char *);在呼叫register_chrdev()時:major引數給0:=回傳值為0 & 0 & 回傳值為0表示核心同意你的要求發生錯誤時:= 回傳值為負數如果你的驅動程式會被用於廣大群眾,或者有可能被納入正式核心,則須設法申請專用的主編號。 cat /proc/devicesCharacter devices: 1 mem 2 pty226 drm253 scull254 pcmciaBlock devices: 2 fd 3 ide0缺點:因為模組分配到的主編號不一定每次都一樣,所以無法事先建立裝置節點。因此,光靠insmod
8、是不夠的,還必須查閱/proc/devices的內容後,找出其隨機取得的主編號,再製作成適當的裝置節點(甚至要刪除上次留下的無用節點)可寫成一個shell script來一次解決 scull_unload= 卸載模組及清理/dev/下的相關節點 scull.init = 由系統開機/關機程序自動載入/卸載 模組。接受傳統命令start,stop,restartCh_11#!/bin/shmodule=scull“device=scullmode=664# Group: since distributions do it differently, look for wheel or use st
9、affif grep staff: /etc/group /dev/null; then group=staffelse group=wheelfi# invoke insmod with all arguments we got# and use a pathname, as newer modutils dont look in . by default/sbin/insmod -f ./$module.o $* | exit 1major=cat /proc/devices | awk $2=$module print $1# Remove stale nodes and replace
10、 them, then give gid and perms# Usually the script is shorter, its scull that has several devices in it.rm -f /dev/$device0-3mknod /dev/$device0 c $major 0mknod /dev/$device1 c $major 1mknod /dev/$device2 c $major 2mknod /dev/$device3 c $major 3ln -sf $device0 /dev/$devicechgrp $group /dev/$device0-
11、3chmod $mode /dev/$device0-3#!/bin/shmodule=scull“ device=scull# invoke rmmod with all arguments we got/sbin/rmmod $module $* | exit 1# Remove stale nodesrm -f /dev/$device /dev/$device0-3rm -f /dev/$deviceprivrm -f /dev/$devicepipe /dev/$devicepipe0-3rm -f /dev/$devicesinglerm -f /dev/$deviceuidrm
12、-f /dev/$devicewuidscull_load & scull_unload也適用其他其他驅動程式,只需重新定義變數,並稍微調整mknod那幾行即可。因為指令稿需要特權身分才能執行,而新建出來的特殊檔自然會屬於root。但裝置節點的存取權限通常不是這樣,所以要修改權限的擁有權。3.2.2移除驅動程式在模組被卸載之前,他必須先釋放主編號,而這動作可由unregister_chrdev()完成,應該在模組的清理函式理呼叫他:major表示要被釋放的主編號;name是當初註冊的名稱對於動態取得主編號的驅動程式,如果在卸載模組之後沒有順便除掉相關的/dev結點,就可能產生意料外的錯誤。譬如
13、,已經沒有作用的/dev/framegrabber可能在一個月後指向火災警報器int unregister_chrdev(unsigned int major, const char *name)int unregister_chrdev(unsigned int major, const char *name):3.2.3-副編號(dev_t & kdev_t)每當核心要呼叫驅動程式,都必須讓驅動程式知道,他應該作用在哪一個裝置上;驅動程式以裝置編號來辨認其作用對象。(裝置編號=主編號+次編號)dev_tUnix以dev_t(代表“device type”)作為裝置編號的資料型別定義在更改不
14、易,因太多應用程式“知道”其內部結構kdev_tLinux核心內部採用另一種不同的資料型別定義在黑盒子每個核心函式都不必知道其內部結構,而應用程式可以不知道kdev_t的存在。=核心改版可以放手修正,不會影響任何驅動程式3.2.3-副編號(dev_t & kdev_t)可操作的kdev_t巨集與函式:MAJOR(kdev_t dev)=從kdev結構取得主編號MINOR(kdev_t dev)=從kdev結構取得次編號MKDEV(int major, int minor)=以指定的主編號與次編號建立一個kdev_t結構kdev_t_to_nr(kdev_t dev)=將一個kdev_t結構轉換
15、成一個數值(dev_t)to_kdev_t(int dev)=將一個數值轉換成kdev_t結構3.3檔案作業驅動程式內部以一個file結構來代表一個已開啟的裝置核心透過一個file_operations結構來存取驅動程式內部的作業函式(method)file結構包含一個f_op欄位,他是一個指向file_operations結構的指標file_operation結構本身是由一系列“函式指標”所構成,這些指標分別指向驅動程式的各項作業函式。Ex:核心收到操作檔案的系統戶叫(ex:read( ),依據系統呼叫指定的fd找出對應驅動程式的file結構,然後再循線從file_operations結構中
16、找出對應於該系統呼叫的作業函式scull_read( )Read()Scull_read()3.3檔案作業fops變數名稱用來表示file_operation結構(或是指向此結構的指標)在file_operations結構中的每一個欄位,都必須指向驅動程式中負責特定作業方法。對於驅動程式不支援的作業項目(method),其對應欄位就必須指向NULL,當核心遇到NULL時會採取適當的預設行為。欄位的預設行為各不相同。每一種作業方法,其回傳值都有同樣的意義:0代表成功,負值為錯誤碼。3.3檔案作業struct module *owner;不同於file_operations結構裡的其它欄位,此欄位不是函式指標,而是一個指向結構所屬模組的指標。驅動程式本身用不到此欄位,因為他是供核心用來維護模組的用量計次(usage count)。loff_t (*llseek) (struct file *, loff_t, int);/seek作業方法的作用,是改變檔案目前的讀寫點位置;如果成功,則傳回新位置(正值),傳回值loff_t是一個至少64-bits “long offset”,即使是在32-