平台自定义数据
在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);
}