• 十八、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的结构体

    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的注册

    int platform_driver_register(struct platform_driver *drv)
    

    3、platform driver的注销

    void platform_driver_unregister(struct platform_driver *drv)
    

    4、资源的获取

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

    功能:获取platform device的资源,

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

    #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进行注册

    #if defined(CONFIG_NXP_WDT)
        printk("mach: add device watchdog\n");
        platform_device_register(&nxp_device_wdt);
    #endif
    (2) platform结构体
    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
    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的注销
    void platform_device_unregister(struct platform_device *pdev)

     

    2、platform driver

    nxp_wdt.c (drivers\watchdog)

    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

    #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

    #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

    #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);
    }
    

      

      

     

      

     

  • 相关阅读:
    使用国内镜像安装pyqt5
    python线程池 ThreadPoolExecutor 的用法及实战
    进程和线程、协程的区别
    python线程池实现
    python 多进程使用总结
    参与开源项目
    脑图——前端技术
    HTML中DTD使用小结
    浅谈面向对象——追溯法
    Dva.js 里面的几个概念
  • 原文地址:https://www.cnblogs.com/yuanqiangfei/p/15777845.html
Copyright © 2020-2023  润新知