歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux綜合 >> Linux內核

Linux內核中的一個宏函數例子

在移植linux到龍芯3210的過程中,調試串口的時候,遇到了一個outb函數,卻找不到這個函數的原型。當時是用VIM的跳轉功能來看的代碼。直接用grep工具也找不到這個函數。後問人才發現其實outb實則上是一個宏函數,而這宏函數的寫法還真是少見,可能是見識少了。

相關閱讀:移植linux到龍芯3210筆記

在./include/asm/io.h(其實asm是一個軟鏈接,實際上是./include/asm-mips/io.h)中:

363 #define __BUILD_IOPORT_SINGLE(pfx, bwlq, type, p, slow)                 \

364                                                                         \

365 static inline void pfx##out##bwlq##p(type val, unsigned long port)      \

366 {                                                                       \

367         volatile type *__addr;                                          \

368         type __val;                                                     \

369                                                                         \

370         __addr = (void *)__swizzle_addr_##bwlq(mips_io_port_base + port); \

371                                                                         \

372         __val = pfx##ioswab##bwlq(__addr, val);                         \

373                                                                         \

374         /* Really, we want this to be atomic */                         \

375         BUILD_BUG_ON(sizeof(type) > sizeof(unsigned long));             \

376                                                                         \

377         *__addr = __val;                                                \

378         slow;                                                           \

379 }

411 #define __BUILD_IOPORT_PFX(bus, bwlq, type)                             \

412         __BUILD_IOPORT_SINGLE(bus, bwlq, type, ,)                       \

413         __BUILD_IOPORT_SINGLE(bus, bwlq, type, _p, SLOW_DOWN_IO)

414

415 #define BUILDIO_IOPORT(bwlq, type)                                      \

416         __BUILD_IOPORT_PFX(, bwlq, type)                                \

417         __BUILD_IOPORT_PFX(__mem_, bwlq, type)

418

419 BUILDIO_IOPORT(b, u8)

420 BUILDIO_IOPORT(w, u16)

421 BUILDIO_IOPORT(l, u32)

從上面的代碼看來,除了“##”比較難理解,其它都行。關鍵也是在“##”。經查資料,了解到這兩個#的作用是連接字符串的作用。

從419行看來,傳入的參數只有兩個b,u8,那麼只有兩個參數,其它的字符串為空。

則看365行,明顯得到:

pxf 為空字符串

bwlq = b

type = u8

那麼得到兩個函數:

static inline void outb(u8 val, unsigned long port)

{

     ... ....

}


static inline void outb_p(u8 val, unsigned long port)

{

     ... ....

     SLOW_DOWN_IO;

}

 

 89 #define __SLOW_DOWN_IO \

 90         __asm__ __volatile__( \

 91                 "sb\t$0,0x80(%0)" \

 92                 : : "r" (mips_io_port_base));


可以看到outb與outb_p的區別在於執行完之後,outb_p調用了一個IO延時。但從這個SLOW_DOWN_IO中看來,相當於匯編中的:
sb $0, 0x80(mips_io_port_base)
意思是清零mips_io_port_base + 0x80這個地址保存的值????
怪怪的。
參考了LDD3中的一段話:
暫停式IO
在處理器試圖從總線上快速傳輸數據時,某些平台(特別是i386)會遇到問題。當處理器時鐘相比外設時鐘快時(比如ISA)就會出現問題,並且在設備卡特別慢時表現出來。斛決的辦法是在每條IO指令之後,如果還有其他類似指令,則插入一個小的延遲。在x86平台上,這種暫停可通過對端口0x80的一條out b指令實現(通常這樣做,但很少使用),或者通過使用忙等待實現。相關細節可參與自己平台上asm子目錄下的io.h文件。

Copyright © Linux教程網 All Rights Reserved