platform驱动编写

平台总线是一条虚拟总线。
在这里插入图片描述
一边的“device”结构体和另一边的“较稳定的 drivice 代码”的联系:
“device_add()”除了将“devcie”结构放到 bus 的“dev 链表”之外,还会从另一边的“drv”
链表中取表元即某个“driver”结构,用总线里的一个(.match)函数来作比较,看另一边的
“driver”是否支持一边的“device”。若是能够支持,则接着调用软件驱动部分的“.probe”
函数。
"driver_register()"会将“bus_drv_dev”模型中的较稳定代码“driver”结构体放到虚拟总线的
某个链表(drv 链表)中。从另一边的“dev”链表中取出每一个“device”结构用 bus 中的
“.match”函数来作比较,若支持则调用“.probe”函数。
在这里插入图片描述
“只不过”左右两个注册建立起来的一种机制。在“.probe”函数中做的事件由自已决定,
打印一句话,或注册一个字符设备,再或注册一个“input_dev”结构体等等都是由自已决定。
强制的把一个驱动程序分为左右两边这种机制而已,可以把这套东西放在任何地方,这里的
“driver”只是个结构体不要被这个名字迷惑,“device”也只是个结构体,里面放什么内容
都是由自已决定的。

实验:用平台分层分离思想点 LED。

1,有三个 LED 灯:
在这里插入图片描述
在这里插入图片描述
现在只想点一个 LED 灯,这里强制的把代码分成左右两边:
想写一个驱动,想达到一个目的:
左边“device”表示某一个 LED 灯。要想修改是哪个 LED 灯,就只需要修改左边这个
led_platform_dev.c 即可。而
右边那个“led_platform_drv.c”保持稳定不变。
Led_platform_dev.c

在这里插入图片描述
平台资源结构体:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

驱动程序里定义了一个平台设备:
struct platform_device led_dev,这个平台设备里还有一些所谓的平台资源。
资源里有它的寄存器地址:
[0] = {
.start = 0x56000050, //LED 的寄存器起始地址:gpfcon = (volatile unsigned long
*)ioremap(0x56000050, 16);
.end = 0x56000050 + 8 - 1, //LED 寄存器结束地址:gpfdat = gpfcon + 1;
.flags = IORESOURCE_MEM,
},
要修改寄存器,就直接修改上面的寄存器起始地址就可以。
资源里还有哪一个引脚的信息:
[1] = {
.start = 4, //LED1 引脚 4 是"4,5,6"中的第一个 LED 灯。
.end = 4,
.flags = IORESOURCE_IRQ,
}
以后想换另一个 LED 灯,就只需要换这里的引脚就好,如第 2 个 LED 灯引脚是 5:
1] = {
.start = 5, //LED2 引脚 5 是"4,5,6"中的第二个 LED 灯。
.end = 5,
.flags = IORESOURCE_IRQ,
}

写“平台设备”
1,定义平台设备:
1,分配、设置、注册一个 platform_device 结构体。
在这里插入图片描述
在这里插入图片描述
2,入口函数:
在这里插入图片描述
2.1,看注册平台设备的过程:
在这里插入图片描述
3,出口函数:
在这里插入图片描述
4,修饰入口函数:
在这里插入图片描述
接着写“平台驱动”:
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)
{
//2.1,根据 platform_device 的资源进行 ioremap .
//2.2,注册字符设备驱动程序.
printk(“led_probe, found led\n”);
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”);
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);
}

平台设备 结构体定义中有一个“device”结构,这个“device”结构在“device.h”中定义:
其中有定义“void (*release)(struct device * dev);”。我们要提供这个 relase 函数,这里
什么都不用做。以后可以放一些硬件相关的到里面。这个例子里暂时不做任何事情。
修改代码如下:

在这里插入图片描述

在这里插入图片描述
注册“dev.ko”后,是将一个平台设备结构注册到平台总线下的“平台设备”链表,这
时另一方“平台驱动”通过“设备名”匹配到一个“平台驱动”结构后,调用此结构下的“.probe”
函数,为这个“平台设备”作相关的处理;当“rmmod xx_dev”后,是从“平台设备”
结构链表中删除了 这个“xx_dev.ko”,这时另一端相关同名的“平台驱动”就调用自已结构
中的“.remove”函数作相关清理工作。

第二部分:下面在“.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");

	if(major){
		 devid = MKDEV(major, 0);
		 register_chrdev_region(devid, 2, "myled");
	 }else{
		 alloc_chrdev_region(&devid, 0, 2, "myled");
		 major = MAJOR(devid);
	 }
	cdev_init(&led_cdev, &led_fops);
	cdev_add(&led_cdev, devid, 2);
	 
	cls = class_create(THIS_MODULE, "led");
	device_create(cls, NULL, MKDEV(major, 0), NULL, "led");//dev/led
 
	
	return 0;
}

在open函数中配置硬件

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

在写函数中操作
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值