poll機(jī)制可實(shí)現(xiàn)有數(shù)據(jù)的時(shí)候就去讀,沒有數(shù)據(jù)的時(shí)候,如果超過規(guī)定一個(gè)時(shí)間,就表示超時(shí)時(shí)間。poll機(jī)制需要應(yīng)用程序主動(dòng)去讀,而異步通知并不需要,一旦設(shè)備就緒,則主動(dòng)通知應(yīng)用程序,應(yīng)用程序不需要主動(dòng)查詢?cè)O(shè)備狀態(tài),類似于中斷的概念,一個(gè)進(jìn)程收到一個(gè)信號(hào)與處理器收到一個(gè)中斷請(qǐng)求可以說(shuō)是一樣的。信號(hào)是異步的,一個(gè)進(jìn)程不必通過任何操作來(lái) 等待信號(hào)的到達(dá)。
在linux中,異步通知是使用信號(hào)來(lái)實(shí)現(xiàn)的,而在linux,大概有30種信號(hào),比如大家熟悉的ctrl+c的SIGINT信號(hào),進(jìn)程能夠忽略或者捕獲除過SIGSTOP和SIGKILL的全部信號(hào),當(dāng)信號(hào)背捕獲以后,有相應(yīng)的函數(shù)來(lái)處理它。
實(shí)現(xiàn)異步通知的四個(gè)要素:
一、應(yīng)用程序要實(shí)現(xiàn):注冊(cè)信號(hào)處理函數(shù),使用signal函數(shù);
二、誰(shuí)來(lái)發(fā)?驅(qū)動(dòng)來(lái)發(fā);
三、發(fā)給誰(shuí)?發(fā)給應(yīng)用程序,但應(yīng)用程序必須告訴驅(qū)動(dòng)PID;
四、怎么發(fā)?驅(qū)動(dòng)程序使用kill_fasync函數(shù);
問:應(yīng)該在驅(qū)動(dòng)的哪里調(diào)用kill_fasync函數(shù)?
答:kill_fasync函數(shù)的作用是,當(dāng)有數(shù)據(jù)時(shí)去通知應(yīng)用程序,理所當(dāng)然的應(yīng)該在用戶終端處理函數(shù)里調(diào)用。
問:file_operations需要添加什么函數(shù)指針成員嗎?
答:要的,需要添加fasync函數(shù)指針,要實(shí)現(xiàn)這個(gè)函數(shù)指針,幸運(yùn)的是,這個(gè)函數(shù)僅僅調(diào)用了fasync_helper函數(shù),而且這個(gè)函數(shù)是內(nèi)核幫我們實(shí)現(xiàn)好了,驅(qū)動(dòng)工程師不用修改,fasync_helper函數(shù)的作用是初始化/釋放fasync_struct
詳細(xì)請(qǐng)參考驅(qū)動(dòng)源碼
#include #include #include #include #include #include #include #include #include #include //class_create#include //S3C2410_GPF1//#include #include //#include #include //wait_event_interruptible#include //poll#include /* 定義并初始化等待隊(duì)列頭 */static DECLARE_WAIT_QUEUE_HEAD(button_waitq);static struct class *fifthdrv_class;static struct device *fifthdrv_device;static struct pin_desc { unsigned int pin; unsigned int key_val;};static struct pin_desc pins_desc[4] = { {S3C2410_GPF1, 0x01}, {S3C2410_GPF4, 0x02}, {S3C2410_GPF2, 0x03}, {S3C2410_GPF0, 0x04},};static int ev_press = 0;/* 鍵值: 按下時(shí), 0x01, 0x02, 0x03, 0x04 *//* 鍵值: 松開時(shí), 0x81, 0x82, 0x83, 0x84 */static unsigned char key_val;int major;static struct fasync_struct *button_fasync;/* 用戶中斷處理函數(shù) */static irqreturn_t buttons_irq(int irq, void *dev_id){ struct pin_desc *pindesc = (struct pin_desc *)dev_id; unsigned int pinval; pinval = s3c2410_gpio_getpin(pindesc->pin); if(pinval) { /* 松開 */ key_val = 0x80 | (pindesc->key_val); } else { /* 按下 */ key_val = pindesc->key_val; } ev_press = 1;/* 表示中斷已經(jīng)發(fā)生 */ wake_up_interruptible(&button_waitq); /* 喚醒休眠的進(jìn)程 */ /* 用kill_fasync函數(shù)告訴應(yīng)用程序,有數(shù)據(jù)可讀了 * button_fasync結(jié)構(gòu)體里包含了發(fā)給誰(shuí)(PID指定) * SIGIO表示要發(fā)送的信號(hào)類型 * POLL_IN表示發(fā)送的原因(有數(shù)據(jù)可讀了) */ kill_fasync(&button_fasync, SIGIO, POLL_IN); return IRQ_HANDLED;}static int fifth_drv_open(struct inode * inode, struct file * filp){ /* K1 ---- EINT1,K2 ---- EINT4,K3 ---- EINT2,K4 ---- EINT0 * 配置GPF1、GPF4、GPF2、GPF0為相應(yīng)的外部中斷引腳 * IRQT_BOTHEDGE應(yīng)該改為IRQ_TYPE_EDGE_BOTH */ request_irq(IRQ_EINT1, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K1",&pins_desc[0]); request_irq(IRQ_EINT4, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K2",&pins_desc[1]); request_irq(IRQ_EINT2, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K3",&pins_desc[2]); request_irq(IRQ_EINT0, buttons_irq, IRQ_TYPE_EDGE_BOTH, "K4",&pins_desc[3]); return 0;}static ssize_t fifth_drv_read(struct file *file, char __user *user, size_t size,loff_t *ppos){ if (size != 1) return -EINVAL; /* 當(dāng)沒有按鍵按下時(shí),休眠。 * 即ev_press = 0; * 當(dāng)有按鍵按下時(shí),發(fā)生中斷,在中斷處理函數(shù)會(huì)喚醒 * 即ev_press = 1; * 喚醒后,接著繼續(xù)將數(shù)據(jù)通過copy_to_user函數(shù)傳遞給應(yīng)用程序 */ wait_event_interruptible(button_waitq, ev_press); copy_to_user(user, &key_val, 1); /* 將ev_press清零 */ ev_press = 0; return 1;}static int fifth_drv_close(struct inode *inode, struct file *file){ free_irq(IRQ_EINT1,&pins_desc[0]); free_irq(IRQ_EINT4,&pins_desc[1]); free_irq(IRQ_EINT2,&pins_desc[2]); free_irq(IRQ_EINT0,&pins_desc[3]); return 0;}static unsigned int fifth_drv_poll(struct file *file, poll_table *wait){ unsigned int mask = 0; /* 該函數(shù),只是將進(jìn)程掛在button_waitq隊(duì)列上,而不是立即休眠 */ poll_wait(file, &button_waitq, wait); /* 當(dāng)沒有按鍵按下時(shí),即不會(huì)進(jìn)入按鍵中斷處理函數(shù),此時(shí)ev_press = 0 * 當(dāng)按鍵按下時(shí),就會(huì)進(jìn)入按鍵中斷處理函數(shù),此時(shí)ev_press被設(shè)置為1 */ if(ev_press) { mask |= POLLIN | POLLRDNORM; /* 表示有數(shù)據(jù)可讀 */ } /* 如果有按鍵按下時(shí),mask |= POLLIN | POLLRDNORM,否則mask = 0 */ return mask;}/* 當(dāng)應(yīng)用程序調(diào)用了fcntl(fd, F_SETFL, Oflags | FASYNC); * 則最終會(huì)調(diào)用驅(qū)動(dòng)的fasync函數(shù),在這里則是fifth_drv_fasync * fifth_drv_fasync最終又會(huì)調(diào)用到驅(qū)動(dòng)的fasync_helper函數(shù) * fasync_helper函數(shù)的作用是初始化/釋放fasync_struct */static int fifth_drv_fasync(int fd, struct file *filp, int on){ return fasync_helper(fd, filp, on, &button_fasync);}/* File operations struct for character device */static const struct file_operations fifth_drv_fops = { .owner = THIS_MODULE, .open = fifth_drv_open, .read = fifth_drv_read, .release = fifth_drv_close, .poll = fifth_drv_poll, .fasync = fifth_drv_fasync,};/* 驅(qū)動(dòng)入口函數(shù) */static int fifth_drv_init(void){ /* 主設(shè)備號(hào)設(shè)置為0表示由系統(tǒng)自動(dòng)分配主設(shè)備號(hào) */ major = register_chrdev(0, "fifth_drv", &fifth_drv_fops); /* 創(chuàng)建fifthdrv類 */ fifthdrv_class = class_create(THIS_MODULE, "fifthdrv"); /* 在fifthdrv類下創(chuàng)建buttons設(shè)備,供應(yīng)用程序打開設(shè)備*/ fifthdrv_device = device_create(fifthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); return 0;}/* 驅(qū)動(dòng)出口函數(shù) */static void fifth_drv_exit(void){ unregister_chrdev(major, "fifth_drv"); device_unregister(fifthdrv_device); //卸載類下的設(shè)備 class_destroy(fifthdrv_class); //卸載類}module_init(fifth_drv_init); //用于修飾入口函數(shù)module_exit(fifth_drv_exit); //用于修飾出口函數(shù)MODULE_AUTHOR("LWJ");MODULE_DESCRIPTION("Just for Demon");MODULE_LICENSE("GPL"); //遵循GPL協(xié)議
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
應(yīng)用測(cè)試程序源碼
#include #include #include #include #include //sleep#include #include #include int fd;void mysignal_fun(int signum){ unsigned char key_val; read(fd, &key_val, 1); printf("key_val = 0x%x ", key_val);}int main(int argc ,char *argv[]){ int flag; signal(SIGIO, mysignal_fun); fd = open("/dev/buttons", O_RDWR); if (fd < 0) { printf("open error "); } /* F_SETOWN: Set the process ID * 告訴內(nèi)核,發(fā)給誰(shuí) */ fcntl(fd, F_SETOWN, getpid()); /* F_GETFL :Read the file status flags * 讀出當(dāng)前文件的狀態(tài) */ flag = fcntl(fd, F_GETFL); /* F_SETFL: Set the file status flags to the value specified by arg * int fcntl(int fd, int cmd, long arg); * 修改當(dāng)前文件的狀態(tài),添加異步通知功能 */ fcntl(fd, F_SETFL, flag | FASYNC); while(1) { /* 為了測(cè)試,主函數(shù)里,什么也不做 */ sleep(1000); } return 0;}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
當(dāng)無(wú)按鍵按下時(shí),應(yīng)用測(cè)試程序一直在sleep,當(dāng)有按鍵按下時(shí),signal會(huì)被調(diào)用,最終會(huì)調(diào)用mysignal_fun,在此函數(shù)里read(fd, &key_val, 1);會(huì)去讀出按鍵值,這樣一來(lái),應(yīng)用程序就相當(dāng)于不用主動(dòng)去讀數(shù)據(jù)了,每當(dāng)驅(qū)動(dòng)里有數(shù)據(jù)時(shí),就會(huì)告訴應(yīng)用程序有數(shù)據(jù)了,此時(shí)read函數(shù)才會(huì)被調(diào)用。
總結(jié)
為了使設(shè)備支持異步通知機(jī)制,驅(qū)動(dòng)程序中涉及以下3項(xiàng)工作:
支持F_SETOWN命令,能在這個(gè)控制命令處理中設(shè)置filp->f_owner為對(duì)應(yīng)進(jìn)程ID。? 不過此項(xiàng)工作已由內(nèi)核完成,設(shè)備驅(qū)動(dòng)無(wú)須處理。
支持F_SETFL命令的處理,每當(dāng)FASYNC標(biāo)志改變時(shí),驅(qū)動(dòng)程序中的fasync()函數(shù)將得以執(zhí)行。驅(qū)動(dòng)中應(yīng)該實(shí)現(xiàn)fasync()函數(shù)。
在設(shè)備資源可獲得時(shí),調(diào)用kill_fasync()函數(shù)激發(fā)相應(yīng)的信號(hào)
應(yīng)用程序:
fcntl(fd, F_SETOWN, getpid()); // 告訴內(nèi)核,發(fā)給誰(shuí)Oflags = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, Oflags | FASYNC); // 改變fasync標(biāo)記,最終會(huì)調(diào)用到驅(qū)動(dòng)的faync > fasync_helper:初始化/釋放fasync_s
?
評(píng)論
查看更多