代码拉取完成,页面将自动刷新
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <asm/atomic.h>
#include <linux/timer.h>
#define GPIOLED_CNT 1
#define GPIOLED_NAME "gpioled"
#define LEDOFF 0
#define LEDON 1
#define CLOSE_CMD (_IO(0XEF, 0x1)) /* 关闭定时器 */
#define OPEN_CMD (_IO(0XEF, 0x2)) /* 打开定时器 */
#define SETPERIOD_CMD (_IO(0XEF, 0x3)) /* 设置定时器周期命令 */
struct gpioled_dev
{
dev_t devid; /* 设备号 */
int major; /* 主设备号 */
int minor; /* 次设备号 */
struct cdev cdev; /* 字符设备 */
struct class *class; /* 类 */
struct device_node *nd; /* 设备节点 */
struct device *device; /* 设备 */
int led_gpio;
spinlock_t lock; /* 自旋锁 */
int timeperiod; /* 周期,单位为 ms */
struct timer_list timer; /* 定时器 */
};
static struct gpioled_dev gpioled;
int ledPin_init(void)
{
int ret = 0;
/* 获取设备节点 */
gpioled.nd = of_find_node_by_path("/gpioled");
if (gpioled.nd == NULL)
{ /* 失败 */
ret = -1;
return ret;
}
printk("find dts node successful!\r\n");
/* 2, 获取LED所对应的GPIO */
gpioled.led_gpio = of_get_named_gpio(gpioled.nd, "led-gpio", 0);
if (gpioled.led_gpio < 0)
{
printk("can't find led gpio\r\n");
ret = -1;
return ret;
}
printk("led gpio num = %d\r\n", gpioled.led_gpio);
/* 3,申请IO */
ret = gpio_request(gpioled.led_gpio, "led-gpio");
if (ret)
{
printk("Failed to request the led gpio\r\n");
ret = -1;
return ret;
}
/* 4,使用IO,设置为输出 */
ret = gpio_direction_output(gpioled.led_gpio, 1);
if (ret)
{
ret = -1;
goto fail_setoutput;
}
/* 5操作gpio*/
gpio_set_value(gpioled.led_gpio, 0);
return 0;
fail_setoutput:
gpio_free(gpioled.led_gpio);
return ret;
}
static int gpioled_open(struct inode *inode, struct file *pfile)
{
// unsigned long flags;
pfile->private_data = &gpioled;
gpioled.timeperiod = 1000; /* 默认周期为 1s */
// spin_lock_irqsave(&gpioled.lock, flags); /* 上锁 */
// spin_unlock_irqrestore(&gpioled.lock, flags); /* 解锁 */
return 0;
}
int gpioled_release(struct inode *pinode, struct file *pfile)
{
// struct gpioled_dev *dev = pfile->private_data;
return 0;
}
static long gpioled_unlocked_ioctl(struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct gpioled_dev *dev = (struct gpioled_dev *)filp->private_data;
int timerperiod;
unsigned long flags;
switch (cmd)
{
case CLOSE_CMD: /* 关闭定时器 */
del_timer_sync(&dev->timer);
break;
case OPEN_CMD: /* 打开定时器 */
spin_lock_irqsave(&dev->lock, flags);
timerperiod = dev->timeperiod;
spin_unlock_irqrestore(&dev->lock, flags);
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(timerperiod));
break;
case SETPERIOD_CMD: /* 设置定时器周期 */
spin_lock_irqsave(&dev->lock, flags);
dev->timeperiod = arg;
spin_unlock_irqrestore(&dev->lock, flags);
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(arg));
break;
default:
break;
}
return 0;
}
static const struct file_operations gpioled_fops = {
.owner = THIS_MODULE,
.open = gpioled_open,
.release = gpioled_release,
.unlocked_ioctl = gpioled_unlocked_ioctl,
};
/* 定时器回调函数 */
void timer_function(unsigned long arg)
{
struct gpioled_dev *dev = (struct gpioled_dev *)arg;
static int sta = 1;
int timerperiod;
unsigned long flags;
sta = !sta; /* 每次都取反,实现 LED 灯反转 */
gpio_set_value(dev->led_gpio, sta);
/* 重启定时器 */
spin_lock_irqsave(&dev->lock, flags);
timerperiod = dev->timeperiod;
spin_unlock_irqrestore(&dev->lock, flags);
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(timerperiod));
}
static int __init gpioled_init(void)
{
int ret = 0;
spin_lock_init(&gpioled.lock);
ret = ledPin_init();
if (ret < 0)
return -EBUSY;
/* 1,申请设备号 */
gpioled.major = 0; /* 设备号由内核分配 */
if (gpioled.major)
{ /* 定义了设备号 */
gpioled.devid = MKDEV(gpioled.major, 0);
ret = register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);
}
else
{ /* 没有给定设备号 */
ret = alloc_chrdev_region(&gpioled.devid, 0, GPIOLED_CNT, GPIOLED_NAME);
gpioled.major = MAJOR(gpioled.devid);
gpioled.minor = MINOR(gpioled.devid);
}
if (ret < 0)
{
goto fail_devid;
}
printk("gpioled_devid = %d\r\n", gpioled.devid);
printk("gpioled_major = %d\r\n", gpioled.major);
printk("gpioled_minor = %d\r\n", gpioled.minor);
/* 2,添加字符设备 */
gpioled.cdev.owner = THIS_MODULE;
cdev_init(&gpioled.cdev, &gpioled_fops);
ret = cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT);
if (ret < 0)
goto fail_cdev;
printk("cdev_add successful!\r\n");
/* 3,自动创建设备节点 */
gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);
if (IS_ERR(gpioled.class))
{
ret = PTR_ERR(gpioled.class);
goto fail_class;
}
printk("class_create successful!\r\n");
gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);
if (IS_ERR(gpioled.device))
{
ret = PTR_ERR(gpioled.device);
goto fail_device;
}
printk("device_create successful!\r\n");
/* 初始化 timer,设置定时器处理函数,还未设置周期,所有不会激活定时器 */
init_timer(&gpioled.timer);
gpioled.timer.function = timer_function;
gpioled.timer.data = (unsigned long)&gpioled;
return 0;
fail_device:
class_destroy(gpioled.class);
fail_class:
cdev_del(&gpioled.cdev);
fail_cdev:
unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);
fail_devid:
return ret;
}
static void __exit gpioled_exit(void)
{
/* 关灯 */
gpio_set_value(gpioled.led_gpio, 1);
del_timer_sync(&gpioled.timer);
/* 释放IO */
gpio_free(gpioled.led_gpio);
/* 删除字符设备 */
cdev_del(&gpioled.cdev);
printk("cdev_del successful!\r\n");
/* 释放设备号 */
unregister_chrdev_region(gpioled.devid, GPIOLED_CNT);
printk("unregister chrdev successful!\r\n");
/* 摧毁设备*/
device_destroy(gpioled.class, gpioled.devid);
printk("device_destroy successful!\r\n");
/* 摧毁类 */
class_destroy(gpioled.class);
printk("class_destroy successful!\r\n");
}
module_init(gpioled_init);
module_exit(gpioled_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhangkewei");
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。