驅動程序也可以多次實例化,每次實例化都可以采用不同的設置,目標設備可以有不同的I2C從ID,連接到不同的SPI從選擇,或者映射到不同的物理存儲器地址。所有實例共用同樣的代碼,以便節省存儲器,但具有各自的數據段。
Linux是一種先占式多任務、多用戶操作系統,因此幾乎所有設備驅動程序和內核子系統都允許多個進程(可能由不同的用戶所有)同時利用設備。常見的例子有network(網絡)、audio(音頻)或input(輸入)接口。QWERTY鍵盤控制器ADP5588的鍵按下或釋放事件會被加上時間戳、排隊并發送至所有已打開input vent device(輸入事件設備)的進程。這些事件代碼在所有架構上都相同,并且與硬件無關。讀USB鍵盤與從用戶空間讀取ADP5588并無區別。事件類型通過代碼加以區分。鍵盤發送鍵事件(EV_KEY)、鍵識別碼以及代表按下或釋放動作的某種狀態值。觸摸屏發送絕對坐標事件(EV_ABS)以及由x、y和觸摸壓力組成的一個三元組,鼠標則發送相對運動事件(EV_REL)。加速度計ADXL346在發送關于加速度的絕對坐標事件的同時,可以發送關于單振或雙振的鍵事件。
某些應用中,加速度計ADXL346產生相對事件或者發送特定鍵代碼(特定應用設置),也很有意義。一般而言,定制驅動程序有兩種方式:運行時或編譯時。
可能在運行時進行定制的設備特性使用模塊參數和或/sys條目。
實現特定目標
使用開源Linux驅動程序—通過定制實現特定目標,對于編譯時配置,將特定板和特定應用配置排除在主驅動程序文件之外是Linux的慣例,一般將其放入board support ?le(板支持文件)中。
對于定制板上的設備(這是嵌入式和基于SoC片上系統硬件的典型現象),Linux使用platform_data指向描述設備及其如何連到SoC的特定板結構。這可以包括可用端口、不同芯片版本、首選模式、默認初始化、引腳的其他作用等。這將能縮小板支持包(BSP),并盡量減少驅動程序中板和應用特定的#ifdef。至于哪些可調變量進入platform_data,哪些應當在運行時具有訪問權,則由驅動程序的作者決定。
數字加速度計特性與應用具有非常密切的關系,不同的板和型號可能具有不同的特性。下例顯示了一組配置選項。這些變量在頭文件adxl34x.h(include/linux/input/adxl34x.h)中有詳細描述。
Analog Dialogue 44-03, March (2010)
#include
static const struct adxl34x_platform_data
adxl34x_info={
.x_axis_offset=0,
.y_axis_offset=0,
.z_axis_offset=0,
.tap_threshold=0x31,
.tap_duration=0x10,
.tap_latency=0x60,
.tap_window=0xF0,
.tap_axis_control=ADXL_TAP_X_EN | ADXL_TAP_
Y_EN | ADXL_TAP_Z_EN,
.act_axis_control=0xFF,
.activity_threshold=5,
.inactivity_threshold=3,
.inactivity_time=4,
.free_fall_threshold=0x7,
.free_fall_time=0x20,
.data_rate=0x8,
.data_range=ADXL_FULL_RES,
.ev_type=EV_ABS,
.ev_code_x=ABS_X,/*EV_REL*/
.ev_code_y=ABS_Y,/*EV_REL*/
.ev_code_z=ABS_Z,/*EV_REL*/
.ev_code_tap={BTN_TOUCH,BTN_TOUCH,BTN_TOUCH},/*EV_KEY x,y,z */
.ev_code_ff=KEY_F,/* EV_KEY */
.ev_code_act_inactivity=KEY_A,/*EV_KEY*/
.power_mode=ADXL_AUTO_SLEEP|ADXL_LINK,
.fifo_mode=ADXL_FIFO_STREAM,
};
為將設備與驅動程序相關聯,“平臺和總線模型”無需設備驅動程序來包含其所控制設備的硬編碼物理地址或總線ID。平臺和總線模型還能防止資源沖突,大大改善便攜性,并與內核的電源管理特性干凈利落地接口。
利用平臺和總線模型,設備驅動程序一旦獲得設備的物理位置和中斷線路,便知道如何控制設備。該信息在探測期間作為一個數據結構傳遞給驅動程序。
與PCI或USB設備不同,I2C或SPI設備不會在硬件層次上進行枚舉。相反,軟件必須知道每個I2C/SPI總線段上連接了哪些設備,以及這些設備使用什么地址。因此,內核代碼必須明確實例化I2C/SPI設備。這可以通過多種不同方法實現,具體取決于上下文和要求。不過,最常用的方法是通過總線號碼聲明I2C/SPI設備。
當I2C/SPI總線是一條系統總線時,這種方法是合適的;許多嵌入式系統正是這種情況,其中每條I2C/SPI總線都有一個事先已知的號碼。因此,可以預先聲明連到該總線的I2C/SPI設備。這可以利用一個結構體i2c_board_info/spi_board_info陣列來完成,該陣列通過調用以下內容注冊i2c_register_board_info()/spi_register_board_info()
static struct i2c_board_info __initdata bfin_ i2c_board_info[] = {#if defined(CONFIG_TOUCHSCREEN_AD7879_I2C)||defined(CONFIG_TOUCHSCREEN_AD7879_I2C_MODULE)
{
I2C_BOARD_INFO("ad7879",0x2F),
.irq=IRQ_PG5,
.platform_data=(void*)&bfin_ad7879_ts_info,
},
#endif
#ifdefined(CONFIG_KEYBOARD_ADP5588)||defined(CONFIG_KEYBOARD_ADP5588_MODULE)
{
I2C_BOARD_INFO("adp5588-keys",0x34),
.irq=IRQ_PG0,
.platform_data=(void*)&adp5588_kpad_data,
},
#endif
#ifdefined(CONFIG_PMIC_ADP5520)||defined(CONFIG_PMIC_ADP5520_MODULE)
{
I2C_BOARD_INFO("pmic-adp5520",0x32),
.irq=IRQ_PG0,
.platform_data=(void*)&adp5520_pdev_data,
},
#endif
#ifefined(CONFIG_INPUT_ADXL34X_I2C)|| defined(CONFIG_INPUT_ADXL34X_I2C_MODULE)
{
I2C_BOARD_INFO("adxl34x", 0x53),
.irq = IRQ_PG0,
.platform_data = (void *)&adxl34x_info,
},
#endif
};
static void __init blackfin_init(void)
{
(...)
i2c_register_board_info(0,bfin_i2c_board_info, ARRAY_SIZE(bfin_i2c_board_info));
spi_register_board_info(bfin_spi_board_info, ARRAY_SIZE(bfin_spi_board_info));
(...)
}
因此,為了啟用這樣一個驅動程序,只需要編輯板支持文件,將適當的條目添加至i2c_board_info(spi_board_info)。
還應注意到,需在內核配置期間選擇驅動程序。驅動程序按照所屬的子系統分類??稍谝韵挛恢貌檎褹DXL34x驅動程序:
Device Drivers--->
Input device support --->
[*] Miscellaneous devices --->
<*>Analog Devices ADXL34x Three-Axis
Digital Accelerometer
<*>support I2C bus connection
<*>support SPI bus connection
評論
查看更多