文章目录
1 ID匹配
id匹配(可想象成八字匹配):一个驱动可以对应多个设备 ------在三种匹配方式中优先级次低。
注意事项:
1. device模块中,id的name成员必须与struct platform_device中的name成员内容一致,因此device模块中,structplatform_device中的name成员必须指定
2. driver模块中,struct platform_driver成员driver的name成员必须指定,但与device模块中name可以不相同
2 ID 匹配编写步骤
1 编写 xxx_device.c(设备)
1 在 platform_device xxxxxx中添加id_entry成员
struct platform_device fs4412led_device=
{
//用于名称匹配
.name="fs4412leds",
//设备回收时会被调用
.dev.release=fs4412led_dev_release,
.resource=fs4412led_dev_res,
//计算资源个数
.num_resources=ARRAY_SIZE(fs4412led_dev_res),
.id_entry=&fs4412leds_id,
};
2 编写 platform_device_id xxxxx
struct platform_device_id fs4412leds_id={
//注意和上面的name一致
.name="fs4412leds",
};
2 编写 xxx_driver.c(驱动)
1 在struct platform_driver xxxxx 中添加id_table成员
struct platform_driver fs4412leds_driver =
{
.driver.name="leds",
.probe=fs4412leds_driver_probe,
.remove=fs4412leds_driver_remove,
.id_table=fs4412leds_drv_ids,
};
2 编写struct platform_device_id xxxx_ids[]
struct platform_device_id fs4412leds_drv_ids[]={
[0]={.name ="fs4412leds"},
[1]={.name ="fs4412keys"},
[2]={}//代表结束必须
};
3 led驱动id匹配版
3.1 fs4412_led.h
#ifndef MY_CHAR_H
#define MY_CHAR_H
#include <asm/ioctl.h>
#define LED_DEV_MAGIC 'g'
//#define MYCHAR_IOCTL_GET_MAXLEN _IOR(MY_CHAR_MAGIC,1,int*)
//#define MYCHAR_IOCTL_GET_CURLEN _IOR(MY_CHAR_MAGIC,2,int*)
#define MY_LED_OFF _IO(LED_DEV_MAGIC,0)
#define MY_LED_ON _IO(LED_DEV_MAGIC,1)
// led2
#define GPX2CON 0x11000C40
#define GPX2DAT 0x11000C44
// led3
#define GPX1CON 0x11000C20
#define GPX1DAT 0x11000C24
//led4,5
#define GPF3CON 0x114001E0
#define GPF3DAT 0x114001E4
#endif
3.2 fs4412leds_device.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include "fs4412_led.h"
//做清理工作
void fs4412led_dev_release(struct device *pdev)
{
printk("fs4412led_dev_release is called\n");
}
struct resource fs4412led_dev_res[]=
{
[0]={.start=GPX1CON,.end=GPX1CON+3,.name="GPX1CON",.flags=IORESOURCE_MEM},
[1]={.start=GPX1DAT,.end=GPX1DAT+3,.name="GPX1DAT",.flags=IORESOURCE_MEM},
[2]={.start=GPX2CON,.end=GPX2CON+3,.name="GPX2CON",.flags=IORESOURCE_MEM},
[3]={.start=GPX2DAT,.end=GPX2DAT+3,.name="GPX2DAT",.flags=IORESOURCE_MEM},
[4]={.start=GPF3CON,.end=GPF3CON+3,.name="GPF3CON",.flags=IORESOURCE_MEM},
[5]={.start=GPF3DAT,.end=GPF3DAT+3,.name="GPF3DAT",.flags=IORESOURCE_MEM},
};
struct platform_device_id fs4412leds_id={
//注意和下面的name一致
.name="fs4412leds",
};
struct platform_device fs4412led_device=
{
//用于名称匹配
.name="fs4412leds",
//设备回收时会被调用
.dev.release=fs4412led_dev_release,
.resource=fs4412led_dev_res,
//计算资源个数
.num_resources=ARRAY_SIZE(fs4412led_dev_res),
.id_entry=&fs4412leds_id,
};
int __init fs4412led_device_init(void)
{
platform_device_register(&fs4412led_device);
return 0;
}
void __exit fs4412led_device_exit(void)
{
platform_device_unregister(&fs4412led_device);
}
MODULE_LICENSE("GPL");
module_init(fs4412led_device_init);
module_exit(fs4412led_device_exit);
3.3 fs4412leds_driver.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/atomic.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include "fs4412_led.h"
#define fs4412leds_driver_DEV_CNT 1
int major =11;//主设备号
int minor = 0;//次设备号
int fs4412leds_driver_num =fs4412leds_driver_DEV_CNT;//设备数量
struct fs4412leds_driver_dev
{
struct cdev mydev;//建立一个设备对象
//volatile为不做优化
volatile unsigned long * led2con;
volatile unsigned long * led2dat;
volatile unsigned long * led3con;
volatile unsigned long * led3dat;
volatile unsigned long * led4con;
volatile unsigned long * led4dat;
volatile unsigned long * led5con;
volatile unsigned long * led5dat;
struct class *pcls;
struct device *pdev;
};
struct fs4412leds_driver_dev *gmydev_arr[fs4412leds_driver_DEV_CNT];
//打开
int fs4412leds_driver_open(struct inode *pnode,struct file *pfile)
{
/*为避免使用全局变量*/
/*
*container_of是一个宏,可以用来求全局结构体变量的地址
*已知其成员的地址和成员名字,就可以求出其地址
*pnode->i_cdev:指向插入系统的设备对象(这里也是gmydev的成员mydev的地址)
*pnode->private_data:本次打开文件的私有数据,驱动中常来在几个操作函数间传递共用数据
*/
pfile->private_data=(void *)(container_of(pnode->i_cdev,struct fs4412leds_driver_dev,mydev));
return 0;
}
//关闭
int fs4412leds_driver_close(struct inode *pnode,struct file *pfile)
{
return 0;
}
void led_on(struct fs4412leds_driver_dev * pmydev,int ledno)
{
switch(ledno)
{
case 2:
printk("2\n");
writel(readl(pmydev->led2dat) | (0x1<<7),pmydev->led2dat);//关闭led2
break;
case 3:
printk("3\n");
writel(readl(pmydev->led3dat) | (0x1<<0),pmydev->led3dat);//关闭led2
break;
case 4:
printk("4\n");
writel(readl(pmydev->led4dat) | (0x1<<4),pmydev->led4dat);//关闭led2
break;
case 5:
printk("5\n");
writel(readl(pmydev->led5dat) | (0x1<<5),pmydev->led5dat);//关闭led2
break;
}
}
void led_off(struct fs4412leds_driver_dev * pmydev,int ledno)
{
switch(ledno)
{
case 2:
writel(readl(pmydev->led2dat) & (~(1<<7)),pmydev->led2dat);//关闭led2
break;
case 3:
writel(readl(pmydev->led3dat) & (~(1<<0)),pmydev->led3dat);//关闭led3
break;
case 4:
writel(readl(pmydev->led4dat) & (~(1<<4)),pmydev->led4dat);//关闭led4
break;
case 5:
writel(readl(pmydev->led5dat) & (~(1<<5)),pmydev->led5dat);//关闭led5
break;
}
}
long fs4412leds_driver_ioctl(struct file *pfile,unsigned int cmd,unsigned long arg)
{
struct fs4412leds_driver_dev * pmydev = (struct fs4412leds_driver_dev*)pfile->private_data;
if(arg<2||arg>5)
{
return -1;
}
switch(cmd)
{
case MY_LED_ON:
led_on(pmydev,arg);
break;
case MY_LED_OFF:
led_off(pmydev,arg);
break;
default:
return -1;
}
return 0;
}
struct file_operations myops={
.owner=THIS_MODULE,
.open=fs4412leds_driver_open,
.unlocked_ioctl=fs4412leds_driver_ioctl,
.release =fs4412leds_driver_close,
};
/**
* @brief 将寄存器物理地址映射为虚拟地址
* @param[in] pmydev:设备对象结构体
* @retval NULL
*
*/
void ioremap_ledreg(struct fs4412leds_driver_dev *pmydev,struct platform_device *p_pltdev)
{
/*得到虚拟内存地址*/
struct resource *pres=NULL;
//获取相应资源
pres =platform_get_resource(p_pltdev,IORESOURCE_MEM,2);
pmydev->led2con=ioremap(pres->start,4);
pres =platform_get_resource(p_pltdev,IORESOURCE_MEM,3);
pmydev->led2dat=ioremap(pres->start,4);
pres =platform_get_resource(p_pltdev,IORESOURCE_MEM,0);
pmydev->led3con=ioremap(pres->start,4);
pres =platform_get_resource(p_pltdev,IORESOURCE_MEM,1);
pmydev->led3dat=ioremap(pres->start,4);
pres =platform_get_resource(p_pltdev,IORESOURCE_MEM,4);
pmydev->led4con=ioremap(pres->start,4);
pres =platform_get_resource(p_pltdev,IORESOURCE_MEM,5);
pmydev->led4dat=ioremap(pres->start,4);
pmydev->led5con=pmydev->led4con;
pmydev->led5dat=pmydev->led4dat;
}
/**
* @brief 将寄存器物理地址映射为虚拟地址
* @param[in] pmydev:设备对象结构体
* @retval NULL
*
*/
void set_output_ledconreg(struct fs4412leds_driver_dev *pmydev)
{
writel((readl(pmydev->led2con) & (~(0xF<<28))) | (0x1<<28),pmydev->led2con);//设置GPX2_7为输出模式
writel((readl(pmydev->led3con) & (~(0xF<<0))) | (0x1<<0),pmydev->led3con);//设置GPX1_0为输出模式
writel((readl(pmydev->led4con) & (~(0xF<<16))) | (0x1<<16),pmydev->led4con);//设置GPF3_4为输出模式
writel((readl(pmydev->led5con) & (~(0xF<<20))) | (0x1<<20),pmydev->led5con);//设置GPF3_5为输出模式
writel(readl(pmydev->led2dat) & (~(1<<7)),pmydev->led2dat);//关闭led2
writel(readl(pmydev->led3dat) & (~(1<<0)),pmydev->led3dat);//关闭led3
writel(readl(pmydev->led4dat) & (~(1<<4)),pmydev->led4dat);//关闭led4
writel(readl(pmydev->led5dat) & (~(1<<5)),pmydev->led5dat);//关闭led5
}
/**
* @brief 解除寄存器物理地址和虚拟地址映射
* @param[in] pmydev:设备对象结构体
* @retval NULL
*
*/
void iounremap_ledreg(struct fs4412leds_driver_dev *pmydev)
{
iounmap(pmydev->led2con);
pmydev->led2con=NULL;
iounmap(pmydev->led2dat);
pmydev->led2dat=NULL;
iounmap(pmydev->led3con);
pmydev->led3con=NULL;
iounmap(pmydev->led3dat);
pmydev->led3dat=NULL;
iounmap(pmydev->led4con);
pmydev->led4con=NULL;
iounmap(pmydev->led4dat);
pmydev->led4dat=NULL;
pmydev->led5con=NULL;
pmydev->led5dat=NULL;
}
//初始化
int fs4412leds_driver_probe(struct platform_device *p_pltdev)
{
int ret = 0;
int i = 0;
dev_t devno =MKDEV(major,minor);//组合成一个完整的设备号
/*
* 手动申请设备号
*int register_chrdev_region(dev_t from, unsigned count, const char *name)
*参数分别为 设备号,设备数量,设备名字
*/
ret=register_chrdev_region(devno,fs4412leds_driver_num,"fs4412leds");
if(ret)
{
/*
*自动申请设备号
*int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count, const char *name)
* dev:分配设备号成功后用来存放分配到的设备号
* baseminior:起始的次设备号,一般为0
* count:申请的设备数量
* name:/proc/devices文件中与该设备对应的名字,方便用户层查询主次设备号
*/
ret = alloc_chrdev_region(&devno,minor,fs4412leds_driver_num,"fs4412leds");
if(ret)
{
printk("get devno failed\n");
return -1;
}
major = MAJOR(devno);//分离主设备号(手动申请失败需要)
}
for(i=0;i<fs4412leds_driver_DEV_CNT;i++)
{
gmydev_arr[i]=(struct fs4412leds_driver_dev*)kmalloc(sizeof(struct fs4412leds_driver_dev),GFP_KERNEL);
if(NULL==gmydev_arr[i])
{
printk("kmalloc failed\n");
unregister_chrdev_region(devno,fs4412leds_driver_num);//注销设备号
return -1;
}
memset(gmydev_arr[i],0,sizeof(struct fs4412leds_driver_dev));//初始化
}
/*指定操作函数集*/
for(i=0;i<fs4412leds_driver_DEV_CNT;i++)
{
devno =MKDEV(major,minor+i);
cdev_init(&gmydev_arr[i]->mydev,&myops);//初始化设备对象
/*将struct_cdev对象添加到内核对应的数据结构里*/
gmydev_arr[i]->mydev.owner=THIS_MODULE;
cdev_add(&gmydev_arr[i]->mydev,devno,1);//添加设备
/*ioremap*/
ioremap_ledreg(gmydev_arr[i],p_pltdev);//映射地址
set_output_ledconreg(gmydev_arr[i]);//led初始化
/*con_register set output*/
gmydev_arr[i]->pcls=class_create(THIS_MODULE,"fs4412led");
if(IS_ERR(gmydev_arr[i]->pcls))
{
printk("class_create failed\n");
cdev_del(&gmydev_arr[i]->mydev);
iounremap_ledreg(gmydev_arr[i]);//取消映射
kfree(gmydev_arr[i]);
unregister_chrdev_region(devno,fs4412leds_driver_num);//注销设备号
gmydev_arr[i]=NULL;
return -1;
}
gmydev_arr[i]->pdev=device_create(gmydev_arr[i]->pcls,NULL,devno,"NULL","fs4412led");
if(NULL==gmydev_arr[i]->pdev)
{
printk("device_create failed\n");
cdev_del(&gmydev_arr[i]->mydev);
iounremap_ledreg(gmydev_arr[i]);//取消映射
kfree(gmydev_arr[i]);
unregister_chrdev_region(devno,fs4412leds_driver_num);//注销设备号
gmydev_arr[i]=NULL;
class_destroy(gmydev_arr[i]->pcls);
return -1;
}
}
return 0;
}
int fs4412leds_driver_remove(struct platform_device *p_pltdev)
{
dev_t devno = MKDEV(major,minor);
int i=0;
/*iounremap*/
for(i=0;i<fs4412leds_driver_DEV_CNT;i++)
{
iounremap_ledreg(gmydev_arr[i]);//取消映射
device_destroy(gmydev_arr[i]->pcls,devno);
class_destroy(gmydev_arr[i]->pcls);
cdev_del(&gmydev_arr[i]->mydev);
}
for(i=0;i<fs4412leds_driver_DEV_CNT;i++)
{
kfree(gmydev_arr[i]);
gmydev_arr[i]=NULL;
}
unregister_chrdev_region(devno,fs4412leds_driver_num);//注销设备号
return 0;
}
struct platform_device_id fs4412leds_drv_ids[]={
[0]={.name ="fs4412leds"},
[1]={.name ="fs4412keys"},
[2]={}//代表结束必须
};
struct platform_driver fs4412leds_driver =
{
.driver.name="leds",
.probe=fs4412leds_driver_probe,
.remove=fs4412leds_driver_remove,
.id_table=fs4412leds_drv_ids,
};
int __init fs4412leds_driver_init(void)
{
platform_driver_register(&fs4412leds_driver);
return 0;
}
void __exit fs4412leds_driver_exit(void)
{
platform_driver_unregister(&fs4412leds_driver);
}
MODULE_LICENSE("GPL");
module_init(fs4412leds_driver_init);
module_exit(fs4412leds_driver_exit);
4 led驱动设备树驱动版
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/atomic.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include "fs4412_led.h"
#define fs4412leds_driver_DEV_CNT 1
int major =11;//主设备号
int minor = 0;//次设备号
int fs4412leds_driver_num =fs4412leds_driver_DEV_CNT;//设备数量
struct fs4412leds_driver_dev
{
struct cdev mydev;//建立一个设备对象
unsigned int Led2Gpio;
unsigned int Led3Gpio;
unsigned int Led4Gpio;
unsigned int Led5Gpio;
struct class *pcls;
struct device *pdev;
};
struct fs4412leds_driver_dev *gmydev_arr[fs4412leds_driver_DEV_CNT];
//打开
int fs4412leds_driver_open(struct inode *pnode,struct file *pfile)
{
/*为避免使用全局变量*/
/*
*container_of是一个宏,可以用来求全局结构体变量的地址
*已知其成员的地址和成员名字,就可以求出其地址
*pnode->i_cdev:指向插入系统的设备对象(这里也是gmydev的成员mydev的地址)
*pnode->private_data:本次打开文件的私有数据,驱动中常来在几个操作函数间传递共用数据
*/
pfile->private_data=(void *)(container_of(pnode->i_cdev,struct fs4412leds_driver_dev,mydev));
return 0;
}
//关闭
int fs4412leds_driver_close(struct inode *pnode,struct file *pfile)
{
return 0;
}
void led_on(struct fs4412leds_driver_dev * pmydev,int ledno)
{
switch(ledno)
{
case 2:
printk("Led2On\n");
gpio_set_value(pmydev->Led2Gpio,1);//设置为高电平
break;
case 3:
printk("Led3On\n");
gpio_set_value(pmydev->Led3Gpio,1);//设置为高电平
break;
case 4:
printk("Led4On\n");
gpio_set_value(pmydev->Led4Gpio,1);//设置为高电平
break;
case 5:
;
printk("Led5On\n");
gpio_set_value(pmydev->Led5Gpio,1);//设置为高电平
break;
}
}
void led_off(struct fs4412leds_driver_dev * pmydev,int ledno)
{
switch(ledno)
{
case 2:
printk("Led2Off\n");
gpio_set_value(pmydev->Led2Gpio,0);//设置为高电平
break;
case 3:
printk("Led3Off\n");
gpio_set_value(pmydev->Led3Gpio,0);//设置为高电平
break;
case 4:
printk("Led4Off\n");
gpio_set_value(pmydev->Led4Gpio,0);//设置为高电平
break;
case 5:
printk("Led5Off\n");
gpio_set_value(pmydev->Led5Gpio,0);//设置为高电平
break;
}
}
long fs4412leds_driver_ioctl(struct file *pfile,unsigned int cmd,unsigned long arg)
{
struct fs4412leds_driver_dev * pmydev = (struct fs4412leds_driver_dev*)pfile->private_data;
if(arg<2||arg>5)
{
return -1;
}
switch(cmd)
{
case MY_LED_ON:
led_on(pmydev,arg);
break;
case MY_LED_OFF:
led_off(pmydev,arg);
break;
default:
return -1;
}
return 0;
}
struct file_operations myops={
.owner=THIS_MODULE,
.open=fs4412leds_driver_open,
.unlocked_ioctl=fs4412leds_driver_ioctl,
.release =fs4412leds_driver_close,
};
/**
* @brief 申请gpio
* @param[in] pmydev:设备对象结构体指针
* pnode:设备树指针
* @retval NULL
*
*/
void RepuestLedsGpio(struct fs4412leds_driver_dev *pmydev,struct device_node *pnode)
{
pmydev->Led2Gpio=of_get_named_gpio(pnode,"led2-gpio",0);//从设备树中提取gpio口
gpio_request(pmydev->Led2Gpio,"led2");//申请led2的io口
pmydev->Led3Gpio=of_get_named_gpio(pnode,"led3-gpio",0);
gpio_request(pmydev->Led3Gpio,"led3");//申请led3的io口
pmydev->Led4Gpio=of_get_named_gpio(pnode,"led4-gpio",0);
gpio_request(pmydev->Led4Gpio,"led4");//申请led4的io口
pmydev->Led5Gpio=of_get_named_gpio(pnode,"led5-gpio",0);
gpio_request(pmydev->Led5Gpio,"led5");//申请led5的io口
}
/**
* @brief 设置对于的gpio管脚为输出模式
* @param[in] pmydev:设备对象结构体
* @retval NULL
*
*/
void set_leds_gpio_output(struct fs4412leds_driver_dev *pmydev)
{
gpio_direction_output(pmydev->Led2Gpio,0);
gpio_direction_output(pmydev->Led3Gpio,0);
gpio_direction_output(pmydev->Led4Gpio,0);
gpio_direction_output(pmydev->Led5Gpio,0);
}
/**
* @brief 释放gpio
* @param[in] pmydev:设备对象结构体
*
*
* @retval NULL
*
*/
void free_leds_gpio(struct fs4412leds_driver_dev *pmydev)
{
gpio_free(pmydev->Led2Gpio);
gpio_free(pmydev->Led3Gpio);
gpio_free(pmydev->Led4Gpio);
gpio_free(pmydev->Led5Gpio);
}
//初始化
int fs4412leds_driver_probe(struct platform_device *p_pltdev)
{
int ret = 0;
int i = 0;
struct device_node *pnode = NULL;
dev_t devno =MKDEV(major,minor);//组合成一个完整的设备号
/*
* 手动申请设备号
*int register_chrdev_region(dev_t from, unsigned count, const char *name)
*参数分别为 设备号,设备数量,设备名字
*/
ret=register_chrdev_region(devno,fs4412leds_driver_num,"fs4412leds_driver");
if(ret)
{
/*
*自动申请设备号
*int alloc_chrdev_region(dev_t *dev,unsigned baseminor,unsigned count, const char *name)
* dev:分配设备号成功后用来存放分配到的设备号
* baseminior:起始的次设备号,一般为0
* count:申请的设备数量
* name:/proc/devices文件中与该设备对应的名字,方便用户层查询主次设备号
*/
ret = alloc_chrdev_region(&devno,minor,fs4412leds_driver_num,"fs4412leds_driver");
if(ret)
{
printk("get devno failed\n");
return -1;
}
major = MAJOR(devno);//分离主设备号(手动申请失败需要)
}
for(i=0;i<fs4412leds_driver_DEV_CNT;i++)
{
gmydev_arr[i]=(struct fs4412leds_driver_dev*)kmalloc(sizeof(struct fs4412leds_driver_dev),GFP_KERNEL);
if(NULL==gmydev_arr[i])
{
printk("kmalloc failed\n");
unregister_chrdev_region(devno,fs4412leds_driver_num);//注销设备号
return -1;
}
memset(gmydev_arr[i],0,sizeof(struct fs4412leds_driver_dev));//初始化
}
/*指定操作函数集*/
for(i=0;i<fs4412leds_driver_DEV_CNT;i++)
{
devno =MKDEV(major,minor+i);
cdev_init(&gmydev_arr[i]->mydev,&myops);//初始化设备对象
/*将struct_cdev对象添加到内核对应的数据结构里*/
gmydev_arr[i]->mydev.owner=THIS_MODULE;
cdev_add(&gmydev_arr[i]->mydev,devno,1);//添加设备
/*ioremap*/
pnode=p_pltdev->dev.of_node;//匹配成功的节点指针
RepuestLedsGpio(gmydev_arr[i],pnode);
set_leds_gpio_output(gmydev_arr[i]);//led初始化
/*con_register set output*/
gmydev_arr[i]->pcls=class_create(THIS_MODULE,"fs4412led");
if(IS_ERR(gmydev_arr[i]->pcls))
{
printk("class_create failed\n");
cdev_del(&gmydev_arr[i]->mydev);
free_leds_gpio(gmydev_arr[i]);
kfree(gmydev_arr[i]);
unregister_chrdev_region(devno,fs4412leds_driver_num);//注销设备号
gmydev_arr[i]=NULL;
return -1;
}
gmydev_arr[i]->pdev=device_create(gmydev_arr[i]->pcls,NULL,devno,"NULL","fs4412led");
if(NULL==gmydev_arr[i]->pdev)
{
printk("device_create failed\n");
cdev_del(&gmydev_arr[i]->mydev);
free_leds_gpio(gmydev_arr[i]);
kfree(gmydev_arr[i]);
unregister_chrdev_region(devno,fs4412leds_driver_num);//注销设备号
gmydev_arr[i]=NULL;
class_destroy(gmydev_arr[i]->pcls);
return -1;
}
}
return 0;
}
int fs4412leds_driver_remove(struct platform_device *p_pltdev)
{
dev_t devno = MKDEV(major,minor);
int i=0;
/*iounremap*/
for(i=0;i<fs4412leds_driver_DEV_CNT;i++)
{
cdev_del(&gmydev_arr[i]->mydev);
free_leds_gpio(gmydev_arr[i]);//释放gpio
device_destroy(gmydev_arr[i]->pcls,devno);
class_destroy(gmydev_arr[i]->pcls);
}
for(i=0;i<fs4412leds_driver_DEV_CNT;i++)
{
kfree(gmydev_arr[i]);
gmydev_arr[i]=NULL;
}
unregister_chrdev_region(devno,fs4412leds_driver_num);//注销设备号
return 0;
}
struct of_device_id fs4412leddrv_of_ids[]=
{
[0]={.compatible = "fs4412,led2-5"},
[1]={.compatible= "origen4412,led6-9"},
[2]={},
};
struct platform_driver fs4412leds_driver =
{
.driver={
.name="leds",
.of_match_table=fs4412leddrv_of_ids,
},
.probe=fs4412leds_driver_probe,
.remove=fs4412leds_driver_remove,
};
int __init fs4412leds_driver_init(void)
{
platform_driver_register(&fs4412leds_driver);
return 0;
}
void __exit fs4412leds_driver_exit(void)
{
platform_driver_unregister(&fs4412leds_driver);
}
MODULE_LICENSE("GPL");
module_init(fs4412leds_driver_init);
module_exit(fs4412leds_driver_exit);
本文详细介绍了Linux驱动开发中的ID匹配原理和步骤,包括如何在`xxx_device.c`和`xxx_driver.c`中进行相应配置。同时,提供了led驱动的ID匹配版实现,包括`fs4412_led.h`、`fs4412leds_device.c`和`fs4412leds_driver.c`三个部分的代码示例。此外,还简要提到了led驱动的设备树驱动版相关内容。
&spm=1001.2101.3001.5002&articleId=126390037&d=1&t=3&u=90f2dac6b50a4e6d87535004c45f02a3)
603

被折叠的 条评论
为什么被折叠?



