嵌入式Linux設(shè)備驅(qū)動(dòng)開發(fā)之:按鍵驅(qū)動(dòng)程序?qū)嵗?/h1>
本文引用地址:http://butianyuan.cn/article/257107.htm按鍵字符設(shè)備的file_operations結(jié)構(gòu)定義為:
staticstructfile_operationsbutton_fops=
{
.owner=THIS_MODULE,
.ioctl=button_ioctl,
.open=button_open,
.read=button_read,
.release=button_release,
};
以下為open和release函數(shù)接口的實(shí)現(xiàn)。
/*打開文件,申請(qǐng)中斷*/
staticintbutton_open(structinode*inode,structfile*filp)
{
intret=nonseekable_open(inode,filp);
if(ret0)
{
returnret;
}
init_gpio();/*相關(guān)GPIO端口的初始化*/
ret=request_irqs();/*申請(qǐng)4個(gè)中斷*/
if(ret0)
{
returnret;
}
init_keybuffer();/*初始化按鍵緩沖數(shù)據(jù)結(jié)構(gòu)*/
returnret;
}
/*關(guān)閉文件,屏蔽中斷*/
staticintbutton_release(structinode*inode,structfile*filp)
{
free_irqs();/*屏蔽中斷*/
return0;
}
在open函數(shù)接口中,進(jìn)行了GPIO端口的初始化、申請(qǐng)硬件中斷以及按鍵緩沖的初始化等工作。在以前的章節(jié)中提過,中斷端口是比較寶貴而且數(shù)量有限的資源。因此需要注意,最好要在第一次打開設(shè)備時(shí)申請(qǐng)(調(diào)用request_irq函數(shù))中斷端口,而不是在驅(qū)動(dòng)模塊加載的時(shí)候申請(qǐng)。如果已加載的設(shè)備驅(qū)動(dòng)占用而在一定時(shí)間段內(nèi)不使用某些中斷資源,則這些資源不會(huì)被其他驅(qū)動(dòng)所使用,只能白白浪費(fèi)掉。而在打開設(shè)備的時(shí)候(調(diào)用open函數(shù)接口)申請(qǐng)中斷,則不同的設(shè)備驅(qū)動(dòng)可以共享這些寶貴的中斷資源。
以下為中斷申請(qǐng)和釋放的部分以及中斷處理函數(shù)。
/*中斷處理函數(shù),其中irq為中斷號(hào)*/
staticirqreturn_tbutton_irq(intirq,void*dev_id,structpt_regs*regs)
{
unsignedcharucKey=0;
disable_irqs();/*屏蔽中斷*/
/*延遲50ms,屏蔽按鍵毛刺*/
udelay(50000);
ucKey=button_scan(irq);/*掃描按鍵,獲得進(jìn)行操作的按鍵的ID*/
if((ucKey>=1)(ucKey=16))
{
/*如果緩沖區(qū)已滿,則不添加*/
if(((key_buffer.head+1)(MAX_KEY_COUNT-1))!=key_buffer.tail)
{
spin_lock_irq(buffer_lock);
key_buffer.buf[key_buffer.tail]=ucKey;
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端口,主要是為了恢復(fù)中斷端口配置*/
enable_irqs();/*開啟中斷*/
returnIRQ_HANDLED;/*2.6內(nèi)核返回值一般是這個(gè)宏*/
}
/*申請(qǐng)4個(gè)中斷*/
staticintrequest_irqs(void)
{
intret,i,j;
for(i=0;iMAX_COLUMN;i++)
{
ret=request_irq(key_info_matrix[i][0].irq_no,
button_irq,SA_INTERRUPT,BUTTONS_DEVICE_NAME,NULL);
if(ret0)
{
for(j=0;ji;j++)
{
free_irq(key_info_matrix[j][0].irq_no,NULL);
}
return-EFAULT;
}
}
return0;
}
/*釋放中斷*/
static__inlinevoidfree_irqs(void)
{
inti;
for(i=0;iMAX_COLUMN;i++)
{
free_irq(key_info_matrix[i][0].irq_no,NULL);
}
}
中斷處理函數(shù)在每次中斷產(chǎn)生的時(shí)候會(huì)被調(diào)用,因此它的執(zhí)行時(shí)間要盡可能得短。通常中斷處理函數(shù)只是簡單地喚醒等待資源的任務(wù),而復(fù)雜且耗時(shí)的工作則讓這個(gè)任務(wù)去完成。中斷處理函數(shù)不能向用戶空間發(fā)送數(shù)據(jù)或者接收數(shù)據(jù),不能做任何可能發(fā)生睡眠的操作,而且不能調(diào)用schedule()函數(shù)。
為了簡單起見,而且考慮到按鍵操作的時(shí)間比較長,在本實(shí)例中的中斷處理函數(shù)button_irq()里,通過調(diào)用睡眠函數(shù)來消除毛刺信號(hào)。讀者可以根據(jù)以上介紹的對(duì)中斷處理函數(shù)的要求改進(jìn)該部分代碼。
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)
linux相關(guān)文章:linux教程
蜂鳴器相關(guān)文章:蜂鳴器原理
按鍵字符設(shè)備的file_operations結(jié)構(gòu)定義為:
staticstructfile_operationsbutton_fops=
{
.owner=THIS_MODULE,
.ioctl=button_ioctl,
.open=button_open,
.read=button_read,
.release=button_release,
};
以下為open和release函數(shù)接口的實(shí)現(xiàn)。
/*打開文件,申請(qǐng)中斷*/
staticintbutton_open(structinode*inode,structfile*filp)
{
intret=nonseekable_open(inode,filp);
if(ret0)
{
returnret;
}
init_gpio();/*相關(guān)GPIO端口的初始化*/
ret=request_irqs();/*申請(qǐng)4個(gè)中斷*/
if(ret0)
{
returnret;
}
init_keybuffer();/*初始化按鍵緩沖數(shù)據(jù)結(jié)構(gòu)*/
returnret;
}
/*關(guān)閉文件,屏蔽中斷*/
staticintbutton_release(structinode*inode,structfile*filp)
{
free_irqs();/*屏蔽中斷*/
return0;
}
在open函數(shù)接口中,進(jìn)行了GPIO端口的初始化、申請(qǐng)硬件中斷以及按鍵緩沖的初始化等工作。在以前的章節(jié)中提過,中斷端口是比較寶貴而且數(shù)量有限的資源。因此需要注意,最好要在第一次打開設(shè)備時(shí)申請(qǐng)(調(diào)用request_irq函數(shù))中斷端口,而不是在驅(qū)動(dòng)模塊加載的時(shí)候申請(qǐng)。如果已加載的設(shè)備驅(qū)動(dòng)占用而在一定時(shí)間段內(nèi)不使用某些中斷資源,則這些資源不會(huì)被其他驅(qū)動(dòng)所使用,只能白白浪費(fèi)掉。而在打開設(shè)備的時(shí)候(調(diào)用open函數(shù)接口)申請(qǐng)中斷,則不同的設(shè)備驅(qū)動(dòng)可以共享這些寶貴的中斷資源。
以下為中斷申請(qǐng)和釋放的部分以及中斷處理函數(shù)。
/*中斷處理函數(shù),其中irq為中斷號(hào)*/
staticirqreturn_tbutton_irq(intirq,void*dev_id,structpt_regs*regs)
{
unsignedcharucKey=0;
disable_irqs();/*屏蔽中斷*/
/*延遲50ms,屏蔽按鍵毛刺*/
udelay(50000);
ucKey=button_scan(irq);/*掃描按鍵,獲得進(jìn)行操作的按鍵的ID*/
if((ucKey>=1)(ucKey=16))
{
/*如果緩沖區(qū)已滿,則不添加*/
if(((key_buffer.head+1)(MAX_KEY_COUNT-1))!=key_buffer.tail)
{
spin_lock_irq(buffer_lock);
key_buffer.buf[key_buffer.tail]=ucKey;
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端口,主要是為了恢復(fù)中斷端口配置*/
enable_irqs();/*開啟中斷*/
returnIRQ_HANDLED;/*2.6內(nèi)核返回值一般是這個(gè)宏*/
}
/*申請(qǐng)4個(gè)中斷*/
staticintrequest_irqs(void)
{
intret,i,j;
for(i=0;iMAX_COLUMN;i++)
{
ret=request_irq(key_info_matrix[i][0].irq_no,
button_irq,SA_INTERRUPT,BUTTONS_DEVICE_NAME,NULL);
if(ret0)
{
for(j=0;ji;j++)
{
free_irq(key_info_matrix[j][0].irq_no,NULL);
}
return-EFAULT;
}
}
return0;
}
/*釋放中斷*/
static__inlinevoidfree_irqs(void)
{
inti;
for(i=0;iMAX_COLUMN;i++)
{
free_irq(key_info_matrix[i][0].irq_no,NULL);
}
}
中斷處理函數(shù)在每次中斷產(chǎn)生的時(shí)候會(huì)被調(diào)用,因此它的執(zhí)行時(shí)間要盡可能得短。通常中斷處理函數(shù)只是簡單地喚醒等待資源的任務(wù),而復(fù)雜且耗時(shí)的工作則讓這個(gè)任務(wù)去完成。中斷處理函數(shù)不能向用戶空間發(fā)送數(shù)據(jù)或者接收數(shù)據(jù),不能做任何可能發(fā)生睡眠的操作,而且不能調(diào)用schedule()函數(shù)。
為了簡單起見,而且考慮到按鍵操作的時(shí)間比較長,在本實(shí)例中的中斷處理函數(shù)button_irq()里,通過調(diào)用睡眠函數(shù)來消除毛刺信號(hào)。讀者可以根據(jù)以上介紹的對(duì)中斷處理函數(shù)的要求改進(jìn)該部分代碼。
linux操作系統(tǒng)文章專題:linux操作系統(tǒng)詳解(linux不再難懂)linux相關(guān)文章:linux教程
蜂鳴器相關(guān)文章:蜂鳴器原理
評(píng)論