平台总线式驱动开发(id匹配和设备树匹配lv12-day3)

本文详细介绍了Linux驱动开发中的ID匹配原理和步骤,包括如何在`xxx_device.c`和`xxx_driver.c`中进行相应配置。同时,提供了led驱动的ID匹配版实现,包括`fs4412_led.h`、`fs4412leds_device.c`和`fs4412leds_driver.c`三个部分的代码示例。此外,还简要提到了led驱动的设备树驱动版相关内容。

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);
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值