platform机制,如何实现驱动层分离
platform机制,如何实现驱动层分离

分离:
把硬件相关的东西抽出来;把相对稳定的软件部分抽出来。
分层:
input.c向上提供统一给APP操作的统一接口。每一层专注于自已的事件。
平台总线是一条虚拟总线:
驱动部分:
"device_add()"会将“bus_drv_dev”模型中的硬件部分“device”结构体放到虚拟总线的某个链表(dev 链表)中。
platform机制,如何实现驱动层分离
硬件部分:
"device_add()"会将“bus_drv_dev”模型中的硬件部分“device”结构体放到虚拟总线的某个链表(dev链表)中。

使用platform机制,编写LED驱动层:
platform机制,如何实现驱动层分离
platform机制,如何实现驱动层分离
现在只想点一个LED灯,这里强制的把代码分成左右两边:
想写一个驱动,想达到一个目的:
左边“device”表示某一个LED灯。要想修改是哪个LED灯,就只需要修改左边这个led_platform_dev.c即可。而
右边那个“led_platform_drv.c”保持稳定不变。
编程:
一、首先创建设备代码和驱动代码:led_dev.c 、led_drv.c
led_dev.c用来指定灯的引脚地址,当更换平台时,只需要修改这个就行。
led_drv.c用来初始化灯以及如何控制灯的逻辑,当更换控制逻辑时,只需要修改这个就行。
二、.编写led.dev.c,写“平台设备”:
#include <linux/module.h>
#include <linux/version.h>

#include <linux/init.h>

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
Led_dev.c 设备部分:
1,定义平台设备:
1,分配、设置、注册一个platform_device 结构体。
static struct resource led_resource[] = {
[0] = { //哪个寄存器:LED的寄存器起始地址:
gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
.start = 0x56000050, //ioremap
.end = 0x56000050 + 8 - 1, //LED寄存器结束地址:gpfdat = gpfcon + 1;
.flags = IORESOURCE_MEM, //内存资源
},
[1] = { //哪个引脚
.start = 4, //LED1引脚4是"4,5,6"中的第1个LED灯
.end = 4,
.flags = IORESOURCE_IRQ, //中断资源
}
};

static void led_release(struct device * dev)
{
}

static struct platform_device led_dev = {
.name = “myled”,
.id = -1,
.num_resources = ARRAY_SIZE(led_resource),
.resource = led_resource,
};

2,入口函数:
static int led_dev_init(void) //2.1,注册一个平台设备
{
platform_device_register (&led_dev);
return 0;
}
/*2.1,看注册平台设备的过程:
platform_device_register (&led_dev);
–>platform_device_add(pdev);
–>device_add(&pdev->dev); 将device放到平台总线的“dev”链表中去。
*/
3,出口函数:
static void led_dev_exit(void) //3.1,卸载平台设备
{
platform_device_unregister(&led_dev);
}
4,修饰入口函数:
module_exit(led_dev_init);
MODULE_LICENSE(“GPL”);
module_init(led_dev_init);
以上便写好了平台设备部分代码。

三、接着写“平台驱动”:
#include <linux/module.h>
#include <linux/version.h>

#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/irq.h>
#include <asm/uaccess.h>
#include <asm/io.h>

static int major;

static struct class *cls;
static volatile unsigned long *gpio_con;
static volatile unsigned long *gpio_dat;
static int pin;

static int led_open(struct inode *inode, struct file file)
{
//printk(“first_drv_open\n”);
/
配置为输出 */
gpio_con &= ~(0x3<<(pin2));
gpio_con |= (0x1<<(pin2));
return 0;
}

static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
int val;

//printk(“first_drv_write\n”);
copy_from_user(&val, buf, count); // copy_to_user();
if (val == 1)
{
// 点灯
*gpio_dat &= ~(1<<pin);
}
else
{
// 灭灯
*gpio_dat |= (1<<pin);
}

return 0;
}

static struct file_operations led_fops = {
.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
.open = led_open,
.write = led_write,
};
1, 定义平台驱动:
//1,分配、设置、注册一个platform_driver 结构体。
//1,1,定义一个平台驱动.因为平台总线的.match函数比较的是"平台设备"和"平台驱动"的名
字.所以两边名字要相同。
//这样才会认为这个drv 能支持这个dev。才会调用平台驱动里面的".probe"函数。
struct platform_driver led_drv = {
.probe = led_probe, //自已写一个probe 函数.
.remove = led_remove; //自已写led_remove 函数.与 led_remov 倒过来写.
.driver = {
.name = “myled”, //名字要与平台设备结构体中的名字一致.
}
};
2,构造平台驱动结构中的“.probe”函数:
//2,平台驱动结构中的".probe"函数.这个函数是自已按照自已的要求写的。
static int led_probe(struct platform_device *pdev)
{
struct resource res;
/
根据platform_device的资源进行ioremap /
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpio_con = ioremap(res->start, res->end - res->start + 1);
gpio_dat = gpio_con + 1;
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
pin = res->start;
/
注册字符设备驱动程序 /
printk(“led_probe, found led\n”);
major = register_chrdev(0, “myled”, &led_fops);
cls = class_create(THIS_MODULE, “myled”);
class_device_create(cls, NULL, MKDEV(major, 0), NULL, “led”); /
/dev/led */
return 0;
}
3,构造平台驱动结构中的“.remove”函数:做与“.probe”相反的事件。
//3,led_remove,与".probe"函数相反.
static int led_remove(struct platform_device *pdev)
{
//3.1,根据 platform_device 的资源进行 iounmap .
//3.2,卸载字符设备驱动程序.
printk(“led_remove, remove led\n”);
class_device_destroy(cls, MKDEV(major, 0));
class_destroy(cls);
unregister_chrdev(major, “myled”);
iounmap(gpio_con);
return 0;
}
4,入口函数:
//4,入口函数.
static int led_drv_init(void)
{
//4.1,注册一个台平台驱动。
platform_driver_register (&led_drv);
return 0;
}
5,出口函数:
//5,出口函数
static void led_drv_exit(void)
{
//5.1,卸载平台驱动。
platform_driver_unregister (&led_drv);
}

5、测试运行

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

/* led_test on

  • led_test off
    */
    int main(int argc, char **argv)
    {
    int fd;
    int val = 1;
    fd = open("/dev/led", O_RDWR);
    if (fd < 0)
    {
    printf(“can’t open!\n”);
    }
    if (argc != 2)
    {
    printf(“Usage :\n”);
    printf("%s <on|off>\n", argv[0]);
    return 0;
    }

    if (strcmp(argv[1], “on”) == 0)
    {
    val = 1;
    }
    else
    {
    val = 0;
    }

    write(fd, &val, 4);
    return 0;
    }

1)如下图,我们先挂载dev设备模块,和我们之前分析的一样,它在platform/devices目录下生成一个"myled"设备
platform机制,如何实现驱动层分离
2)如下图,我们再来挂载drv驱动模块,同样的在platform/drivers目录下生成一个"myled"驱动,devices目录下的"myled"设备匹配成功,进入.probe函数创建设备,接下来就可以使用应用程序来控制led灯了
platform机制,如何实现驱动层分离
3)如下图,卸载驱动时,也会进入.remove函数卸载设备

platform机制,如何实现驱动层分离

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-09-06
  • 2022-12-23
  • 2022-12-23
  • 2021-09-17
  • 2021-07-22
猜你喜欢
  • 2021-08-07
  • 2021-12-05
  • 2021-08-09
  • 2021-08-28
  • 2021-07-19
  • 2021-07-24
  • 2021-07-25
相关资源
相似解决方案