Linux设备驱动程式之读书笔记(二) [转]
生活随笔
收集整理的這篇文章主要介紹了
Linux设备驱动程式之读书笔记(二) [转]
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
http://www.sudu.cn/info/html/edu/code/20070102/286543.html
setlevel.c 非常實用 google 查找 #define _syscall3 可以查到很多相關信息
Linux設備驅動程式之讀書筆記(二)
?? ?? ?? ?? ?? ——第二章調試技術中的printk
在Linux中系統信息的顯示有以下3種情況:
1、假如系統中只運行klogd,那么能夠通過klogd -c 重新啟動klogd并配置console_loglevel,然后小于console_loglevel的任何信息都會打印到控制臺;
2、假如系統中只運行syslogd,那么消息不會傳遞到用戶空間,只能通過讀/proc/kmsg來察看消息;
3、假如系統中同時允許klogd和syslogd,那么在根據console_loglevel將消息篩選打印到控制臺的前提下,任何消息都會被追加到文檔/var/log/messages中。
在Linux下寫驅動程式的過程中肯定要用到printk語句輸出信息,printk和普通printf語句的差別之一就是,printk根據附加的不同的日志級別(loglevel),或說是消息級別,來表示的嚴重程度對消息進行分類。
比如:printk(KERN_DEBUG “Hi, My printk!”);
上述語句所要輸出的信息就是調試級別的。需要注意的是KERN_DEBUG和后面引號中的內容之間不能用逗號隔開,否則編譯時會報錯!
Linux在頭文檔中定義了8種可用的日志級別字符串,根據嚴重程度排序如下:
KERN_EMERG ?? KERN_ALERT ?? KERN_CRIT?? KERN_ERR
KERN_WARNING KERN_NOTICE ??? KERN_INFO?? KERN_DEBUG
未指定日志級別的printk語句采用默認級別,也就是在kernel/printk.c中被指定的宏DEFAULT_MESSAGE_LOGLEVEL,這個宏通常就是KERN_WARNING。
另外,控制臺(一般是指文本終端,也有可能是串口)也有一個表示級別的整數變量,叫做console_loglevel,他在系統啟動后的初始值是DEFAULT_CONSOLE_LOGLEVEL。
內核會將程式中信息的日志級別和console_loglevel進行比較,只有當信息的日志級別小于console_loglevel這個整數變量的值時,信息才會在當前控制臺上顯示出來。
因此,我們需要事先將系統的console_loglevel調到一個適當的數值,以便控制臺正確顯示我們所需要的信息。比如上面語句中的“Hi, My first printk!”,若不修改console_loglevel的值,就無法在控制終端上顯示。
修改方法有兩種:一是通過sys_syslog系統調用進行修改;二是用dmesg進行修改 或修改/proc/sys/kernel/printk文檔中的第一行,比如dmesg -n 1(命令中的1就是要配置的console_loglevel值,其實上面所說的KERN_EMERG到KERN_DEBUG也就是從0到7的整數值)。 其中前者是臨時性的,每當系統重啟后console_logleve就會回到默認狀態,而后者卻是永久性的,只要用dmesg修改了 console_loglevel的值,那么以后他就一直是這個值了。
我選擇前者,因為不想任意改變系統的狀態,而且Linux Device Drvier3的作者也提供了一個叫做setlevel的小程式,能夠通過由這個程式編譯得到的可執行文檔來配置console_loglevel,很方便。
但現在的問題是,Linux Device Driver3提供的setlevel.c在2.6.20內核上編譯通但是,在編譯時提示:expected declaration specifiers or ‘…’ before syslog
setlevel.c中的代碼如下:
#include
#include
#include
#include
/* #include?? */ /* conflicting on the alpha */
#define __LIBRARY__ /* _syscall3 and friends are only available through this */
#include
/* define the system call, to override the library function */
_syscall3(int, syslog, int, type, char *, bufp, int, len);
int main(int argc, char **argv)
{
int level;
if (argc==2) {
?? level = atoi(argv[1]); /* the chosen console */
} else {
?? ??? fprintf(stderr, "%s: need a single arg\n",argv[0]); exit(1);
}
if (syslog(8,NULL,level)
?? ??? fprintf(stderr,"%s: syslog(setlevel): %s\n",
?? ?? ?? ?? argv[0],strerror(errno));
?? ??? exit(1);
}
exit(0);
}
問題很顯然出現在_syscall3上。
程式中_syscall3(int, syslog, int, type, char *, bufp, int, len)這條語句的作用是告訴編譯器,需要的系統調用是syslog,返回值是int,而后面的字符串則是syslog需要的3個參數及其類型。
而setlevel.c之所以編譯通但是,是因為Linux Device Driver3的作者是在2.6.10的Linux內核中寫的這個程式,但是2.6.20的Linux內核中卻并沒有定義_syscall3這個函 數。(我在Red Hat 9.0(2.4的內核)中編譯過setlevel.c,能夠正常通過。)
于是只要在setlevel.c中調用_syscall3之前定義他的原型,那么setlevel.c就能夠正常編譯和使用了。增加代碼后的setlevel.c如下:
#include
#include
#include
#include
#include /*需要加上這個頭文檔,否則編譯不能通過*/
#define __syscall_return(type, res) \
do { \
?? if ((unsigned long)(res) >= (unsigned long)(-125)) { \
?? ?? ?? ??? errno = -(res); \
?? ?? ?? ??? res = -1; \
?? } \
?? return (type) (res); \
} while (0)
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
?? : "=a" (__res) \
?? : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
?? ?? ?? ?? "d" ((long)(arg3))); \
__syscall_return(type,__res); \
}
_syscall3(int,syslog, int,type, char *,bufp, int,len);
int main(int argc, char **argv)
{
int level;
if (argc==2) {
?? level = atoi(argv[1]); /* the chosen console */
} else {
?? ??? fprintf(stderr, "%s: need a single arg\n",argv[0]); exit(1);
}
if (syslog(8,NULL,level)
?? ??? fprintf(stderr,"%s: syslog(setlevel): %s\n",
?? ?? ?? ?? argv[0],strerror(errno));
?? ??? exit(1);
}
exit(0);
}
setlevel.c 非常實用 google 查找 #define _syscall3 可以查到很多相關信息
Linux設備驅動程式之讀書筆記(二)
?? ?? ?? ?? ?? ——第二章調試技術中的printk
在Linux中系統信息的顯示有以下3種情況:
1、假如系統中只運行klogd,那么能夠通過klogd -c 重新啟動klogd并配置console_loglevel,然后小于console_loglevel的任何信息都會打印到控制臺;
2、假如系統中只運行syslogd,那么消息不會傳遞到用戶空間,只能通過讀/proc/kmsg來察看消息;
3、假如系統中同時允許klogd和syslogd,那么在根據console_loglevel將消息篩選打印到控制臺的前提下,任何消息都會被追加到文檔/var/log/messages中。
在Linux下寫驅動程式的過程中肯定要用到printk語句輸出信息,printk和普通printf語句的差別之一就是,printk根據附加的不同的日志級別(loglevel),或說是消息級別,來表示的嚴重程度對消息進行分類。
比如:printk(KERN_DEBUG “Hi, My printk!”);
上述語句所要輸出的信息就是調試級別的。需要注意的是KERN_DEBUG和后面引號中的內容之間不能用逗號隔開,否則編譯時會報錯!
Linux在頭文檔中定義了8種可用的日志級別字符串,根據嚴重程度排序如下:
KERN_EMERG ?? KERN_ALERT ?? KERN_CRIT?? KERN_ERR
KERN_WARNING KERN_NOTICE ??? KERN_INFO?? KERN_DEBUG
未指定日志級別的printk語句采用默認級別,也就是在kernel/printk.c中被指定的宏DEFAULT_MESSAGE_LOGLEVEL,這個宏通常就是KERN_WARNING。
另外,控制臺(一般是指文本終端,也有可能是串口)也有一個表示級別的整數變量,叫做console_loglevel,他在系統啟動后的初始值是DEFAULT_CONSOLE_LOGLEVEL。
內核會將程式中信息的日志級別和console_loglevel進行比較,只有當信息的日志級別小于console_loglevel這個整數變量的值時,信息才會在當前控制臺上顯示出來。
因此,我們需要事先將系統的console_loglevel調到一個適當的數值,以便控制臺正確顯示我們所需要的信息。比如上面語句中的“Hi, My first printk!”,若不修改console_loglevel的值,就無法在控制終端上顯示。
修改方法有兩種:一是通過sys_syslog系統調用進行修改;二是用dmesg進行修改 或修改/proc/sys/kernel/printk文檔中的第一行,比如dmesg -n 1(命令中的1就是要配置的console_loglevel值,其實上面所說的KERN_EMERG到KERN_DEBUG也就是從0到7的整數值)。 其中前者是臨時性的,每當系統重啟后console_logleve就會回到默認狀態,而后者卻是永久性的,只要用dmesg修改了 console_loglevel的值,那么以后他就一直是這個值了。
我選擇前者,因為不想任意改變系統的狀態,而且Linux Device Drvier3的作者也提供了一個叫做setlevel的小程式,能夠通過由這個程式編譯得到的可執行文檔來配置console_loglevel,很方便。
但現在的問題是,Linux Device Driver3提供的setlevel.c在2.6.20內核上編譯通但是,在編譯時提示:expected declaration specifiers or ‘…’ before syslog
setlevel.c中的代碼如下:
#include
#include
#include
#include
/* #include?? */ /* conflicting on the alpha */
#define __LIBRARY__ /* _syscall3 and friends are only available through this */
#include
/* define the system call, to override the library function */
_syscall3(int, syslog, int, type, char *, bufp, int, len);
int main(int argc, char **argv)
{
int level;
if (argc==2) {
?? level = atoi(argv[1]); /* the chosen console */
} else {
?? ??? fprintf(stderr, "%s: need a single arg\n",argv[0]); exit(1);
}
if (syslog(8,NULL,level)
?? ??? fprintf(stderr,"%s: syslog(setlevel): %s\n",
?? ?? ?? ?? argv[0],strerror(errno));
?? ??? exit(1);
}
exit(0);
}
問題很顯然出現在_syscall3上。
程式中_syscall3(int, syslog, int, type, char *, bufp, int, len)這條語句的作用是告訴編譯器,需要的系統調用是syslog,返回值是int,而后面的字符串則是syslog需要的3個參數及其類型。
而setlevel.c之所以編譯通但是,是因為Linux Device Driver3的作者是在2.6.10的Linux內核中寫的這個程式,但是2.6.20的Linux內核中卻并沒有定義_syscall3這個函 數。(我在Red Hat 9.0(2.4的內核)中編譯過setlevel.c,能夠正常通過。)
于是只要在setlevel.c中調用_syscall3之前定義他的原型,那么setlevel.c就能夠正常編譯和使用了。增加代碼后的setlevel.c如下:
#include
#include
#include
#include
#include /*需要加上這個頭文檔,否則編譯不能通過*/
#define __syscall_return(type, res) \
do { \
?? if ((unsigned long)(res) >= (unsigned long)(-125)) { \
?? ?? ?? ??? errno = -(res); \
?? ?? ?? ??? res = -1; \
?? } \
?? return (type) (res); \
} while (0)
#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
type name(type1 arg1,type2 arg2,type3 arg3) \
{ \
long __res; \
__asm__ volatile ("int $0x80" \
?? : "=a" (__res) \
?? : "0" (__NR_##name),"b" ((long)(arg1)),"c" ((long)(arg2)), \
?? ?? ?? ?? "d" ((long)(arg3))); \
__syscall_return(type,__res); \
}
_syscall3(int,syslog, int,type, char *,bufp, int,len);
int main(int argc, char **argv)
{
int level;
if (argc==2) {
?? level = atoi(argv[1]); /* the chosen console */
} else {
?? ??? fprintf(stderr, "%s: need a single arg\n",argv[0]); exit(1);
}
if (syslog(8,NULL,level)
?? ??? fprintf(stderr,"%s: syslog(setlevel): %s\n",
?? ?? ?? ?? argv[0],strerror(errno));
?? ??? exit(1);
}
exit(0);
}
轉載于:https://blog.51cto.com/axlrose/1288990
總結
以上是生活随笔為你收集整理的Linux设备驱动程式之读书笔记(二) [转]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Cisco对中国CCIE认证下重手了
- 下一篇: 用Flash创建一个类似Nano War