1.記 憶 體 配 置 、 釋 放 和 轉 移

void *kmalloc(unsigned int size, int priority)

void *kfree_s(void * obj, int size)

kfree(char *)

memcpy_fromfs(dest, src, size)

memcpy_tofs(dest, src, size)

put_fs_byte(src, dest)

byte get_fs_byte(char *s)

 

kmalloc()、 kfree()用 法 =  C Language中 使 用 於 User Program的 malloc(), free()用 法 

只 是 其 動 態 配 置 的 空 間 是 Kernel Space而 已 ;

=>因 為 Kernel的 空 間 是 有 限 制 的 , 所 以 記 得 做 源 回 收 不 要 浪 費 記 憶 空 間

memcpy _fromfs():User program寫 入 的 資 料 搬 移 到  => Kernel Space的 位 置

memcpy_tofs(): 從 Kernel Space的 位 置 搬 移 到 檔 案 系 統 (File System)的 空 間 , 以 便 User Program讀 取 資 料 。 這 兩 者 大 致 應 用 於 Read, Write的 動 作 程 序 當 中 。

 

  至 於 put_fs_byte()與 get_fs_byte()的 動 作 是 寫 入 和 讀 取 一 個 字 元 的 資 料 , 分 別 從 User program的 檔 案 系 統 空 間 到 Kernel Space, 或 是 相 反 的 動 作 。

2.輸 出 入 程 序

inb(port)
outb(char, port)

  此 兩 程 序 分 別 用 於 介 面 埠 (Interface I/O Port)以 讀 取 和 寫 出 一 個 字 元 , 達 到 控 制 介 面 、 讀 取 狀 態 、 輸 出 入 資 料 的 目 的 。

3.巨 集 指 令

cli()

sti()

minor=MINOR(inode->i_rdev)

major=MAJOR(inode->i_rdev)

boolean suser()

save_flags(long flag)

restore_flags(long flag)

  cli()與 sti()的 功 能 和 C語 言 中 的 disable(), enable()以 及 Assembly語 言 的 cli, sti是 一 樣 的 ; 分 別 用 以 清 除 插 斷 旗 幟 (Interrupt flag), 達 到 抑 制 插 斷 的 發 生 , 和 設 定 旗 幟 , 允 許 插 斷 於 下 一 個 指 令 執 行 結 束 後 可 以 回 應 任 何 型 式 插 斷 的 發 生 。 接 下 來 解 釋 major number和 minor number的 意 義 。 major number用 以 識 別 Devices的 類 別 , 而 minor number用 以 區 別 每 一 類 別 中 , 每 一 個 Device。 舉 個 例 子 來 說 明 : 你 可 以 用 ls-l command於 目 錄 /d ev中 列 印 資 料 如 下 :

crw-rw-rw- 1  bin   bin    5, 0  Oct 9 14:00  /dev/tty1a

crw-rw-rw- 1 bin bin 5, 1 Oct 9 14:02 /dev/tty1b

crw-rw-rw- 1 bin bin 5, 2 Oct 9 14:05 /dev/tty1c

  範 例 中 , 數 目 5代 表 tty Device的 major Device number; 而 其 中 0, 1, 2 就 是 代 表 minor number, 分 別 表 示 Device tty1a, tty1b, tty1c。 說 明 至 此 , 相 信 你 已 了 解 什 麼 是 major number, minor number 了 , 那 又 怎 麼 使 用 呢 ? 在 User Program 中 , 根 本 不 用 考 慮 這 個 問 題 , 僅 是 使 用 open()來 開 啟 /dev/tty1a Device, 以 得 到 一 個 file descriptor而 已 ; 然 而 , 在 Kernel Device Driver中 , open、 close、 read、 write等 函 數 就 是 利 用 minor number來 區 別 到 底 是 那 一 個 Device要 求 服 務 (Service)。 只 要 是 應 用 inode Kernel資 料 結 構 來 取 得 minor number。 用 法 如 下 :
minor= MINOR(inode->i_rdev)

  至 於 inode structure將 於 資 料 結 構 單 元 中 介 紹 。 suser()這 是 個 檢 核 使 用 者 是 否 為 supervisor privilege的 函 數 , 以 決 定 使 用 者 的 使 用 權 限 。 save_flags(), restore _flags()是 用 以 存 取 系 統 旗 幟 (System Flags)的 函 數 。

4.插 斷 函 數

request_irq(dev_irq, handler())

irqaction(irq, (struct sigaction *))

free_irq(dev_irq)

interruptible_sleep_on(struct wait_queue *)

wake_up(struct wait_queue *)

wake_up_interruptible(struct wait_queue *)

  第 四 點 提 到 的 是 與 插 斷 動 作 有 關 的 函 數 , 不 見 得 每 一 個 Device Driver皆 會 用 得 到 ; 因 為 有 些 Device Driver是 使 用 詢 問 (Polling)的 方 式 來 撰 寫 的 , 其 應 用 固 定 週 期 對 需 要 的 Device做 詢 問 , 是 否 需 要 Service, 再 做 進 一 步 處 理 ; 至 於 比 較 有 效 率 的 Interrupt方 式 還 是 要 了 解 。

  request_irq()與 irqaction()兩 者 的 功 用 是 相 同 的 ; 都 是 向 系 統 註 冊 (Register)本 身 Device Driver使 用 的 IRQ和 Interrupt Handler是 什 麼 。 其 作 用 與 MS-DOS下 寫 C語 言 使 用 的 setvect()函 數 相 類 似 , 只 不 過 在 Linux Driver就 不 需 要 自 己 enable IRQ的 宣 告 罷 了 。 free_irq()的 功 用 就 是 釋 放 (Rel ease)IRQ的 使 用 權 , 歸 還 給 系 統 。

  在 寫 Device Driver的 I/O動 作 時 , 不 能 與 在 寫 一 般 的 User Program的 I/O一 樣 , 放 任 其 不 管 。 一 定 要 注 意 其 I/O是 否 在 Busy或 Waiting狀 態 , 做 出 必 要 的 反 應 動 作 。 例 如 發 現 Device在 Busy狀 態 時 , 最 好 呼 叫 interrupt_sleep_on()去 休 息 一 下 , 把 執 行 權 (Running)交 還 給 系 統 ; 若 發 現 是 在 Waiting狀 態 時 , 就 可 借 用 wake_up()或 是 wait_up_interruptible()函 數 , 把 你 的 Sleeping Process叫 醒 來 工 作 。

5.其 他

 printk() 

register_chrdev(unsigned int major, const char *name,

struct file_operations &fops)

unregister_chrdev(unsigned int major, const char *name)

有 經 驗 的 軟 體 工 程 師 , 一 定 有 這 樣 的 經 驗 , 在 軟 體 開 發 的 時 候 , 早 就 事 先 埋 下 伏 筆 , 將 有 需 要 查 證 、 除 錯 (Debug)的 資 料 做 個 處 理 , 且 配 合 測 試 軟 體 做 個 安 排 , 以 便 節 省 除 錯 時 間 。 printk()的 功 能 與 printf()相 似 , 只 是 僅 能 應 用 於 Kernel的 軟 體 中 。 register_chrdev()是 Character Device Driver用 來 向 系 統 註 冊 (Register)的 函 數 , 其 參 數 包 括 Character Device的 major number, Driver名 稱 以 及 檔 案 作 業 (File Operation)指 定 的 幾 個 函 數 宣 告 的 名 稱 。 對 於 File Operation的 結 構 及 如 何 應 用 , 將 於 後 面 做 詳 細 的 討 論 。

  unregister_chrdev()顧 名 思 義 , 就 是 系 統 取 消 註 冊 名 稱 。

6.資 料 結 構

      struct file_operations  fops

struct file *filp

struct wait_queue dev_q

struct inode dev_node

struct sigaction sa

  上 式 所 列 幾 個 資 料 結 構 在 開 發 Device Driver時 , 是 比 較 常 見 的 。 像 struct file_operations是 Device Driver的 主 要 結 構 , 其 定 義 於 /usr/src/linux/include 目 錄 下 的 fs.h檔 案 。 Driver中 使 用 到 主 要 函 數 如 xx_read、 xx_write、 xx_open、 xx_ close等 必 須 以 此 結 構 加 以 宣 稱 。 現 在 列 印 此 結 構 如 下 :

 struct file_operations {

int (*lseek)(....);

int (*read) (...);

int (*write) (...);

int (*readdir) (...);

int (*select) (...);

int (*ioctl) (...);

int (*mmap) (....);

int (*open) (...);

void (*release) (...);

int (*fsync) (....);

int (*fasync) (...);

};

  詳 細 結 構 請 參 考 fs.h, 它 的 每 一 個 element, 都 是 一 函 數 指 標 , 指 向 你 的 Device Driver所 寫 的 函 數 。 我 們 舉 個 例 子 如 下 , 或 是 參 閱 本 文 的 Listing程 式 。

static struct file_operations testty_fops = {

NULL,

testty_read,

testty_write,

NULL,

NULL,

NULL,

NULL,

testty_open,

testty_close,

NULL,

NULL,

};

  讀 者 只 要 將 此 資 料 結 構 在 Driver中 宣 告 , 然 後 應 用 register_chrdev()向 kernel system註 冊 , 宣 告 你 的 major number和 Driver名 稱 , 此 時 你 已 接 近 完 成 一 半 的 工 作 了 。 接 下 來 就 依 照 你 宣 告 的 函 數 名 稱 , 逐 一 完 成 相 關 的 程 式 , 此 刻 你 的 Device Driver 就 算 完 成 了 coding的 動 作 了 。 其 餘 的 我 們 後 面 再 慢 慢 介 紹 了 。

  struct file結 構 定 義 於 fs.h include file 中 , 假 如 你 的 Driver是 應 用 於 I/O Device 方 面 時 , 此 結 構 大 致 配 合 function的 參 數 (Parameter)來 使 用 , 其 elements的 應 用 就 少 了 ; 假 如 是 data file方 面 的 應 用 , 那 就 應 用 許 多 了 , 包 括 file mode、 file’ s offset position等 。

  struct wait_queue是 一 個 Process處 理 時 , 發 生 I/O動 作 需 要 進 入 睡 眠 (Sleep)或 甦 醒 (Wake up)狀 態 時 , 所 用 到 的 一 個 結 構 ; 用 以 記 錄 Process目 前 所 處 的 狀 況 (St- atus)。 像 interruptible_sleep_on(), wake_up()及 wake_up_interruptible()皆 以 此 結 構 為 主 , 配 合 Driver來 完 成 I/O的 動 作 , 僅 須 宣 告 一 參 數 於 這 些 函 數 中 就 可 以 了 。 接 下 來 就 繼 續 說 明 inode結 構 的 應 用 。

  inode結 構 是 組 成 file system的 元 素 , 其 內 容 為 file owner identifier、 file type 、 file access permissions, 檔 案 存 取 的 時 間 紀 錄 , 檔 案 的 大 小 , 檔 案 資 料 於 disk address的 表 格 (table), 以 及 file link的 數 目 , 還 有 許 多 結 構 的 嵌 入 , 詳 細 的 內 容 可 參 閱 fs.h中 的 定 義 。 其 中 的 i_rdev係 用 來 決 定 Device的 minor和 major number:

minor=MINOR(inode->i_rdev)
major=MAJOR(inode->i_rdev)

  當 你 取 得 minor number時 , 你 就 可 決 定 目 前 工 作 的 Device是 那 一 個 需 要 服 務 (Service), 以 便 取 得 Device Driver中 的 結 構 , 得 到 Current Device的 狀 態 。 Struct Sigaction是 用 來 向 Kernel系 統 註 冊 IRQ及 插 斷 處 理 程 式 (Interrupt Handler) 的 結 構 。 例 如 宣 告 一 變 數 為 sa: struct sigaction sa;

     sa.sa_handler = test_interrupt;

sa.sa_flags = SA_INTERRUPT;

sa.sa_mask = 0;

sa.sa_restorer = NULL;

irqaction(irq, &sa);

  應 用 上 面 幾 行 statements宣 告 你 的 Interrupt handler函 數 了 ; 亦 可 使 用 requestirq(dev_irq, handler)來 完 成 相 同 的 功 能 。

arrow
arrow
    全站熱搜

    pcman 發表在 痞客邦 留言(0) 人氣()