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;

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章