<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    驅動程序調試方法之printk――printk的原理與直接使用

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接 1、基本原理 (1)在UBOOT里設置console=ttySAC0或者console=tty1 這里是設置控制終端,tySAC0 表示串口, tty1 表示lcd
    (2)內核用printk打印 內核就會根據命令行參數來找到對應的硬件操作函數,并將信息通過對應的硬件終端打印出來!   2、printk的使用 (1)printk函數的信息如何才能在終端顯示出來 在內核代碼include/linux/kernel.h中,定義了控制臺的級別: extern int console_printk[]; #define console_loglevel (console_printk[0]) #define default_message_loglevel (console_printk[1]) #define minimum_console_loglevel (console_printk[2]) #define default_console_loglevel (console_printk[3])   我們在到kernel/printk.c里找到console_printk的定義:   /* printk's without a loglevel use this.. */ #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */   /* We show everything that is MORE important than this.. */ #define MINIMUM_CONSOLE_LOGLEVEL 1 /* Minimum loglevel we let people use */ #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */   DECLARE_WAIT_QUEUE_HEAD(log_wait);   int console_printk[4] = {         DEFAULT_CONSOLE_LOGLEVEL,       /* console_loglevel */         DEFAULT_MESSAGE_LOGLEVEL,       /* default_message_loglevel */         MINIMUM_CONSOLE_LOGLEVEL,       /* minimum_console_loglevel */         DEFAULT_CONSOLE_LOGLEVEL,       /* default_console_loglevel */ };   于是我們知道控制臺的級別是: 7   4     1     7 我們當然可以再這里修改,但是還有一個更簡單的修改方法,即在用戶空間使用下面的命令:   echo “1 4 1 7” > /proc/sys/kernel/printk   將1 4 1 7寫入 /proc/sys/kernel/printk即可!   當我們使用printk函數時往往要加上信息級別,比如:   printk(KERN_WARNING"there is a warning here!\n")   其中KERN_WARNING就表示信息的級別,相關宏在函數include/linux/kernel.h中:   #define KERN_EMERG      "<0>"   /* system is unusable                   */ #define KERN_ALERT      "<1>"   /* action must be taken immediately     */ #define KERN_CRIT       "<2>"   /* critical conditions                  */ #define KERN_ERR        "<3>"   /* error conditions                     */ #define KERN_WARNING    "<4>"   /* warning conditions                   */ #define KERN_NOTICE     "<5>"   /* normal but significant condition     */ #define KERN_INFO       "<6>"   /* informational                        */ #define KERN_DEBUG      "<7>"   /* debug-level messages                 */   如果沒有指明信息級別的話,就會采用默認的信息級別,這個默認的信息級別我們在上面見到過的,就是: #define default_message_loglevel (console_printk[1]) 沒有改動的情況下是4   上面我們說到了信息級別和控制臺級別,下面我們要說到重點了!當信息級別的數值小于控制臺的級別時,printk要打印的信息才會在終端打印出來,否則不會顯示在終端!   (2)串口控制臺 printk         vprintk(fmt, args);                  vscnprintf(printk_buf, sizeof(printk_buf), fmt, args);                           vsnprintf(buf,size,fmt,args);//先把輸出信息輸入到臨時buffer                           //把臨時buffer里面的數據稍作處理,寫入log_buffer                           //可以將信息級別與信息合并                           //在用戶空間使用命令dmesg可以把log_buffer里面的數據打印出來                           release_console_sem();                                   call_console_drivers(_con_start, _log_end);                                           _call_console_drivers(start_print, cur_index, msg_level);                                                    __call_console_drivers(start, end);                                                             con->write(con, &LOG_BUF(start), end - start);//調用具體的輸出函數   這個輸出函數要把數據從串口輸出的話,肯定要調用到串口硬件相關的函數 我們到文件:drivers/serial/s3c2410.c里面去這里有個串口初始化函數:   s3c24xx_serial_initconsole        register_console(&s3c24xx_serial_console);   我們來看看它的注冊函數: static struct console s3c24xx_serial_console = { .name = S3C24XX_SERIAL_NAME, .device = uart_console_device, .flags = CON_PRINTBUFFER, .index = -1, .write = s3c24xx_serial_console_write, .setup = s3c24xx_serial_console_setup }; 里面的確有個write函數!   但是我們還不知道printk選擇的控制臺為什么是串口呢?   我們知道uboot傳入了參數:console=ttySAC0 或者 console=tty1   內核就通過如下的函數來處理傳入的參數: __setup("console=", console_setup); 這是個宏 ,它的作用就是用函數console_setup來處理我們傳入的參數 console_ setup          //先解碼字符串為:name, idx, options,然后就使用這些:name, idx, options         add_preferred_console(name, idx, options);                   strcmp(console_cmdline[i].name, name)                   console_cmdline[i].index == idx   //將索引和名字都記錄在了console_cmdline數組中了   我們記住這個數組,回過頭來再來看:  register_console(&s3c24xx_serial_console);          if (strcmp(console_cmdline[i].name, console->name) != 0)                  continue; 我們看到在注冊串口控制臺的時候,會將串口控制臺的名字與uboot傳進來的參數相比較,一旦匹配才會注冊。這樣的話,只有與uboot傳進來的控制臺參數相一致的控制臺才能注冊成功。那么也就是說,printk會通過uboot設置的控制臺的write函數,將信息打印出來!   另外還有一點需要牢記的就是,printk輸出的信息會先保存在緩沖區log_buf中,所以我們當然可以通過查看log_buf來看輸出信息了!而這個查看命令就是:dmesg 實際上,dmesg這個命令的作用就是去讀/proc/kmsg這個文件。也就是說log_buf里面的內容是存放在/proc/kmsg這個文件里面的!


    (3)使用printk 方法一: 我們可以再內核中使用如下打印語句: #define DEG_PRINTK printk //#define DEG_PRINTK(x...)   DEG_PRINTK("%s %s %d\n",_FILE_,_FUNCTION_,_LINE_); 這行打印語句的意思就是講本行代碼所在的文件的名(包括路徑)、所在的函數、所在的行打印出來! 當我們需要調試的時候,就使用#define DEG_PRINTK printk這個宏,當不需要調試的時候,就使用#define DEG_PRINTK(x...)這個宏。其中#define DEG_PRINTK(x...)里面的"..."的意思是DEG_PRINTK的參數是可變的! 當代碼比較少的時候,我們可以在每一行都加上這個打印語句,這樣很容易就會發現錯誤的位置! 當代碼比較多的時候,我們可以采用對半查找的方法!先在代碼中間加上打印語句!然后判斷出錯位置在打印語句之前還是之后,如果出現在之前,就在之前的代碼代碼里面再次采用對半查找!   方法二: 上面我們說到過,要打印的信息會存放在log_buf中,通過文件/proc/kmsg可以來訪問這個buf,然后將信息打印出來。由此我們就想了,我們是否可以構造這樣一個mylog_buf,里面存放我們所需要的打印信息,通過一個/proc/kmsg文件可以訪問該buf,然后打印出來?答案是肯定的!下面我們就一步步來完成!RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全