输入系统之led灯控制

      目前下面的程序在卸载时会出现问题,原因有待查找,问题出现在input_unregister_device(),程序如下:

     

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <linux/gpio.h> 
#include <asm/irq.h>
#include <linux/sched.h>   
#include <linux/irq.h>
#include <asm/io.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/wait.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/timer.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/input.h>


#define DRVNAME "s5pv210_gpio"
struct led_device_ops{

        struct input_dev *input;
        wait_queue_head_t my_waitqueue;

        struct timer_list timer;        /* statistic timer */
        int irq;
        unsigned long virt;
};
static struct led_device_ops led_info;

static uint32_t last_timer; 

static volatile int press = 0; 
struct pin_desc{
        unsigned char key_val;
};
static unsigned char witch_key = 0;
static struct pin_desc key_descs[8] ={ 
    [0] = { 
        .key_val = KEY_1, 
    }, 
    [1] = { 
        .key_val = KEY_2, 
    }, 
 
    [2] = { 
        .key_val = KEY_3, 
    }, 
 
    [3] = { 
        .key_val = KEY_4, 
    }, 
 
    [4] = { 
        .key_val = KEY_5, 
    }, 
 
    [5] = { 
        .key_val = KEY_6, 
    }, 
 
    [6] = {  
        .key_val = KEY_7, 
    }, 
 
    [7] = { 
        .key_val = KEY_8, 
    }, 
 };

volatile unsigned long *GPC0CON, *GPC0DAT;//用与存放两个个寄存器的地址
volatile unsigned long *GPH0CON, *GPH0DAT;//按键
static unsigned char KeyFlag;

static void all_leds_off(void);
static void led_config(void)
{
        volatile unsigned long  phys;//用于存放虚拟地址和物理地址
        phys = 0xE0200060; 
        led_info.virt =(unsigned long)ioremap(phys, 0xf00);
        GPC0CON = (unsigned long *)(led_info.virt + 0x00);//指定需要操作的三个寄存器的地址
        GPC0DAT = (unsigned long *)(led_info.virt + 0x04);
        GPH0CON = (unsigned long *)(led_info.virt + 0xc00-0x60); //keY1配置为输入
        GPH0DAT = (unsigned long *)(led_info.virt + 0xc00-0x60+0x04);
        *GPC0CON &= ~(0xFF << 12);
        *GPC0CON |= 0x11 << 12;                 // 配置GPC0_3和GPC0_4为输出
        *GPH0CON &= ~0x0F; //配置为输入
        all_leds_off();
}

static void led1_on(void)
{
        *GPC0DAT |= 1 << 3;
        *GPC0DAT &= ~(0x01 << 4);
//      printk("led1 light\n");
}

static void led2_on(void)
{
        *GPC0DAT |= 1 << 4;
        *GPC0DAT &= ~(0x01 << 3);
//      printk("led2 light\n");
}

static void all_leds_on(void)
{
                *GPC0DAT |= 1 << 3;             // 点亮LED1
                *GPC0DAT |= 1 << 4;             // 点亮LED2
                printk("all leds light\n");
}
static void all_leds_off(void)
{

        *GPC0DAT &= ~(0x3 << 3);                // 熄灭LED1和LED2
        printk("all leds off\n");
}

static void led_timer_event(unsigned long arg)
{
        press = 1;
        KeyFlag = !KeyFlag;

        if(KeyFlag)
        {
                led1_on();
        }
        else
        {
                        led2_on();
        }


        printk("Timer event time = %ld\n",jiffies-last_timer);
        input_event(led_info.input, EV_KEY, witch_key, 0);
        input_sync(led_info.input);

}


static irqreturn_t led_handler(int irq, void *devid)
{
        struct pin_desc * pindesc = (struct pin_desc *)devid;
        mod_timer(&led_info.timer,jiffies+HZ);  //这里设置定时中断程序多久之后执行,可适当变短些,
        last_timer=jiffies;                                                                      //这里为了使程序实验效果更加明显,直接用1s
        witch_key = pindesc->key_val;
        printk("KERNEL:irq == %d  witch_key= %d\n",irq,witch_key);
        return IRQ_RETVAL(IRQ_HANDLED); 

}



static int led_device_open(struct inode *inode, struct file *file)
{
        printk("led_drv_open\n");

        file->private_data = &led_info;

        return 0;
}


static int led_device_release(struct inode *inode, struct file *file)
{
        return 0;
}




static const struct file_operations led_device_fileops = {
        .owner   = THIS_MODULE,
        .open    = led_device_open,
        .release = led_device_release,
};

static int led_device_init(void)
{
          int rc,i,error;
                //struct led_device_ops *ddata;
                //struct input_dev *input;
                //ddata = kzalloc(sizeof(struct led_device_ops),GFP_KERNEL);
                led_info.input = input_allocate_device();
                if (!led_info.input) {
                    printk(KERN_ERR"failed to allocate state\n");
                    error = -ENOMEM;
                    goto fail1;
                }
                //ddata->input = input;
                led_info.input->name = "key_device";
                set_bit(EV_KEY, led_info.input->evbit);
                set_bit(KEY_1, led_info.input->keybit);
                set_bit(KEY_2, led_info.input->keybit);
                set_bit(KEY_3, led_info.input->keybit);
                set_bit(KEY_4, led_info.input->keybit);
                set_bit(KEY_5, led_info.input->keybit);
                set_bit(KEY_6, led_info.input->keybit);
                set_bit(KEY_7, led_info.input->keybit);
                set_bit(KEY_8, led_info.input->keybit);

                //led_info.input = ddata->input;
                error = input_register_device(led_info.input);
                if (error) {
                                printk(KERN_ERR"Unable to register input device, error: %d\n",
                                error);
                                goto fail2;
                }
          input_sync(led_info.input);
        for(i=0;i<5;i++)
        {
                    rc = request_irq(IRQ_EINT(i), &led_handler, IRQ_TYPE_EDGE_FALLING,"led_irq",  &key_descs[i]);
                    if(rc)
                    {
                                    printk(KERN_ERR"function request_irq(%d) excute error\n",i);
                                    goto led_request_irq_error;
                    }
                }
                init_timer(&led_info.timer);
                led_info.timer.function = led_timer_event;
                add_timer(&led_info.timer);
                led_config();
                all_leds_off();
                return 0; /* succeed */
 led_request_irq_error:  
 fail2:
 fail1:
                input_free_device(led_info.input);

                return error;

}

static void led_device_exit(void)
{
        iounmap((void *)led_info.virt); //撤销映射关系
        free_irq(IRQ_EINT(0), &key_descs[0]);
        free_irq(IRQ_EINT(1), &key_descs[1]);
        free_irq(IRQ_EINT(2), &key_descs[2]);
        free_irq(IRQ_EINT(3), &key_descs[3]);
        free_irq(IRQ_EINT(4), &key_descs[4]);
        printk("led_drv_exit ....excute ok\n");
        //all_leds_off();
        printk("led_drv_exit ....excute ok0\n");
        printk("led_drv_exit ....excute ok1\n");
        printk("led_drv_exit ....excute ok2\n");
         input_free_device(led_info.input);
        printk("led_drv_exit ....excute ok3\n");
         input_unregister_device(led_info.input); //此处有段错误出现
        printk("led_drv_exit ....excute ok4\n");
 
 

}

module_init(led_device_init);
module_exit(led_device_exit);

MODULE_AUTHOR("Ethyn blog:http://blog.csdn.net/humanspider1");
MODULE_DESCRIPTION("cortex a8 S5pv210 led test Driver");


猜你喜欢

转载自blog.csdn.net/humanspider1/article/details/41061069