Linux驅動基礎 platform裝置驅動

2021-07-26 14:45:09 字數 4945 閱讀 4142

以高通平台為例,會在kernel/arch/arm/mach-msm下的相應的board-***.c檔案裡邊用

dt_machine_start()這個巨集定義一系列的晶元。以高通8916為例:

在kernel/arch/arm/mach-msm/board-8916.c檔案裡定義了

//當然下面使用哪個要看一下。

dt_machine_start(msm8916_dt,

"qualcomm technologies, inc. msm 8916 (flattened device tree)")

.map_io = msm8916_map_io,

.init_machine = msm8916_init,

.dt_compat = msm8916_dt_match,

.reserve = msm8916_dt_reserve,

.smp = &msm8916_smp_ops,

machine_end

//下面還定了很多其他名字的,比如msm8939。但最終會根據dt_compat,也就是msm8916_dt_match的名字找到相應的dts檔案。比如

static

const

char *msm8916_dt_match __initconst = ;

這個會找到dts檔案裡邊的對應名字的compatible。比如:

/ ;....

在.init_machine對應的msm8916_init()函式裡,會查詢到裝置所有的platform裝置進行初始化。

static

void __init msm8916_init(void)

const

struct of_device_id of_default_bus_match_table = ,//搜一下******-bus

#ifdef config_arm_amba

,#endif /* config_arm_amba */

{} /* empty terminated list */

};//搜一下上面的comatible,比如「******-bus」可以在類似msm8916.dtsi檔案裡邊找到

&soc ;

//....

在找到******-bus並初始化&soc下面所有的platform device之後,就可以在

sys/devices/soc.0下面找到所有的device節點。比如拿上面tsens為例會根據device tree設定的名字platform device id等給裝置取名字。

/sys/devices/soc.0/4a8000.tsens
而且platform device建立的時候在platform_device_add函式中,dev.bus都會預設設定成platform_bus_type

所以上面4a8000.tsens也會在/sys/bus/platform/devices下面生成一樣的節點,並被symlink。

/sys/bus/platform/devices # ls -l

lrwxrwxrwx root root 2015-01-13

18:30

4a8000.tsens -> ../../../devices/soc.0/4a8000.tsens

platform裝置的名字,通常是@後面的名字.加上:後面的名字。如果什麼都沒有,就名字加上platform id。

但也有例外,確切的device tree節點名字讀一下uevent節點就可以知道。

cpubw: qcom,cpubw@0 {}就會生成/sys/devices/soc.0/0.qcom,cpubw

qcom,armbw-pm {}就會生成/sys/devices/soc.0/qcom,armbw-pm

.32

當然&soc{}這個有效果的前提也是需要包含在整個device tree的根目錄下。

/ ;

aliases ;

cpus ;

};cpu1: cpu@1 ;

cpu2: cpu@2 ;

cpu3: cpu@3 ;

};soc: soc ;//沒有這個,platform裝置相關的&soc{}包含的都是不會被初始化的!!!

};

具體的platform驅動在找到對應的compatible的名字之後,就可以新增裝置驅動。

這個過程中會在/sys/bus/platform/driver目錄下生成與驅動的名字對應名字的節點。

比如下面定義的platform driver在被找到對應的platform device之後會生成

相應的節點。

static struct platform_driver mdm_driver = ,

};生成的節點是:

/sys/bus/platform/drivers/ext-mdm

現在platform device都是從device tree裡邊讀出並進行platform device的初始化。

以前是對應platform device和platform driver的名字的話,現在是對比device相關的compatible的內容了。

像下面i2c-versatile驅動中,在i2c_versatile_match.compatible的字串,如果與某個&soc{}裡邊的compatible內容一致,就回去呼叫相應的probe函式去初始化platform。

drivers/i2c/busses/i2c-versatile.c檔案裡邊可以看到像下面的基本的platform裝置的定義以及函式呼叫

static

const

struct of_device_id i2c_versatile_match = ,

{},};module_device_table(of, i2c_versatile_match);

static

struct platform_driver i2c_versatile_driver = ,

};static

int __init i2c_versatile_init(void)

static

void __exit i2c_versatile_exit(void)

subsys_initcall(i2c_versatile_init);

module_exit(i2c_versatile_exit);

module_description("arm versatile i2c bus driver");

module_license("gpl");

module_alias("platform:versatile-i2c");

/sys/bus/platform/devices/versatile-i2c.0/

modalias ,uevent這幾個檔案,power,subsystem資料夾

/sys/devices/platform/versatile-i2c.0/

modalias ,uevent這幾個檔案,power,subsystem資料夾

int platform_driver_register(struct platform_driver *drv)

struct bus_type platform_bus_type= ;

static

struct device_attribute platform_dev_attrs = ;

這裡的platform_bus_type會用bus_register()先註冊一下。

int bus_register(struct bus_type *bus)

priv->drivers_kset = kset_create_and_add("drivers", null,

&priv->subsys.kobj);

if (!priv->drivers_kset)

init_list_head(&priv->inte***ces);

__mutex_init(&priv->mutex, "subsys mutex", key);

klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);

klist_init(&priv->klist_drivers, null, null);

retval = add_probe_files(bus);

if (retval)

goto bus_probe_files_fail;

retval = bus_add_attrs(bus);

if (retval)

goto bus_attrs_fail;

pr_debug("bus: '%s': registered\n", bus->name);

return

0;bus_attrs_fail:

remove_probe_files(bus);

bus_probe_files_fail:

kset_unregister(bus->p->drivers_kset);

bus_drivers_fail:

kset_unregister(bus->p->devices_kset);

bus_devices_fail:

bus_remove_file(bus, &bus_attr_uevent);

bus_uevent_fail:

kset_unregister(&bus->p->subsys);

out:

kfree(bus->p);

bus->p =

null;

return retval;

}

待續….

Linux驅動基礎

裝置驅動充當了硬體和應用軟體之間的紐帶,它使得應用軟體只需要呼叫系統軟體的應用程式設計介面 api 就可讓硬體去完成要求的工作。本文主要講解了linux裝置驅動與硬體的關係,linux裝置驅動的開發模式以及核心中相關的重要基礎資料結構。對裝置驅動最通俗的解釋就是 驅使硬體裝置行動 驅動與底層硬體直接...

Linux驅動模組基礎

1 模組載入函式 linux核心模組載入函式一般以 init標識宣告,典型的模組載入函式的形式如下 static int init initialization function void module init initialization function 模組載入函式必須以 module in...

Linux驅動基礎開發1

目前,linux軟體工程師大致可分為兩個層次 主要利用c庫函式和linux api進行應用軟體的編寫 從事這方面的開發工作,主要需要學習 符合linux posix標準的api函式及系統呼叫,linux的多工程式設計技巧 多程序 多執行緒 程序間通訊 多工之間的同步互斥等,嵌入式資料庫的學習,ui程...