实现设备与驱动分离的思想
先解析设备信息,成功后执行probe函数控制相关硬件信息文章来源:https://www.toymoban.com/news/detail-513864.html
实例:文章来源地址https://www.toymoban.com/news/detail-513864.html
/*
* Filename: /home/ubuntu/vscode/day9_/pdrv.c
* Path: /home/ubuntu/vscode/day9_
* Created Date: Sunday, June 25th 2023, 1:51:32 pm
* Author: xinyue
*
* Copyright (c) 2023 Your Company
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include "led.h"
struct resource* res;
unsigned int irqnum;
//主设备号
int major = 0;
struct gpio_desc *gpionum1, *gpionum2, *gpionum3; //描述GPIO结构体
char kbuf[1024] = {0};
struct class* cls; //向上提交目录信息结构体指针
struct device* dev; //向上提交设备结点结构体指针
struct device_node* dnode;
int mycdev_open (struct inode * inode, struct file * file)
{
printk("%s:%s:%d\n", __FUNCTION__, __FILE__, __LINE__);
return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
//逻辑控制
switch(cmd)
{
case LED1_ON:
gpiod_set_value(gpionum1, 1);
break;
case LED1_OFF:
gpiod_set_value(gpionum1, 0);
break;
case LED2_ON:
gpiod_set_value(gpionum2, 1);
break;
case LED2_OFF:
gpiod_set_value(gpionum2, 0);
break;
case LED3_ON:
gpiod_set_value(gpionum3, 1);
break;
case LED3_OFF:
gpiod_set_value(gpionum3, 0);
break;
default:
break;
}
return 0;
}
int mycdev_close (struct inode * inode, struct file * file)
{
printk("%s:%s:%d\n", __FUNCTION__, __FILE__, __LINE__);
return 0;
}
struct file_operations fops = {
.open=mycdev_open,
.unlocked_ioctl=mycdev_ioctl,
.release=mycdev_close
};
int dev_create(void)
{
//向上提交目录信息
cls = class_create(THIS_MODULE, "mycdev");
if(IS_ERR(cls)) //返回值指向错误码区
{
printk("class_create failed\n");
return -PTR_ERR(cls);
}
printk("class_create succeeded\n");
//向上提交设备结点信息
dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "mycleds");
if(IS_ERR(dev))
{
printk("device_create failed\n");
return -PTR_ERR(dev);
}
printk("device_create succeeded\n");
return 0;
}
//解析设备树结点,找出GPIO编号
int find_gpiox(void)
{
//根据结点找到对应的GPIO编号,并申请使用编号,初始化为低电平输出模式
gpionum1 = gpiod_get_from_of_node(dnode, "led1", 0, GPIOD_OUT_LOW, NULL);//led1
if(IS_ERR(gpionum1))
{
printk("gpiod_get_from_of_node failed\n");
return -PTR_ERR(gpionum1);
}
gpionum2 = gpiod_get_from_of_node(dnode, "led2", 0, GPIOD_OUT_LOW, NULL);//led2
if(IS_ERR(gpionum2))
{
printk("gpiod_get_from_of_node failed\n");
return -PTR_ERR(gpionum2);
}
gpionum3 = gpiod_get_from_of_node(dnode, "led3", 0, GPIOD_OUT_LOW, NULL);//led3
if(IS_ERR(gpionum3))
{
printk("gpiod_get_from_of_node failed\n");
return -PTR_ERR(gpionum3);
}
return 0;
}
//定义相关成员函数
//probe函数用于匹配设备成功后执行
int pdrv_probe(struct platform_device *pdev)//当和设备匹配成功之后执行probe
{
major = register_chrdev(0, "mycleds", &fops);
if(0 == major)
{
printk("%s\n", "mycdev register failed");
return -1;
}
printk("%s:%s:%d major=%d\n", __FUNCTION__, __FILE__, __LINE__, major);
dev_create(); //向上提交信息(创建设备结点)
dnode = pdev->dev.of_node; //解析成功后,该指针存放了成功找到的设备结点对象的指针
find_gpiox(); //初始化GPIO引脚
//printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
//remove用于和设备分离时执行
int pdrv_remove(struct platform_device *pdev)//当设备和驱动分离时执行remove
{
//释放申请的编号
gpiod_put(gpionum1);
gpiod_put(gpionum2);
gpiod_put(gpionum3);
//销毁设备节点
device_destroy(cls, MKDEV(major, 0));
class_destroy(cls);
//注销设备驱动
unregister_chrdev(major, "mycleds");
//printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
//在驱动中创建一个用于设备树匹配的表
struct of_device_id oftable[]={
{.compatible="hqyj,myplatform",},
{.compatible="hqyj,myplatform1",},
{.compatible="hqyj,myplatform2",},
{},
};
//分配对象并初始化
struct platform_driver pdrv={
.probe=pdrv_probe,
.remove=pdrv_remove,
.driver={
.name = "hqyj",
.of_match_table = oftable //设备树匹配方式
}
};
//一键注册宏,代替入口出口
module_platform_driver(pdrv);
MODULE_LICENSE("GPL");
到了这里,关于驱动开发-platform的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!