歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Linux基礎:在驅動中增加異步通知的例子

異步通知的意思是:一旦設備就緒,則主動通知應用程序,這樣應用程序就根本不需要查詢設備的狀態,

這一點非常類似於硬件上的“中斷”的概念,比較准確的稱謂是“信號驅動的異步I/O”。信號是在軟件層次上對

中斷機制的一種模擬,在原理上一個進程接收到一個信號與處理器接收到一個中斷請求是一樣的。

1>在把驅動從2.6.32 移植到2.6.36時 報錯

/home/kernel_test/globalfifo/globalfifo.c:240:2: error: unknown field 'ioctl' specified in initializer

才發現2.6.36的file_operations結構發生了重大變化。(但基本的思想還是不變的)

取消了原有的ioctl成員,添加來新的成員(變化部分在下面源碼中用綠色字體)
  1.         long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
  2.         long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

2>/home/kernel_test/globalfifo/globalfifo.c:245:2: warning: initialization from incompatible pointer type

出現此種warnning 的原因  “不兼容的指針類型初始化”

是你定義的函數類型與接口函數的類型不一樣如 把 把返回值 long 定義成了 int

要看清差異
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

少寫const 也會引起 warning 因為在這裡const所起的作用是 避免函數使用指針去改變了傳進來的值


以下是增加(紅色字體)異步通知後的globalfifo 的驅動程序:

  1 /*
  2  * a globalfifo driver as example of char device drivers
  3  * This example is to introduce poll, blocking and non-blocking access
  4  *
  5  *The initial developer of the original code is Baohua Song
  6  *<[email protected]>. All Rights Reserved
  7  *
  8  * 1>只當FIFO 中有數據時(有進程把數據寫到這個 FIFO而且沒有被 讀進程 讀空)
  9  *   讀進程才能把數據讀出,讀出後數據 從 FIFO 中拿掉
 10  * 2>只有當FIFO 非滿時(即還有空間未被讀寫或滿後被讀進程讀出了數據)
 11  *   寫進程才能往裡面寫數據,
 12  * 這樣 讀喚醒寫 寫喚醒讀
 13  */
 14
 15 #include<linux/module.h>
 16 #include<linux/types.h>
 17 #include<linux/fs.h>  /*異步通知機制 fasync*/
 18 #include<linux/errno.h>
 19 #include<linux/mm.h>
 20 #include<linux/sched.h>
 21 #include<linux/init.h>
 22 #include<linux/cdev.h>
 23 #include<asm/io.h>
 24 #include<asm/system.h>
 25 #include<asm/uaccess.h>
 26 #include<linux/poll.h>
 27 #include <linux/ioctl.h>
 28
 29 /*不加此頭文件在linux-2.6.36會報錯但在linux-2.6.32.2不會*/
 30 /*使用的是arm-linux-gcc-4.5.1編譯器*/
 31 #include<linux/slab.h>
 32
 33 #define DEBUG
 34
 35 #define GLOBALFIFO_SIZE  10             /*全局fifo最大10字節 方便測試寫滿*/
 36 #define FIFO_CLEAR 0X1                  /*清0全局內存的長度*/
 37 #define GLOBALFIFO_MAJOR 249            /*預設的globalfifo 的主設備號*/
 38
 39 static int globalfifo_major = GLOBALFIFO_MAJOR;
 40
 41 /*globalfifo設備結構體*/
 42 struct globalfifo_dev{
 43     struct cdev cdev;                   /*cdev結構體*/
 44     unsigned int current_len;           /*fifo有效數據長度*/
 45     unsigned char mem[GLOBALFIFO_SIZE];  /*全局內存*/
 46     struct semaphore sem;               /*並發控制用的信號量*/
 47     wait_queue_head_t r_wait;           /*阻塞讀用的等待隊列 內核 雙向 循環     鏈表 都可以 為頭*/
 48     wait_queue_head_t w_wait;           /*阻塞寫用的等待隊列頭*/
 49     struct fasync_struct *async_queue; /*異步結構體指針,用於讀*/
 50 };
 51
 52 struct globalfifo_dev *globalfifo_devp; /*設備結構體指針*/
 53
 54 /*增加支持異步通知的函數 在release 函數中調用 */
 55 static int globalfifo_fasync(int fd, struct file *filp, int mode)
 56 {

 57    struct globalfifo_dev *dev = filp->private_data;

 58

 59     /*將文件從異步通知列表(相關進程列表)中刪除*/

 60     return fasync_helper(fd, filp, mode, &dev->async_queue);
 61 }
 62
 63 /*globalfifo讀函數*/
 64 static ssize_t globalfifo_read(struct file *filp, char __user *buf, size_t c    ount, loff_t *ppos)
 65 {
 66     int ret;
 67     struct globalfifo_dev *dev = filp->private_data;
 68     DECLARE_WAITQUEUE(wait, current);
 69
 70     down(&dev->sem);                     /*獲得信號量*/
 71     add_wait_queue(&dev->r_wait, &wait); /*加入讀等待隊列頭 到內核*/
 72
 73     /*等待FIFO 非空*/
 74     if(dev->current_len == 0){
 75         if(filp->f_flags & O_NONBLOCK){   /*如果進程為 非阻塞打開 設備文件*/
 76             ret = -EAGAIN;
 77             goto out;
 78         }
 79         __set_current_state(TASK_INTERRUPTIBLE); /*改變進程狀態為睡眠*/
 80         up(&dev->sem);                           /*釋放信號量*/
 81
 82         schedule();                              /*調度其他進程執行*/
 83         if(signal_pending(current)){
 84                                                 /*如果是因為信號喚醒*/
 85             ret = -ERESTARTSYS;
 86             goto out2;
 87         }
 88         down(&dev->sem);
 89     }
 90
 91     /*拷貝到用戶空間*/
 92     if(count > dev->current_len)
 93         count = dev->current_len;
 94     if(copy_to_user(buf, dev->mem, count)){
 95         ret = -EFAULT;
 96         goto out;
 97     }else{
 98         memcpy(dev->mem, dev->mem + count, dev->current_len - count);/*fifo>    數據前移*/
 99         dev->current_len -= count; /*有效數據長度減少*/
100         printk(KERN_INFO"read %d bytes(s),current_len:%d\n",count, dev->curr    ent_len);
101
102         wake_up_interruptible(&dev->w_wait); /*喚醒寫等待隊列*/
103         ret = count;
104     }
105 out:
106     up(&dev->sem); /*釋放信號量*/
107 out2:
108     remove_wait_queue(&dev->w_wait, &wait); /*從屬的等待隊列頭移除*/
109     set_current_state(TASK_RUNNING);
110     return ret;
111 }
112
113 /*globalfifo 寫操作*/
114 static ssize_t globalfifo_write(struct file *filp, const char __user *buf, s    ize_t count, loff_t *ppos)
115 {
116     struct globalfifo_dev *dev = filp->private_data;
117     int ret;
118     DECLARE_WAITQUEUE(wait, current);    /*定義等待隊列*/
119
120     down(&dev->sem);                     /*獲得信號量*/
121     add_wait_queue(&dev->w_wait, &wait); /*進入寫等待隊列頭*/
122
123     /*等待FIFO非滿*/
124     if(dev->current_len == GLOBALFIFO_SIZE){
125         if(filp->f_flags & O_NONBLOCK){   /*如果進程非阻塞打開的文件*/
126             ret = -EAGAIN;
127             goto out;
128         }
129
130         __set_current_state(TASK_INTERRUPTIBLE); /*改變進程狀態為睡眠*/
131         up(&dev->sem);                     /*釋放信號量*/
132
133         schedule();                         /*調度其他進程執行*/
134         if(signal_pending(current)){
135                                             /*如果是因為信號喚醒*/
136             ret = -ERESTARTSYS;
137             goto out2;
138         }
139         down(&dev->sem);                    /*獲得信號量*/
140     }
141
142     /*從用戶空間拷貝數據到內核空間*/
143     if(count > GLOBALFIFO_SIZE - dev->current_len){
144         /*如果要拷貝的數據大於 剩余有效內存長度
145          *則 只拷貝最大 能裝下的長度
146          */
147         count = GLOBALFIFO_SIZE - dev->current_len;
148     }
149     if(copy_from_user(dev->mem + dev->current_len, buf, count)){
150         ret = -EFAULT;
151         goto out;
152     }else {
153         dev->current_len += count;
154         printk(KERN_INFO"written %d bytes(s), current_len: %d\n",count, dev-    >current_len);
155
156         wake_up_interruptible(&dev->r_wait); /*喚醒讀等待隊列*/
157
158         /*產生異步讀信號通知相關進程 把要發送的SIGIO 信號發送出去*/
159         if(dev->async_queue){
160             kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
161 #ifdef DEBUG
162             printk("<0>%s kill SIGIO\n", __func__);
163 #endif
164         }
165         ret = count;
166     }
167     out:
168         up(&dev->sem); /*釋放信號量*/
169     out2:
170         remove_wait_queue(&dev->w_wait, &wait); /*從附屬的等待隊列頭移除*/
171         set_current_state(TASK_RUNNING);
172         return ret;
173 }
174
175
176 /*ioctl 設備控制函數*/
177 //static int globalfifo_ioctl(struct inode *inodep, struct file *filp, unsig    ned int cmd, unsigned long arg)
178 static long globalfifo_ioctl(struct file *filp, unsigned int cmd, unsigned l    ong arg)
179 {
180     struct globalfifo_dev *dev = filp->private_data;/*獲得設備結構體指針*/
181
182     switch(cmd){
183         case FIFO_CLEAR:
184             down(&dev->sem);                        /*獲得信號量*/
185             dev->current_len = 0;
186             memset(dev->mem, 0, GLOBALFIFO_SIZE);
187             up(&dev->sem);                          /*釋放信號量*/
188
189             printk(KERN_INFO"globalfifo is set to zero\n");
190             break;
191
192         default:
193             return -EINVAL;
194     }
195     return 0;
196 }
197
198 /*在驅動中的增加輪詢操作*/
199 static unsigned int globalfifo_poll(struct file *filp, poll_table *wait)
200 {
201     unsigned int mask = 0;
202     struct globalfifo_dev *dev = filp->private_data;/*獲得設備結構體指針*/
203
204     down(&dev->sem);
205     poll_wait(filp, &dev->r_wait, wait);
206     poll_wait(filp, &dev->w_wait, wait);
207
208     /*fifo非空*/
209     if(dev->current_len != 0){
210         mask |= POLLIN | POLLRDNORM; /*標示數據可以獲得*/
211     }
212
213     /*fifo 非滿*/
214     if(dev->current_len != GLOBALFIFO_SIZE){
215         mask |= POLLOUT | POLLWRNORM ; /*標示數據可以寫入*/
216     }
217
218     up(&dev->sem);
219     return mask; /*返回驅動是否可讀 或可寫的 狀態*/
220 }
221
222 /*文件打開函數*/
223 int globalfifo_open(struct inode *inode, struct file *filp)
224 {
225     /**/
226     filp->private_data = globalfifo_devp;
227     return 0;
228 }
229
230 /*文件釋放函數*/
231 int globalfifo_release(struct inode *inode, struct file *filp)
232 {
233     /*將文件從異步通知列表中刪除*/
234     globalfifo_fasync(-1, filp, 0);
235     return 0;
236 }
237
238 /*文件操作結構體*/
239 static const struct file_operations globalfifo_fops = {
240     .owner = THIS_MODULE,
241     .read = globalfifo_read,
242     .write = globalfifo_write,
243     //.ioctl = globalfifo_ioctl,
244     .unlocked_ioctl = globalfifo_ioctl,
245     .poll = globalfifo_poll,
246     .fasync = globalfifo_fasync, /*不要完了在這裡也要加上 與內核聯系的接口*/
247     .open = globalfifo_open,
248     .release = globalfifo_release,
249 };
250
251 /*初始化並注冊cdev*/
252 static void globalfifo_setup_cdev(struct globalfifo_dev *dev, int index)
253 {
254     int err, devno = MKDEV(globalfifo_major, index);
255
256     cdev_init(&dev->cdev, &globalfifo_fops);
257     dev->cdev.owner = THIS_MODULE;
258     err = cdev_add(&dev->cdev, devno, 1);
259     if(err)
260         printk(KERN_NOTICE "Error %d adding LED %d", err, index);
261 }
262
263 /*設備驅動模塊加載函數*/
264 int globalfifo_init(void)
265 {
266     int ret;
267     dev_t devno = MKDEV(globalfifo_major, 0);
268
269     /*申請設備號*/
270     if(globalfifo_major)
271         ret = register_chrdev_region(devno, 1, "globalfifo");
272     else{/*動態申請設備號*/
273         ret = alloc_chrdev_region(&devno, 0, 1, "globalfifo");
274         globalfifo_major = MAJOR(devno);
275     }
276
277     if(ret < 0)
278         return ret;
279
280     /*動態申請設備結構體的內存*/
281     globalfifo_devp = kmalloc(sizeof(struct globalfifo_dev), GFP_KERNEL);
282     if(!globalfifo_devp){
283         ret = - ENOMEM;
284 goto fail_malloc;
285     }
286
287     memset(globalfifo_devp, 0, sizeof(struct globalfifo_dev));
288
289     globalfifo_setup_cdev(globalfifo_devp, 0);
290
291     init_MUTEX(&globalfifo_devp->sem);              /*初始化信號量*/
292     init_waitqueue_head(&globalfifo_devp->r_wait);  /*初始化讀等待隊列頭*/
293     init_waitqueue_head(&globalfifo_devp->w_wait);  /*初始化寫等待隊列頭*/
294
295     return 0;
296
297 fail_malloc: unregister_chrdev_region(devno, 1);
298              return ret;
299 }
300
301 void globalfifo_exit(void)
302 {
303     cdev_del(&globalfifo_devp->cdev); /*注銷cdev*/
304     kfree(globalfifo_devp); /*釋放設備結構體內存*/
305     unregister_chrdev_region(MKDEV(globalfifo_major, 0), 1); /*釋放設備號*/
306 }
307
308 MODULE_AUTHOR("Song Baohua");
309 MODULE_LICENSE("Dual BSD/GPL");
310
311 //module_param()
312
313 module_init(globalfifo_init);
314 module_exit(globalfifo_exit);


Copyright © Linux教程網 All Rights Reserved