zoukankan      html  css  js  c++  java
  • Linux下实现流水灯等功能的LED驱动代码及测试实例

    驱动代码:

    #include <linux/errno.h>
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/slab.h>
    #include <linux/input.h>
    #include <linux/init.h>
    #include <linux/serio.h>
    #include <linux/delay.h>
    #include <linux/clk.h>
    #include <linux/miscdevice.h>
    #include <linux/gpio.h>
    
    #include <asm/io.h>
    #include <asm/irq.h>
    #include <asm/uaccess.h>
    #include <mach/regs-clock.h>
    #include <plat/regs-timer.h>
         
    #include <mach/regs-gpio.h>
    #include <linux/cdev.h>
    //-------------class_create,device_create------
    #include <linux/device.h>
    
    /*用udev机制自动添加设备节点*/
    struct class *led_class;
    
    static int led_major = 0;     /* 主设备号 */
    static struct cdev LedDevs;
    
    /* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */
    #define LED_MAGIC 'k'
    #define IOCTL_LED_ON _IOW (LED_MAGIC, 1, int)
    #define IOCTL_LED_OFF _IOW (LED_MAGIC, 2, int)
    #define IOCTL_LED_RUN _IOW (LED_MAGIC, 3, int)
    #define IOCTL_LED_SHINE _IOW (LED_MAGIC, 4, int)
    #define IOCTL_LED_ALLON _IOW (LED_MAGIC, 5, int)
    #define IOCTL_LED_ALLOFF _IOW (LED_MAGIC, 6, int)
    
    
    
    /* 用来指定LED所用的GPIO引脚 */
    static unsigned long led_table [] = {
        S5PV210_MP04(4),
        S5PV210_MP04(5),
        S5PV210_MP04(6),
        S5PV210_MP04(7),
    
    };
    #define LED_NUM ARRAY_SIZE(led_table)
    
    
    /* 应用程序对设备文件/dev/led执行open(...)时,
     * 就会调用leds_open函数
     */
    static int leds_open(struct inode *inode, struct file *file)
    {
        int i;    
        for (i = 0; i < 4; i++) {
            // 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能
            s3c_gpio_cfgpin(led_table[i], S3C_GPIO_OUTPUT);
        }
        return 0;
    }
    
    //LEDS all light on
    static void leds_all_on()
    {
        int i;
        for (i=0; i<4; i++) {
            gpio_set_value(led_table[i], 0);
        }
    }
    
    //LEDs all light off
    static void leds_all_off()
    {
        int i;
        for (i=0; i<4; i++) {
            gpio_set_value(led_table[i], 1);
        }
    }
    
    /* 应用程序对设备文件/dev/leds执行ioctl(...)时,
     * 就会调用leds_ioctl函数
     */
    static int leds_ioctl(struct file *file, 
                                    unsigned int cmd, 
                                    unsigned long arg)//没有inode,用邋unlocked_ioctl
    {
        printk("in the leds_ioctl!!\n");
    
    
     //   if (__get_user(data, (unsigned int __user *)arg)) //方法二:指针参数传递
     //       return -EFAULT;
        printk("arg is %d!!\n",arg);
    
    
    
        switch(cmd) {
            case IOCTL_LED_ON:
                printk("in the IOCTL_LED_ON!!\n");
                // 设置指定引脚的输出电平为0
                gpio_set_value(led_table[arg], 0);
                break;
    
            case IOCTL_LED_OFF:
                printk("in the IOCTL_LED_OFF!!\n");
                // 设置指定引脚的输出电平为1
                gpio_set_value(led_table[arg], 1);
               break;
                
            case IOCTL_LED_RUN:
                // 跑马灯
                {
                    printk("in the IOCTL_LED_RUN!!\n");
                    int i,j;
                    leds_all_off();            
                    //printk("IOCTL_LED_RUN");
                    for (i=0;i<arg;i++)
                        for (j=0;j<4;j++) {
                            gpio_set_value(led_table[j], 0);
                            mdelay(400); //delay 400ms
                            gpio_set_value(led_table[j], 1);
                            mdelay(400); //delay 400ms
                        }  
                    break;
                 }
              
            case IOCTL_LED_SHINE:
                // LED 闪烁
                {
                    printk("in the IOCTL_LED_SHINE!!\n");
                    int i,j;
                    leds_all_off();
                    printk("IOCTL_LED_SHINE\n");
                    for (i=0;i<arg;i++) {
                        for (j=0;j<4;j++)
                            gpio_set_value(led_table[j], 0);
                        mdelay(400); //delay 400ms
                        for (j=0;j<4;j++)
                            gpio_set_value(led_table[j], 1);
                        mdelay(400);
                    }
                    break ;
               }
            case IOCTL_LED_ALLON:
                printk("in the IOCTL_LED_ALLON!!\n");
                // 设置指定引脚的输出电平为0
                leds_all_on();
                break;
            case IOCTL_LED_ALLOFF:
                printk("in the IOCTL_LED_ALLOFF!!\n");
                // 设置指定引脚的输出电平为1
                leds_all_off();
                break;
    
            default:
                printk("in the default!!\n");
                return -EINVAL;
        }
        return 0;
    }
    
    /* 这个结构是字符设备驱动程序的核心
     * 当应用程序操作设备文件时所调用的open、read、write等函数,
     * 最终会调用这个结构中指定的对应函数
     */
    static struct file_operations leds_fops = {
        .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
        .open   =   leds_open,     
        .unlocked_ioctl  =   leds_ioctl,
    };
    
    
    /*
     * Set up the cdev structure for a device.
     */
    static void led_setup_cdev(struct cdev *dev, int minor,
            struct file_operations *fops)
    {
        int err, devno = MKDEV(led_major, minor);
        
        cdev_init(dev, fops);
        dev->owner = THIS_MODULE;
        dev->ops = fops;
        err = cdev_add (dev, devno, 1);
        /* Fail gracefully if need be */
        if (err)
            printk (KERN_NOTICE "Error %d adding Led%d", err, minor);
    }
    
    /*
     * 执行“insmod leds.ko”命令时就会调用这个函数
     */
    
    static int __init leds_init(void)
    
    {
        int result;
        dev_t dev = MKDEV(led_major, 0);
        char dev_name[]="led";  /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
    
        /*gpio_request*/
        int i,ret;
        for (i = 0; i < LED_NUM; i++)
        {
           
            
            ret=gpio_request(led_table[i],"LED");
            if(ret)//注意,是ret
            {
                printk("%s:request GPIO %d for LED failed,ret= %d\n",dev_name,led_table[i],ret);
                return ret;
            }
            s3c_gpio_cfgpin(led_table[i],S3C_GPIO_SFN(1));//output
            gpio_set_value(led_table[i],1);
        }
    
        /* Figure out our device number. */
        if (led_major)
            result = register_chrdev_region(dev, 1, dev_name);
        else {
            result = alloc_chrdev_region(&dev, 0, 1, dev_name);
            led_major = MAJOR(dev);
        }
        if (result < 0) {
            printk(KERN_WARNING "leds: unable to get major %d\n", led_major);
            return result;
        }
        if (led_major == 0)
            led_major = result;
    
        /* Now set up cdev. */
        led_setup_cdev(&LedDevs, 0, &leds_fops);
    
        /*udev机制可以自动添加设备节点,只需要添加xxx_class这个类,以及device_create()*/
        led_class = class_create(THIS_MODULE, "led_class");/*在sys目录下创建xx_class这个类,/sys/class/~*/
        device_create(led_class, NULL, LedDevs.dev,  dev_name,  dev_name);/*自动创建设备/dev/$DEVICE_NAME*/
        
    
        
        printk("Led device installed, with major %d\n", led_major);
        printk("The device name is: %s\n", dev_name);
        return 0;
    
    }
    
    /*
     * 执行”rmmod leds”命令时就会调用这个函数 
     */
    static void __exit leds_exit(void)
    {
        /*gpio_free*/
        int i;
        for (i = 0; i < LED_NUM; i++)
        {
         
            gpio_free(led_table[i]);
        }
    
        /* 卸载驱动程序 */
        cdev_del(&LedDevs);
        unregister_chrdev_region(MKDEV(led_major, 0), 1);
        printk("Led device uninstalled\n");
    }
    
    /* 这两行指定驱动程序的初始化函数和卸载函数 */
    module_init(leds_init);
    module_exit(leds_exit);
    
    /* 描述驱动程序的一些信息,不是必须的 */
    MODULE_AUTHOR("");             // 驱动程序的作者
    MODULE_DESCRIPTION("LED Driver");   // 一些描述信息
    MODULE_LICENSE("Dual BSD/GPL");                             // 遵循的协议

    测试代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/ioctl.h>
    
    #define LED_MAGIC 'k'
    #define IOCTL_LED_ON _IOW (LED_MAGIC, 1, int)
    #define IOCTL_LED_OFF _IOW (LED_MAGIC, 2, int)
    #define IOCTL_LED_RUN _IOW (LED_MAGIC, 3, int)
    #define IOCTL_LED_SHINE _IOW (LED_MAGIC, 4, int)
    #define IOCTL_LED_ALLON _IOW (LED_MAGIC, 5, int)
    #define IOCTL_LED_ALLOFF _IOW (LED_MAGIC, 6, int)
    
    /*
    led_test on   //对应四个LED全亮
    led_test off  // 对应四个LED全灭
    led_test run  // 运行跑马灯实验
    led_test shine //4个LED灯全灭、全亮交替闪烁
    
    led_test 1 on   //对应LED1点亮
    led_test 1 off  // 对应LED1熄灭
    ...
    led_test 4 on   //对应LED4点亮
    led_test 4 off  // 对应LED4熄灭
    
    */
    void usage(char *exename)
    {
        printf("Usage:\n");
        printf("    %s <led_no> <on/off>\n", exename);
        printf("    led_no = 1, 2, 3 or 4\n");
    }
    
    int main(int argc, char **argv)
    {
        unsigned int led_no;
        int fd = -1;
            unsigned int count=10;
        
        if (argc > 3 || argc == 1)
            goto err;
            
        fd = open("/dev/led", 0);  // 打开设备
        if (fd < 0) {
            printf("Can't open /dev/led\n");
            return -1;    
        }    
        
    
        if (argc == 2) {
            if (!strcmp(argv[1], "on")) {
                ioctl(fd, IOCTL_LED_ALLON, count);    // 点亮它
            } else if (!strcmp(argv[1], "off")) {
                ioctl(fd, IOCTL_LED_ALLOFF, count);   // 熄灭它
            } else if (!strcmp(argv[1], "run")) {
                ioctl(fd, IOCTL_LED_RUN, count);   //运行跑马灯
                    } else if (!strcmp(argv[1], "shine")) {
                ioctl(fd, IOCTL_LED_SHINE, count);   //闪烁
            } else {
                goto err;
            }
        }
            
        if (argc == 3) {
            led_no = atoi(argv[1]);    // 操作哪个LED?
            if (led_no > 3)
                goto err;        
            if (!strcmp(argv[2], "on")) {
                ioctl(fd, IOCTL_LED_ON, led_no);    // 点亮
            } else if (!strcmp(argv[2], "off")) {
                ioctl(fd, IOCTL_LED_OFF, led_no);   // 熄灭
            } else {
                goto err;
            }
        }
        
        close(fd);
        return 0;
        
    err:
        if (fd > 0) 
            close(fd);
        usage(argv[0]);
        return -1;
        
    
    }
  • 相关阅读:
    mysql基础
    协程
    锁与队列
    线程练习
    线程
    并发编程
    进程
    操作系统发展史
    第六周----例行报告
    附加题找bug
  • 原文地址:https://www.cnblogs.com/hello2mhb/p/3282698.html
Copyright © 2011-2022 走看看