色偷偷偷亚洲综合网另类,亚洲欧美另类在线观看,欧美午夜激情在线,久久久精品一区

Hi,歡迎來到嵌入式培訓高端品牌 - 華清遠見教育科技集團<北京總部官網>,專注嵌入式工程師培養15年!
當前位置: > 華清遠見教育科技集團 > 嵌入式學習 > 講師博文 > FS2410開發板上的按鍵驅動程序(2)續
FS2410開發板上的按鍵驅動程序(2)續
時間:2016-12-28作者:華清遠見

按鍵字符設備的file_operations結構定義為:

static struct file_operations button_fops =
    {
        .owner = THIS_MODULE,
        .ioctl = button_ioctl,
        .open = button_open,
        .read = button_read,
        .release = button_release,
    };

以下為open和release函數接口的實現。

/* 打開文件, 申請中斷 */
    static int button_open(struct inode *inode,struct file *filp) 
    {
        int ret = nonseekable_open(inode, filp);
        if (ret < 0) 
        {
             return ret;
        }
        init_gpio(); /* 相關GPIO端口的初始化*/
        request_irqs(); /* 申請4個中斷 */
        if (ret < 0) 
        {
             return ret;
        }
        init_keybuffer(); /* 初始化按鍵緩沖數據結構 */
        return ret;
    }
    /* 關閉文件, 屏蔽中斷 */
    static int button_release(struct inode *inode,struct file *filp)
    {
        free_irqs(); /* 屏蔽中斷 */
        return 0;
    }

在open函數接口中,進行了GPIO端口的初始化、申請硬件中斷以及按鍵緩沖的初始化等工作。在以前的章節中提過,中斷端口是比較寶貴而且數量有限的資源。因此需要注意,好要在第一次打開設備時申請(調用request_irq函數)中斷端口,而不是在驅動模塊加載的時候申請。如果已加載的設備驅動占用而在一定時間段內不使用某些中斷資源,則這些資源不會被其他驅動所使用,只能白白浪費掉。而在打開設備的時候(調用open函數接口)申請中斷,則不同的設備驅動可以共享這些寶貴的中斷資源。

以下為中斷申請和釋放的部分以及中斷處理函數。

/* 中斷處理函數,其中irq為中斷號 */
    static irqreturn_t button_irq(int irq, void *dev_id, struct pt_regs *regs)
    {
        unsigned char ucKey = 0;
        disable_irqs(); /* 屏蔽中斷 */
        /* 延遲50毫秒, 屏蔽按鍵毛刺 */
        udelay(50000);
        ucKey = button_scan(irq); /* 掃描按鍵,獲得進行操作的按鍵的ID */
        if ((ucKey >= 1) && (ucKey <= 16))
        {
            /* 如果緩沖區已滿, 則不添加 */
            if (((key_buffer.head + 1) & (MAX_KEY_COUNT - 1)) != key_buffer.tail)
            {
                 spin_lock_irq(&buffer_lock);
                 key_buffer.jiffy[key_buffer.tail] = get_tick_count();
               key_buffer.tail ++;
               key_buffer.tail &= (MAX_KEY_COUNT -1);
                 spin_unlock_irq(&buffer_lock);
             }
        }
        init_gpio(); /* 初始化GPIO端口,主要是為了恢復中斷端口配置 */
        enable_irqs(); /* 開啟中斷 */
        return IRQ_HANDLED;/* 2.6內核返回值一般是這個宏 */
    }
    /* 申請4個中斷 */
    static int request_irqs(void)
    {
        int ret, i, j;
        for (i = 0; i < MAX_COLUMN; i++)
    {
             ret = request_irq(key_info_matrix[i][0].irq_no, 
                      button_irq, SA_INTERRUPT, BUTTONS_DEVICE_NAME, NULL);
             if (ret < 0)
             {
                     for (j = 0; j < i; j++)
                     {
                         free_irq(key_info_matrix[j][0].irq_no, NULL); 
                     }
                     return -EFAULT;
             }
         }
         return 0;
    }
    /* 釋放中斷 */
    static __inline void free_irqs(void)
    {
        int i;
        for (i = 0; i < MAX_COLUMN; i++)
        {
            free_irq(key_info_matrix[i][0].irq_no, NULL);
        }
    }

中斷處理函數在每次中斷產生的時候會被調用,因此它的執行時間要盡可能得短。通常中斷處理函數只是簡單地喚醒等待資源的任務,而復雜且耗時的工作則讓這個任務去完成。中斷處理函數不能向用戶空間發送數據或者接收數據,不能做任何可能發生睡眠的操作,而且不能調用schedule()函數。

為了簡單起見,而且考慮到按鍵操作的時間比較長,在本實例中的中斷處理函數button_irq()里,通過調用睡眠函數來消除毛刺信號。讀者可以根據以上介紹的對中斷處理函數的要求改進該部分代碼。

按鍵掃描函數如下所示。首先根據中斷號確定操作按鍵所在行的位置,然后采用逐列掃描法終確定操作按鍵所在的位置。

/* 
    ** 進入中斷后, 掃描銨鍵碼 
    ** 返回: 按鍵碼(1-16), 0xff表示錯誤 
    */
    static __inline unsigned char button_scan(int irq)
    {
        unsigned char key_id = 0xff;
        unsigned char column = 0xff, row = 0xff;
        s3c2410_gpio_cfgpin(S3C2410_GPF0, S3C2410_GPF0_INP); /* GPF0 */
       s3c2410_gpio_cfgpin(S3C2410_GPF2, S3C2410_GPF2_INP); /* GPF2 */
       s3c2410_gpio_cfgpin(S3C2410_GPG3, S3C2410_GPG3_INP); /* GPG3 */
       s3c2410_gpio_cfgpin(S3C2410_GPG11, S3C2410_GPG11_INP); /* GPG11 */
        switch (irq)
        { /* 根據irq值確定操作按鍵所在行的位置*/
            case IRQ_EINT0:
            {
                  column = 0;
            }
            break;
            case IRQ_EINT2:
            {
                  column = 1;
            }
            break;
            case IRQ_EINT11:
            {
                  column = 2;
            }
            break;
            case IRQ_EINT19:
            {
                  column = 3;
            }
            break;
        } 
        if (column != 0xff)
        { /* 開始逐列掃描, 掃描第0列 */
             s3c2410_gpio_setpin(S3C2410_GPE11, 0); /* 將KSCAN0置為低電平 */
             s3c2410_gpio_setpin(S3C2410_GPG6, 1);
             s3c2410_gpio_setpin(S3C2410_GPE13, 1);
             s3c2410_gpio_setpin(S3C2410_GPG2, 1);
         if(!s3c2410_gpio_getpin(key_info_matrix[column][0].irq_gpio_port))
             { /* 觀察對應的中斷線的輸入端口值 */
                  key_id = key_info_matrix[column][0].key_id;
                  return key_id;
             }
             /* 掃描第1列*/
             s3c2410_gpio_setpin(S3C2410_GPE11, 1);
             s3c2410_gpio_setpin(S3C2410_GPG6, 0); /* 將KSCAN1置為低電平 */
             s3c2410_gpio_setpin(S3C2410_GPE13, 1);
             s3c2410_gpio_setpin(S3C2410_GPG2, 1);
             if(!s3c2410_gpio_getpin(key_info_matrix[column][1].irq_gpio_port))
             {
                  key_id = key_info_matrix[column][1].key_id; 
                  return key_id;
             }
             /* 掃描第2列*/
             s3c2410_gpio_setpin(S3C2410_GPE11, 1);
             s3c2410_gpio_setpin(S3C2410_GPG6, 1);
             s3c2410_gpio_setpin(S3C2410_GPE13, 0); /* 將KSCAN2置為低電平 */
             s3c2410_gpio_setpin(S3C2410_GPG2, 1); 
             if(!s3c2410_gpio_getpin(key_info_matrix[column][2].irq_gpio_port))
             {
                  key_id = key_info_matrix[column][2].key_id;
                  return key_id;
             }
             /* 掃描第3列*/
             s3c2410_gpio_setpin(S3C2410_GPE11, 1);
             s3c2410_gpio_setpin(S3C2410_GPG6, 1);
             s3c2410_gpio_setpin(S3C2410_GPE13, 1);
             s3c2410_gpio_setpin(S3C2410_GPG2, 0); /* 將KSCAN3置為低電平 */
             if(!s3c2410_gpio_getpin(key_info_matrix[column][3].irq_gpio_port))
             {
                   key_id = key_info_matrix[column][3].key_id;
                   return key_id;
             }
         } 
         return key_id;
     }

以下是read函數接口的實現。首先在按鍵緩沖中刪除已經過時的按鍵操作信息,接下來,從按鍵緩沖中讀取一條信息(按鍵ID)并傳遞給用戶層。

/* 從緩沖刪除過時數據(5秒前的按鍵值) */
    static void remove_timeoutkey(void)
    {
        unsigned long tick;
        spin_lock_irq(&buffer_lock); /* 獲得一個自旋鎖 */
        while(key_buffer.head != key_buffer.tail)
        {
             tick = get_tick_count() - key_buffer.jiffy[key_buffer.head];
             if (tick < 5000) /* 5秒 */
             break;
             key_buffer.buf[key_buffer.head] = 0;
             key_buffer.jiffy[key_buffer.head] = 0;
             key_buffer.head ++;
             key_buffer.head &= (MAX_KEY_COUNT -1);
        }
        spin_unlock_irq(&buffer_lock); /* 釋放自旋鎖 */
    }
    /* 讀鍵盤 */
    static ssize_t button_read(struct file *filp, 
                            char *buffer, size_t count, loff_t *f_pos)
    {
         ssize_t ret = 0;
         remove_timeoutkey(); /* 刪除過時的按鍵操作信息 */
         spin_lock_irq(&buffer_lock);
         while((key_buffer.head != key_buffer.tail) && (((size_t)ret) < count))
         {
               put_user((char)(key_buffer.buf[key_buffer.head]), &buffer[ret]);
               key_buffer.buf[key_buffer.head] = 0;
               key_buffer.jiffy[key_buffer.head] = 0;
               key_buffer.head ++;
               key_buffer.head &= (MAX_KEY_COUNT -1);
               ret ++;
         }
         spin_unlock_irq(&buffer_lock);
         return ret;
    }

以上介紹了按鍵驅動程序中的主要內容。

 
發表評論
評論列表(網友評論僅供網友表達個人看法,并不表明本站同意其觀點或證實其描述)
色偷偷偷亚洲综合网另类,亚洲欧美另类在线观看,欧美午夜激情在线,久久久精品一区
主站蜘蛛池模板: 国产精品国产自产拍高清av水多| 国产第一区电影| 久久久人成影片一区二区三区| 91av在线播放| 国产精品无码专区在线观看| 91欧美视频网站| 一本色道久久88综合亚洲精品ⅰ | 欧美激情女人20p| 国产精品一区二区久久精品| 欧美日韩国产91| 亚洲欧美变态国产另类| 人九九综合九九宗合| 亚洲成人网av| 日本精品在线视频| 精品国产鲁一鲁一区二区张丽 | 欧美电影在线观看高清| 亚洲欧美激情视频| www.久久草.com| 国产一区二区精品丝袜| 欧美日韩中文在线| 国产精品美女久久久免费 | 亚洲影视中文字幕| 麻豆国产va免费精品高清在线| 2021国产精品视频| 亚洲人成网站在线播| 欧美精品激情在线观看| 日韩av中文字幕在线免费观看| 欧美日韩国产一中文字不卡| 国产在线视频一区| 精品国产乱码久久久久久婷婷| 亚洲自拍另类欧美丝袜| 日韩在线观看免费全| 成人黄色在线免费| 51视频国产精品一区二区| 欧美性猛交xxxx乱大交极品| 久久精品成人欧美大片| 亚洲午夜女主播在线直播| 日韩av综合中文字幕| 精品一区二区亚洲| 亚洲韩国欧洲国产日产av | 91欧美精品成人综合在线观看|