中级会员
- 积分
- 351
- 金钱
- 351
- 注册时间
- 2016-4-20
- 在线时间
- 162 小时
|
发表于 2020-3-30 18:34:54
|
显示全部楼层
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/mutex.h>
#include <linux/of_gpio.h>
#define LED_DEVS_NUM 3
#define LED_DEV_NAME "led"
typedef struct
{
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *dev;
struct device_node *node;
int gpio;
unsigned char value;
struct mutex lock;
} led_dev_t;
static led_dev_t *led_dev;
static void led_off(led_dev_t *dev)
{
if (gpio_direction_output(dev->gpio, 1))
{
printk("%s: gpio_direction_output fail!\r\n", __func__);
}
}
static void led_on(led_dev_t *dev)
{
if (gpio_direction_output(dev->gpio, 0))
{
printk("%s: gpio_direction_output fail!\r\n", __func__);
}
}
static int led_open(struct inode *inode, struct file *file)
{
led_dev_t *dev = container_of(inode->i_cdev, led_dev_t, cdev);
file->private_data = dev;
return 0;
}
static int led_release(struct inode *inode, struct file *file)
{
//led_dev_t *dev = file->private_data;
//led_off(dev);
return 0;
}
static ssize_t led_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
led_dev_t *dev = file->private_data;
mutex_lock(&dev->lock);
if (copy_to_user(buf, &(dev->value), sizeof(unsigned char)))
{
return -EFAULT;
}
mutex_unlock(&dev->lock);
return sizeof(unsigned char);
}
static ssize_t led_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
led_dev_t *dev = file->private_data;
mutex_lock(&dev->lock);
if (copy_from_user(&(dev->value), buf, sizeof(unsigned char)))
{
return -EFAULT;
}
mutex_unlock(&dev->lock);
switch (dev->value)
{
case 1:
led_on(dev);
break;
case 0:
led_off(dev);
break;
default:
return -ENOTTY;
}
return sizeof(unsigned char);
}
static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
led_dev_t *dev = file->private_data;
switch (cmd)
{
case 1:
led_on(dev);
break;
case 0:
led_off(dev);
break;
default:
return -ENOTTY;
}
return 0;
}
static const struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.release = led_release,
.read = led_read,
.write = led_write,
.unlocked_ioctl = led_ioctl,
};
static int __init led_init(void)
{
int ret = 0;
dev_t devid;
int major;
unsigned int i;
char dev_name[20];
// 为驱动数据分配内存
led_dev = kmalloc(LED_DEVS_NUM * sizeof(led_dev_t), GFP_KERNEL);
if (led_dev == NULL)
{
printk("%s: kmalloc fail!\r\n", __func__);
return -EFAULT;
}
memset(led_dev, 0, LED_DEVS_NUM * sizeof(led_dev_t));
// 申请自动分配的设备号
ret = alloc_chrdev_region(&devid, 0, LED_DEVS_NUM, LED_DEV_NAME);
if (ret)
{
printk("%s: alloc_chrdev_region fail!\r\n", __func__);
return ret;
}
else
{
major = MAJOR(devid);
}
for (i = 0; i != LED_DEVS_NUM; ++i)
{
led_dev_t *dev = led_dev + i;
// 设备ID
dev->devid = MKDEV(major, i);
// 初始化互斥体
mutex_init(&dev->lock);
// 添加字符设备并添加至内核
dev->cdev.owner = led_fops.owner;
cdev_init(&dev->cdev, &led_fops);
ret = cdev_add(&dev->cdev, dev->devid, 1);
if (ret)
{
printk("%s: cdev_add fail!\r\n", __func__);
return -ret;
}
// 创建类
sprintf(dev_name, "%s%d", LED_DEV_NAME, i);
dev->class = class_create(THIS_MODULE, dev_name);
if (IS_ERR(dev->class))
{
printk("%s: class_create fail!\r\n", __func__);
return PTR_ERR(dev->class);
}
// 创建设备
dev->dev = device_create(dev->class, NULL, dev->devid, NULL, dev_name);
if (IS_ERR(dev->dev))
{
return PTR_ERR(dev->dev);
}
// 获取设备树节点
dev->node = of_find_node_by_path("/led");
if (dev->node == NULL)
{
printk("%s: of_find_node_by_path fail!\r\n", __func__);
return -EFAULT;
}
// 获取GPIO属性
dev->gpio = of_get_named_gpio(dev->node, "led-gpio", i);
if (!gpio_is_valid(dev->gpio))
{
printk("%s: of_get_named_gpio fail!\r\n", __func__);
return -ENODEV;
}
// 默认关闭LED
led_off(dev);
}
printk("%s : sucess!\r\n", __func__);
return 0;
}
static void __exit led_exit(void)
{
unsigned int i;
for (i = 0; i != LED_DEVS_NUM; ++i)
{
led_dev_t *dev = led_dev + i;
led_off(dev);
device_destroy(dev->class, dev->devid);
class_destroy(dev->class);
cdev_del(&dev->cdev);
unregister_chrdev_region(dev->devid, 1);
}
kfree(led_dev);
printk("%s : sucess!\r\n", __func__);
}
module_init(led_init);
module_exit(led_exit);
MODULE_DESCRIPTION("led driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("hannuaa");
|
|