驱动代码
/*************************************************************************
> File Name: led_drv.c
> Author: XXDK
> Email: v.manstein@qq.com
> Created Time: Sat 18 Mar 2017 06:27:26 AM PDT
************************************************************************/
#include<linux/init.h>
#include<linux/module.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/slab.h>
#include<asm/gpio.h>
#include<mach/iomux-mx6q.h>
#define SABRESD_GPIO_LED4 IMX_GPIO_NR(3, 21)
struct led{
char name[10];
int gpio;
int data;
int open_cnt;
spinlock_t splock;
dev_t led_dev_id;
struct cdev led_cdev;
struct class* led_cls;
struct file_operations led_fops;
}*sabre_led = NULL;
static int led_open(struct inode* inodp, struct file* filp)
{
unsigned long flags;
// 获取自旋锁
spin_lock_irqsave(&sabre_led->splock, flags);
if(--sabre_led->open_cnt != 0) {
printk("sabre led already be opened\n");
sabre_led->open_cnt++;
// 释放自旋锁
spin_unlock_irqrestore(&sabre_led->splock, flags);
return -EBUSY;
}
spin_unlock_irqrestore(&sabre_led->splock, flags);
printk("opening sabre led......\n");
gpio_set_value(sabre_led->gpio, 1);
return 0;
}
static int led_close(struct inode* inodp, struct file* filp)
{
unsigned long flags;
spin_lock_irqsave(&sabre_led->splock, flags);
sabre_led->open_cnt++;
spin_unlock_irqrestore(&sabre_led->splock, flags);
gpio_set_value(sabre_led->gpio, 0);
return 0;
}
static int led_init(void)
{
sabre_led = (struct led*)kmalloc(sizeof(struct led), GFP_KERNEL);
if(NULL == sabre_led) {
printk("kmalloc error\n");
return -1;
}
sabre_led->led_fops.owner = THIS_MODULE,
sabre_led->led_fops.open = led_open,
sabre_led->led_fops.release = led_close;
sabre_led->gpio = SABRESD_GPIO_LED4;
strcpy(sabre_led->name, "led");
gpio_request(sabre_led->gpio, sabre_led->name);
gpio_direction_output(sabre_led->gpio, 0);
// 1. 申请设备号
alloc_chrdev_region(&sabre_led->led_dev_id, 0, 1, "leds");
// 2. 初始化字符设备对象
cdev_init(&sabre_led->led_cdev, &sabre_led->led_fops);
// 3. 添加字符设备对象到内核
cdev_add(&sabre_led->led_cdev, sabre_led->led_dev_id, 1);
// 4. 自动创建设备文件
sabre_led->led_cls = class_create(THIS_MODULE, "xxdk");
device_create(sabre_led->led_cls, NULL,
sabre_led->led_dev_id, NULL, "sabre_led");
// 初始化自旋锁
sabre_led->open_cnt = 1;
spin_lock_init(&sabre_led->splock);
return 0;
}
static void led_exit(void)
{
gpio_set_value(sabre_led->gpio, 0);
gpio_free(sabre_led->gpio);
device_destroy(sabre_led->led_cls, sabre_led->led_dev_id);
class_destroy(sabre_led->led_cls);
cdev_del(&sabre_led->led_cdev);
unregister_chrdev_region(sabre_led->led_dev_id, 1);
kfree(sabre_led);
sabre_led = NULL;
printk("bye bye\n");
return;
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
测试代码
/*************************************************************************
> File Name: led_test.c
> Author: XXDK
> Email: v.manstein@qq.com
> Created Time: Sat 18 Mar 2017 08:24:16 AM PDT
************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
int main()
{
int fd;
if((fd = open("/dev/sabre_led", O_RDWR)) < 0) {
perror("open sabreled failed");
}
sleep(100);
close(fd);
while(1);
}