linux led驱动子系统是怎么实现和应用空间交互的

linux led驱动子系统是怎么实现和应用空间交互的,第1张

1、struct file_operations是一个把字符设备驱动的 *** 作和设备号联系在一起的纽带,是一系列指针的集合,每个被打开的文件 都对应于一系列的 *** 作,这就是file_operations,用来执行一系列的系统调用。

从上面的原理图可以看到两个LED的一端连接到电源VSYS上,另一端通过三极管接地,通过控制三极管的基极,可以点亮或关闭LED。两个三极管的基极分别通过底板连接到核心板上Exynos 4412的GPIO GPL2_0和GPK1_1上。

上一章节已经讲过iTOP-4412开发板中GPIO的驱动,LED的驱动里面将会用到上一章节介绍的几个 *** 作GPIO的函数

LED驱动的入口函数是leds_init,其实现如下:

static int __init leds_init(void)

{

        return platform_driver_register(&leds_driver)

}

该函数会调用内核函数platform_driver_register向内核注册一个硬件设备,这个函数的参数是一个platform_driver结构,leds_driver定义如下:

static struct platform_driver leds_driver = {

        .probe = leds_probe,

        .remove = leds_remove,

        .suspend = leds_suspend,

        .resume = leds_resume,

        .driver = {

                .name = DRIVER_NAME,

                .owner = THIS_MODULE,

        },

}

内核调用platform_driver_register注册硬件设备的时候,最终会调用到platform_driver结构里面的probe探测函数,iTOP-4412开发板的LED驱动里探测函数是leds_probe,定义如下:

static int leds_probe(struct platform_device *pdev)

{

        int ret, i

        char *banner = "leds Initialize\n"

        printk(banner)

        for(i=0 i<LED_NUM i++)

        {

                ret = gpio_request(led_gpios[i], "LED")

                if (ret) {

                        printk("%s: request GPIO %d for LED failed, ret = %d\n", DRIVER_NAME,

                                        led_gpios[i], ret)

                        return ret

                }

                s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT)

                gpio_set_value(led_gpios[i], 1)

        }

        ret = misc_register(&leds_dev)

        if(ret<0)

        {

                printk("leds:register device failed!\n")

                goto exit

        }

        return 0

exit:

        misc_deregister(&leds_dev)

        return ret

}

在这个函数里会使用GPIO的 *** 作函数来配置LED的两个GPIO引脚的功能为输出,默认输出高电平。控制LED的两个GPIO的定义在数组led_gpios中,如下:

static int led_gpios[] = {

        EXYNOS4_GPL2(0),

        EXYNOS4_GPK1(1),

}

接着回到LED的探测函数往下看,接着会调用misc_register向内核注册字符设备。misc_register函数传递的参数类型是miscdevice,miscdevice被称作杂项设备,嵌入式系统中用得比较多的一种设备驱动。在Linux内核的include/linux目录下有Miscdevice.h文件,要把自己定义的misc device从设备号定义在这里。其实是因为这些字符设备不符合预先确定的字符设备范畴,所有这些设备采用主编号10 ,一起归于misc device,其实misc_register就是用主标号10调用register_chrdev()的。iTOP-4412开发板的LED驱动里miscdevice的结构定义如下:

static struct miscdevice leds_dev = {

        .minor  = MISC_DYNAMIC_MINOR,

        .fops   = &leds_ops,

        .name   = "leds",

}

从上面的定义可以看到minor次设备号定义成了MISC_DYNAMIC_MINOR,在misc子系统里如果此设备号定义成MISC_DYNAMIC_MINOR,那么在驱动注册的时候,内核会动态的为这个设备分配子设备号。LED驱动会在/devu录下创建设备节点leds。

驱动里面提供了设备文件的几个 *** 作函数open,release,ioctl,上层应用首先调用open函数打开leds设备,然后调用ioctl来设置led的亮灭。leds_ioctl函数的实现如下所示:

long leds_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)

{

        printk("debug: leds_ioctl cmd is %d\n" , cmd)

        switch(cmd)

        {

                case 0:

                case 1:

                        if (arg > LED_NUM) {

                                return -EINVAL

                        }

                        gpio_set_value(led_gpios[arg], cmd)

                        break

                default:

                        return -EINVAL

        }

        return 0

}

通过上面的代码,可以知道上层应用使用ioctl,需要传递两个参数cmd和arg,cmd是led的状态(0是灭,1是亮),arg是代表 *** 作哪个led。

linux2.6以后的内核在加载驱动的时候是可以动态添加的,不用每次添加之后都make zImage,

你只用先编译一边,然后就可以一直用这个做驱动的开发喽,

只要生成了led.ko,然后insmod led.ko,就可以了,至于是不是用应用层,我觉得你还是先学一下应用层的东西吧,比如nuix系统高级编程之内的书,


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8359773.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-15
下一篇 2023-04-15

发表评论

登录后才能评论

评论列表(0条)

保存