LED字符设备驱动实例及测试代码

驱动代码如下:

#include <linux/kernel.h>//内核头文件
#include <linux/init.h>//__init等
#include <linux/module.h>//模块加载的头文件
#include <linux/fs.h>//file_operations
#include <linux/errno.h>//错误状态常数
#include <linux/types.h>//size_t,ssize_t等

//--------------cdev----------------
#include <linux/cdev.h>

//-------------class_create,device_create------
#include <linux/device.h>

//--------------GPIO-----------------
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <mach/regs-gpio.h>

//-------CMD COMMAND----------------
#define LED1_ON 0x1
#define LED1_OFF 0x0

#define DEVICE_NAME "LED1"

static int led1_gpios[]=
{
    S5PV210_MP04(4),
    S5PV210_MP04(5),
    S5PV210_MP04(6),
    S5PV210_MP04(7)
};

#define LED1_NUM ARRAY_SIZE(led1_gpios)

/*用udev机制自动添加设备节点*/
struct class *led1_class;

/*设备结构体*/
struct led1_dev_t
{
    struct cdev cdev;
}led1_dev;

/*
// ------------------- READ ------------------------
ssize_t led1_read (struct file * file ,char * buf, size_t count, loff_t * f_ops)
{
    return count;
}    

// ------------------- WRITE -----------------------
ssize_t led1_write (struct file * file ,const char * buf, size_t count, loff_t * f_ops)
{
    return count;
}    
// ------------------- OPEN ------------------------
ssize_t led1_open (struct inode * inode ,struct file * file)
{
    return 0;
}    
// ------------------- RELEASE/CLOSE ---------------
ssize_t led1_release (struct inode  * inode ,struct file * file)
{
    return 0;
}
// -------------------------------------------------
*/

// ------------------- IOCTL -----------------------
static int  led1_ioctl (struct inode * inode ,struct file * file, unsigned int cmd, unsigned long arg)
{
    if(arg > LED1_NUM)
    {
        printk("arg is %u ,led num is %d\n",arg,LED1_NUM);
        printk("num is err!!\n");
        return - EINVAL;
    }
    switch (cmd)
        {
        case LED1_ON: 
            {
                /*code*/
                gpio_set_value(led1_gpios[arg],0);
                printk("led1 is on!!\n");
                break;
            }
        case LED1_OFF:
            {
                /*code*/
                gpio_set_value(led1_gpios[arg],1);
                printk("led1 is off!!\n");
                break;
            }
        default :
            {
                printk ("CMD err!!\n");
                return - EINVAL;
            }
        }
    return 0;
    
}


struct file_operations led1_fops ={

    .owner   =  THIS_MODULE,
//  .open    =    led1_open,
//    .read    =    led1_read,
//    .write   =  led1_write,
    .ioctl   =    led1_ioctl,
//    .release =    led1_release,
};


// ------------------- INIT ------------------------
static int __init led1_init(void)
{
    printk("led num is : %d\n",LED1_NUM);
    int i,ret;
    for (i = 0; i < LED1_NUM; i++)
    {
       
        /*
        ret=gpio_request(led1_gpios[i],"LED1");
        if(ret)//注意,是ret
        {
            printk("%s:request GPIO %d for LED1 failed,ret= %d\n",DEVICE_NAME,led1_gpios[i],ret);
            return ret;
        }
        */
        s3c_gpio_cfgpin(led1_gpios[i],S3C_GPIO_SFN(1));
        gpio_set_value(led1_gpios[i],1);
    }
        
    /*init cdev*/
    cdev_init(&led1_dev.cdev,&led1_fops);
    led1_dev.cdev.owner=THIS_MODULE;

    /*向系统动态申请未被占用的设备号*/
    ret = alloc_chrdev_region(&led1_dev.cdev.dev,0,1,DEVICE_NAME);//int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
    
    if (ret)
    {
        printk("register failed\n");    
        return ret;
    }

    /*添加字符设备*/
    ret = cdev_add(&led1_dev.cdev, led1_dev.cdev.dev, 1);
    if (ret)
    {
        printk("cdev add failed\n");    
        goto fail1;
    }
    /*udev机制可以自动添加设备节点,只需要添加xxx_class这个类,以及device_create()*/
    led1_class = class_create(THIS_MODULE, "led1_class");/*在sys目录下创建xx_class这个类,/sys/class/~*/
    if (IS_ERR(led1_class))
    {
        printk("class create failed\n");    
        goto fail2;
    }
    device_create(led1_class, NULL, led1_dev.cdev.dev, DEVICE_NAME, DEVICE_NAME);/*自动创建设备/dev/$DEVICE_NAME*/
    return ret;

fail2:
    cdev_del(&led1_dev.cdev);
fail1:
    unregister_chrdev_region(led1_dev.cdev.dev, 1);
    return ret;
}

static void __exit led1_exit(void)
{
    int i;
    /*
    for (i = 0; i < LED1_NUM; i++)
    {
     
        gpio_free(led1_gpios[i]);
    }
    */
    device_destroy(led1_class, led1_dev.cdev.dev);
    class_destroy(led1_class);
    cdev_del(&led1_dev.cdev);
    unregister_chrdev_region(led1_dev.cdev.dev, 1);
}

module_init(led1_init);
module_exit(led1_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("mhb@seu");

 测试代码如下:

#include <stdio.h>
//#include "sys/types.h"
#include <sys/ioctl.h>
#include <stdlib.h>
#include <unistd.h>
//#include "termios.h"
//#include "sys/stat.h"
#include <fcntl.h>

#define LED1_ON 0x1
#define LED1_OFF 0x0

main(int argc,char *argv[])
{
    int fd;

    if ((fd=open("/dev/LED1",O_RDWR /*| O_NDELAY | O_NOCTTY*/)) < 0)
    {
        printf("Open Device  failed.\r\n");
        exit(1);
    }
    else
    {
        printf("Open Device  successed.\r\n");
    }
    if (argc<3)
    {
        /* code */
        printf("Usage: %s <on|off num>\n",argv[0]);
        exit(2);
    }
    if(!strcmp(argv[1],"on"))
    {
        printf("led1 will on!!\n");
        printf("argv[2]=%d\n",atoi(argv[2]));
       if(ioctl(fd,LED1_ON,atoi(argv[2]))<0)
       {
           printf("ioctl err!!\n");     
       }
    
    }
    if(!strcmp(argv[1],"off"))
    {
        printf("led1 will off!!\n");
        if(ioctl(fd,LED1_OFF,atoi(argv[2]))<0)
        {
            printf("ioctl err!!\n");
        }
    }
    close(fd);
}
原文地址:https://www.cnblogs.com/hello2mhb/p/3280845.html