十八、platform模型

一、概念

platform是一个驱动管理模型,它不是从设计驱动的角度考虑,而是从管理驱动的角度考虑

  • platform device:描述硬件信息的部分(硬件不通,信息或资源不同)。
  • platform driver:描述软件信息的部分(对硬件资源的操作,保持相对稳定,较少修改)。
  • platform bus:是platform driver和platform device的管理者(管理着两条链表)。

二、platform模型的优点

  • 方便驱动的移植(争取做到移植时,只修改device,而driver部分基本不变)。
  • 内核中绝大部分设备驱动都是基于platform驱动模型的,,方便分析内核驱动源码,更便于理解驱动程序的框架。
  • 当platform driver和platform device匹配时,调用driver->probe函数
  • platform driver和platform device一般在不同的源文件中。

三、platform dirver实现步骤

1、platform driver的结构体

1
2
3
4
5
6
7
8
9
struct platform_driver {
    int (*probe)(struct platform_device *);-----在platform device 和platform driver 的driver的name匹配时会调用该函数
    int (*remove)(struct platform_device *);----是probe的反函数
    void (*shutdown)(struct platform_device *);
    int (*suspend)(struct platform_device *, pm_message_t state);
    int (*resume)(struct platform_device *);
    struct device_driver driver;
    const struct platform_device_id *id_table;
};

2、platform driver的注册

1
int platform_driver_register(struct platform_driver *drv)

3、platform driver的注销

1
void platform_driver_unregister(struct platform_driver *drv)

4、资源的获取

1
2
struct resource *platform_get_resource(struct platform_device *dev,
                       unsigned int type, unsigned int num)   

功能:获取platform device的资源,

最常用的资源类型有下面几种:

1
2
3
4
#define IORESOURCE_IO       0x00000100            //GPIO资源
#define IORESOURCE_MEM      0x00000200        //IO内存资源
#define IORESOURCE_IRQ      0x00000400       //中断号资源 
#define IORESOURCE_DMA      0x00000800            //DMA资源

返回值:成功返回有效的资源结构体地址,失败返回NULL  

 

四、platform模型驱动实例

以内核源码看门狗驱动为例

1、plafrom device 

(1)注册platform device

大部分的platform device都会在nxp_cpu_devs_register中使用platform_device_register进行注册

1
2
3
4
#if defined(CONFIG_NXP_WDT)
    printk("mach: add device watchdog\n");
    platform_device_register(&nxp_device_wdt);
#endif
(2) platform结构体
1
2
3
4
5
6
struct platform_device nxp_device_wdt = {
        .name           = DEV_NAME_WDT,         //设备名,资源通过设备名和platform driver匹配,匹配成功后会调用驱动中的probe进行初始化
        .id             = -1,
        .num_resources  = ARRAY_SIZE(nxp_wdt_resource),
        .resource       = nxp_wdt_resource,      //看门狗的资源
};
(3) resource
1
2
3
4
static struct resource nxp_wdt_resource[] = {
        [0] = DEFINE_RES_MEM(PHY_BASEADDR_WDT, SZ_1K),   //内存资源
        [1] = DEFINE_RES_IRQ(IRQ_PHY_WDT),               //中断资源  
};
(4)platform device的注销
1
void platform_device_unregister(struct platform_device *pdev)

 

2、platform driver

nxp_wdt.c (drivers\watchdog)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
static struct platform_driver nxp_wdt_driver = {-------platform driver
    .probe      = nxp_wdt_probe,-----------------基于某个驱动模型的初始化函数
    .remove     = __devexit_p(nxp_wdt_remove),----相当于probe函数的反函数
    .shutdown   = nxp_wdt_shutdown,
    .suspend    = nxp_wdt_suspend,
    .resume     = nxp_wdt_resume,
    .driver     = {
        .owner  = THIS_MODULE,
        .name   = DEV_NAME_WDT,-----------------用于注册时跟device的name比较
        .of_match_table = nxp_wdt_match,
    },
};
 
 
static int __init watchdog_init(void)
{
    pr_info("NXP Watchdog Timer, (c) 2014 SLsiAP\n");
 
    return platform_driver_register(&nxp_wdt_driver);----------注册platform driver
}
 
static void __exit watchdog_exit(void)
{
    platform_driver_unregister(&nxp_wdt_driver);-------注销platform driver
     
}
 
static int __devinit nxp_wdt_probe(struct platform_device *pdev)
{
    1.获取platform device 的资源(IO内存资源、中断号资源)
    2.申请IO内存
    3.获取/使能时钟
    4.具体硬件相关的操作,停止看门狗、设置定时时间
    5.注册看门狗中断
    6.其它的资源操作的代码
 
}        

 

五、platform实例 

使用platform模型实现蜂鸣器打开和关闭。

1、beep_dev.c

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/uaccess.h> 
#include <linux/types.h>
#include <linux/ioctl.h>
#include <mach/platform.h>
#include <mach/soc.h>
#include <mach/devices.h>
 
static void beep_release(struct device *dev)
{
        printk(KERN_INFO"beep_release\n");
}
 
 
//platform device拥有的资源
//定义了两种资源类型,可以使用IO口,也可以使用io内存
static struct resource beep_res[] =
{
    {
        .start =0xC001C000,
        .end = 0xC001C000+0x64+3,   //加3是因为最后一个寄存器还有四位
        .name = "GPIOC_IOMEM",
        .flags = IORESOURCE_MEM,
    },
    {
        .start =PAD_GPIO_C+14,
        .end = PAD_GPIO_C+14,
        .name = "GPIOC_IONUM",
        .flags = IORESOURCE_IO,
    },
         
 
};
 
static struct platform_device beep_pdev =
{
    .name           = "beep_pdev_pdrv"//和驱动匹配的设备名
    .id                 = -1,
    .num_resources  = ARRAY_SIZE(beep_res), //得到的是数组元素的个数
    .resource           = beep_res,
    .dev                =
                    {
                        .release = beep_release,
                    },
};
 
static int __init beep_dev_init(void)
{
    printk(KERN_INFO"beep_dev_init\n");
    //注册平台设备
    platform_device_register(&beep_pdev);
    return 0;
}
 
static void __exit beep_dev_exit(void)
{
    //销毁平台设备
    printk(KERN_INFO"beep_dev_exit\n");
    platform_device_unregister(&beep_pdev);
}
 
 
module_init(beep_dev_init);
module_exit(beep_dev_exit);
MODULE_AUTHOR("yqf");
MODULE_DESCRIPTION("beep device program");
MODULE_LICENSE("GPL");

 

2、beep_drv.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/uaccess.h> 
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
 
 
static struct resource *beep_mem_res  = NULL;
static void __iomem *GPIOCBASE = NULL;
static void __iomem *GPIOCOUT = NULL;
static void __iomem *GPIOCOUTENB= NULL;
static void __iomem *GPIOCALTFN0 = NULL;
static void __iomem *GPIOCALTFN1 = NULL;
 
 
#define BEEP_ON  _IO('B',0)
#define BEEP_OFF   _IO('B',1)
 
static  int beep_open(struct inode* inode,struct file *filp)
{
    printk(KERN_INFO"beep_open\n");
    return 0;
}
 
static  int beep_close(struct inode* inode,struct file *filp)
{
    printk(KERN_INFO"beep_close\n");
    return 0;
}
 
static ssize_t beep_write(struct file *filp, const char __user *user, size_t  size, loff_t *oft)
{
 
    printk(KERN_INFO"beep_write\n");
     return size;
}
 
static long beep_ioctl (struct file *filp, unsigned int cmd, unsigned long  arg)
{
      switch(cmd)
      {
            case BEEP_ON:
                writel(readl(GPIOCOUT)|((0x01<<14)),GPIOCOUT);
                break;
        case BEEP_OFF:
                writel(readl(GPIOCOUT)&(~(0x01<<14)),GPIOCOUT);
        default:
            return -ENOIOCTLCMD;           
      }
     return 0;
}
struct file_operations beep_fops=
{
    .open = beep_open,
    .release = beep_close,
    .write = beep_write,
    .unlocked_ioctl = beep_ioctl,
};
 
static struct miscdevice beep_misc=
{
    .minor = MISC_DYNAMIC_MINOR,
    .name = "beep_misc",
    .fops = &beep_fops,
};
static int  beep_probe(struct platform_device *pdev)
{
    int ret;
    printk(KERN_INFO"beep_probe\n");
    misc_register(&beep_misc);
    if(ret < 0)
    {
        printk(KERN_INFO"beep misc register fail\n");
        goto misc_register_err;
    }
    //获取IO内存资源
    beep_mem_res = platform_get_resource(pdev,IORESOURCE_MEM,0);
    if(beep_mem_res==NULL)
    {
        printk(KERN_INFO"platform_get_resource failed\n");
        ret = -ENODEV;
        goto platform_get_resource_err;
    }
    //映射到虚拟地址
    GPIOCBASE = ioremap(beep_mem_res->start,beep_mem_res->end-beep_mem_res->start+1);
    if(GPIOCBASE==NULL)
    {
        printk(KERN_INFO"ioremap failed");
        ret = -EBUSY;
        goto ioremap_err;
    }
    GPIOCOUT = GPIOCBASE+0x00;
    GPIOCOUTENB = GPIOCBASE+0x04;
    GPIOCALTFN0 = GPIOCBASE+0x20;
    GPIOCALTFN1 = GPIOCBASE+0x24;
    //beep
    writel(readl(GPIOCOUTENB)|(0x01<<14),GPIOCOUTENB);
    writel(readl(GPIOCALTFN0) &(~(0x03<<28)),GPIOCALTFN0);
    writel(readl(GPIOCALTFN0) |(1<<28),GPIOCALTFN0);
    writel(readl(GPIOCOUT)&(~(0x01<<14)),GPIOCOUT);
    return 0;
ioremap_err:
    release_mem_region(beep_mem_res->start,beep_mem_res->end-beep_mem_res->start+1);
platform_get_resource_err:
    misc_deregister(&beep_misc);
misc_register_err:
        return 0;  
}
 
static int  beep_remove(struct platform_device *pdev)
 
{
     
    printk(KERN_INFO"beep_remove\n");
    iounmap(GPIOCBASE);
    release_mem_region(beep_mem_res->start,beep_mem_res->end-beep_mem_res->start+1);
    misc_deregister(&beep_misc);   
    return 0;
}
 
static struct platform_driver beep_drv={
    .probe  = beep_probe,
    .remove = beep_remove,
    .driver     ={
                .owner = THIS_MODULE,
                .name = "beep_pdev_pdrv",  
               },
    };
 
static int  __init  beep_init(void)
{
       printk(KERN_INFO"beep_init\n");
    platform_driver_register(&beep_drv);  
    return 0;
}
 
static void __exit beep_exit(void)
 
{
    
    printk(KERN_INFO"beep_exit\n");
    platform_driver_unregister(&beep_drv);
}
 
module_init(beep_init);
 
module_exit(beep_exit);
 
MODULE_AUTHOR("yqf");
 
MODULE_DESCRIPTION("beep platform driver");
MODULE_LICENSE("GPL");  

3、main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/ioctl.h>
 
#define BEEP_ON _IO('B',0)
#define BEEP_OFF _IO('B',1)
 
int main()
{
    int fd;
    char buff[2]={0};
    fd = open("/dev/beep_misc",O_RDWR);
    if(fd<0)
    {
        perror("open bepp misc error!");       
    }
    while(1)
    {
         
        ioctl(fd,BEEP_ON);
        sleep(1);
        ioctl(fd,BEEP_OFF);
         sleep(1);
    }
     
     close(fd);
}

  

  

 

  

 

posted @   轻轻的吻  阅读(220)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
历史上的今天:
2019-01-08 计算机中内存、cache和寄存器之间的关系及区别
点击右上角即可分享
微信分享提示