驱动:
#include<linux/init.h>
#include<linux/module.h>
#include<linux/of.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/err.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/smp.h>
#include<linux/io.h>
#include<linux/delay.h>
#include<linux/string.h>
#include<linux/cdev.h>
#include <linux/slab.h>
#include<linux/uaccess.h>
#include<linux/gpio.h>
#include<linux/of_gpio.h>
#include<linux/time.h>
#include"led.h"
struct device_node *node;
struct property *nd;
struct gpio_desc *core_led[3];
struct gpio_desc *extern_led[3];
struct device_node *core_node;
struct device_node *extern_node;
//定义设备号
#define CHRNAME "myled"
static int minor = 0;
#if 1
static unsigned int major = 0;
#else
unsigned int major = 200;
#endif
#define COUNT 3
struct cdev *cdev;
struct class *cls;
struct device *dev;
#define MY_TIME jiffies+HZ
struct timer_list mytimer;
int i = 0;
//定时器事件
void timer_hander(struct timer_list *timer)
{
gpiod_set_value(extern_led[i],!gpiod_get_value(extern_led[i]));
if(gpiod_get_value(extern_led[i])==0)
{
if((i++) == 2)
i = 0;
}
mod_timer(&mytimer,MY_TIME);
}
void led_ctl(unsigned int cmd,unsigned long num)
{
if(cmd == LED_ON(EXTERN))
{
switch (num)
{
case LED1:
gpiod_set_value(extern_led[0],1);
break;
case LED2:
gpiod_set_value(extern_led[1],1);
break;
case LED3:
gpiod_set_value(extern_led[2],1);
break;
}
}
else if(cmd == LED_OFF(EXTERN))
{
switch (num)
{
case LED1:
gpiod_set_value(extern_led[0],0);
break;
case LED2:
gpiod_set_value(extern_led[1],0);
break;
case LED3:
gpiod_set_value(extern_led[2],0);
break;
}
}
else if(cmd == LED_ON(CORE))
{
switch (num)
{
case LED1:
gpiod_set_value(core_led[0],1);
break;
case LED2:
gpiod_set_value(core_led[1],1);
break;
case LED3:
gpiod_set_value(core_led[2],1);
break;
}
}
else if(cmd == LED_OFF(CORE))
{
switch (num)
{
case LED1:
gpiod_set_value(core_led[0],0);
break;
case LED2:
gpiod_set_value(core_led[1],0);
break;
case LED3:
gpiod_set_value(core_led[2],0);
break;
}
}
}
long chrdev_ioctl (struct file *file, unsigned int cmd, unsigned long num)
{
int whitch,ret;
ret = copy_from_user(&whitch,(void *)num,sizeof(int));
printk("whitch = %d\r\n",whitch);
if (ret)
{
printk("copy_from_user failed!\r\n");
return -1;
}
led_ctl(cmd,whitch);
return 0;
}
int chrdev_open (struct inode *node, struct file *file)
{
return 0;
}
int chrdev_release (struct inode *inode, struct file *file)
{
return 0;
}
struct file_operations ops = {
.open = chrdev_open,
.release = chrdev_release,
.unlocked_ioctl = chrdev_ioctl,
};
//初始化led灯
int led_init(void)
{
int i;
node=of_find_node_by_path("/mtnode@0x12345678");
node=of_get_child_by_name(node,"myleds");
extern_node = of_get_child_by_name(node,"extern_leds");
core_node = of_get_child_by_name(node,"core_leds");
if(node == NULL)
{
printk("获取节点信息失败\r\n");
return -1;
}
printk("获取节点信息成功!\r\n");
extern_led[0] = gpiod_get_from_of_node(extern_node,"led1",0,GPIOD_OUT_LOW,NULL);
extern_led[1] = gpiod_get_from_of_node(extern_node,"led2",0,GPIOD_OUT_LOW,NULL);
extern_led[2] = gpiod_get_from_of_node(extern_node,"led3",0,GPIOD_OUT_LOW,NULL);
core_led[0] = gpiod_get_from_of_node(core_node,"led1",0,GPIOD_OUT_LOW,NULL);
core_led[1] = gpiod_get_from_of_node(core_node,"led2",0,GPIOD_OUT_LOW,NULL);
core_led[2] = gpiod_get_from_of_node(core_node,"led3",0,GPIOD_OUT_LOW,NULL);
for(i = 0;i<3;i++)
{
if(IS_ERR(extern_led[i]))
{
printk("申请led%d编号失败\r\n",i+1);
return PTR_ERR(extern_led[0]);
}
}
gpiod_set_value(extern_led[0],0);
gpiod_set_value(extern_led[1],0);
gpiod_set_value(extern_led[2],0);
gpiod_set_value(core_led[0],1);
gpiod_set_value(core_led[1],1);
gpiod_set_value(core_led[2],1);
// mytimer.expires = MY_TIME;
// timer_setup(&mytimer,timer_hander,0);
// add_timer(&mytimer);
return 0;
}
//注册字符设备驱动
int chrdev_logon(void)
{
int ret,i;
dev_t devno;
//分配对象
cdev=cdev_alloc();
if(cdev == NULL)
{
printk("cdev alloc memory default\n");
ret = -ENOMEM;
goto END1;
}
printk("分配对象成功\n");
//对象的初始化
cdev_init(cdev,&ops);
//设备号申请
if(major == 0)
{
ret = alloc_chrdev_region(&devno,minor,COUNT,CHRNAME);
if(ret)
{
printk("动态设备号申请失败\n");
goto ERR2;
}
major = MAJOR(devno);
minor = MINOR(devno);
printk("动态申请设备号成功\n");
}
else if(major>0)
{
ret = register_chrdev_region(MKDEV(major,minor),COUNT,CHRNAME);
if(ret)
{
printk("静态申请设备号失败\n");
goto ERR2;
}
printk("静态申请设备号成功\n");
}
ret=cdev_add(cdev,MKDEV(major,minor),COUNT);
if(ret)
{
printk("字符设备驱动注册失败\n");
goto ERR3;
}
printk("字符设备驱动成功\n");
//自动创建设备节点
cls = class_create(THIS_MODULE,"led");
if(IS_ERR(cls))
{
printk("创建节点目录失败\n");
ret = PTR_ERR(cls);
goto ERR4;
}
printk("创建节点目录成功\n");
for(i = 0;i<COUNT;i++)
{
dev = device_create(cls,NULL,MKDEV(major,i),NULL,"led%d",i);
if(IS_ERR(dev))
{
printk("创建节点失败\n");
ret = PTR_ERR(dev);
goto ERR5;
}
}
printk("创建节点成功\n");
return 0;
ERR5:
for(--i;i>=0;i--)
{
device_destroy(cls,MKDEV(major,i));
}
class_destroy(cls);
ERR4:
cdev_del(cdev);
ERR3:
unregister_chrdev_region(MKDEV(major,minor),COUNT);
ERR2:
kfree(cdev);
END1:
return ret;
}
int __init devtree_init(void)
{
if (chrdev_logon()!=0)
{
printk("创建节点失败\r\n");
return -1;
}
led_init();
return 0;
}
//nd = of_find_property(node,"compatible",&len);
//printk("compatible = %s,values = %s\r\n",nd->name,(char*)nd->value);
/*
nd = of_find_property(node,"astring",&len);
printk("compatible = %s,values = %s\r\n",nd->name,(char*)nd->value);
nd = of_find_property(node,"uint",&len);
printk("compatible = %s,values = %x,%x\r\n",nd->name,(__be32_to_cpup)(nd->value),(__be32_to_cpup)(nd->value+4));
nd = of_find_property(node,"binarry",&len);
if(nd == NULL)
{
printk("fond binarry failed!\r\n");
return -1;
}
*/
void __exit devtree_exit(void)
{
int i;
for(i = 0;i<3;i++)
{
gpiod_set_value(extern_led[i],0);
gpiod_set_value(core_led[i],0);
gpiod_put(extern_led[i]);
gpiod_put(core_led[i]);
}
//del_timer(&mytimer);
for(i = 0;i<3;i++)
{
device_destroy(cls,MKDEV(major,i));
}
printk("销毁设备节点成功\n");
class_destroy(cls);
printk("销毁节点目录成功\n");
cdev_del(cdev);
printk("删除字符设备\n");
unregister_chrdev_region(MKDEV(major,minor),COUNT);
kfree(cdev);
}
module_init(devtree_init);
module_exit(devtree_exit);
MODULE_LICENSE("GPL");
应用层:
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/ioctl.h>
#include"led.h"
#include<wait.h>
#include<sys/epoll.h>
void func(int fd,int place,int num,int state)
{
printf("place = %d , num = %c , state = %d\n",place,num,state);
if(state)
{
ioctl(fd,LED_ON(place),&num);
printf("%d LED_ON = %ld\n",state,LED_ON(place));
}
else
{
ioctl(fd,LED_OFF(place),&num);
printf("%d LED_ON = %ld\n",state,LED_OFF(place));
}
}
char buf[128] = {0};
int main()
{
int fd = open("/dev/led1",O_RDWR);
if(fd < 0 )
{
printf("文件打开失败\n");
return -1;
}
int i;
char buf[50] = {0};
char name[50] = {0};
int state;
while (1)
{
printf("请输入您要控制的设备位置(main or extern)>>>");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1] = '\0';
printf("buf = %s\n",buf);
printf("请输入要控制的设备和状态 例(LED1 1)>>>");
scanf("%s %d",name,&state);
while (getchar()!=10);
if(strcmp(buf,"main") == 0)
{
i = CORE;
func(fd,i,name[3],state);
}
else if(strcmp(buf,"extern") == 0)
{
i = EXTERN;
func(fd,i,name[3],state);
}
else
{
printf("输入错误,请重新输入\n");
}
}
close(fd);
return 0;
}