设备树
myleds{
myled1 = <&gpioe 10 0>;
myled2 = <&gpiof 10 0>;
myled3 = <&gpioe 8 0>;
};
驱动代码
#include<linux/init.h>
#include<linux/module.h>
#include<linux/of.h>
#include<linux/of_gpio.h>
#include<linux/gpio.h>
#include<linux/fs.h>
#include<linux/uaccess.h>
#include<linux/io.h>
#include<linux/cdev.h>
#include<linux/slab.h>
#include"./six.h"
/*
myleds{
myled1 = <&gpioe 10 0>;
myled2 = <&gpiof 10 0>;
myled3 = <&gpioe 8 0>;
*/
#define GNAME "mydev"
unsigned int major =0;
char kbuf[128]={0};
struct cdev* cdev;
struct class * cls;
struct device *devic;
dev_t dev1;
int minor = 0;
unsigned count=6;
wait_queue_head_t wq;
int condition=0;
int mydev_open(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
long mydev_ioctl(struct file *file,unsigned int cmd,unsigned long arg)
{
int addr;
switch(cmd)
{
case LED_ON:
{
ret = copy_from_user(&addr,(void*)arg,sizeof(int));
if(ret)
{
printk("copy from user on is error\n");
return -EIO;
}
switch(addr)
{
case LED1:
{
gpiod_set_value(gpiono1,1);
break;
}
case LED2:
{
gpiod_set_value(gpiono2,1);
break;
}
case LED3:
{
gpiod_set_value(gpiono3,1);
break;
}
}
break;
}
case LED_OFF:
{
ret = copy_from_user(&addr,(void*)arg,sizeof(int));
if(ret)
{
printk("copy from user on is error\n");
return -EIO;
}
switch(addr)
{
case LED1:
{
gpiod_set_value(gpiono1,0);
break;
}
case LED2:
{
gpiod_set_value(gpiono2,0);
break;
}
case LED3:
{
gpiod_set_value(gpiono3,0);
break;
}
}
break;
}
}
return 0;
}
int mydev_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
return 0;
}
struct file_operations fops={
.open=mydev_open,
.unlocked_ioctl=mydev_ioctl,
.release=mydev_close,
};
static int __init mynode_init(void)
{
int i;
int ret;
//分配字符设备驱动
cdev=cdev_alloc();
if(NULL==cdev)
{
printk("cdev alloc error\n");
goto ERR1;
}
//设备驱动初始化
cdev_init(cdev,&fops);
//申请设备号
if(major>0)
{
ret=register_chrdev_region(MKDEV(major,minor),count,GNAME);
if(ret!=0)
{
printk("register chrdev region error\n");
ret = -ENOMEM;
goto ERR2;
}
}
else
{
ret=alloc_chrdev_region(&dev1,0,count,GNAME);
if(ret!=0)
{
printk("alloc chrdev region error\n");
ret = -ENOMEM;
goto ERR2;
}
major = MAJOR(dev1);
minor = MINOR(dev1);
}
//驱动的注册
ret = cdev_add(cdev,MKDEV(major,minor),count);
if(ret!=0)
{
printk("cdev add error\n");
ret = -EIO;
goto ERR3;
}
//通过名字获取设备树节点信息
node = of_find_node_by_name(NULL,"myleds");
if(NULL == node)
{
printk("of find node by name error\n");
return -EFAULT;
}
//获取并申请LED1的gpio编号
gpiono1 = gpiod_get_from_of_node(node,"myled1",0,GPIOD_OUT_LOW,NULL);
if(IS_ERR(gpiono1))
{
printk("1gpiod get from of node error\n");
return PTR_ERR(gpiono1);
}
//获取并申请LED2的gpio编号
gpiono2 = gpiod_get_from_of_node(node,"myled2",0,GPIOD_OUT_LOW,NULL);
if(IS_ERR(gpiono2))
{
printk("2gpiod get from of node error\n");
return PTR_ERR(gpiono2);
}
//获取并申请LED3的gpio编号
gpiono3 = gpiod_get_from_of_node(node,"myled3",0,GPIOD_OUT_LOW,NULL);
if(IS_ERR(gpiono3))
{
printk("3gpiod get from of node error\n");
return PTR_ERR(gpiono3);
}//设置LED1管脚为输出
gpiod_direction_output(gpiono1,0);
//设置LED2管脚为输出
gpiod_direction_output(gpiono2,0);
//设置LED3管脚为输出
gpiod_direction_output(gpiono3,0);//自动创建设备节点
cls = class_create(THIS_MODULE,GNAME);
if(IS_ERR(cls))
{
ret = PTR_ERR(cls);
goto ERR4;
}
for(i=0;i<count;i++)
{
devic = device_create(cls,NULL,MKDEV(major,i),NULL,"myled%d",i);
if(IS_ERR(devic))
{
ret = PTR_ERR(devic);
goto ERR5;
}
}
init_waitqueue_head(&wq);
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);
ERR1:
return -EIO;
}
static void __exit mynode_exit(void)
{
int i;
//卸载驱动前熄灭灯LED1
gpiod_set_value(gpiono1,0);
//卸载驱动前熄灭灯LED2
gpiod_set_value(gpiono2,0);
//卸载驱动前熄灭灯LED3
gpiod_set_value(gpiono3,0);
//卸载驱动前熄灭灯LED1//释放申请得到的LED1gpio编号
gpiod_put(gpiono1);
//释放申请得到的LED2gpio编号
gpiod_put(gpiono2);
//释放申请得到的LED3gpio编号
gpiod_put(gpiono3);
//销毁设备节点信息
for(i=0;i<count;i++)
{
device_destroy(cls,MKDEV(major,i));
}
class_destroy(cls);
//释放驱动
cdev_del(cdev);
//释放设备号
unregister_chrdev_region(MKDEV(major,minor),count);
//注销字符设备驱动
kfree(cdev);
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");
应用层代码
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>
#include<sys/ioctl.h>
#include"./six.h"
int main(int argc, char const *argv[])
{
int fd1 = -1;
int fd2 = -1;
int fd3 = -1;int i=0;
int whitch;
fd1 = open("/dev/myled1",O_RDWR);
if(-1 == fd1)
{
perror("open is error");
exit(1);
}
fd2 = open("/dev/myled2",O_RDWR);
if(-1 == fd2)
{
perror("open is error");
exit(1);
}
fd3 = open("/dev/myled3",O_RDWR);
if(-1 == fd3)
{
perror("open is error");
exit(1);
}while(1)
{
whitch=LED1;
ioctl(fd1,LED_ON,&whitch);
sleep(1);
ioctl(fd1,LED_OFF,&whitch);
whitch=LED2;
ioctl(fd2,LED_ON,&whitch);
sleep(1);
ioctl(fd2,LED_OFF,&whitch);
whitch=LED3;
ioctl(fd3,LED_ON,&whitch);
sleep(1);
ioctl(fd3,LED_OFF,&whitch);
sleep(1);
}
close(fd1);
close(fd2);
close(fd3);return 0;
}