linux驱动学习笔记---杂项设备注册和ioctl+gpio库函数使用以及平台自定义数据(十)

平台自定义数据

 在pdev中创建自定义对象

 

在pdrv中声明,接收平台自定义数据

 

 

使用平台自定义数据

 

 

释放平台自定义数据

 

杂项设备注册 

pdev端驱动代码 







#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>


#include "plat_led.h"



struct led_platdata my_pdata = {
	.name = "this is a platform_data test",
	.conf_reg_clr = 0xff<<12,
	.conf_reg_set = 0x11<<12,
	.data_reg = 0x3<<3,
	.led1_gpio = S5PV210_GPC0(3),
	.led2_gpio = S5PV210_GPC0(4),
};


struct resource	 led_res[] = {
	[0] = {
		.start = GPC0_CONF,
		.end = GPC0_CONF + GPC0_SIZE -1,
		.flags = IORESOURCE_MEM,  //类型
	},

	//以下对于led实际是不存在,演示如何在代码中定义多个资源
	[1] = {
		.start = 0x666,
		.end = 0x666,
		.name = "fake_irq",
		.flags = IORESOURCE_IRQ,  //类型
	},

	[2] = {
		.start = 0x12345678,
		.end = 0x12345678 + 8 -1,
		.name = "fake_mem",
		.flags = IORESOURCE_MEM,  //类型
	},

};

//解决pdev移除总线有警告
void	led_pdev_release(struct device *dev)
{


}

struct platform_device  led_pdev = {
	.name = "fs210_led",
	.id = -1, // 一般填-1, 用于区分不同组的控制器
	.num_resources = ARRAY_SIZE(led_res),
	.resource = led_res,
	.dev = {
		.release = led_pdev_release,
		.platform_data = &my_pdata,
	},
};


static int __init plat_led_dev_init(void)
{
	

	// 构建pdev,  并注册到总线中去
	return  platform_device_register(&led_pdev);
	
}


static void __exit plat_led_dev_exit(void)
{

	platform_device_unregister(&led_pdev);

}


module_init(plat_led_dev_init);
module_exit(plat_led_dev_exit);
MODULE_LICENSE("GPL");

pdrv端驱动代码 



#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>

#include <asm/io.h>
#include <asm/uaccess.h>

#include "plat_led.h"



struct led_global  *mydev;

int plat_led_drv_open(struct inode *inode, struct file *filp)
{
	

	// 操作寄存器--配置成输出
	unsigned long value = __raw_readl(mydev->reg_base);
	value &= ~(mydev->pdata->conf_reg_clr);
	value |= (mydev->pdata->conf_reg_set);
	__raw_writel(value, mydev->reg_base);


	return 0;
}
ssize_t plat_led_drv_write(struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
	int ret;
	int value;
	
	 ret = copy_from_user(&value,  buf, count);
     if(ret > 0)
     {
          printk("copy_from_user error\n");
          return -EFAULT;
     }

	if(value)
	{
		//点灯
		__raw_writel(__raw_readl(mydev->reg_base + 4) |(mydev->pdata->data_reg)  ,  mydev->reg_base + 4);
	
	}else
	{
		//灭灯
		__raw_writel(__raw_readl(mydev->reg_base + 4) &~(mydev->pdata->data_reg)  ,  mydev->reg_base + 4);
	}
	

	return 0;
}

long plat_led_drv_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{
	int gpio;

		
	switch(cmd)
	{
		case PLAT_IOC_LED1_ON:
			//参数1--gpio的号码
			//参数2--描述--自定义
			gpio = mydev->pdata->led1_gpio;
			
			gpio_request(gpio,  "led1");
			gpio_direction_output(gpio,  1);
			gpio_free(gpio);
	
			break;

		case PLAT_IOC_LED1_OFF:
			gpio = mydev->pdata->led1_gpio;

			gpio_request(gpio,  "led1");
			gpio_direction_output(gpio,  0);
			gpio_free(gpio);
			
			break;

		case PLAT_IOC_LED2_ON:
			gpio = mydev->pdata->led2_gpio;
			
			gpio_request(gpio,  "led2");
			gpio_direction_output(gpio,  1);
			gpio_free(gpio);
	
			break;

		case PLAT_IOC_LED2_OFF:
			gpio = mydev->pdata->led2_gpio;
			
			gpio_request(gpio,  "led2");
			gpio_direction_output(gpio,  0);
			gpio_free(gpio);
			break;

		default:
			printk("unkown cmd \n");
			return -EINVAL;

	}


	return 0;
}

int plat_led_drv_close(struct inode *inode, struct file *filp)
{

	__raw_writel(__raw_readl(mydev->reg_base + 4) &~(0x3<<3)  ,  mydev->reg_base + 4);
	
	return 0;
}

const struct file_operations plat_led_fops = {
	.open = plat_led_drv_open,
	.write = plat_led_drv_write,
	.unlocked_ioctl = plat_led_drv_ioctl,
	.release = plat_led_drv_close,
};


int led_pdrv_probe(struct platform_device *pdev)
{
	int ret;
	printk("---------%s------------\n", __FUNCTION__);


	mydev = kzalloc(sizeof(struct led_global),  GFP_KERNEL);

	//获取到平台自定义数据
	mydev->pdata = pdev->dev.platform_data;

	printk("in probe : %s\n", mydev->pdata->name);
	
	//  任务1---与用户交互: a,申请主设备号 b,创建设备节点 c, 实现fops

	// 内核在启动的时候,会自动去申请一个主设备号: 10, 并且将10号认为是杂项类设备
	// 我们将当前的设备led, 当做为杂项类设备中一个次设备
	//misc_register一调用,实际就将a,申请主设备号 b,创建设备节点 c, 实现fops全部搞定

	mydev->miscdev.minor = MISC_DYNAMIC_MINOR; //一般选择255以下的--MISC_DYNAMIC_MINOR动态指定
	mydev->miscdev.name = "plat_led0"; //设备节点的名字
	mydev->miscdev.fops = &plat_led_fops;
	misc_register(&mydev->miscdev);  //错误为负数,正确为0

	

	// 任务2 --- 获取到资源, d,对硬件进行初始化
	//如果获取到地址资源,需要映射,操作寄存器

	//参数1--从哪个pdev中获取资源
	//参数2--资源的类型:IORESOURCE_MEM/IORESOURCE_IRQ
	//参数3--同种资源的编号
	mydev->mem_res = platform_get_resource(pdev,  IORESOURCE_MEM, 0);
	
	
	//正式开始映射
	mydev->reg_base= ioremap(mydev->mem_res->start, resource_size(mydev->mem_res));
	
	


	return 0;


}


int led_pdrv_remove(struct platform_device *pdev)
{
	printk("---------%s------------\n", __FUNCTION__);

	iounmap(mydev->reg_base);
	misc_deregister(&mydev->miscdev);
	kfree(mydev);
	

	return 0;
}
	

const struct platform_device_id led_id_table[] = {
		{"s5pv210_led",  0x210}, //第二个成员随便写
		{"fs210_led",  0x210}, 
		{"exynos4412_led",  0x4412}, 
		{"s3c2410_led",  0x2410}, 
};

struct platform_driver led_pdrv = {
	.probe = led_pdrv_probe, 
	.remove = led_pdrv_remove,
	.driver = { //一定要初始化
		.name = "samsung_led_pdrv", // 自定义,可以用于和pdev进行匹配
	},
	.id_table = led_id_table, //优先匹配这里面的名字
};

static int __init plat_led_drv_init(void)
{
	

	// 构建pdrv,  并注册到总线中去
	return  platform_driver_register(&led_pdrv);
	
}


static void __exit plat_led_drv_exit(void)
{
	platform_driver_unregister(&led_pdrv);
}


module_init(plat_led_drv_init);
module_exit(plat_led_drv_exit);
MODULE_LICENSE("GPL");

头文件

#ifndef __PLAT_LED_H__
#define __PLAT_LED_H__


#include <linux/miscdevice.h>

#define GPC0_CONF  0xE0200060
#define GPC0_SIZE 0x8

//设计一个平台自定义的数据
struct led_platdata{
	char *name;//用于描述
	__u32 conf_reg_clr; //用于清配置寄存器中的值
	__u32 conf_reg_set; //用于给配置寄存器的值
	__u32 data_reg ; //给数据寄存器的值
	int led1_gpio;
	int led2_gpio;
};


#define PLAT_IOC_LED1_ON  0x7788
#define PLAT_IOC_LED1_OFF  0x7787
#define PLAT_IOC_LED2_ON   0x7786
#define PLAT_IOC_LED2_OFF  0x7785

//设计一个全局的设备对象
struct led_global{
	 void *reg_base;
	 struct resource *mem_res;
	 struct resource *res_temp;
	 struct miscdevice miscdev;
	 struct led_platdata *pdata;
};




#endif

应用层app 


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

#define PLAT_IOC_LED1_ON  0x7788
#define PLAT_IOC_LED1_OFF  0x7787
#define PLAT_IOC_LED2_ON   0x7786
#define PLAT_IOC_LED2_OFF  0x7785

int main(int argc, char *argv[])
{

	int on;
	int ret;
	
	//直接将驱动模块当做文件来操作
	int fd = open("/dev/plat_led0", O_RDWR);
	if(fd < 0)
	{
		perror("open");
		exit(1);
	}

	//先全灭
	on = 0;
	ret = write(fd, &on, 4);
	if(ret < 0)
	{
		perror("write off ");
		exit(1);
	}

	while(1)
	{

		//led1 on 
		ioctl(fd, PLAT_IOC_LED1_ON, 0);
		
		sleep(1);
		

		ioctl(fd, PLAT_IOC_LED1_OFF, 0);
		sleep(1);
	
		ioctl(fd, PLAT_IOC_LED2_ON, 0);
		sleep(1);

		ioctl(fd, PLAT_IOC_LED2_OFF, 0);
		sleep(1);


		on = 1;
		ret = write(fd, &on, 4);
		if(ret < 0)
		{
			perror("write off ");
			exit(1);
		}
		sleep(1);

		on = 0;
		ret = write(fd, &on, 4);
		if(ret < 0)
		{
			perror("write off ");
			exit(1);
		}
		sleep(1);
	}
	

	close(fd);


}

发布了38 篇原创文章 · 获赞 42 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/weixin_42471952/article/details/81711662
今日推荐