总线设备驱动框架

本文介绍了Linux平台设备树的管理,包括如何在设备树中添加设备节点、platform_driver的结构和功能,以及平台设备与驱动的匹配机制,重点讲解了devicetree的compatible属性在驱动匹配中的作用。此外,还讨论了设备线驱动模型的优点和platform_device与字符设备的关系。
摘要由CSDN通过智能技术生成

1.platform_device:修改设备树,添加设备(device)节点,设备树节点部分会被转换为 platform_device。

2.platform_driver:

        首先定义入口,出口函数;构建platform_driver结构体;在入口函数注册platform_driver(采用platform_driver_register()函数),卸载驱动程序时,就会去调用这个出口函数;

        构建file_operations结构体为APP层提供open,read等函数接口。

        在platform_driver.probe里面注册file_operations。

3.platform_device与platform_driver如何匹配(一般方法):

        使用设备树信息来判断 dev 和 drv 是否配对:

        如果 of_match_table 中含有 compatible 值,就跟 dev 的 compatile 属性比较,若一致则成功,否则返回失败;

eg:

//设备树
#define GROUP_PIN(g,p) ((g<<16) | (p))
 
/ {
	100ask_led@0 {
		compatible = "sym,leddrv";
		pin = <GROUP_PIN(3, 1)>;
	};
 
	100ask_led@1 {
		compatible = "sym,leddrv";
		pin = <GROUP_PIN(5, 8)>;
	};
 
};

//驱动

static struct platform_driver chip_demo_gpio_driver = {
    .probe      = chip_demo_gpio_probe,
    .remove     = chip_demo_gpio_remove,
    .driver     = {
        .name   = "100ask_led", /*这个对应的就是dts文件里面的名字*/ 
        .of_match_table = sym_leds,  
    },
};
static const struct of_device_id sym_leds[] = {
    { .compatible = "sym,leddrv" },
    { },
};

static int chip_demo_gpio_probe(struct platform_device *pdev)
{
	//int err;
	
	printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);

	/* 4.1 设备树中定义有: led-gpios=<...>;	led就是那个name*/
    led_gpio = gpiod_get(&pdev->dev, "led", 0);
	if (IS_ERR(led_gpio)) {
		dev_err(&pdev->dev, "Failed to get GPIO for led\n");
		return PTR_ERR(led_gpio);
	}
    
	/* 4.2 注册file_operations 	*/
	major = register_chrdev(0, "100ask_led", &led_drv);  /* /dev/led */

	led_class = class_create(THIS_MODULE, "100ask_led_class");
	if (IS_ERR(led_class)) {
		printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
		unregister_chrdev(major, "led");
		gpiod_put(led_gpio);
		return PTR_ERR(led_class);
	}
     // MKDEV 是一个宏,用于将主设备号和次设备号组合成一个 dev_t 类型的设备号
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "100ask_led%d", 0); /* /dev/100ask_led0 */
        
    return 0;
    
}

        PS:

       1. 没有转换为 platform_device 的节点,如何使用呢设备树里面定义的信息呢?

        任意驱动程序里,都可以采用操作设备树的常用函数直接访问设备树,从而获得我们想要的节点数据。

        2.platform总线的匹配规则是什么?在具体应用上要不要先注册驱动再注册设备?有先后顺序没?
        总线,设备,驱动。匹配规则就是当有一个新的设备挂起时,总线被唤醒,match函数被调用,用device名字去跟本总线下的所有驱动名字去比较。相反就是用驱动的名字去device链表中和所有device的名字比较。如果匹配上,才会调用驱动中的probe函数,否则不调用。至于先后顺序,鉴于个人理解,不会有影响,不管谁先谁后,bus都会完成匹配工作。

       3. 设备线驱动模型的出现主要有三个好处,设备与驱动分离,驱动可移植性增强;设备驱动抽象结构以总线结构表示看起来更加清晰明了,谁是属于哪一条bus的;最后,就是大家最熟悉的热插拔了,设备与驱动分离,很好的奠定了热插拔机制。

      4. 注意: 所谓的platform_device并不是与字符设备、块设备和网络设备并列的概念,而是Linux系统提供的一种附加手段,例如,把内部集成的I2C、RTC、SPI、LCD、看门狗等控制器都归纳为platform_device,而它们本身就是字符设备。我们要记住,platform驱动只是在字符设备驱动外套一层platform_driver的外壳。引入platform模型符合Linux设备模型――总线、设备、驱动,设备模型中配套的sysfs节点都可以用,方便我们的开发;当然你也可以选择不用,不过就失去了一些platform带来的便利。

       5.设备号

        register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)

 具体可以看register_chrdev()内部实现。

        第一个参数是主设备号,0代表动态分配,当然也可以由我们指定,第二个参数name任取。

        dev是设备号,包含有主设备号和次设备号的信息。主设备号用于区分设备的类型,次设备号用于标记相同类型的设备的不同个体。如串口1和串口2使用同一驱动程序,则其主设备号相同,但次设备号不同。Linux内核中使用dev_t类型来定义设备号,dev_t这种类型其实质为32位的unsigned int,其中高12位为主设备号,低20位为次设备号。主设备号相同的设备都使用同一个 file_operations 来操作。
        1.知道主设备号与次设备号,可通过dev_t dev = MKDEv(主设备号,次设备号)获得设号;                2.从设备号分解出主设备号:主设备号=MAJOR(dev_t dev)
        3.从设备号分解出次设备号:次设备号=MINOR(dev_t dev)

参考书籍..-CSDN博客

  • 22
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值