• 8.platform驱动分离


    1.框架

    platformbus总线结构将一个硬件驱动分为device设备和driver驱动两部分。使用platform将两个联系到一起

    就是把devicedriver分开注册到内核中去。在根据相应的name之类的去匹配使用。

    2.关键函数和结构

    device_driver:device和driver的相关性数据和函数存放

    struct device_driver {
    	const char		*name;            //设备驱动程序的名字
    	struct bus_type		*bus;            //所属总线类型
    
    	struct module		*owner;            //模块所有者
    	const char		*mod_name;	/* used for built-in modules */
    
    	bool suppress_bind_attrs;	/* disables bind/unbind via sysfs */
    
    	const struct of_device_id	*of_match_table;            //match device table
    
    	int (*probe) (struct device *dev);                        //匹配度到设备的name与driver中的name一致时将会在注册时执行
    	int (*remove) (struct device *dev);                        //移除一个绑定的驱动
    	void (*shutdown) (struct device *dev);                  //关机
    	int (*suspend) (struct device *dev, pm_message_t state);      //将设备调到休眠模式
    	int (*resume) (struct device *dev);                        //唤醒休眠模式
    	const struct attribute_group **groups;
    
    	const struct dev_pm_ops *pm;                              //电源管理操作
    
    	struct driver_private *p;
    };
    

    platform_device :硬件相关

    struct platform_device {
    	const char	* name;
    	int		id;
    	struct device	dev;
    	u32		num_resources;
    	struct resource	* resource;
    
    	const struct platform_device_id	*id_entry;
    
    	/* MFD cell pointer */
    	struct mfd_cell *mfd_cell;
    
    	/* arch specific additions */
    	struct pdev_archdata	archdata;
    };
    

    platform_driver
    这里的platform是一个普通的驱动,可用最原始的方法来注册创建class类,再在下面添加具体的设备文件来使用。platform只是bus中的一种,挂载到platform_bus_type。

    struct platform_driver {
    	int (*probe)(struct platform_device *);
    	int (*remove)(struct platform_device *);
    	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;
    };
    

    resource

    struct resource {
    	resource_size_t start;
    	resource_size_t end;
    	const char *name;
    	unsigned long flags;
    	struct resource *parent, *sibling, *child;
    };
    

    platform_get_resource
    获取platform资源

      struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)
      // type:资源类型
      // num:资源索引
    

    platform_driver_register-

      int platform_driver_register(struct platform_driver *drv)
    

    platform_driver_unregister

      void platform_driver_unregister(struct platform_driver *drv)
    

    platform_device_register

      int platform_device_register(struct platform_device *pdev)
    

    platform_device_unregister

      void platform_device_unregister(struct platform_device *pdev)
    

    3.代码解析

    led_dev.c

      //定义资源
    static struct resource myled_resource[] = {
            //内存资源
    	[0] = {
    		.start = 0x56000050,
    		.end   = 0x56000050 + 8 - 1,
    		.flags = IORESOURCE_MEM,
    	},
            //中断资源
    	[1] = {
    		.start = 4,
    		.end   = 4,
    		.flags = IORESOURCE_IRQ,
    	},
    };
    
    static int myled_release(struct platform_device *pdev)
    {
    
    }
    
    static struct platform_device myled_dev = {
    	.name = "myled",
    	.id = -1,
    	.num_resources = ARRAY_SIZE(myled_resource),      //申请内存
    	.resource = myled_resource,                       //赋值
    	.dev = {
    		.release = myled_release,                  //释放函数
    	},
    };
    
    static int myled_init(void)
    {
    	platform_device_register(&myled_dev);
    
    	return 0;
    }
    
    static void myled_exit(void)
    {
    	platform_device_unregister(&myled_dev);
    }
    
    module_init(myled_init);
    module_exit(myled_exit);
    MODULE_LICENSE("GPL");
    

    led_drv.c

    static struct class *myled_class;
    static struct class_device *myled_device_class;
    
    static volatile unsigned long *gpfcon;
    static volatile unsigned long *gpfdat;
    
    static unsigned int pin;
    
    static int myled_open (struct inode *inode, struct file *file)
    {
    	/*	设置gpio	*/
    	*gpfcon &= ~(3 << (pin * 2));
    	*gpfcon |= (1 << (pin * 2));
    
    	return 0;
    }
    
    static ssize_t myled_write (struct file *file, const char __user *buf, size_t count, loff_t *ppos)
    {
    	int val;
    
    	copy_from_user(&val, buf, count);
    
    	if(val)
    	{
    		/*	点灯	*/
    		*gpfdat &= ~(1 << pin);
    	}
    	else
    	{
    		/*	灭灯	*/
    		*gpfdat |= (1 << pin);
    	}
    
    	return 0;
    }
    
    
    static struct file_operations myled_fops = {
    	.owner = THIS_MODULE,
    	.open  = myled_open,
    	.write = myled_write,
    };
    
    int major;
    
    static int myled_probe (struct platform_device *pdev)
    {
    	struct resource *res;
    	/*	从平台获取信息	*/
            //根据platform_device的资源进行ioremap
    	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    
    	gpfcon = ioremap(res->start, res->end - res->start + 1);
    	gpfdat = gpfcon + 1;
    
    	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    	pin = res->start;
    	
    	/*	注册字符设备	*/
    	major = register_chrdev(0, "myled", &myled_fops);
    
    	myled_class = class_create(THIS_MODULE, "myled");
    	myled_device_class = class_device_create(myled_class, NULL, MKDEV(major, 0), NULL, "myled");
    
    	return 0;
    }
    
    static int myled_remove(struct platform_device *pdev)
    {
    	/*	卸载字符设备	*/
    	unregister_chrdev(major, "myled");
    
    	class_device_unregister(myled_device_class);
    	class_destroy(myled_class);
    
    	iounmap(gpfcon);
    }
    
    static struct platform_driver myled_drv = {
    	.probe = myled_probe,
    	.remove = myled_remove,
    	.driver = {
    		.name = "myled",
    	},
    };
    
    static int myled_drv_init(void)
    {
    	platform_driver_register(&myled_drv);
    
    	return 0;
    }
    
    static void myled_drv_exit(void)
    {
    	platform_driver_unregister(&myled_drv);
    }
    
    module_init(myled_drv_init);
    module_exit(myled_drv_exit);
    MODULE_LICENSE("GPL");
    

    led_test.c

    int main(int argc, char **argv)
    {
    	int fb;
    	int val;
    
    	fb = open("/dev/myled", O_RDWR);
    
    	if(fb < 0)
    	{
    		printf("can't open!
    ");
    	}
    
    	if(argc != 2)
    	{
    		printf("Uage: 
    ");
    		printf("%s <on | off>
    ", argv[0]);
    		return 0;
    	}
    
    	if(strcmp(argv[1], "on") == 0)
    	{
    		val = 1;
    	}
    	else
    	{
    		val = 0;
    	}
    
    	write(fb, &val, 4);
    
    	return 0;
    }
    

    Makefile

    KERN_DIR = /home/book/linux-2.6.22.6
    
    all:
    	make -C $(KERN_DIR) M=`pwd` modules 
    
    clean:
    	make -C $(KERN_DIR) M=`pwd` modules clean
    	rm -rf modules.order
    
    obj-m	+= led_drv.o
    obj-m	+= led_dev.o
  • 相关阅读:
    多线程中,上锁的理解
    sql server 2008 联机丛书
    序列化是线程安全的么
    对象化下的编程——字段
    Dic实现工厂模式
    design principle:java 回调与委派/委托机制(转)
    风筝数据结构学习笔记(2)后序遍历二叉树(非递归)
    风筝数据结构学习笔记(1)利用链式存储结构和递归构建二叉树
    吕震宇老师《设计模式系列》
    吕震宇老师《设计模式随笔系列》
  • 原文地址:https://www.cnblogs.com/huangdengtao/p/13336659.html
Copyright © 2020-2023  润新知