1. 程式人生 > >linux裝置驅動歸納總結(九):1.platform匯流排的裝置和驅動

linux裝置驅動歸納總結(九):1.platform匯流排的裝置和驅動

linux裝置驅動歸納總結(九):1.platform匯流排的裝置和驅動

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

這一節可以理解是第八章的延伸,從這節開始介紹platform裝置驅動。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

一、什麼是paltform匯流排

一個現實的linux裝置和驅動通常都需要掛接在一種總線上,比較常見的匯流排有USB

PCI匯流排等。但是,在嵌入式系統裡面,SoC系統中整合的獨立的外設控制器、掛接在SoC記憶體空間的外設卻不依附與此類匯流排。基於這樣的背景下,2.6核心加入了platform虛擬匯流排。platform機制將裝置本身的資源註冊進核心,有核心統一管理,在驅動程式使用這些資源時使用統一的介面,這樣提高了程式的可移植性。

如果簡單的說,就像我在第八章第三節模擬的usb匯流排一樣(原始碼路徑:8th_devModule_3/2nd),platform匯流排對加入到該匯流排的裝置和驅動分別封裝了兩個結構體——platform_deviceplatform_driver。並且提供了對應的註冊函式。當然,前提是要包含標頭檔案<linux/flatform_device.h>

來個圖:

由上面兩個的關係我們可以看出來,需要在platform總線上註冊裝置和驅動,只要定義指定的結構體後呼叫platform給出的註冊函式就可以了。

下面就介紹一下platform匯流排、裝置和驅動。

1platform匯流排:

和我之前虛擬的usb匯流排一樣,linux在系統啟動時就註冊了platform匯流排,看核心程式碼:

/*drivers/base/platform.c*/

604 static int platform_match(struct device *dev, struct device_driver *drv)

605 {

606     struct platform_device *pdev;

607

608     pdev = container_of(dev, struct platform_device, dev);

609     return (strcmp(pdev->name, drv->name) == 0); //配對函式檢驗名字是否一致

610 }

。。。。。

949 struct bus_type platform_bus_type = {

950     .name = "platform", //定義了匯流排名字為platform,匯流排註冊後新建目錄sys/bus/platform

951     .dev_attrs = platform_dev_attrs,

952     .match = platform_match, //指定配對函式

953     .uevent = platform_uevent,

954     .pm = PLATFORM_PM_OPS_PTR,

955 };

可以看到,和我的usb虛擬匯流排一樣,匯流排中定義了成員名字和match函式,當有匯流排或者設備註冊到platform匯流排時,核心自動呼叫match函式,判斷裝置和驅動的name是否一致

2platform裝置:

同樣的,先看一下platform裝置對應的結構體paltform_device

/*linux/platform_device.h*/

16 struct platform_device {

17     const char * name; //裝置的名字,這將代替device->dev_id,用作sys/device下顯示的目錄名

18     int id; //裝置id,用於給插入給該匯流排並且具有相同name的裝置編號,如果只有一個裝置的話填-1

19     struct device dev; //結構體中內嵌的device結構體。

20     u32 num_resources; //資源數。

21 struct resource * resource; //用於存放資源的陣列。

22 };

上面的結構體中先不介紹idnum_resourcesresource。可以看到,platform_device的封裝就是指定了一個目錄的名字name,並且內嵌device

platform_device的註冊和登出使用以下函式:

/*drivers/base/platform.c*/

322 int platform_device_register(struct platform_device *pdev) //同樣的,需要判斷返回值

。。。

337 void platform_device_unregister(struct platform_device *pdev)

註冊後,同樣會在/sys/device/目錄下建立一個以name命名的目錄,並且建立軟連線到/sys/bus/platform/device下。

3platform驅動:

先看一下platform驅動對應的結構體paltform_driver

/*linux/platform_device.h*/

50 struct platform_driver {

51 int (*probe)(struct platform_device *);

52 int (*remove)(struct platform_device *);

53 void (*shutdown)(struct platform_device *);

54 int (*suspend)(struct platform_device *, pm_message_t state);

55 int (*suspend_late)(struct platform_device *, pm_message_t state);

56 int (*resume_early)(struct platform_device *);

57 int (*resume)(struct platform_device *);

58 struct device_driver driver;

59 };

可以看到,platform_driver結構體內嵌了device_driver,並且實現了probremove等操作。其實,當核心需要呼叫probe函式時,它會呼叫driver->probe,在dricer->probe中再呼叫platform_driver->probe。如果想了解清楚的話建議檢視核心原始碼。

platform_driver的註冊和登出使用以下函式:

/*drivers/base/platform.c*/

492 int platform_driver_register(struct platform_driver *drv)

。。。。。

513 void platform_driver_unregister(struct platform_driver *drv)

註冊成功後核心會在/sys/bus/platform/driver/目錄下建立一個名字為driver->name的目錄。

介紹完後,那我就根據第八章第三節(linux裝置驅動歸納總結(八):3.裝置管理的分層與面向物件思想)的源程式(8th_devModule_3/2nd),將我想象出來的usb滑鼠裝置和驅動新增到platform總線上:

/*9th_platform_1/1st/device.c*/

4 #include <linux/platform_device.h>

5

6 void usb_dev_release(struct device *dev)

7 {

printk("<kernel> release\n");

9 }

10 struct platform_device mouse_dev = {

11 .name = "plat_usb_mouse", //將以這個名字建立目錄

12 .dev = {

13 .bus_id = "usb_mouse", //不會用這個名字建立目錄了,這裡不設定bus_id也行的。

14 .release = usb_dev_release,

15 },

16 };

17

18 static int __init usb_device_init(void)

19 {

20 int ret;

21

22 ret = platform_device_register(&mouse_dev);

23 if(ret){

24 printk("device register failed!\n");

25 return ret;

26 }

27

28 printk("usb device init\n");

29 return 0;

30 }

31

32 static void __exit usb_device_exit(void)

33 {

34 platform_device_unregister(&mouse_dev);

35 printk("usb device bye!\n");

36 }

一看就很簡單,將之前usb結構體和註冊函式更改為platform型別就可以了。dirver.c也是一樣:

/*9th_platform_1/1st/driver.c */

25 struct platform_driver mouse_drv = {

26 .probe = usb_driver_probe,

27 .remove = usb_driver_remove,

28 .driver = {

29 .name = "plat_usb_mouse", ///sys/中的驅動目錄名字

30 },

31 };

32

33 static int __init usb_driver_init(void)

34 {

35 int ret;

36 /*驅動註冊,註冊成功後在/sys/platform/usb/driver目錄下建立目錄

37 * plat_usb_mouse*/

38 ret = platform_driver_register(&mouse_drv);

39 if(ret){

40 printk("driver register failed!\n");

41 return ret;

42 }

43 printk("usb driver init\n");

44 return 0;

45 }

46

47 static void __exit usb_driver_exit(void)

48 {

49 platform_driver_unregister(&mouse_drv);

50 printk("usb driver bye!\n");

51 }

由上面的程式看到,裝置和驅動都以”plat_usb_mouse”命名,這樣的話match函式也就能配對成功。

看效果:

[root: 1st]# insmod device.ko

usb device init

[root: 1st]# insmod driver.ko

init usb mouse

usb driver init

[root: 1st]# lsmod

driver 1604 0 - Live 0xbf006000

device 1584 0 - Live 0xbf000000

[root: 1st]# cd /

[root: /]# find -name "*usb_mouse*"

./sys/devices/platform/plat_usb_mouse.0

./sys/bus/platform/devices/plat_usb_mouse.0

./sys/bus/platform/drivers/plat_usb_mouse

./sys/bus/platform/drivers/plat_usb_mouse/plat_usb_mouse.0

當我查詢usb_mouse時出現了四個目錄,但是為什麼後面有個“0”?這個0代表裝置的編號,是由paltform_device->id指定的。我的程式沒有裝置,所以預設為0。如果你不想的你的目錄名字沒有後綴,那你就設定platform_device->id = -1;

platform_device->id = 3的效果:

[root: /]# find -name "*usb_mouse*"

./sys/devices/platform/plat_usb_mouse.3

./sys/bus/platform/devices/plat_usb_mouse.3

./sys/bus/platform/drivers/plat_usb_mouse

./sys/bus/platform/drivers/plat_usb_mouse/plat_usb_mouse.3

platform_device->id = -1的效果:

[root: /]# find -name "*usb_mouse*"

./sys/devices/platform/plat_usb_mouse

./sys/bus/platform/devices/plat_usb_mouse

./sys/bus/platform/drivers/plat_usb_mouse

相關推薦

linux裝置驅動歸納總結1.platform匯流排裝置驅動

linux裝置驅動歸納總結(九):1.platform匯流排的裝置和驅動 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 這一節可

linux裝置驅動歸納總結1.platform裝置驅動

http://blog.chinaunix.net/uid-25014876-id-111745.html 這一節可以理解是第八章的延伸,從這節開始介紹platform裝置驅動。 一、什麼是paltform匯流排 一個現實的linux裝置和驅

裝置驅動歸納總結1.匯流排裝置驅動 —— 匯流排的註冊

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 這幾天一直在看裝置模型,核心的程式碼看得我越來越沮喪,特別是kboject、kset和ktype之間的關係。但是,裝置

linux裝置驅動歸納總結2.操作硬體——IO記憶體

<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSi

linux裝置驅動歸納總結3.中斷下半部之tasklet

linux裝置驅動歸納總結(六):3.中斷的上半部和下半部——tasklet xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 一、什麼是下半部 中斷是一個很霸道的東西,處理

java基礎學習總結深入理解Java泛型

一、什麼是泛型         “泛型” 意味著編寫的程式碼可以被不同型別的物件所重用。泛型的提出是為了編寫重用性更好的程式碼。泛型的本質是引數化型別,也就是說所操作的資料型別被指定為一個引數。 比如常見的集合類 LinkedList: publi

linux】Valgrind工具集詳解Memcheck檢查的內容方法

一、值的有效性 1、什麼是值的有效性? 英文原文是Valid-value (V) bits,直譯過來就是有效值(V)位。 我將它理解為值的有效性,就是判斷在記憶體或CPU的實體地址中儲存的資料是否有效,比如在記憶體中變數(int i)代表的物理位置(不是地址),沒有初始化,就去使用它

Linux小小白入門教程查詢檔案或者文字內容

以下操作在Linux終端進行。Linux因為許可權非常嚴格,所以暫時所有的命令操作全部是在/home資料夾下的/yangjw資料夾下進行。/yangjw資料夾就是登入使用者名稱所在的資料夾,出了此資料

Struts2學習總結資料驗證

在Struts2框架中,可以實現客戶端驗證和伺服器驗證; 伺服器驗證分為兩種方式:   一,程式設計實現驗證      在之前的,已經對ActionSupport進行了瞭解。知道了ActionSupport類實現了Vaildateable介面,但對vaildate()方法的

機器學習總結梯度消失vanishing gradient與梯度爆炸exploding gradient問題

(1)梯度不穩定問題: 什麼是梯度不穩定問題:深度神經網路中的梯度不穩定性,前面層中的梯度或會消失,或會爆炸。 原因:前面層上的梯度是來自於後面層上梯度的乘乘積。當存在過多的層次時,就出現了內在本質

Spring Boot總結構建高效能的服務平臺

使用Spring Cloud開發的微服務,其獨立而有相對隔離的特性,與Docker的理念有異曲同工之妙,所以使用Docker來發布微服務,能夠發揮其更大的優勢,並且可以非常輕易的構建一個高效能和高可用的服務平臺; Docker

Linux之大資料技術修改ip地址

大資料技術之修改ip地址 5.2.3 修改IP地址 1)修改IP地址 [[email protected] 桌面]#vim /etc/sysconfig/network-scripts/ifcfg-eth0 以下標紅的項必須修改,有值的按照下面的值修

C#實戰小技巧List<string>string[]的相互轉換

List是string型別列表,string[]是string型別陣列,二者可以互相轉換。 1.string[]轉List string[] strArray = {"a", "ab", "abc"}; List<string> strList = new List<s

C++ STL開發溫習與總結 1.C++程式設計技術

 C++ STL開發溫習與總結(一):1.C++程式設計技術       使用了多年C++,沒有系統的溫習總結過,所以準備溫習《C++STL程式設計師開發指南》,本系列篇章將會是溫習總結該書本概念和技術點。 1概論 l  C++語言是基於C語言的語法基礎上融入了其他語

Linux學習總結-源碼包rpm包安裝

onf 之間 免費版 好的 remove 提高 裝包 rem 好處 我們熟悉下linux 軟件安裝:https://zhidao.baidu.com/question/504980243.html這裏寫了源碼安裝和yum安裝的優缺點,可以看看 一.源碼包安裝 通常辦法是安裝

linux驅動開發總結

基礎性總結 1, linux驅動一般分為3大類: * 字元裝置 * 塊裝置 * 網路裝置 2, 開發環境構建: * 交叉工具鏈構建 * NFS和tftp伺服器安裝 3, 驅動開發中設計到的硬體: * 數位電路知識 * ARM硬體知

Redis總結Linux環境如何安裝redis

以前總結Redis 的一些基本的安裝和使用,由於是測試方便,直接用的window 版的reids,並沒有講redis在linux下的安裝。今天就補一下Linux環境如何安裝redis。 大家可以這這裡檢視Redis 系列文章:https://www.cnblogs.com/zhangweizhong/cate

【原創】Linux虛擬化KVM-Qemu分析之virtio裝置

# 背景 - `Read the fucking source code!` --By 魯迅 - `A picture is worth a thousand words.` --By 高爾基 說明: 1. KVM版本:5.9.1 2. QEMU版本:5.0.0 3. 工具:Source Insight

Linux kernel中斷子系統之驅動申請中斷API

思路 esc 設計師 數組 還需 申請 進一步 time num 一、前言本文主要的議題是作為一個普通的驅動工程師,在撰寫自己負責的驅動的時候,如何向Linux Kernel中的中斷子系統註冊中斷處理函數?為了理解註冊中斷的接口,必須了解一些中斷線程化(threaded i

Linux驅動入門篇基本的字符設備模塊(2)

連接 truct ace alloc orm 負數 -s tabs idt   上一節中介紹了設備號的申請和釋放,這一節開始了解字符設備的相關操作。   首先定位到<linux/cdev.h>文件,查看內核提供給字符設備的接口。 cdev結構 str