嵌入式Linux驅(qū)動(dòng)開(kāi)發(fā)(六)——異步通知

之前楚昭,獲取按鍵值的方式都是應(yīng)用程序主動(dòng)去查詢冈涧,無(wú)論是 poll 機(jī)制還是阻塞的 read茂附,那么,另外一種思路就是讓驅(qū)動(dòng)程序來(lái)通知應(yīng)用程序督弓,而不讓他自己去查詢营曼,那么這樣做的好處就是不會(huì)干擾到應(yīng)用程序的工作,只需要等具體的事情發(fā)生了再去處理即可愚隧。

  • 應(yīng)用程序從硬件獲取信息主要有三種方式:
    • 死循環(huán)read:耗費(fèi)資源嚴(yán)重蒂阱,無(wú)意義
    • read + wait_event_interruptible
    • poll + read

關(guān)于異步通知,會(huì)用到信號(hào)的概念狂塘,可以參考我之前的文章录煤,來(lái)看如何發(fā)送和接收信號(hào)的。
->《Linux 信號(hào)(signal)》

那么發(fā)送和接收信號(hào)荞胡,有幾個(gè)要素必須成立妈踊,在這里簡(jiǎn)單歸納:

  1. 接受者注冊(cè)信號(hào)處理函數(shù) (等于signal 或 sigaction 函數(shù))
  2. 接收者需要告訴自己的 PID (等于 ps 命令來(lái)獲取 pid)
  3. 發(fā)送者需要知道接受者是誰(shuí)(kill 命令中輸入的 pid )
  4. 發(fā)送者要發(fā)送信號(hào)(kill 命令發(fā)送信號(hào)或者 kill 函數(shù)、sigqueue 函數(shù)發(fā)送信號(hào))

了解了以上幾個(gè)要點(diǎn)泪漂,現(xiàn)在可以理一下具體的思路了廊营。
目標(biāo):按下按鍵時(shí),驅(qū)動(dòng)程序通過(guò)發(fā)送信號(hào)的方式通知應(yīng)用程序狀態(tài)發(fā)生了變化窖梁,可以去讀取相應(yīng)的數(shù)據(jù)了赘风。
那么應(yīng)用程序是接收者,驅(qū)動(dòng)程序是發(fā)送者纵刘,他們分別都需要做哪些工作呢邀窃?

  • 應(yīng)用程序作為 接收者 需要:
    將自己的 PID 告訴驅(qū)動(dòng)程序,并且注冊(cè)某種信號(hào)的捕捉函數(shù)
  • 驅(qū)動(dòng)程序作為 發(fā)送者 需要:
    將信號(hào)發(fā)送到應(yīng)用程序(PID),發(fā)送信號(hào)

根據(jù)信號(hào)的開(kāi)發(fā)經(jīng)驗(yàn)瞬捕,我們知道對(duì)于信號(hào)的發(fā)送函數(shù)無(wú)論是 kill 還是 sigqueue 函數(shù)都是實(shí)際都是綜合發(fā)送者的兩個(gè)要素的鞍历,通過(guò)這個(gè)函數(shù)既可以告訴內(nèi)核接收者的 pid,調(diào)用的同時(shí)也發(fā)送了具體的信號(hào)肪虎。那么驅(qū)動(dòng)程序是不是也是通過(guò)這樣的方式來(lái)發(fā)送信號(hào)呢劣砍?
發(fā)送的幾個(gè)要素肯定都要完成,但是其中問(wèn)題就出現(xiàn)在扇救,發(fā)送者需要知道接受者是誰(shuí)刑枝,往往驅(qū)動(dòng)程序是先于應(yīng)用程序完成開(kāi)發(fā)的,那么迅腔,在獲取應(yīng)用程序的 PID 環(huán)節(jié)肯定需要一套應(yīng)用程序向驅(qū)動(dòng)程序注冊(cè)的機(jī)制装畅。

驅(qū)動(dòng)程序發(fā)送信號(hào)的具體流程如下:

  1. 定義一個(gè)全局靜態(tài)變量指針static struct fasync_struct *xxx_async_queue
  2. struct file_operations結(jié)構(gòu)體中,注冊(cè)fasync成員沧烈,他的函數(shù)指針類型為:int (*fasync) (int, struct file *, int);掠兄,定義該函數(shù)
  3. 在 fasync 函數(shù)中,使用int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)函數(shù)對(duì)全局靜態(tài)的變量進(jìn)行初始化锌雀,以上的步驟就是為了方便應(yīng)用程序向驅(qū)動(dòng)程序注冊(cè) PID 的
  4. 使用函數(shù)void kill_fasync(struct fasync_struct **fp, int sig, int band)在需要發(fā)送信號(hào)的地方進(jìn)行調(diào)用蚂夕,調(diào)用時(shí),指定了發(fā)送信號(hào)的類型腋逆,一般驅(qū)動(dòng)程序常用的信號(hào)類型是 SIGIO婿牍,bind 是 POLL_IN 代表,應(yīng)用程序可以讀取數(shù)據(jù)了惩歉。

那么應(yīng)用程序牍汹,想要接受驅(qū)動(dòng)程序發(fā)送的信號(hào),需要做以下的工作:

  1. signal(SIGIO, signal_fun);:注冊(cè)新號(hào)捕捉函數(shù)
  2. fcntl(fd, F_SETOWN, getpid());:設(shè)置文件描述符 fd 接收進(jìn)程或者進(jìn)程組接收 SIGIO 或 SIGURG 信號(hào)柬泽。
  3. oflags = fcntl(fd, F_GETFL);//獲取文件描述符的 flag
  4. fcntl(fd, F_SETFL, oflags | FASYNC);:將文件描述符設(shè)置為FASYNC模式

ps:發(fā)送和接收信號(hào)驅(qū)動(dòng)程序和應(yīng)用程序的流程已完成了行施,那么系統(tǒng)幫我們完成了一件事璧榄,就是讓驅(qū)動(dòng)程序知道應(yīng)該把信號(hào)發(fā)送到哪個(gè)PID,實(shí)際這個(gè)階段是內(nèi)核通過(guò)設(shè)置結(jié)構(gòu)體中的變量來(lái)完成的:fasync_struct->fa_file->f_owner->pid,這一步內(nèi)核完成了形娇,無(wú)需驅(qū)動(dòng)程序來(lái)完成了表制,只需要調(diào)用fasync_helper函數(shù)初始化即可撩炊。

那么放仗,Show me the code!
驅(qū)動(dòng)程序:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/irq.h>
#include <asm/io.h>
#include <asm/arch/regs-gpio.h>
#include <asm/hardware.h>
#include <asm/irq.h>

#include <asm/signal.h>


#define EINT_PIN_COUNT 4

static const char* dev_name = "fasync_eint";
static volatile unsigned int major = 0;

static struct class* fasync_class;
static struct class_device* fasync_class_device;

struct pin_desc
{
    unsigned int pin;
    unsigned int value;
};

//%kernel%\include\asm-arm\arch\irqs.h
//#define IRQ_EINT0      S3C2410_IRQ(0)     /* 16 */
//中斷號(hào)數(shù)組
static const int eints[EINT_PIN_COUNT] =
{
    IRQ_EINT0,
    IRQ_EINT2,
    IRQ_EINT11,
    IRQ_EINT19
};

static struct pin_desc pins[4] =
{
    {S3C2410_GPF0,  0x1},
    {S3C2410_GPF2,  0x2},
    {S3C2410_GPG3,  0x3},
    {S3C2410_GPG11, 0x4},
};

unsigned int status = 0;
unsigned char value = 0;
static struct fasync_struct * fs;
static irqreturn_t irq_handler(int irq, void *dev_id)
{
    struct pin_desc* desc = (struct pin_desc*) dev_id;
    status = s3c2410_gpio_getpin(desc->pin);
    if(status)
        value = desc->value | 0x80;
    else
        value = desc->value;
    
    //void kill_fasync(struct fasync_struct **fp, int sig, int band)
    kill_fasync(&fs, SIGIO, POLL_IN);
    
    return 0;
}


static ssize_t fasync_read (struct file *file, char __user *buff, size_t size, loff_t *ppos)
{
    copy_to_user(buff, &value, 1);
    
    return 0;
}



static int fasync_open (struct inode *inode, struct file *file)
{
    int i;
    for(i = 0; i < EINT_PIN_COUNT; ++i){
        request_irq(eints[i], irq_handler, IRQT_BOTHEDGE, dev_name, &pins[i]);
    }
    printk("interrupt register\n");

    return 0;
}


int fasync_fasync (int fd, struct file * filp, int on)
{
    //int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)
    fasync_helper(fd, filp, on, &fs);
    return 0;
}

static int fasync_release (struct inode *inode, struct file *file)
{
    //void free_irq(unsigned int irq, void *dev_id)
    int i = 0;
    for(;i < EINT_PIN_COUNT; ++i){
        free_irq(eints[i], &pins[i]);
    }
    
    printk("button released\n");
    return 0;
}

struct file_operations fasync_fops = 
{
    .owner = THIS_MODULE,
    .open = fasync_open,
    .read = fasync_read,
    .fasync = fasync_fasync,
    .release = fasync_release,
};

static int __init fasync_init(void)
{
    major = register_chrdev(major, dev_name, &fasync_fops);
    fasync_class = class_create(THIS_MODULE, dev_name);
    fasync_class_device = class_device_create(fasync_class, NULL, MKDEV(major, 0), NULL, dev_name);
    printk("init\n");
    return 0;
}

static void __exit fasync_exit(void)
{
    unregister_chrdev(major, dev_name);
    class_device_unregister(fasync_class_device);
    class_destroy(fasync_class);
    printk("exit\n");
}

module_init(fasync_init);
module_exit(fasync_exit);

MODULE_AUTHOR("Ethan Lee <4128127@qq.com>");
MODULE_LICENSE("GPL");

應(yīng)用程序:

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>

void signal_fun(int signum);

int fd;

int main()
{
    fd = open("/dev/fasync_eint", O_RDWR);
    int oflags;
    if(fd < 0)
    {
        printf("open error\n");
        return -1;
    }
    
    signal(SIGIO, signal_fun);//注冊(cè)捕捉函數(shù)
    
    fcntl(fd, F_SETOWN, getpid());//設(shè)置文件描述符 fd 接收進(jìn)程或者進(jìn)程組接收 SIGIO 或 SIGURG 信號(hào)包警。
    oflags = fcntl(fd, F_GETFL);//獲取 flag
    fcntl(fd, F_SETFL, oflags | FASYNC);//原來(lái) flag或上 FASYNC撵摆,并設(shè)置 flag
    //將 fd 設(shè)置為 FASYNC 方式打開(kāi)
    //該設(shè)置,會(huì)觸發(fā)驅(qū)動(dòng)程序中`file_operations`中注冊(cè)的 fasync 函數(shù)害晦。
    //驅(qū)動(dòng)程序中特铝,該函數(shù)調(diào)用了 fasync_helper 函數(shù)來(lái)初始化了 fasync_struct 結(jié)構(gòu)體。
    //該結(jié)構(gòu)體中維護(hù)了要接收信號(hào)的進(jìn)程 PID(fasync_struct->fa_file->f_owner->pid)
    
    
    while(1)
    {
        sleep(1000);
    }
    
    return 0;
}
void signal_fun(int signum)
{
    unsigned char key_val;
    read(fd, &key_val, 1);
    printf("key_val: 0x%x\n", key_val);
}

那么現(xiàn)在基本上完成了字符設(shè)備的驅(qū)動(dòng)程序的編寫(xiě),還存在一些小問(wèn)題鲫剿,在下次來(lái)解決吧鳄逾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市灵莲,隨后出現(xiàn)的幾起案子雕凹,更是在濱河造成了極大的恐慌,老刑警劉巖政冻,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件枚抵,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡明场,警方通過(guò)查閱死者的電腦和手機(jī)俄精,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)榕堰,“玉大人,你說(shuō)我怎么就攤上這事嫌套∧媛牛” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵踱讨,是天一觀的道長(zhǎng)魏蔗。 經(jīng)常有香客問(wèn)我,道長(zhǎng)痹筛,這世上最難降的妖魔是什么莺治? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮帚稠,結(jié)果婚禮上谣旁,老公的妹妹穿的比我還像新娘。我一直安慰自己滋早,他們只是感情好榄审,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著杆麸,像睡著了一般搁进。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上昔头,一...
    開(kāi)封第一講書(shū)人閱讀 51,115評(píng)論 1 296
  • 那天饼问,我揣著相機(jī)與錄音,去河邊找鬼揭斧。 笑死莱革,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播驮吱,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼茧妒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了左冬?” 一聲冷哼從身側(cè)響起桐筏,我...
    開(kāi)封第一講書(shū)人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拇砰,沒(méi)想到半個(gè)月后梅忌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡除破,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年牧氮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瑰枫。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡踱葛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出光坝,到底是詐尸還是另有隱情尸诽,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布盯另,位于F島的核電站性含,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏鸳惯。R本人自食惡果不足惜商蕴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望芝发。 院中可真熱鬧绪商,春花似錦、人聲如沸辅鲸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瓢湃。三九已至理张,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绵患,已是汗流浹背雾叭。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留落蝙,地道東北人织狐。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓暂幼,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親移迫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子旺嬉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 本文摘抄自linux基礎(chǔ)編程 IO概念 Linux的內(nèi)核將所有外部設(shè)備都可以看做一個(gè)文件來(lái)操作。那么我們對(duì)與外部設(shè)...
    VD2012閱讀 1,021評(píng)論 0 2
  • 串口操作 串口操作需要的頭文件 #include /*標(biāo)準(zhǔn)輸入輸出定義*/ #include /*標(biāo)準(zhǔn)函數(shù)庫(kù)定...
    旅行家John閱讀 1,316評(píng)論 0 3
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理厨埋,服務(wù)發(fā)現(xiàn)邪媳,斷路器,智...
    卡卡羅2017閱讀 134,651評(píng)論 18 139
  • 又來(lái)到了一個(gè)老生常談的問(wèn)題荡陷,應(yīng)用層軟件開(kāi)發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢雨效? 今天就這個(gè)問(wèn)題開(kāi)始,來(lái)談?wù)劜?..
    tangsl閱讀 4,122評(píng)論 0 23
  • 《海上鋼琴師》里,曾有一段很經(jīng)典的關(guān)于“選擇”的論述唉地,拒絕下船的主角1900對(duì)世界上唯一知曉他存在的朋友Max說(shuō)“...
    taony閱讀 685評(píng)論 0 1