亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問(wèn)板塊 發(fā)新帖
查看: 1193 | 回復(fù): 0
打印 上一主題 下一主題

linux設(shè)備驅(qū)動(dòng)歸納總結(jié)(九):1.platform設(shè)備驅(qū)動(dòng) [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2011-02-05 22:12 |只看該作者 |倒序?yàn)g覽
linux設(shè)備驅(qū)動(dòng)歸納總結(jié)(九):1.platform總線的設(shè)備和驅(qū)動(dòng)


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

這一節(jié)可以理解是第八章的延伸,從這節(jié)開(kāi)始介紹platform設(shè)備驅(qū)動(dòng)。

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


一、什么是paltform總線


一個(gè)現(xiàn)實(shí)的linux設(shè)備和驅(qū)動(dòng)通常都需要掛接在一種總線上,比較常見(jiàn)的總線有USB、PCI總線等。但是,在嵌入式系統(tǒng)里面,SoC系統(tǒng)中集成的獨(dú)立的外設(shè)控制器、掛接在SoC內(nèi)存空間的外設(shè)卻不依附與此類總線。基于這樣的背景下,2.6內(nèi)核加入了platform虛擬總線。platform機(jī)制將設(shè)備本身的資源注冊(cè)進(jìn)內(nèi)核,有內(nèi)核統(tǒng)一管理,在驅(qū)動(dòng)程序使用這些資源時(shí)使用統(tǒng)一的接口,這樣提高了程序的可移植性。

如果簡(jiǎn)單的說(shuō),就像我在第八章第三節(jié)模擬的usb總線一樣(源代碼路徑:8th_devModule_3/2nd),platform總線對(duì)加入到該總線的設(shè)備和驅(qū)動(dòng)分別封裝了兩個(gè)結(jié)構(gòu)體——platform_deviceplatform_driver。并且提供了對(duì)應(yīng)的注冊(cè)函數(shù)。當(dāng)然,前提是要包含頭文件<linux/flatform_device.h>。

來(lái)個(gè)圖:

由上面兩個(gè)的關(guān)系我們可以看出來(lái),需要在platform總線上注冊(cè)設(shè)備和驅(qū)動(dòng),只要定義指定的結(jié)構(gòu)體后調(diào)用platform給出的注冊(cè)函數(shù)就可以了。


下面就介紹一下platform總線、設(shè)備和驅(qū)動(dòng)。


1platform總線:


和我之前虛擬的usb總線一樣,linux在系統(tǒng)啟動(dòng)時(shí)就注冊(cè)了platform總線,看內(nèi)核代碼:

/*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); //配對(duì)函數(shù)檢驗(yàn)名字是否一致

610 }

。。。。。

949 struct bus_type platform_bus_type = {

950     .name = "platform", //定義了總線名字為platform,總線注冊(cè)后新建目錄sys/bus/platform

951     .dev_attrs = platform_dev_attrs,

952     .match = platform_match, //指定配對(duì)函數(shù)

953     .uevent = platform_uevent,

954     .pm = PLATFORM_PM_OPS_PTR,

955 };

可以看到,和我的usb虛擬總線一樣,總線中定義了成員名字和match函數(shù),當(dāng)有總線或者設(shè)備注冊(cè)到platform總線時(shí),內(nèi)核自動(dòng)調(diào)用match函數(shù),判斷設(shè)備和驅(qū)動(dòng)的name是否一致


2、platform設(shè)備:


同樣的,先看一下platform設(shè)備對(duì)應(yīng)的結(jié)構(gòu)體paltform_device

/*linux/platform_device.h*/

16 struct platform_device {

17     const char * name; //設(shè)備的名字,這將代替device->dev_id,用作sys/device下顯示的目錄名

18     int id; //設(shè)備id,用于給插入給該總線并且具有相同name的設(shè)備編號(hào),如果只有一個(gè)設(shè)備的話填-1。

19     struct device dev; //結(jié)構(gòu)體中內(nèi)嵌的device結(jié)構(gòu)體。

20     u32 num_resources; //資源數(shù)。

21     struct resource * resource; //用于存放資源的數(shù)組。

22 };

上面的結(jié)構(gòu)體中先不介紹id、num_resourcesresource?梢钥吹,platform_device的封裝就是指定了一個(gè)目錄的名字name,并且內(nèi)嵌device。

platform_device的注冊(cè)和注銷使用以下函數(shù):

/*drivers/base/platform.c*/

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

。。。

337 void platform_device_unregister(struct platform_device *pdev)

注冊(cè)后,同樣會(huì)在/sys/device/目錄下創(chuàng)建一個(gè)以name命名的目錄,并且創(chuàng)建軟連接到/sys/bus/platform/device下。


3、platform驅(qū)動(dòng):


先看一下platform驅(qū)動(dòng)對(duì)應(yīng)的結(jié)構(gòu)體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結(jié)構(gòu)體內(nèi)嵌了device_driver,并且實(shí)現(xiàn)了prob、remove等操作。其實(shí),當(dāng)內(nèi)核需要調(diào)用probe函數(shù)時(shí),它會(huì)調(diào)用driver->probe,在dricer->probe中再調(diào)用platform_driver->probe。如果想了解清楚的話建議查看內(nèi)核源代碼。

platform_driver的注冊(cè)和注銷使用以下函數(shù):

/*drivers/base/platform.c*/

492 int platform_driver_register(struct platform_driver *drv)

。。。。。

513 void platform_driver_unregister(struct platform_driver *drv)

注冊(cè)成功后內(nèi)核會(huì)在/sys/bus/platform/driver/目錄下創(chuàng)建一個(gè)名字為driver->name的目錄。


介紹完后,那我就根據(jù)第八章第三節(jié)(linux設(shè)備驅(qū)動(dòng)歸納總結(jié)(八):3.設(shè)備管理的分層與面向?qū)ο笏枷?/font>)的源程序(8th_devModule_3/2nd),將我想象出來(lái)的usb鼠標(biāo)設(shè)備和驅(qū)動(dòng)添加到platform總線上:

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

4 #include <linux/platform_device.h>

5

6 void usb_dev_release(struct device *dev)

7 {

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

9 }

10 struct platform_device mouse_dev = {

11     .name = "plat_usb_mouse", //將以這個(gè)名字創(chuàng)建目錄

12     .dev = {

13         .bus_id = "usb_mouse", //不會(huì)用這個(gè)名字創(chuàng)建目錄了,這里不設(shè)置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 }

一看就很簡(jiǎn)單,將之前usb結(jié)構(gòu)體和注冊(cè)函數(shù)更改為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/中的驅(qū)動(dòng)目錄名字

30     },

31 };

32

33 static int __init usb_driver_init(void)

34 {

35     int ret;

36     /*驅(qū)動(dòng)注冊(cè),注冊(cè)成功后在/sys/platform/usb/driver目錄下創(chuàng)建目錄

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 }


由上面的程序看到,設(shè)備和驅(qū)動(dòng)都以”plat_usb_mouse”命名,這樣的話match函數(shù)也就能配對(duì)成功。

看效果:

[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

當(dāng)我查找usb_mouse時(shí)出現(xiàn)了四個(gè)目錄,但是為什么后面有個(gè)“0”?這個(gè)0代表設(shè)備的編號(hào),是由paltform_device->id指定的。我的程序沒(méi)有設(shè)備,所以默認(rèn)為0。如果你不想的你的目錄名字沒(méi)有后綴,那你就設(shè)置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

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


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


二、platform設(shè)備的資源和數(shù)據(jù)


上面講的usb鼠標(biāo)都是假的,接下來(lái)簡(jiǎn)單實(shí)現(xiàn)一個(gè)led驅(qū)動(dòng),實(shí)現(xiàn)的功能很簡(jiǎn)單,加載后燈亮,卸載后燈滅,我的led燈對(duì)應(yīng)管腳GPE12。順便介紹一些platform_device中的resourceplatform_data

再看一下platform_device

16 struct platform_device {

17     const char * name;

18     int id;

19     struct device dev;

20     u32 num_resources;

21     struct resource * resource;

22 };

前三個(gè)已經(jīng)介紹了,現(xiàn)在來(lái)介紹一下最后兩個(gè)。

resource是一個(gè)指向platform資源數(shù)組的指針,該數(shù)組中有num_resource個(gè)資源,看一下資源結(jié)構(gòu)體:

/*linux/ioport.h"*/

18 struct resource {

19     resource_size_t start;

20     resource_size_t end;

21     const char *name;

22     unsigned long flags;

23     struct resource *parent, *sibling, *child;

24 };

常用的就是紅色標(biāo)記的三個(gè),分別是資源的開(kāi)始值,結(jié)束值和類型。

常見(jiàn)的flagsIORESOURCE_MEMIORESOURCE_IRQ。其他的可以自己查看include/linux/ioport.h

如果fiagsIORESOURCE_MEM,startend分別是該設(shè)備的連續(xù)的開(kāi)始和結(jié)束地址,如果不連續(xù)你可以定義兩個(gè)或者更多的資源結(jié)構(gòu)體。

如果flagsIORESOURCE_IRQ,startend分別是該設(shè)備連續(xù)的開(kāi)始和結(jié)束的連續(xù)中斷號(hào),如果不連續(xù)可以分開(kāi)定義。

當(dāng)然,如果地址或者中斷只有一個(gè),你可以將startend定義成一樣。

device.c定義了led的資源:

/*9th_platform_1/2nd/device.c*/

10 struct resource s3c_led_res[1] = {

11     [0] = {

12         .start = 0x56000000,

13         .end = 0x560000ff,

14         .flags = IORESOURCE_MEM,

15     },

16 };

17

18 struct platform_device s3c_led_dev = {

19     .name = "plat_led",

20     .id = -1,

21     .dev = {

22         .release = led_dev_release,

23     },

24     .num_resources = ARRAY_SIZE(s3c_led_res), //platform資源的數(shù)量,為1

25     .resource = s3c_led_res,

26 };

同時(shí),還要修改一下driver.c中的的proberemoveprobe函數(shù)中點(diǎn)亮led,remove滅掉led

/*9th_platform_1/2nd/driver.c*/

9 struct _plat_led_t {

10     unsigned long phys, virt;

11     unsigned long gpecon, gpedat, gpeup;

12     unsigned long reg;

13 };

14

15 struct _plat_led_t pled;

16

17 int led_driver_probe(struct platform_device *pdev)

18 {

19     pled.phys = pdev->resource[0].start;

20     pled.virt = ioremap(pled.phys, SZ_4K);

21     pled.gpecon = pled.virt + 0x40;

22     pled.gpedat = pled.virt + 0x44;

23     pled.gpeup = pled.virt + 0x48;

24

25     //config

26     pled.reg = ioread32(pled.gpecon);

27     pled.reg &= ~(3 << 24);

28     pled.reg |= (1 << 24);

29     iowrite32(pled.reg, pled.gpecon);

30

31     //up

32     pled.reg = ioread32(pled.gpeup);

33     pled.reg |= (1 << 12);

34     iowrite32(pled.reg, pled.gpeup);

35

36     //dat

37     pled.reg = ioread32(pled.gpedat);

38     pled.reg &= ~(1 << 12);

39     iowrite32(pled.reg, pled.gpedat);

40

41     printk("led on\n");

42     return 0;

43 }

上面的probe只要看紅色標(biāo)記就可以了,在platform_device的資源中獲取資源的start,而其他的都是之前介紹過(guò)的led操作。

45 int led_driver_remove(struct platform_device *pdev)

46 {

47     pled.reg = ioread32(pled.gpedat);

48     pled.reg |= (1 << 12);

49     iowrite32(pled.reg, pled.gpedat);

50

51     printk("led off\n");

52     return 0;

53 }

接下來(lái)驗(yàn)證一下:

[root: 2nd]# insmod device.ko

led device init

[root: 2nd]# insmod driver.ko

led on

led driver init

[root: 2nd]# rmmod driver

led off

led driver bye!

[root: 2nd]# rmmod device

<kernel> release

led device bye!


最后在介紹一下paltform設(shè)備的數(shù)據(jù):

device結(jié)構(gòu)體下有一個(gè)paltform_data

390 void *platform_data; /* Platform specific data, device

391 core doesn't touch it */

它也說(shuō)明了,這是用與platformdevice的代碼不會(huì)使用該結(jié)構(gòu)體。

這是一個(gè)void指針類型,用于存放platform的數(shù)據(jù)地址,類似字符設(shè)備時(shí)介紹的private_data。這里就不寫代碼了。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


三、platform設(shè)備的靜態(tài)注冊(cè)


在上面的程序中,設(shè)備和驅(qū)動(dòng)都是通過(guò)手動(dòng)加載的,但有些情況下,內(nèi)核已經(jīng)為設(shè)備注冊(cè)到platform總線上,只需要我們注冊(cè)驅(qū)動(dòng)就可以了。接下來(lái)介紹一下設(shè)備的靜態(tài)注冊(cè)。


先看一下內(nèi)核是從哪里獲取靜態(tài)注冊(cè)的platform_device。


內(nèi)核是從 arch/arm/mach-s3c2440/mach-mini2440.c文件中獲取到platform_device的信息:

/*arch/arm/mach-s3c2440/mach-mini2440.c*/

250 static struct platform_device *mini2440_devices[] __initdata = {

251     &s3c_device_usb,

252     &s3c_device_rtc,

253     &s3c_device_lcd,

254     &s3c_device_wdt,

255     &s3c_device_led, //這是我新加的

257     &s3c_device_i2c0,

258     &s3c_device_iis,

259     &s3c_device_dm9k,

260     &net_device_cs8900,

261     &s3c24xx_uda134x,

262 };

可以看到,這個(gè)數(shù)組存放著所有靜態(tài)注冊(cè)的platform_device信息,我按照它們的格式,也添加了一個(gè)s3c_device_led結(jié)構(gòu)體指針在這個(gè)數(shù)組中。接下來(lái)就要看看是在哪里定義了。

我全局搜索內(nèi)核代碼中含有s3c_device_wdt的文件,然后在這結(jié)構(gòu)體后面依樣畫(huà)葫蘆。

讓我搜到兩個(gè)相關(guān)的文件:

1arch/arm/plat-s3c24xx/devs.c


可以看到,內(nèi)核在在這個(gè)文件中聲明并定義s3c_device_wdtplatform_device結(jié)構(gòu)體,所以,我也在這里定義的個(gè)strucr platform_device s3c_device_led

/*arch/arm/plat-s3c24xx/devs.c*/

359 /*test by xiaobai*/

360 /* led_test */

361

362 static struct resource s3c_led_resource[] = {

363     [0] = {

364         .start = 0x56000000,

365         .end = 0x560000ff,

366         .flags = IORESOURCE_MEM,

367     }

368 };

369

370 struct platform_device s3c_device_led = {

371     .name = "plat_led",

372     .id = -1,

373     .num_resources = ARRAY_SIZE(s3c_led_resource),

374     .resource = s3c_led_resource,

375 };

376

377 EXPORT_SYMBOL(s3c_device_led);

會(huì)發(fā)現(xiàn),上面的內(nèi)容跟我前面卸載device.c的代碼一模一樣。


2)第二個(gè)文件是arch/arm/plat-s3c/include/plat/devs.h


platform_match函數(shù)是通過(guò)包含該文件后讀取里面的platform_device信息來(lái)跟platform_driver匹配。所以,必須在這里加上一行代碼:

/*arch/arm/plat-s3c/include/plat/devs.h*/

32 extern struct platform_device s3c_device_wdt;

33 extern struct platform_device s3c_device_led; //這是我新添加的


修改完上面的3個(gè)文件后,重新編譯內(nèi)核后就實(shí)現(xiàn)了靜態(tài)注冊(cè)platform設(shè)備,在內(nèi)核啟動(dòng)時(shí)會(huì)自動(dòng)注冊(cè)s3c_device_led。所以,我們只需要注冊(cè)platform驅(qū)動(dòng)就可以了,代碼在driver.c中,和上一個(gè)程序一模一樣(2nd/driver.c),我就不貼出來(lái)了,可以自己看3th/driver.c。接下來(lái)看效果:

Please press Enter to activate this console.

[root: /]# find -name "*plat_led*" //開(kāi)機(jī)后查找plat_led

./sys/devices/platform/plat_led //發(fā)現(xiàn)led設(shè)備已經(jīng)被靜態(tài)注冊(cè)上

./sys/bus/platform/devices/plat_led

[root: /]# cd review_driver/9th_platform/9th_platform_1/3rd/

[root: 3rd]# insmod driver.ko //加載led驅(qū)動(dòng)

led on //燈亮

led driver init

[root: 3rd]# rmmod driver

led off

led driver bye!


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


四、總結(jié)


這節(jié)由第八章的usb虛擬總線的延伸開(kāi)始介紹platform的設(shè)備和驅(qū)動(dòng)使用和注冊(cè)。


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

源代碼: 9th_platform_1.rar  

您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP