2020年11月21日 星期六

Linux device number

device number 由 major number 和 minor number 組成[註1]

major 號碼識別使用的驅動程式,例如 /dev/null 和 /dev/zero 使用 driver 1、virtual consoles 和 serial terminals 使用 driver 4、 vcs1 和 vcsa1 使用 driver 7[註1]。現代 Linux kernel 允許多個驅動程式共用同一個 major 號碼,但看到的大部分還是一個 major 對一個 driver。

minor 號碼由 major 號碼的驅動程式使用,來控制數個 device,kernel 本身只知道對應到某個驅動程式。kernel 用 minor 號碼決定確切是那個 device,取決於驅動程式寫法,device 可以直接用指標,或使用 minor number 對應。

kernel 內部用 dev_t 存 major 和 minor,在 Linux 2.6 是 32-bit,其中 major 12-bit、minor 20-bit (兩者在之前的 kernel 都只有 8-bit),但程式不能做這樣假設,應該用 <linux/kdev_t.h> 的 macros MAJOR(dev_t dev) 和 MINOR(dev_t dev) 分別取得,並用 MKDEV(int major, int minor) 轉換成 dev_t。

簡單來說就是:註冊時用 0 會動態指定,mknod 時再去 /proc/devices 查實際使用的 major number。

取得 device number

有些常見設備的 major number 是靜態指定的,可查 kernel 原始碼的 Documentation/devices.txt。新驅動程式可以自己選一個看起來沒正在使用的 device number,或者動態取得。如果驅動程式擴散使用,自選 device number 就不適合,比較適合動態取得。動態取得的缺點是不能事先建立 device node,但通常不需要事先建立。

如果事先知道要用的 device number,用

int register_chrdev_region(
    dev_t first,
    unsigned int count,
    char *name);

first 是範圍起始的 device number,其中 minor number 部份通常是 0,但非必要。count 是連續的數目,如果大的話可能會跨到下個 major 號碼,仍可以正常使用。name 是關聯的 device 名稱,出現在 /proc/devices 和 sysfs。成功回傳 0,失敗回傳負值。

不知道要用的 device number,則動態取得,用

int alloc_chrdev_region(
    dev_t *dev,
    unsigned int firstminor,
    unsigned int count,
    char *name);

此時,dev 只用在輸出,成功時放範圍起始的 device number。firstminor 是請求的第一個 minor number,通常為 0。

device number 不用了要釋出,通常在 module 的 cleanup 函式。

void unregister_chrdev_region(dev_t first, unsigned int count);

Linux 2.4 引入可選用的 device file system (devfs),但 ...。

不用 devfs 時,major 號碼由驅動程式登記時指定,出現在 /proc/devices。major 可設為 0 動態配置沒用的 major 號碼:

int register_chrdev(
    unsigned int major,
    const char *name,
    struct file_operations *fops);

回傳動態配置的 major 號碼,0 使用指定 major 號碼成功,負值表示失敗。多於 256 driver?register_chrdev_region()?

再來要 mknod 建立 device node 時,去 /proc/devices 查使用的 major:

major=`awk "\\$2==\"$module\" {print \\$1}" /proc/devices`
mknod /dev/${device}0 c $major 0

在 /dev ,使用指定的驅動程式

註:register_chrdev_region() 和 alloc_chrdev_region() 在 kernel 內部都是呼叫 __register_chrdev_region() 註冊一個範圍 major:minor 給 char 驅動程式,如果 major 為 0 動態取得 major。alloc_chrdev_region() 強制動態取得 major 並回傳。register_chrdev_region() 則會無法得知動態取得的 major。另外 register_chrdev() 註冊一個 major 的整個 minor,除了 __register_chrdev_region() 外,還進行 cdev_alloc()、cdev_add()。

char devices
namemajorminor說明
/dev/mem11?
/dev/kmem12?
/dev/null13沒輸出
/dev/zero15提供無限的 0
/dev/random18?
/dev/urandom19?
/dev/ptypN2N舊式 BSD Pseudo-TTY 對,pty 是 master,tty 是 slave。第四個字母順序是 pqrstuvwxyzabcde,第五個字母是 0123456789abcdef。Unix98 用 major 128 和 136 以上,並使用 PTY master multiplex (/dev/ptmx) 動態取得 PTY。
/dev/ttypN3N
/dev/ttyN4Nvirtual console
/dev/ttySN464+NUART
/dev/tty50Current TTY device
/dev/console51System Console
/dev/ptmx52PTY master multiplex
/dev/psaux101PS/2 型式滑鼠
/dev/rtc10135Real Time Clock
/dev/input/eventN1364+N?
/dev/fbN29Nframe buffer
/dev/ttyPN57NHayes ESP serial card
/dev/ppp1080?
/dev/ttySA2045+N?
/dev/ttyAM20416+N?
/dev/ttyCPM20446+N?
/dev/ttyAMA
/dev/ttySAC
20464+N?
/dev/ttyPSC204148+N?
/dev/ttyUL204187+N?
/dev/ttymxc20716?
block devices
namemajorminor說明
/dev/ram11?
/dev/ramN1N?
/dev/loopN7N?

參考

  1. LDD ch3
  2. https://www.kernel.org/doc/Documentation/admin-guide/devices.txt
  1. char 或 block 設備透過 /dev 下類型為 c 或 b 的檔案存取,ls -l /dev 可列出並看到 major 及 minor 號碼出現在時間之前。

沒有留言:

張貼留言

SIP header Via

所有 SIP 訊息 都要有 Via,縮寫 v。一開始的 UAC 和後續途經的每個 proxy 都會疊加一個 Via 放傳送的位址,依序作為回應的路徑。 格式 sent-protocol sent-by [ ;branch= branch ][ ; 參數 ...] s...