通过GPIO子系统接口完成LED驱动的编写,编写应用程序控制灯亮灭(流水灯)
驱动程序
#include
#include
#include
#include
#include
#include "led.h"
unsigned int major;//主设备号
struct class *cls;//类指针
struct device *dev;//设备指针
struct device_node *np; // 设备树节点指针
// struct property *pp;//属性指针
int gpiono[3]; // gpio编号
char kbuf[128] = {};
/*************************************封装各种操作方法*******************************************/
int mycdev_open(struct inode *inode, struct file *file)
{
unsigned int minor;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
minor = MINOR(inode->i_rdev);
file->private_data = (void *)minor;
return 0;
}
ssize_t mycdev_read(struct file *file, char __user *ubuf, size_t size, loff_t *loff_t)
{
unsigned long ret;
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_to_user(ubuf, kbuf, size);
if (ret)
{
printk("copy_to_user filad\n");
return ret;
}
return 0;
}
ssize_t mycdev_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loff_t)
{
unsigned long ret;
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_from_user(kbuf, ubuf, size);
if (ret)
{
printk("copy_from_user filad\n");
return ret;
}
return 0;
}
long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
case LED_ON:
switch ((unsigned int)file->private_data)
{
case 0: // LED1控制
gpio_set_value(gpiono[0], 1);
break;
case 1: // LED2控制
gpio_set_value(gpiono[1], 1);
break;
case 2: // LED3控制
gpio_set_value(gpiono[2], 1);
break;
default:
break;
}
break;
case LED_OFF:
switch ((unsigned int)file->private_data)
{
case 0: // LED1控制
gpio_set_value(gpiono[0], 0);
break;
case 1: // LED2控制
gpio_set_value(gpiono[1], 0);
break;
case 2: // LED3控制
gpio_set_value(gpiono[2], 0);
break;
default:
break;
}
break;
default:
break;
}
return 0;
}
int mycdev_close(struct inode *inode, struct file *file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
struct file_operations fops = {
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.unlocked_ioctl = mycdev_ioctl,
.release = mycdev_close,
};
int all_led_init(void)
{
int i;
for (i = 0; i < 3; i++)
{
gpiono[i] = of_get_named_gpio(np, "led-gpios", i); // 通过属性名字获取gpio编号
if (gpiono[i] < 0)
{
printk("get gpio failed\n");
return -1;
}
printk("get gpio success,gpio=%d\n", gpiono[i]);
// 申请解析到的gpio编号
if (gpio_request(gpiono[i], NULL) < 0)
{
printk("request gpio failed\n");
return -1;
}
// 设置gpio为输出模式,默认输出低电平
if (gpio_direction_output(gpiono[i], 0))
{
printk("set gpio output failed\n");
return -1;
}
printk("set gpio output success\n");
}
return 0;
}
static int __init mycdev_init(void)
{
// int i,len;
// np = of_find_node_by_name(NULL,"mynode");
/**********字符设备驱动注册**********/
int i;
major = register_chrdev(0, "led", &fops);
if (major < 0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功 major=%d\n", major);
// 向上提交设备类
cls = class_create(THIS_MODULE, "led");
if (IS_ERR(cls))
{
printk("class_create falie\n");
unregister_chrdev(major, "led");
return PTR_ERR(cls);
}
printk("class_create success\n");
// 向上提交设备信息
for (i = 0; i < 3; i++)
{
dev = device_create(cls, NULL, MKDEV(major, i), NULL, "led%d", i);
if (IS_ERR(dev))
{
printk("device_create filed\n");
class_destroy(cls);
unregister_chrdev(major, "led");
return PTR_ERR(dev);
}
printk("device_create success\n");
}
// 通过路径查找设备树节点
np = of_find_node_by_path("/leds");
if (np == NULL)
{
printk("find node failed\n");
return -1;
}
printk("find node success\n");
all_led_init();
return 0;
}
static void __exit mycdev_exit(void)
{
int i;
for (i = 0; i < 3; i++)
{
gpio_free(gpiono[i]); // 释放gpio
device_destroy(cls, MKDEV(major, i));//注销设备
}
// 将设备类注销
class_destroy(cls);
/*注销设备驱动*/
unregister_chrdev(major, "led");
printk("unregister_chrdev success\n");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
应用程序
#include
#include
#include
#include
#include
#include
#include
#include
#include "led.h"
int stop_thread = 0; // 全局变量,用于控制线程停止
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *led_ctl(void *arg)
{
int *fd = (int *)arg;
while (1)
{
pthread_mutex_lock(&mutex);
if (stop_thread)
{
pthread_mutex_unlock(&mutex);
break;
}
pthread_mutex_unlock(&mutex);
ioctl(fd[0], LED_ON);
ioctl(fd[1], LED_OFF);
ioctl(fd[2], LED_OFF);
sleep(1);
ioctl(fd[0], LED_OFF);
ioctl(fd[1], LED_ON);
ioctl(fd[2], LED_OFF);
sleep(1);
ioctl(fd[0], LED_OFF);
ioctl(fd[1], LED_OFF);
ioctl(fd[2], LED_ON);
sleep(1);
}
return NULL;
}
int main(int argc, char const *argv[])
{
int a,i;
int fd[3];
pthread_t tid;
fd[0] = open("/dev/led0", O_RDWR);
if (fd[0] < 0)
{
perror("open");
exit(1);
}
fd[1] = open("/dev/led1", O_RDWR);
if (fd[1] < 0)
{
perror("open");
exit(1);
}
fd[2] = open("/dev/led2", O_RDWR);
if (fd[2] < 0)
{
perror("open");
exit(1);
}
printf("open success\n");
while (1)
{
printf("请输入控制操作:0(关闭) 1(打开)\n");
printf("请输入:");
scanf("%d", &a);
switch (a)
{
case 0:
{
pthread_mutex_lock(&mutex);
stop_thread = 1; // 设置全局变量,通知线程停止
pthread_mutex_unlock(&mutex);
pthread_join(tid, NULL);
for(i=0;i<3;i++)
{
ioctl(fd[i], LED_OFF);
printf("i=%d\n",i);
}
}
break;
case 1:
{
pthread_mutex_lock(&mutex);
stop_thread = 0; // 重置全局变量
pthread_mutex_unlock(&mutex);
if (pthread_create(&tid, NULL, led_ctl, fd) != 0)
{
perror("pthread_create");
exit(1);
}
}
break;
default:
break;
}
}
for(i=0;i<3;i++)
{
close(fd[i]);
}
return 0;
}