s3c2410矩阵键盘驱动

fs2410开发板上矩阵键盘的硬件连接图如下:

      

连接矩阵键盘的8IO口与核心板IO依次对应为:

行:EINT0         GPF0  EINT2      GPF2  EINT11      GPF3   EINT19      GPF11

列:KCAN0        GPE11  KCAN1     GPG6  KCAN2     GPE13  KCAN3    GPG2

 

 

分析驱动入口函数button_init();

/*

   配置GPE,GPF,GPG的控制寄存器GPCON,和数据寄存器GPDAT,通过iremap()

   得到相应的IO口的虚拟地址,查数据手册可得,0x04表示32为。

*/

gpecon = ioremap(0x56000040, 0x04);//得到相应IO口的虚拟地址,下同

    gpedat = ioremap(0x56000044, 0x04);

    gpfcon = ioremap(0x56000050, 0x04);

    gpfdat = ioremap(0x56000054, 0x04);

    gpgcon = ioremap(0x56000060, 0x04);

gpgdat = ioremap(0x56000064, 0x04);

 

 

/*初始化GPIO*/

static void init_gpio(void)

{

    //GPE13 11 设置低位

    writel((readl(gpecon) |(~3<<(2*13)|(~3<<(2*11))) , gpecon); //GPE13,11 设置为输出

    writel(readl(gpedat) & (~1<<13) |(~1<<11), gpedat);  //GPE13,11 输出为0

 

    //GPG6, 2 设置低位

    writel((readl(gpgcon) | (~(3<<(2*6)|(~3<<(2*2)))), gpgcon);  //GPG6,2 设置为输出

    writel(readl(gpgdat) & 0xffffffbb, gpgdat);       //GPG6,2 输出为0

 

    writel((readl(gpfcon) | 0x33) & 0xffffffee, gpfcon);            //GPF2, 0 设置为中断

    writel((readl(gpgcon) | (3 << 22) | (3 << 6)) & (~((1 << 22) | (1 << 6))), gpgcon); //GPG11,3 设置为中断

 

    /*调用set_irq_type设置中断为下降沿中断*/

    set_irq_type(IRQ_EINT0, IRQT_FALLING);

    // printk("dddddddddddd=%x/n",EXTINT0);

    EXTINT0 = (EXTINT0 & (~0x07)) + 0x02;

    set_irq_type(IRQ_EINT2, IRQT_FALLING);

    EXTINT0 = (EXTINT0 & (~(0x07 << 8))) + (0x02 << 8);

    set_irq_type(IRQ_EINT11, IRQT_FALLING);

    EXTINT1 = (EXTINT1 & (~(0x07 << 12))) + (0x02 << 12);

    set_irq_type(IRQ_EINT19, IRQT_FALLING);

    EXTINT2 = (EXTINT2 & (~(0x07 << 12))) + (0x02 << 12);

                         

        进入申请中断函数request_irq:

 

static  int request_irqs()

{

                 int ret;

          /*

     IRQ_EINT0为中断号,button_irq为中断处理函数,SA_INTERUPT标志为快速中断方式,最后一个参数设为NULL.

                     */

ret = request_irq(IRQ_EINT0, button_irq, SA_INTERRUPT, DEVICE_NAME, NULL);

                 if (ret < 0)

                   {

               return ret;

                   }

ret = request_irq(IRQ_EINT2, button_irq, SA_INTERRUPT, DEVICE_NAME, NULL);

            if (ret >= 0)

             {

            ret = request_irq(IRQ_EINT11, button_irq, SA_INTERRUPT, DEVICE_NAME, NULL);

            }

          if (ret >= 0)

          {

            ret = request_irq(IRQ_EINT19, button_irq, SA_INTERRUPT, DEVICE_NAME, NULL);

            if (ret >= 0)

                return ret;

            /*释放中断*/

            free_irq(IRQ_EINT11, button_irq);

          }

          free_irq(IRQ_EINT2, button_irq);

          free_irq(IRQ_EINT0, button_irq);

           return ret;

}

 

 

进入中断处理函数:

static irqreturn_t button_irq(int irq, void *dev_id, struct pt_regs *regs)

{

    unsigned char ucKey;

    /*屏蔽中断*/

    disable_irqs();

    printk("in irq/n");

    //延迟50毫秒, 屏蔽按键毛刺

    mdelay(50);

    //进入键盘扫描程序

    ucKey = button_scan(irq);

    if ((ucKey >= 1) && (ucKey <= 16))

    {

        //如果缓冲区已满, 则不添加

        if (((g_keyBuffer.head + 1) & (MAX_KEY_COUNT - 1)) != g_keyBuffer.tail)

        {

            spin_lock_irq(&buffer_lock);

            g_keyBuffer.buf[g_keyBuffer.tail] = ucKey;

            g_keyBuffer.jiffy[g_keyBuffer.tail] = GetTickCount();

            g_keyBuffer.tail ++;

            g_keyBuffer.tail &= (MAX_KEY_COUNT - 1);

            spin_unlock_irq(&buffer_lock);

        }

    }

    init_gpio();

    enable_irqs();

    //printk("in irq! %x/n",EXTINT0);

 

    return IRQ_HANDLED;//2.6内核返回值一般是这个宏。

}

 

 

 

static __inline unsigned char button_scan(int irq)

{

    long lGPF, lGPG;     

    writel((readl(gpfcon) | 0x33) & 0xffffffcc, gpfcon);                            //GPF2,0 input

 writel((readl(gpgcon) | (3 << 22) | (3 << 6)) & (~((3 << 22) | (3 << 6))), gpgcon);     //GPG11,3 input

 

    //不利用irq, 直接扫描键盘

    //设置G2低位, G6, E11, E13高位

    writel((readl(gpgdat) | (1 << 6)) & (~(1 << 2)), gpgdat);

    writel(readl(gpedat) | (1 << 11) | (1 << 13), gpedat);

    //GPF0, GPF2, GPG3, GPG11的值

    lGPF = readl(gpfdat);

    lGPG = readl(gpgdat);

    //判断按键

    if ((lGPF & (1 << 0)) == 0)

    {

        return 16;

    }

    else if ((lGPF & (1 << 2)) == 0)

    {

        return 15;

    }

    else if ((lGPG & (1 << 3)) == 0)

    {

        return 14;

    }

    else if ((lGPG & (1 << 11)) == 0)

    {

        return 13;

    }

 

    //设置G6低位, G2, E11, E13高位

    writel((readl(gpgdat) | (1 << 2)) & (~(1 << 6)), gpgdat);

    lGPF = readl(gpfdat);

    lGPG = readl(gpgdat);

    if ((lGPF & (1 << 0)) == 0)

    {

        return 11;

    }

    else if ((lGPF & (1 << 2)) == 0)

    {

        return 8;

    }

    else if ((lGPG & (1 << 3)) == 0)

    {

        return 5;

    }

    else if ((lGPG & (1 << 11)) == 0)

    {

        return 2;

    }

 

    //设置E11低位, G2, G6, E13高位

    writel(readl(gpgdat) | (1 << 6) | (1 << 2), gpgdat);

    writel((readl(gpedat) | (1 << 13)) & (~(1 << 11)), gpedat);

    lGPF = readl(gpfdat);

    lGPG = readl(gpgdat);

    if ((lGPF & (1 << 0)) == 0)

    {

        return 10;

    }

    else if ((lGPF & (1 << 2)) == 0)

    {

        return 7;

    }

    else if ((lGPG & (1 << 3)) == 0)

    {

        return 4;

    }

    else if ((lGPG & (1 << 11)) == 0)

    {

        return 1;

    }

 

    //设置E13低位, G2, G6, E11高位

    //writel(readl(gpgdat) | (1<<6) | (1<<2), gpgdat);

    writel((readl(gpedat) | (1 << 11)) & (~(1 << 13)), gpedat);

    lGPF = readl(gpfdat);

    lGPG = readl(gpgdat);

    if ((lGPF & (1 << 0)) == 0)

    {

        return 12;

    }

    else if ((lGPF & (1 << 2)) == 0)

    {

        return 9;

    }

    else if ((lGPG & (1 << 3)) == 0)

    {

        return 6;

    }

    else if ((lGPG & (1 << 11)) == 0)

    {

        return 3;

    }

    return 0xff ;

}

 

进入屏蔽中断函数:

 

static __inline void disable_irqs(void)

{

    disable_irq(IRQ_EINT0);

    disable_irq(IRQ_EINT2);

    disable_irq(IRQ_EINT11);

    disable_irq(IRQ_EINT19);

}

 

驱动退出函数:

static void __exit button_exit(void)

{

    disable_irqs();

    free_irqs();

    iounmap(gpecon);

    iounmap(gpedat);

    iounmap(gpfcon);

    iounmap(gpfdat);

    iounmap(gpgcon);

    iounmap(gpgdat);

    cdev_del(&SimpleDevs);//删除结构体struct cdev

    printk("button_major=%d/n", button_major);

    unregister_chrdev_region(MKDEV(button_major, 0), 1);//卸载设备驱动所占有的资源

    printk("button device uninstalled/n");

}

 

 

 

 

进入应用程序app:

main()

{

    int fd;

    char key = 0;

    fd = open("/dev/button", O_RDWR);//打开设备

    if (fd == -1)

    {

        printf("open device button errr!/n");

        return 0;

    }

    ioctl(fd, 0, 0);  //清空键盘缓冲区, 后面两个参数没有意义,

    while (key != 16)

    {

        if (read(fd, &key, 1) > 0)//读键盘设备,得到相应的键值

        {

            printf("*********************Key Value = %d*****************************/n", key);

        }

    }

    close(fd);//     //关闭设备

    return 0;

}

 

fileoperation结构体知道openioctlread对应系统调用函数是button_openbutton_ioctlbutton_read.

 

static int button_open(struct inode *inode, struct file *filp)

{

    int ret = nonseekable_open(inode, filp);

    if (ret >= 0)

{

    /*初始化键盘缓冲区*/

    init_keybuffer();

        /*使能中断*/

        enable_irqs();

    }

    return ret;

}

 

 

 

 

 

 

 

static ssize_t button_read(struct file *filp, char *buffer, size_t count, loff_t *ppos)

{

    ssize_t ret = 0;

 

    remove_timeoutkey();

    spin_lock_irq(&buffer_lock);

    while ((g_keyBuffer.head != g_keyBuffer.tail) && (((size_t) ret) < count))

    {

        buffer[ret] = (char) (g_keyBuffer.buf[g_keyBuffer.head]);

        g_keyBuffer.buf[g_keyBuffer.head] = 0;

        g_keyBuffer.jiffy[g_keyBuffer.head] = 0;

        g_keyBuffer.head ++;

        g_keyBuffer.head &= (MAX_KEY_COUNT - 1);

        ret ++;

    }

    spin_unlock_irq(&buffer_lock);

return ret;

}

 

GetTickCount()用于获取当前的毫秒数:

 

static unsigned long GetTickCount(void)

{

    struct timeval currTick;

    unsigned long ulRet;

    do_gettimeofday(&currTick);

    ulRet = currTick.tv_sec;

    ulRet *= 1000;

    ulRet += (currTick.tv_usec + 500) / 1000;

    return ulRet;

}

你可能感兴趣的:(s3c2410矩阵键盘驱动)