2009年2月14日 星期六

c - ioctl

ioctl(io control)是應用程式用來和驅動程式溝通的API
讓應用程式可以對某個裝置下命令
你想要用ioctl做什麼事呢?

在unix環境中, 裝置的存取和檔案是一樣的
一般會先用open函式來取得對裝置的一個控制權
open會傳回一個handle值
一般用法 ioctl(handle, command, ...)
前面兩個參數是必須的, 後面的參數則視情況而定
handle就是open函式傳回來的值
command就是一個command code
command code每個值所代表的命令會因裝置而異
完全由驅動程式來解釋command code的意義
有的command code還需要傳進額外的參數時, 就會使用第3, 第4...個參數了

所以你要使用ioctl之前, 要先看你是要對那個裝置下命令
再去查那個裝置的驅動程式支援那些command code讓應用程式使用
應用程式呼叫 ioctl時, 相對應的驅動程式會有一個callback function被呼叫到
這個callback function專門用來處理 ioctl command code
你呼叫ioctl時可以傳那些command code, 還有要傳那些參數都和此callback有關


timepf=open("/dev/RTC",O_RDWR);
ioctl(timefd,1,&tm_time);
例子, 你要去查 rtc driver支援那些command code
如果你找不到現成的document介紹 rtc driver支援那些 ioctl command code
可以直接去查 linux rtc driver 的source code, 看 command code 1代表什麼


/usr/src/linux/drivers/char/rtc.c 是 rtc driver的code
我不確定你linux kernel 的source code path是否和我一樣
如果不一樣, 就搜尋一下 rtc.c
搜尋其中函式名稱有包含ioctl的函式, 就是rtc driver處理 ioctl的函式
我看到的函式名稱叫 rtc_do_ioctl(unsigned int cmd, unsigned long arg, int kernel)
函式名稱可能會因linux kernel版本不同而異
參數 cmd 就是你傳進來的 command code, 你是傳 1 進來

參數 arg 就是另外一個參數, 就是你傳的 &m_time
你可以看看當你傳 command code = 1進來, 它做了那些事
你可以看到在函式裏面會把傳進來的cmd和一些常數比對
比如說, RTC_AIE_OFF, RTC_AIE_ON, RTC_PIE_OFF.....
一般會把command code在 .h檔定義成一些看得懂的常數

所以你要去查同一個目錄中的 rtc.h
裏面就可以發現 rtc driver到底支援了那些 command code
對照 .h定義的常數和涵式內對每個command code的處理
就可以知道有那些command code可以下, 該下怎樣的參數給 rtc driver
在此可以發現是RTC_AIE_ON定義成 1
函式裏面收到 RTC_AIE_ON的程式碼註解是Allow alarm interrupts.
意思是將時間的interrupt啟動
應該是你如果要使用time函式之前, 必須先將timer的interrupt啟動才有作用
在此可以發現另一個參數arg在cmd=RTC_AIE_ON並不會用到
只不過因為這個函式在cmd為其它值時會需要用到
所以函式在宣告時必須要宣告參數arg
你另外傳的那個參數 &tm_time在此時是沒有什麼作用的
你的呼叫式最好改成 ioctl(timefd, RTC_AIE_ON, &tm_time)會比較容易讓人看懂

===============================================================
錯誤號碼定義在/usr/include/asm-generic/errno-base.h

#define EPERM            1      /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */

=================================================================
errno在每一個thread都會有一個數值,每一個thread並不會影響到其它thread的值。
一開始值會是0,只有當system call發生錯誤時,errno的值才會被更改。
透過perror()可以顯示錯誤訊息
errno變量問題
錯誤:UNIX 程序中的錯誤代碼


參考資料:
C/C 函式 ioctl
Linux 驅動程式的 I/O, #4: fops->ioctl 實作

沒有留言: