base/ipc/fifos/fifos.c

Go to the documentation of this file.
00001 /**
00002  * @ingroup fifos
00003  * @ingroup fifos_ipc
00004  * @ingroup fifos_sem
00005  * @file
00006  *
00007  * Implementation of the @ref fifos "RTAI FIFO module".
00008  *
00009  * @author Paolo Mantegazza
00010  *
00011  * @note Copyright &copy; 1999-2003 Paolo Mantegazza <mantegazza@aero.polimi.it>
00012  *
00013  * This program is free software; you can redistribute it and/or
00014  * modify it under the terms of the GNU General Public License as
00015  * published by the Free Software Foundation; either version 2 of the
00016  * License, or (at your option) any later version.
00017  *
00018  * This program is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00026  */
00027 
00028 /* 
00029 ACKNOWLEDGEMENTS: 
00030 - nice proc file contributed by Steve Papacharalambous (stevep@zentropix.com);
00031 - added proc handler info contributed by Rich Walker (rw@shadow.org.uk)
00032 - 11-19-2001, Truxton Fulton (trux@truxton.com) fixed a race in mbx_get.
00033 - 10-23-2003 added atomic send contributed by Jan Kiszka 
00034   (kiszka@rts.uni-hannover.de) and expanded it to rtf_get_if.
00035 - 12-10-2003 a fix of rtf_resize odds contributed by Abramo Bagnara
00036   (abramo.bagnara@tin.it).
00037 */
00038 
00039 /**
00040  * @defgroup fifos RTAI FIFO module
00041  *
00042  * See @ref fifos_overview "the general overview of RTAI fifos".
00043  */
00044 
00045 /**
00046  * @ingroup fifos
00047  * @defgroup fifos_ipc Inter-process communications.
00048  *
00049  * RTAI FIFO communication functions.
00050  *
00051  * RTAI fifos maintain full compatibility with those available in NMT_RTLinux
00052  * while adding many other useful services that avoid the clumsiness of
00053  * Unix/Linux calls. So if you need portability you should bent yourself to the
00054  * use of select for timing out IO operations, while if you have not to satisfy
00055  * such constraints use the available simpler, and more direct, RTAI fifos
00056  * specific services.
00057  *
00058  * In the table below the standard Unix/Linux services in user space are
00059  * enclosed in []. See standard Linux man pages if you want to use them, they
00060  * need not be explained here.
00061  *
00062  * <CENTER><TABLE>
00063  * <TR><TD> Called from RT task </TD><TD> Called from Linux process </TD></TR>
00064  * <TR><TD> #rtf_create         </TD><TD> #rtf_open_sized           <BR>
00065  *                                         [open]                   </TD></TR>
00066  * <TR><TD> #rtf_destroy        </TD><TD>  [close]                  </TD></TR>
00067  * <TR><TD> #rtf_reset          </TD><TD> #rtf_reset                </TD></TR>
00068  * <TR><TD> #rtf_resize         </TD><TD> #rtf_resize               </TD></TR>
00069  * <TR><TD> #rtf_get            </TD><TD>  [read]                   <BR>
00070  *                                        #rtf_read_timed           <BR>
00071  *                                        #rtf_read_all_at_once     </TD></TR>
00072  * <TR><TD> #rtf_put            </TD><TD>  [write]                  <BR>
00073  *                                        #rtf_write_timed          </TD></TR>
00074  * <TR><TD> #rtf_create_handler </TD><TD>                           </TD></TR>
00075  * <TR><TD>                     </TD><TD> #rtf_suspend_timed        </TD></TR>
00076  * <TR><TD>                     </TD><TD> #rtf_set_async_sig        </TD></TR>
00077  * </TABLE></CENTER>
00078  *
00079  * In Linux, fifos have to be created by :
00080  * @verbatim $ mknod /dev/rtf<x> c 150 <x> @endverbatim
00081  * where <x> is the minor device number, from 0 to 63; thus on the Linux side
00082  * RTL fifos can be used as standard character devices. As it was said above to
00083  * use standard IO operations on such devices there is no need to explain
00084  * anything, go directly to Linux man pages. RTAI fifos specific services
00085  * available in kernel and user space are instead explained here.
00086  *
00087  * What is important to remember is that in the user space side you address
00088  * fifos through the file descriptor you get at fifo device opening while in
00089  * kernel space you directly address them by their minor number. So you will
00090  * mate the @a fd you get in user space by using
00091  * @verbatim open(/dev/rtfxx,...) @endverbatim
00092  * to the integer @p xx you will use in kernel space.
00093  *
00094  * @note RTAI fifos should be used just with applications that use only real
00095  * time interrupt handlers, so that no RTAI scheduler is installed, or if you
00096  * need compatibility with NMT RTL.  If you are working with any RTAI scheduler
00097  * already installed you are strongly invited to think about avoiding them, use
00098  * LXRT instead.
00099  *
00100  * It is far better and flexible, and if you really like it the fifos way
00101  * mailboxes are a one to one, more effective, substitute.   After all RTAI
00102  * fifos are implemented on top of them.
00103  */
00104 
00105 /**
00106  * @ingroup fifos
00107  * @defgroup fifos_sem Semaphores.
00108  *
00109  * RTAI FIFO semaphore functions.
00110  *
00111  * Fifos have an embedded synchronization capability, however using them only
00112  * for such a purpose can be clumsy. So RTAI fifos have binary semaphores for
00113  * that purpose. Note that, as for put and get fifos functions, only nonblocking
00114  * functions are available in kernel space.
00115  * 
00116  * <CENTER><TABLE>
00117  * <TR><TD> Called from RT task </TD><TD> Called from Linux process </TD></TR>
00118  * <TR><TD> #rtf_sem_init       </TD><TD> #rtf_sem_init             </TD></TR>
00119  * <TR><TD> #rtf_sem_post       </TD><TD> #rtf_sem_post             </TD></TR>
00120  * <TR><TD> #rtf_sem_trywait    </TD><TD> #rtf_sem_wait             <BR>
00121  *                                        #rtf_sem_trywait          <BR>
00122  *                                        #rtf_sem_timed_wait       </TD></TR>
00123  * <TR><TD> #rtf_sem_destroy    </TD><TD> #rtf_sem_destroy          </TD></TR>
00124  * </TABLE></CENTER>
00125  *
00126  * To add a bit of confusion (J), with respect to RTAI schedulers semaphore
00127  * functions, fifos semaphore functions names follow the POSIX mnemonics.
00128  *
00129  * It should be noted that semaphores are associated to a fifo for
00130  * identification purposes. So it is once more important to remember is that
00131  * in the user space side you address fifos through the file descriptor you get
00132  * at fifo device opening while in kernel space you directly address them by
00133  * their minor number.   So you will mate the fd  you get in user space by
00134  * @verbatim open(/dev/rtfxx,) @endverbatim to the integer @p xx youll use in
00135  * kernel space.
00136  */
00137 
00138 
00139 #include <linux/module.h>
00140 #include <linux/init.h>
00141 #include <linux/kernel.h>
00142 #include <linux/version.h>
00143 #include <linux/errno.h>
00144 #include <linux/mm.h>
00145 #include <linux/vmalloc.h>
00146 #include <linux/poll.h>
00147 #include <linux/termios.h>
00148 #include <linux/tty_driver.h>
00149 #include <linux/console.h>
00150 #include <linux/slab.h>
00151 #include <linux/stat.h>
00152 #include <linux/proc_fs.h>
00153 
00154 #include <rtai_fifos.h>
00155 #include <rtai_trace.h>
00156 #include <rtai_proc_fs.h>
00157 #include <rtai_sched.h>
00158 #include <rtai_lxrt.h>
00159 
00160 MODULE_LICENSE("GPL");
00161 
00162 /* these are copied from <rt/rt_compat.h> */
00163 #define rtf_save_flags_and_cli(x)   do{x=rt_spin_lock_irqsave(&rtf_lock);}while(0)
00164 #define rtf_restore_flags(x)        rt_spin_unlock_irqrestore((x),&rtf_lock)
00165 #define rtf_spin_lock_irqsave(x,y)  do{x=rt_spin_lock_irqsave(&(y));}while(0)
00166 #define rtf_spin_unlock_irqrestore(x,y) rt_spin_unlock_irqrestore((x),&(y))
00167 #define rtf_request_srq(x)      rt_request_srq(0, (x), 0)
00168 #define rtf_free_srq(x)         rt_free_srq((x))
00169 #define rtf_pend_srq(x)         rt_pend_linux_srq((x))
00170 
00171 #ifdef CONFIG_PROC_FS
00172 static int rtai_proc_fifo_register(void);
00173 static void rtai_proc_fifo_unregister(void);
00174 #endif
00175 
00176 typedef struct lx_queue {
00177     struct lx_queue *prev;
00178     struct lx_queue *next;
00179     struct lx_task_struct *task;
00180 } F_QUEUE;
00181 
00182 typedef struct lx_semaphore {
00183     int free;
00184     int qtype;
00185     F_QUEUE queue;
00186 } F_SEM;
00187 
00188 typedef struct lx_task_struct {
00189     int blocked;
00190     int priority;
00191     F_QUEUE queue;
00192     struct task_struct *task;
00193 } LX_TASK;
00194 
00195 typedef struct lx_mailbox {
00196     int size;   // size of the entire buffer
00197     int fbyte;  // head
00198     int lbyte;  // tail
00199     int avbs;   // bytes available in the buffer
00200     int frbs;   // free bytes in the buffer
00201     char *bufadr;
00202     F_SEM sndsem, rcvsem;
00203     struct task_struct *waiting_task;
00204     spinlock_t buflock;
00205 } F_MBX;
00206 
00207 typedef struct rt_fifo_struct {
00208     F_MBX mbx;      // MUST BE THE FIRST!
00209     int opncnt;
00210     int malloc_type;
00211     int pol_asyn_pended;
00212     wait_queue_head_t pollq;
00213     struct fasync_struct *asynq;
00214     rtf_handler_t handler;
00215     F_SEM sem;
00216     char name[RTF_NAMELEN+1];
00217 } FIFO;
00218 
00219 static int fifo_srq, async_sig;
00220 static spinlock_t rtf_lock = SPIN_LOCK_UNLOCKED;
00221 static spinlock_t rtf_name_lock = SPIN_LOCK_UNLOCKED;
00222 
00223 #define MAX_FIFOS 64
00224 //static FIFO fifo[MAX_FIFOS] = {{{0}}};
00225 static FIFO *fifo;
00226 
00227 #define MAXREQS 64  // KEEP IT A POWER OF 2!!!
00228 static struct { int in, out; struct task_struct *task[MAXREQS]; } taskq;
00229 static struct { int in, out; FIFO *fifo[MAXREQS]; } pol_asyn_q;
00230 
00231 static int do_nothing(unsigned int arg, int rw) { return 0; }
00232 
00233 static inline void enqueue_blocked(LX_TASK *task, F_QUEUE *queue, int qtype, int priority)
00234 {
00235     F_QUEUE *q;
00236 
00237     task->blocked = 1;
00238     q = queue;
00239     if (!qtype) {
00240         while ((q = q->next) != queue && (q->task)->priority >= priority);
00241     }
00242     q->prev = (task->queue.prev = q->prev)->next  = &(task->queue);
00243     task->queue.next = q;
00244 }
00245 
00246 static inline void dequeue_blocked(LX_TASK *task)
00247 {
00248     task->blocked = 0;
00249     (task->queue.prev)->next = task->queue.next;
00250     (task->queue.next)->prev = task->queue.prev;
00251 }
00252 
00253 static inline void mbx_sem_signal(F_SEM *sem, FIFO *fifop)
00254 {
00255     unsigned long flags;
00256     LX_TASK *task;
00257 
00258     rtf_save_flags_and_cli(flags);
00259     if ((task = (sem->queue.next)->task)) {
00260         dequeue_blocked(task);
00261         taskq.task[taskq.in] = task->task;
00262         taskq.in = (taskq.in + 1) & (MAXREQS - 1);
00263         rtf_pend_srq(fifo_srq);
00264     } else {
00265         sem->free = 1;
00266         if (fifop && !(fifop->pol_asyn_pended) &&
00267             (((F_MBX *)fifop)->avbs || ((F_MBX *)fifop)->frbs) &&
00268             (waitqueue_active(&fifop->pollq) || fifop->asynq)) {
00269             fifop->pol_asyn_pended = 1;
00270             pol_asyn_q.fifo[pol_asyn_q.in] = fifop;
00271             pol_asyn_q.in = (pol_asyn_q.in + 1) & (MAXREQS - 1);
00272             rtf_pend_srq(fifo_srq);
00273         }
00274     }
00275     rtf_restore_flags(flags);
00276     return;
00277 }
00278 
00279 static inline void mbx_signal(F_MBX *mbx)
00280 {
00281     unsigned long flags;
00282     struct task_struct *task;
00283 
00284     rtf_save_flags_and_cli(flags);
00285     if ((task = mbx->waiting_task)) {
00286         mbx->waiting_task = 0;
00287         taskq.task[taskq.in] = task;
00288         taskq.in = (taskq.in + 1) & (MAXREQS - 1);
00289         rtf_pend_srq(fifo_srq);
00290     }
00291     rtf_restore_flags(flags);
00292     return;
00293 }
00294 
00295 static inline int mbx_sem_wait_if(F_SEM *sem)
00296 {
00297     unsigned long flags;
00298 
00299     rtf_save_flags_and_cli(flags);
00300     if (sem->free) {
00301         sem->free = 0;
00302         rtf_restore_flags(flags);
00303         return 1;
00304     }
00305     rtf_restore_flags(flags);
00306     return 0;
00307 }
00308 
00309 static inline int mbx_sem_wait(F_SEM *sem)
00310 {
00311     unsigned long flags;
00312     LX_TASK task;
00313     int ret;
00314 
00315     ret = 0;
00316     rtf_save_flags_and_cli(flags);
00317     if (!sem->free) {
00318         task.queue.task = &task;
00319         task.priority = current->rt_priority;
00320         enqueue_blocked(&task, &sem->queue, sem->qtype, task.priority);
00321         task.task = current;
00322         rtf_restore_flags(flags);
00323         current->state = TASK_INTERRUPTIBLE;
00324         schedule();
00325         if (signal_pending(current)) {
00326             ret = -ERESTARTSYS;
00327         }
00328         rtf_save_flags_and_cli(flags);
00329         if (task.blocked) { 
00330             dequeue_blocked(&task);
00331             if (!(sem->queue.next)->task) {
00332                 sem->free = 1;
00333             }
00334             if (!ret) {
00335                 ret = -1;
00336             }
00337         }
00338     } else {
00339         sem->free = 0;
00340     }
00341     rtf_restore_flags(flags);
00342     return ret;
00343 }
00344 
00345 static inline int mbx_wait(F_MBX *mbx, int *fravbs)
00346 {
00347     unsigned long flags;
00348 
00349     rtf_save_flags_and_cli(flags);
00350     if (!(*fravbs)) {
00351         mbx->waiting_task = current;
00352         current->state = TASK_INTERRUPTIBLE;
00353         rtf_restore_flags(flags);
00354         schedule();
00355         if (signal_pending(current)) {
00356             return -ERESTARTSYS;
00357         }
00358         rtf_save_flags_and_cli(flags);
00359         if (mbx->waiting_task == current) {
00360             mbx->waiting_task = 0;
00361             rtf_restore_flags(flags);
00362             return -1;
00363         }
00364     }
00365     rtf_restore_flags(flags);
00366     return 0;
00367 }
00368 
00369 static inline int mbx_sem_wait_timed(F_SEM *sem, int delay)
00370 {
00371     unsigned long flags;
00372     LX_TASK task;
00373 
00374     rtf_save_flags_and_cli(flags);
00375     if (!sem->free) {
00376         task.queue.task = &task;
00377         task.priority = current->rt_priority;
00378         enqueue_blocked(&task, &sem->queue, sem->qtype, task.priority);
00379         task.task = current;
00380         rtf_restore_flags(flags);
00381         current->state = TASK_INTERRUPTIBLE;
00382         schedule_timeout(delay);
00383         if (signal_pending(current)) {
00384             return -ERESTARTSYS;
00385         }
00386         rtf_save_flags_and_cli(flags);
00387         if (task.blocked) { 
00388             dequeue_blocked(&task);
00389             if (!((sem->queue.next)->task)) {
00390                 sem->free = 1;
00391             }
00392             rtf_restore_flags(flags);
00393             return -1;
00394         }
00395     } else {
00396         sem->free = 0;
00397     }
00398     rtf_restore_flags(flags);
00399     return 0;
00400 }
00401 
00402 static inline int mbx_wait_timed(F_MBX *mbx, int *fravbs, int delay)
00403 {
00404     unsigned long flags;
00405 
00406     rtf_save_flags_and_cli(flags);
00407     if (!(*fravbs)) {
00408         mbx->waiting_task = current;
00409         rtf_restore_flags(flags);
00410         current->state = TASK_INTERRUPTIBLE;
00411         schedule_timeout(delay);
00412         if (signal_pending(current)) {
00413             return -ERESTARTSYS;
00414         }
00415         rtf_save_flags_and_cli(flags);
00416         if (mbx->waiting_task == current) {;
00417             mbx->waiting_task = 0;
00418             rtf_restore_flags(flags);
00419             return -1;
00420         }
00421     }
00422     rtf_restore_flags(flags);
00423     return 0;
00424 }
00425 
00426 #define MOD_SIZE(indx) ((indx) < mbx->size ? (indx) : (indx) - mbx->size)
00427 
00428 static inline int mbx_put(F_MBX *mbx, char **msg, int msg_size, int lnx)
00429 {
00430     unsigned long flags;
00431     int tocpy;
00432 
00433     while (msg_size > 0 && mbx->frbs) {
00434         if ((tocpy = mbx->size - mbx->lbyte) > msg_size) {
00435             tocpy = msg_size;
00436         }
00437         if (tocpy > mbx->frbs) {
00438             tocpy = mbx->frbs;
00439         }
00440         if (lnx) {
00441             rt_copy_from_user(mbx->bufadr + mbx->lbyte, *msg, tocpy);
00442         } else {
00443             memcpy(mbx->bufadr + mbx->lbyte, *msg, tocpy);
00444         }
00445         rtf_spin_lock_irqsave(flags, mbx->buflock);
00446         mbx->lbyte = MOD_SIZE(mbx->lbyte + tocpy);
00447         mbx->frbs -= tocpy;
00448         mbx->avbs += tocpy;
00449         rtf_spin_unlock_irqrestore(flags, mbx->buflock);
00450         msg_size -= tocpy;
00451         *msg     += tocpy;
00452     }
00453     return msg_size;
00454 }
00455 
00456 static inline int mbx_ovrwr_put(F_MBX *mbx, char **msg, int msg_size, int lnx)
00457 {
00458     unsigned long flags;
00459     int tocpy,n;
00460 
00461     if ((n = msg_size - mbx->size) > 0) {
00462         *msg += n;
00463         msg_size -= n;
00464     }       
00465     while (msg_size > 0) {
00466         if (mbx->frbs) {    
00467             if ((tocpy = mbx->size - mbx->lbyte) > msg_size) {
00468                 tocpy = msg_size;
00469             }
00470             if (tocpy > mbx->frbs) {
00471                 tocpy = mbx->frbs;
00472             }
00473             if (lnx) {
00474                 rt_copy_from_user(mbx->bufadr + mbx->lbyte, *msg, tocpy);
00475             } else {
00476                 memcpy(mbx->bufadr + mbx->lbyte, *msg, tocpy);
00477             }
00478             rtf_spin_lock_irqsave(flags, mbx->buflock);
00479             mbx->frbs -= tocpy;
00480             mbx->avbs += tocpy;
00481             rtf_spin_unlock_irqrestore(flags, mbx->buflock);
00482             msg_size -= tocpy;
00483             *msg     += tocpy;
00484             mbx->lbyte = MOD_SIZE(mbx->lbyte + tocpy);
00485         }   
00486         if (msg_size) {
00487             while ((n = msg_size - mbx->frbs) > 0) {
00488                 if ((tocpy = mbx->size - mbx->fbyte) > n) {
00489                     tocpy = n;
00490                 }
00491                 if (tocpy > mbx->avbs) {
00492                     tocpy = mbx->avbs;
00493                 }
00494                 rtf_spin_lock_irqsave(flags, mbx->buflock);
00495                 mbx->frbs  += tocpy;
00496                 mbx->avbs  -= tocpy;
00497                 rtf_spin_unlock_irqrestore(flags, mbx->buflock);
00498                 mbx->fbyte = MOD_SIZE(mbx->fbyte + tocpy);
00499             }
00500         }       
00501     }
00502     return 0;
00503 }
00504 
00505 static inline int mbx_get(F_MBX *mbx, char **msg, int msg_size, int lnx)
00506 {
00507     unsigned long flags;
00508     int tocpy;
00509 
00510     while (msg_size > 0 && mbx->avbs) {
00511         if ((tocpy = mbx->size - mbx->fbyte) > msg_size) {
00512             tocpy = msg_size;
00513         }
00514         if (tocpy > mbx->avbs) {
00515             tocpy = mbx->avbs;
00516         }
00517         if (lnx) {
00518             rt_copy_to_user(*msg, mbx->bufadr + mbx->fbyte, tocpy);
00519         } else {
00520             memcpy(*msg, mbx->bufadr + mbx->fbyte, tocpy);
00521         }
00522         rtf_spin_lock_irqsave(flags, mbx->buflock);
00523         mbx->fbyte = MOD_SIZE(mbx->fbyte + tocpy);
00524         mbx->frbs += tocpy;
00525         mbx->avbs -= tocpy;
00526         rtf_spin_unlock_irqrestore(flags, mbx->buflock);
00527         msg_size  -= tocpy;
00528         *msg      += tocpy;
00529     }
00530     return msg_size;
00531 }
00532 
00533 static inline int mbx_evdrp(F_MBX *mbx, char **msg, int msg_size, int lnx)
00534 {
00535     int tocpy, fbyte, avbs;
00536 
00537     fbyte = mbx->fbyte;
00538     avbs  = mbx->avbs;
00539     while (msg_size > 0 && avbs) {
00540         if ((tocpy = mbx->size - fbyte) > msg_size) {
00541             tocpy = msg_size;
00542         }
00543         if (tocpy > avbs) {
00544             tocpy = avbs;
00545         }
00546         if (lnx) {
00547             rt_copy_to_user(*msg, mbx->bufadr + fbyte, tocpy);
00548         } else {
00549             memcpy(*msg, mbx->bufadr + fbyte, tocpy);
00550         }
00551         avbs     -= tocpy;
00552         msg_size -= tocpy;
00553         *msg     += tocpy;
00554         fbyte = MOD_SIZE(fbyte + tocpy);
00555     }
00556     return msg_size;
00557 }
00558 
00559 static inline void mbx_sem_init(F_SEM *sem, int value)
00560 {
00561     sem->free  = value;
00562     sem->qtype = 0;
00563     sem->queue.prev = &(sem->queue);
00564     sem->queue.next = &(sem->queue);
00565     sem->queue.task = 0;
00566 }
00567 
00568 static inline int mbx_sem_delete(F_SEM *sem)
00569 {
00570     unsigned long flags;
00571     LX_TASK *task;
00572 
00573     rtf_save_flags_and_cli(flags);
00574     while ((task = (sem->queue.next)->task)) {
00575         sem->queue.next = task->queue.next;
00576         (task->queue.next)->prev = &(sem->queue);
00577         taskq.task[taskq.in] = task->task;
00578         taskq.in = (taskq.in + 1) & (MAXREQS - 1);
00579         rtf_pend_srq(fifo_srq);
00580     }
00581     rtf_restore_flags(flags);
00582     return 0;
00583 }
00584 
00585 static inline void mbx_init(F_MBX *mbx, int size, char *bufadr)
00586 {
00587     mbx_sem_init(&(mbx->sndsem), 1);
00588     mbx_sem_init(&(mbx->rcvsem), 1);
00589     mbx->waiting_task = 0;
00590     mbx->bufadr = bufadr;
00591     mbx->size = mbx->frbs = size;
00592     mbx->fbyte = mbx->lbyte = mbx->avbs = 0;
00593 #ifdef CONFIG_SMP
00594         spin_lock_init(&mbx->buflock);
00595 #endif
00596     spin_lock_init(&(mbx->buflock));
00597 }
00598 
00599 static inline int mbx_delete(F_MBX *mbx)
00600 {
00601     mbx_signal(mbx);
00602     if (mbx_sem_delete(&(mbx->sndsem)) || mbx_sem_delete(&(mbx->rcvsem))) {
00603         return -EFAULT;
00604     }
00605     return 0;
00606 }
00607 
00608 static inline int mbx_send(F_MBX *mbx, const char *msg, int msg_size, int lnx)
00609 {
00610     if (mbx_sem_wait(&(mbx->sndsem))) {
00611         return msg_size;
00612     }
00613     while (msg_size) {
00614         if (mbx_wait(mbx, &mbx->frbs)) {
00615             mbx_sem_signal(&(mbx->sndsem), (FIFO *)mbx);
00616             return msg_size;
00617         }
00618         msg_size = mbx_put(mbx, (char **)(&msg), msg_size, lnx);
00619         mbx_signal(mbx);
00620     }
00621     mbx_sem_signal(&(mbx->sndsem), (FIFO *)mbx);
00622     return 0;
00623 }
00624 
00625 static inline int mbx_send_wp(F_MBX *mbx, const char *msg, int msg_size, int lnx)
00626 {
00627     unsigned long flags;
00628 
00629     rtf_save_flags_and_cli(flags);
00630     if (mbx->sndsem.free && mbx->frbs) {
00631         mbx->sndsem.free = 0;
00632         rtf_restore_flags(flags);
00633         msg_size = mbx_put(mbx, (char **)(&msg), msg_size, lnx);
00634         mbx_signal(mbx);
00635         mbx_sem_signal(&(mbx->sndsem), (FIFO *)mbx);
00636     } else {
00637         rtf_restore_flags(flags);
00638     }
00639     return msg_size;
00640 }
00641 
00642 static inline int mbx_send_if(F_MBX *mbx, const char *msg, int msg_size, int lnx)
00643 {
00644     unsigned long flags;
00645 
00646     rtf_save_flags_and_cli(flags);
00647     if (mbx->sndsem.free && (mbx->frbs >= msg_size)) {
00648         mbx->sndsem.free = 0;
00649         rtf_restore_flags(flags);
00650         msg_size = mbx_put(mbx, (char **)(&msg), msg_size, lnx);
00651         mbx_signal(mbx);
00652         mbx_sem_signal(&(mbx->sndsem), (FIFO *)mbx);
00653     } else {
00654         rtf_restore_flags(flags);
00655     }
00656     return msg_size;
00657 }
00658 
00659 static int mbx_send_timed(F_MBX *mbx, const char *msg, int msg_size, int delay, int lnx)
00660 {
00661     if (mbx_sem_wait_timed(&(mbx->sndsem), delay)) {
00662         return msg_size;
00663     }
00664     while (msg_size) {
00665         if (mbx_wait_timed(mbx, &(mbx->frbs), delay)) {
00666             mbx_sem_signal(&(mbx->sndsem), (FIFO *)mbx);
00667             return msg_size;
00668         }
00669         msg_size = mbx_put(mbx, (char **)(&msg), msg_size, lnx);
00670         mbx_signal(mbx);
00671     }
00672     mbx_sem_signal(&(mbx->sndsem), (FIFO *)mbx);
00673     return 0;
00674 }
00675 
00676 static inline int mbx_receive(F_MBX *mbx, void *msg, int msg_size, int lnx)
00677 {
00678     if (mbx_sem_wait(&(mbx->rcvsem))) {
00679         return msg_size;
00680     }
00681     while (msg_size) {
00682         if (mbx_wait(mbx, &mbx->avbs)) {
00683             mbx_sem_signal(&(mbx->rcvsem), (FIFO *)mbx);
00684             return msg_size;
00685         }
00686         msg_size = mbx_get(mbx, (char **)(&msg), msg_size, lnx);
00687         mbx_signal(mbx);
00688     }
00689     mbx_sem_signal(&(mbx->rcvsem), (FIFO *)mbx);
00690     return 0;
00691 }
00692 
00693 static inline int mbx_receive_wjo(F_MBX *mbx, void *msg, int msg_size, int lnx)
00694 {
00695     if (mbx_sem_wait(&(mbx->rcvsem))) {
00696         return msg_size;
00697     }
00698     if (msg_size) {
00699         if (mbx_wait(mbx, &mbx->avbs)) {
00700             mbx_sem_signal(&(mbx->rcvsem), (FIFO *)mbx);
00701             return msg_size;
00702         }
00703         msg_size = mbx_get(mbx, (char **)(&msg), msg_size, lnx);
00704         mbx_signal(mbx);
00705     }
00706     mbx_sem_signal(&(mbx->rcvsem), (FIFO *)mbx);
00707     return msg_size;
00708 }
00709 
00710 static inline int mbx_receive_wp(F_MBX *mbx, void *msg, int msg_size, int lnx)
00711 {
00712     unsigned long flags;
00713 
00714     rtf_save_flags_and_cli(flags);
00715     if (mbx->rcvsem.free && mbx->avbs) {
00716         mbx->rcvsem.free = 0;
00717         rtf_restore_flags(flags);
00718         msg_size = mbx_get(mbx, (char **)(&msg), msg_size, lnx);
00719         mbx_signal(mbx);
00720         mbx_sem_signal(&(mbx->rcvsem), (FIFO *)mbx);
00721     } else {
00722         rtf_restore_flags(flags);
00723     }
00724     return msg_size;
00725 }
00726 
00727 static inline int mbx_receive_if(F_MBX *mbx, void *msg, int msg_size, int lnx)
00728 {
00729     unsigned long flags;
00730 
00731     rtf_save_flags_and_cli(flags);
00732     if (mbx->rcvsem.free && mbx->avbs >= msg_size) {
00733         mbx->rcvsem.free = 0;
00734         rtf_restore_flags(flags);
00735         msg_size = mbx_get(mbx, (char **)(&msg), msg_size, lnx);
00736         mbx_signal(mbx);
00737         mbx_sem_signal(&(mbx->rcvsem), (FIFO *)mbx);
00738     } else {
00739         rtf_restore_flags(flags);
00740     }
00741     return msg_size;
00742 }
00743 
00744 static int mbx_receive_timed(F_MBX *mbx, void *msg, int msg_size, int delay, int lnx)
00745 {
00746     if (mbx_sem_wait_timed(&(mbx->rcvsem), delay)) {
00747         return msg_size;
00748     }
00749     while (msg_size) {
00750         if (mbx_wait_timed(mbx, &(mbx->avbs), delay)) {
00751             mbx_sem_signal(&(mbx->rcvsem), (FIFO *)mbx);
00752             return msg_size;
00753         }
00754         msg_size = mbx_get(mbx, (char **)(&msg), msg_size, lnx);
00755         mbx_signal(mbx);
00756     }
00757     mbx_sem_signal(&(mbx->rcvsem), (FIFO *)mbx);
00758     return 0;
00759 }
00760 
00761 static inline int mbx_ovrwr_send(F_MBX *mbx, void *msg, int msg_size, int lnx)
00762 {
00763     unsigned long flags;
00764 
00765     rtf_save_flags_and_cli(flags);
00766     if (mbx->sndsem.free) {
00767         mbx->sndsem.free = 0;
00768         rtf_restore_flags(flags);
00769         msg_size = mbx_ovrwr_put(mbx, (char **)(&msg), msg_size, lnx);
00770         mbx_signal(mbx);
00771         mbx_sem_signal(&(mbx->sndsem), (FIFO *)mbx);
00772     } else {
00773         rtf_restore_flags(flags);
00774     }
00775     return msg_size;
00776 }
00777 
00778 static void rtf_sysrq_handler(void)
00779 {
00780     FIFO *fifop;
00781     while (taskq.out != taskq.in) {
00782         if (taskq.task[taskq.out]->state == TASK_INTERRUPTIBLE) {
00783             wake_up_process(taskq.task[taskq.out]);
00784         }
00785         taskq.out = (taskq.out + 1) & (MAXREQS - 1);
00786     }
00787 
00788     while (pol_asyn_q.out != pol_asyn_q.in) {
00789         fifop = pol_asyn_q.fifo[pol_asyn_q.out];
00790         fifop->pol_asyn_pended = 0;
00791         if (waitqueue_active(&(fifop = pol_asyn_q.fifo[pol_asyn_q.out])->pollq)) {
00792             wake_up_interruptible(&(fifop->pollq));
00793         }
00794         if (fifop->asynq) { 
00795             kill_fasync(&fifop->asynq, async_sig, POLL_IN);
00796         }
00797         pol_asyn_q.out = (pol_asyn_q.out + 1) & (MAXREQS - 1);
00798     }
00799     set_tsk_need_resched(current);
00800 }
00801 
00802 #define VALID_FIFO  if (minor >= MAX_FIFOS) { return -ENODEV; } \
00803             if (!(fifo[minor].opncnt)) { return -EINVAL; }
00804 
00805 /**
00806  * @ingroup fifos_ipc
00807  * Reset a real-time FIFO
00808  *
00809  * rtf_reset resets RT-FIFO @a fd_fifo by setting its buffer pointers to zero,
00810  * so that any existing data is discarded and the fifo started anew like at its
00811  * creations.   It can be used both in kernel and user space.
00812  *
00813  * @param minor is a file descriptor returned by standard UNIX open in user
00814  * space while it is directly the chosen fifo number in kernel space.
00815  *
00816  * @retval 0 on succes.
00817  * @retval ENODEV if @a fd_fifo is greater than or equal to RTF_NO.
00818  * @retval EINVAL if @a fd_fifo refers to a not opened fifo.
00819  * @retval EFAULT if the operation was unsuccessful.
00820  */
00821 RTAI_SYSCALL_MODE int rtf_reset(unsigned int minor)
00822 {
00823     int semval;
00824     F_MBX *mbx;
00825     
00826     VALID_FIFO;
00827 
00828     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_RESET, minor, 0);
00829 
00830     mbx = &(fifo[minor].mbx);
00831     if (!mbx_sem_wait(&(mbx->rcvsem))) {
00832         while (!(semval = mbx_sem_wait_if(&mbx->sndsem)) && !mbx->waiting_task) {
00833             current->state = TASK_INTERRUPTIBLE;
00834             schedule_timeout(1);
00835         }
00836     } else {
00837         return -EBADF;
00838     }
00839     mbx->frbs = mbx->size;
00840     mbx->fbyte = mbx->lbyte = mbx->avbs = 0;
00841     if (semval) {
00842         mbx_sem_signal(&mbx->sndsem, (FIFO *)mbx);
00843     } else {
00844         mbx_signal(mbx);
00845     }
00846     mbx_sem_signal(&mbx->rcvsem, (FIFO *)mbx);
00847     return 0;
00848 }
00849 
00850 
00851 /**
00852  * @ingroup fifos_ipc
00853  * Resize a real-time FIFO
00854  *
00855  * rtf_resize modifies the real-time fifo fifo, previously created with,
00856  * rtf_create(), to have a new size of @a size. Any data in the fifo is
00857  * discarded.
00858  *
00859  * @param minor is a file descriptor returned by standard UNIX open in user
00860  * space while it is directly the chosen fifo number in kernel space.
00861  *
00862  * @param size is the requested new size.
00863  *
00864  * @retval size on success.
00865  * @retval -ENODEV if @a fifo is greater than or equal to RTF_NO.
00866  * @retval -EINVAL if @a fifo refers to a not opened fifo.
00867  * @retval -ENOMEM if @a size bytes could not be allocated for the RT-FIFO. Fifo
00868  * @retval -EBUSY if @a size is smaller than actual content
00869  * size is unchanged.
00870  */
00871 RTAI_SYSCALL_MODE int rtf_resize(unsigned int minor, int size)
00872 {
00873     void *oldbuf, *newbuf;
00874     int old_malloc_type, new_malloc_type, semval;
00875     F_MBX *mbx;
00876     
00877     VALID_FIFO;
00878 
00879     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_RESIZE, minor, size);
00880 
00881     mbx = &(fifo[minor].mbx);
00882     if (!size) {
00883         return -EINVAL;
00884     }
00885     if (size <= PAGE_SIZE*32) {
00886         if (!(newbuf = kmalloc(size, GFP_KERNEL))) {
00887             return -ENOMEM;
00888         }
00889         new_malloc_type = 'k';
00890     } else {
00891         if (!(newbuf = vmalloc(size))) {
00892             return -ENOMEM;
00893         }
00894         new_malloc_type = 'v';
00895     }
00896     if (!mbx_sem_wait(&(mbx->rcvsem))) {
00897         while (!(semval = mbx_sem_wait_if(&mbx->sndsem)) && !mbx->waiting_task) {
00898             current->state = TASK_INTERRUPTIBLE;
00899             schedule_timeout(1);
00900         }
00901     } else {
00902         return -EBADF;
00903     }
00904     if (size < mbx->avbs) {
00905         if (semval) {
00906             mbx_sem_signal(&mbx->sndsem, (FIFO *)mbx);
00907         }
00908         mbx_sem_signal(&mbx->rcvsem, (FIFO *)mbx);
00909         new_malloc_type == 'k' ? kfree(newbuf) : vfree(newbuf);
00910         return -EBUSY;
00911     }
00912     oldbuf = newbuf;
00913     mbx->frbs = mbx_get(mbx, (char **)(&oldbuf), size, 0);
00914     mbx->avbs = mbx->lbyte = size - mbx->frbs;
00915     mbx->fbyte = 0;
00916     oldbuf = mbx->bufadr;
00917     mbx->bufadr = newbuf;
00918     old_malloc_type = fifo[minor].malloc_type;
00919     fifo[minor].malloc_type = new_malloc_type;
00920     if (semval) {
00921         mbx->size = size;
00922         mbx_sem_signal(&mbx->sndsem, (FIFO *)mbx);
00923     } else if (size > mbx->size) {
00924         mbx->size = size;
00925         mbx_signal(mbx);
00926     }
00927     mbx_sem_signal(&mbx->rcvsem, (FIFO *)mbx);
00928     old_malloc_type == 'k' ? kfree(oldbuf) : vfree(oldbuf);
00929     return size;
00930 }
00931 
00932 
00933 /**
00934  * @ingroup fifos_ipc
00935  * Create a real-time FIFO
00936  *
00937  * rtf_create creates a real-time fifo (RT-FIFO) of initial size @a size and
00938  * assigns it the identifier @a fifo.  It must be used only in kernel space.
00939  *
00940  * @param minor is a positive integer that identifies the fifo on further
00941  * operations. It has to be less than RTF_NO.
00942  *
00943  * @param size is the requested size for the fifo. 
00944  * 
00945  * @a fifo may refer to an existing RT-FIFO. In this case the size is adjusted
00946  * if necessary.
00947  *
00948  * The RT-FIFO is a character based mechanism to communicate among real-time
00949  * tasks and ordinary Linux processes. The rtf_* functions are used by the
00950  * real-time tasks; Linux processes use standard character device access
00951  * functions such as read, write, and select.
00952  *
00953  * If this function finds an existing fifo of lower size it resizes it to the
00954  * larger new size. Note that the same condition apply to the standard Linux
00955  * device open, except that when it does not find any already existing fifo it
00956  * creates it with a default size of 1K bytes.
00957  *
00958  * It must be remarked that practically any fifo size can be asked for. In
00959  * fact if @a size is within the constraint allowed by kmalloc such a function
00960  * is used, otherwise vmalloc is called, thus allowing any size that can fit
00961  * into the available core memory.
00962  *
00963  * Multiple calls of this function are allowed, a counter is kept internally to
00964  * track their number, and avoid destroying/closing a fifo that is still used.
00965  *
00966  * @retval 0 on success
00967  * @retval ENODEV if fifo is greater than or equal to RTF_NO
00968  * @retval ENOMEM if the necessary size could not be allocated for the RT-FIFO.
00969  *
00970  */
00971 RTAI_SYSCALL_MODE int rtf_create(unsigned int minor, int size)
00972 {
00973     void *buf;
00974 
00975     if (minor >= MAX_FIFOS) {
00976         return -ENODEV;
00977     }
00978     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_CREATE, minor, size);
00979     if (!atomic_cmpxchg((atomic_t *)&fifo[minor].opncnt, 0, 1)) {
00980         if (size <= PAGE_SIZE*32) {
00981             if (!(buf = kmalloc(size, GFP_KERNEL))) {
00982                 fifo[minor].opncnt = 0;
00983                 return -ENOMEM;
00984             }
00985             fifo[minor].malloc_type = 'k';
00986         } else {
00987             if (!(buf = vmalloc(size))) {
00988                 fifo[minor].opncnt = 0;
00989                 return -ENOMEM;
00990             }
00991             fifo[minor].malloc_type = 'v';
00992         }
00993         fifo[minor].handler = do_nothing;
00994         mbx_init(&(fifo[minor].mbx), size, buf);
00995         mbx_sem_init(&(fifo[minor].sem), 0);
00996         fifo[minor].pol_asyn_pended = 0;
00997         fifo[minor].asynq = 0;
00998     } else {
00999         if (size > fifo[minor].mbx.size) {
01000             rtf_resize(minor, size);
01001         }
01002         atomic_inc((atomic_t *)&fifo[minor].opncnt);
01003     }
01004     return 0;
01005 }
01006 
01007 /**
01008  * @ingroup fifos_ipc
01009  * Close a real-time FIFO
01010  *
01011  * rtf_destroy closes, in kernel space, a real-time fifo previously
01012  * created or reopened with rtf_create() or rtf_open_sized(). An internal
01013  * mechanism counts how many times a fifo was opened. Opens and closes must be
01014  * in pair. rtf_destroy should be called as many times as rtf_create was.
01015  * After the last close the fifo is really destroyed.
01016  *
01017  * No need for any particular function for the same service in user space,
01018  * simply use the standard Unix close.
01019  *
01020  * @return a non-negative value on success. Actually it is the open counter, that
01021  * means how many times rtf_destroy should be called yet to destroy the fifo.
01022  *
01023  * @return a a negative value is returned as described below.
01024  * @retval ENODEV if @a fifo is greater than or equal to RTF_NO.
01025  * @retval EINVAL if @a fifo refers to a not opened fifo.
01026  *
01027  * @note The equivalent of rtf_destroy in user space is the standard UNIX
01028  * close.
01029  */
01030 RTAI_SYSCALL_MODE int rtf_destroy(unsigned int minor)
01031 {
01032     VALID_FIFO;
01033 
01034     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_DESTROY, minor, 0);
01035 
01036     if (atomic_dec_and_test((atomic_t *)&fifo[minor].opncnt)) {
01037         if (fifo[minor].malloc_type == 'k') {
01038             kfree(fifo[minor].mbx.bufadr); 
01039         } else {
01040             vfree(fifo[minor].mbx.bufadr); 
01041         }
01042         fifo[minor].handler = do_nothing;
01043         mbx_delete(&(fifo[minor].mbx));
01044         fifo[minor].pol_asyn_pended = 0;
01045         fifo[minor].asynq = 0;
01046         fifo[minor].name[0] = 0;
01047     }
01048     return fifo[minor].opncnt;
01049 }
01050 
01051 /**
01052  * @ingroup fifos_ipc
01053  * Install a FIFO handler function.
01054  *
01055  * rtf_create_handler installs a handler which is executed when data is written
01056  * to or read from a real-time fifo.
01057  *
01058  * @param minor is an RT-FIFO that must have previously been created with a call
01059  * to rtf_create().
01060  *
01061  * @param handler is a pointer on a function wich will be called whenever a
01062  * Linux process accesses that fifo.
01063  *
01064  * rtf_create_handler is often used in conjunction with rtf_get() to process
01065  * data acquired asynchronously from a Linux process. The installed handler
01066  * calls rtf_get() when data is present. Because the handler is only executed
01067  * when there is activity on the fifo, polling is not necessary.
01068  *
01069  * @retval 0 on success.
01070  * @retval EINVAL if @a fifo is greater than or equal to RTF_NO, or handler is
01071  * @c NULL.
01072  *
01073  * @note rtf_create_handler does not check if FIFO referred by @a fifo is open
01074  * or not. The next call of rtf_create will uninstall the handler just
01075  * "installed".
01076  */
01077 int rtf_create_handler(unsigned int minor, void *handler)
01078 {
01079     if (minor >= MAX_FIFOS || !handler) {
01080         return -EINVAL;
01081     }
01082 
01083     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_CREATE_HANDLER, minor, handler);
01084 
01085     fifo[minor].handler = handler;
01086     return 0;
01087 }
01088 
01089 /**
01090  * @ingroup fifos_ipc
01091  * Write data to FIFO
01092  *
01093  * rtf_put tries to write a block of data to a real-time fifo previously created
01094  * with rtf_create().
01095  *
01096  * @param minor is the ID with which the RT-FIFO was created.
01097  * @param buf points the block of data to be written.
01098  * @param count is the size of the block in bytes.
01099  *
01100  * This mechanism is available only in kernel space, i.e. either in real-time
01101  * tasks or handlers; Linux processes use a write to the corresponding
01102  * /dev/fifo<n> device to enqueue data to a fifo. Similarly, Linux processes
01103  * use read or similar functions to read the data previously written via rtf_put
01104  * by a real-time task.
01105  *
01106  * @return the number of bytes written on succes. Note that this value may
01107  * be less than @a count if @a count bytes of free space is not available in the
01108  * fifo.
01109  * @retval ENODEV if @a fifo is greater than or equal to RTF_NO.
01110  * @retval EINVAL if @a fifo refers to a not opened fifo.
01111  *
01112  * @note The equivalent of rtf_put in user space is the standard UNIX write,
01113  * which can be either blocking or nonblocking according to how you opened the
01114  * related device.
01115  */
01116 RTAI_SYSCALL_MODE int rtf_put(unsigned int minor, void *buf, int count)
01117 {
01118     VALID_FIFO;
01119 
01120     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_PUT, minor, count);
01121 
01122     count -= mbx_send_wp(&(fifo[minor].mbx), buf, count, 0);
01123     return count;
01124 }
01125 
01126 RTAI_SYSCALL_MODE int rtf_ovrwr_put(unsigned int minor, void *buf, int count)
01127 {
01128     VALID_FIFO;
01129     return mbx_ovrwr_send(&(fifo[minor].mbx), buf, count, 0);
01130 }
01131 
01132 RTAI_SYSCALL_MODE int rtf_put_if(unsigned int minor, void *buf, int count)
01133 {
01134     VALID_FIFO;
01135 
01136     count -= mbx_send_if(&(fifo[minor].mbx), buf, count, 0);
01137     return count;
01138 }
01139 
01140 RTAI_SYSCALL_MODE int rtf_get_avbs(unsigned int minor)
01141 {
01142     VALID_FIFO;
01143     return fifo[minor].mbx.avbs;
01144 }
01145 
01146 RTAI_SYSCALL_MODE int rtf_get_frbs(unsigned int minor)
01147 {
01148     VALID_FIFO;
01149     return fifo[minor].mbx.frbs;
01150 }
01151 
01152 /**
01153  * @ingroup fifos_ipc
01154  * Read data from FIFO
01155  *
01156  * rtf_get tries to read a block of data from a real-time fifo previously
01157  * created with a call to rtf_create().
01158  *
01159  * @param minor is the ID with which the RT-FIFO was created.
01160  * @param buf points a buffer provided by the caller.
01161  * @param count is the size of @a buf in bytes.
01162  *
01163  * This mechanism is available only to real-time tasks; Linux processes use a
01164  * read from the corresponding fifo device to dequeue data from a fifo.
01165  * Similarly, Linux processes use write or similar functions to write the data
01166  * to be read via rtf_put() by a real-time task.
01167  *
01168  * rtf_get is often used in conjunction with rtf_create_handler() to process
01169  * data received asynchronously from a Linux process. A handler is installed
01170  * via rtf_create_handler(); this handler calls rtf_get to receive any data
01171  * present in the RT-FIFO as it becomes available. In this way, polling is not
01172  * necessary; the handler is called only when data is present in the fifo.
01173  *
01174  * @return the size of the received data block on success. Note that this
01175  * value may be less than count if count bytes of data is not available in the
01176  * fifo.
01177  * @retval ENODEV if @a fifo is greater than or equal to RTF_NO.
01178  * @retval EINVAL if @a fifo refers to a not opened fifo.
01179  *
01180  * @note The equivalent of rtf_get in user space is the standard UNIX read,
01181  * which can be either blocking or nonblocking according to how you opened the
01182  * related device.
01183  */
01184 RTAI_SYSCALL_MODE int rtf_get(unsigned int minor, void *buf, int count)
01185 {
01186     VALID_FIFO;
01187 
01188     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_GET, minor, count);
01189 
01190     count -= mbx_receive_wp(&(fifo[minor].mbx), buf, count, 0);
01191     return count;
01192 }
01193 
01194 int rtf_evdrp(unsigned int minor, void *msg, int msg_size)
01195 {
01196     VALID_FIFO;
01197 
01198     return msg_size - mbx_evdrp(&(fifo[minor].mbx), (char **)(&msg), msg_size, 0);
01199 }
01200 
01201 RTAI_SYSCALL_MODE int rtf_get_if(unsigned int minor, void *buf, int count)
01202 {
01203     VALID_FIFO;
01204 
01205     return count - mbx_receive_if(&(fifo[minor].mbx), buf, count, 0);
01206 }
01207 
01208 /**
01209  * @ingroup fifos_sem
01210  * Initialize a binary semaphore
01211  *
01212  * rtf_sem_init initializes a semaphore identified by the file descriptor or
01213  * fifo number @a fd_fifo.
01214  *
01215  * A fifo semaphore can be used for communication and synchronization between
01216  * kernel and user space.
01217  *
01218  * @param minor is a file descriptor returned by standard UNIX open in user
01219  * space while it is directly the chosen fifo number in kernel space. In fact
01220  * fifos semaphores must be associated to a fifo for identification purposes.
01221  * @param value is the initial value of the semaphore, it must be either 0 or
01222  * 1.
01223  *
01224  * rt_sem_init can be used both in kernel and user space.
01225  *
01226  * @retval 0 on success.
01227  * @retval EINVAL if @a fd_fifo refers to an invalid file descriptor or fifo.
01228  */
01229 RTAI_SYSCALL_MODE int rtf_sem_init(unsigned int minor, int value)
01230 {
01231     VALID_FIFO;
01232 
01233     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_INIT, minor, value);
01234 
01235     mbx_sem_init(&(fifo[minor].sem), value);
01236     return 0;
01237 }
01238 
01239 /**
01240  * @ingroup fifos_sem
01241  * Posting (signaling) a semaphore.
01242  *
01243  * rtf_sem_post signal an event to a semaphore. The semaphore value is set to
01244  * one and the first process, if any, in semaphore's waiting queue is allowed to
01245  * run.
01246  *
01247  * @param minor is a file descriptor returned by standard UNIX open in user
01248  * space while it is directly the chosen fifo number in kernel space. In fact
01249  * fifos semaphores must be associated to a fifo for identification purposes.
01250  *
01251  * Since it is not blocking rtf_sem_post can be used both in kernel and user
01252  * space.
01253  *
01254  * @retval 0 on success.
01255  * @retval EINVAL if @a fd_fifo refers to an invalid file descriptor or fifo.
01256  */
01257 RTAI_SYSCALL_MODE int rtf_sem_post(unsigned int minor)
01258 {
01259     VALID_FIFO;
01260 
01261     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_POST, minor, 0);
01262 
01263     mbx_sem_signal(&(fifo[minor].sem), 0);
01264     return 0;
01265 }
01266 
01267 /**
01268  * @ingroup fifos_sem
01269  * Take a semaphore, only if the calling task is not blocked.
01270  *
01271  * rtf_sem_trywait is a version of the semaphore wait operation is similar to
01272  * rtf_sem_wait() but it is never blocks the caller.   If the semaphore is not
01273  * free, rtf_sem_trywait returns immediately and the semaphore value remains
01274  * unchanged.
01275  *
01276  * @param minor is a file descriptor returned by standard UNIX open in user
01277  * space while it is directly the chosen fifo number in kernel space. In fact
01278  * fifos semaphores must be associated to a fifo for identification purposes.
01279  *
01280  * Since it is not blocking rtf_sem_trywait can be used both in kernel and user
01281  * space.
01282  *
01283  * @retval 0 on success.
01284  * @retval EINVAL if @a fd_fifo  refers to an invalid file descriptor or fifo.
01285  */
01286 RTAI_SYSCALL_MODE int rtf_sem_trywait(unsigned int minor)
01287 {
01288     VALID_FIFO;
01289 
01290     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_TRY_WAIT, minor, 0);
01291 
01292     return mbx_sem_wait_if(&(fifo[minor].sem));
01293 }
01294 
01295 /**
01296  * @ingroup fifos_sem
01297  * Delete a semaphore
01298  *
01299  * rtf_sem_destroy deletes a semaphore previously created with rtf_sem_init().
01300  *
01301  * @param minor is a file descriptor returned by standard UNIX open in user
01302  * space while it is directly the chosen fifo number in kernel space. In fact
01303  * fifos semaphores must be associated to a fifo for identification purposes.
01304  *
01305  * Any tasks blocked on this semaphore is returned in error and allowed to run
01306  * when semaphore is destroyed.
01307  *
01308  * rtf_sem_destroy can be used both in kernel and user space.
01309  *
01310  * @retval 0 on sucess.
01311  * @retval EINVAL if @a fd_fifo refers to an invalid file descriptor or fifo.
01312  */
01313 RTAI_SYSCALL_MODE int rtf_sem_destroy(unsigned int minor)
01314 {
01315     VALID_FIFO;
01316 
01317     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_DESTROY, minor, 0);
01318 
01319     return mbx_sem_delete(&(fifo[minor].sem));
01320 }
01321 
01322 static int rtf_open(struct inode *inode, struct file *filp)
01323 {
01324 #define DEFAULT_SIZE 1000
01325     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_OPEN, MINOR(inode->i_rdev), DEFAULT_SIZE);
01326 
01327     return rtf_create(MINOR(inode->i_rdev), DEFAULT_SIZE);
01328 }
01329 
01330 static int rtf_fasync(int fd, struct file *filp, int mode)
01331 {   
01332     int minor;
01333     minor = MINOR((filp->f_dentry->d_inode)->i_rdev);
01334 
01335     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_FASYNC, minor, fd);
01336 
01337     return fasync_helper(fd, filp, mode, &(fifo[minor].asynq));
01338     if (!mode) {
01339         fifo[minor].asynq = 0;
01340     }
01341 }
01342 
01343 static int rtf_release(struct inode *inode, struct file *filp)
01344 {
01345     int minor;
01346     minor = MINOR(inode->i_rdev);
01347 
01348     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_RELEASE, minor, 0);
01349 
01350     if (waitqueue_active(&(fifo[minor].pollq))) {
01351         wake_up_interruptible(&(fifo[minor].pollq));
01352     }
01353     rtf_fasync(-1, filp, 0);
01354     set_tsk_need_resched(current);
01355     return rtf_destroy(minor);
01356 }
01357 
01358 static ssize_t rtf_read(struct file *filp, char *buf, size_t count, loff_t* ppos)
01359 {
01360     struct inode *inode = filp->f_dentry->d_inode;
01361     unsigned int minor = MINOR(inode->i_rdev);
01362     int handler_ret;
01363 
01364     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_READ, minor, count);
01365 
01366     if (filp->f_flags & O_NONBLOCK) {
01367         count -= mbx_receive_wp(&(fifo[minor].mbx), buf, count, 1);
01368         if (!count) {
01369             return -EAGAIN;
01370         }
01371     } else {
01372         count -= mbx_receive_wjo(&(fifo[minor].mbx), buf, count, 1);
01373     }
01374 
01375     if (count) {
01376         inode->i_atime = CURRENT_TIME;
01377         if ((handler_ret = (fifo[minor].handler)(minor, 'r')) < 0) {
01378             return handler_ret;
01379         }
01380     }
01381 
01382     return count;
01383 }
01384 
01385 static ssize_t rtf_write(struct file *filp, const char *buf, size_t count, loff_t* ppos)
01386 {
01387     struct inode *inode = filp->f_dentry->d_inode;
01388     unsigned int minor = MINOR(inode->i_rdev);
01389     int handler_ret;
01390 
01391     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_WRITE, minor, count);
01392 
01393     if (filp->f_flags & O_NONBLOCK) {
01394         count -= mbx_send_wp(&(fifo[minor].mbx), (char *)buf, count, 1);
01395         if (!count) {
01396             return -EAGAIN;
01397         }
01398     } else {
01399         count -= mbx_send(&(fifo[minor].mbx), (char *)buf, count, 1);
01400     }
01401 
01402     inode->i_ctime = inode->i_mtime = CURRENT_TIME;
01403     if ((handler_ret = (fifo[minor].handler)(minor, 'w')) < 0) {
01404         return handler_ret;
01405     }
01406 
01407     return count;
01408 }
01409 
01410 #define DELAY(x) (((x)*HZ + 500)/1000)
01411 
01412 static int rtf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
01413 {   
01414     unsigned int minor;
01415     FIFO *fifop;
01416 
01417     fifop = fifo + (minor = MINOR(inode->i_rdev));
01418 
01419     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_IOCTL, minor, cmd);
01420 
01421     switch(cmd) {
01422         case RESET: {
01423             return rtf_reset(minor);
01424         }
01425         case RESIZE: {
01426             return rtf_resize(minor, arg);
01427         }
01428         case SUSPEND_TIMED: {
01429             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SUSPEND_TIMED, DELAY(arg), 0);
01430             current->state = TASK_INTERRUPTIBLE;
01431             schedule_timeout(DELAY(arg));
01432             if (signal_pending(current)) {
01433                 return -ERESTARTSYS;
01434             }
01435             return 0;
01436         }
01437         case OPEN_SIZED: {
01438             return rtf_create(minor, arg);
01439         }
01440         case READ_ALL_AT_ONCE: {
01441             struct { char *buf; int count; } args;
01442             int handler_ret;
01443             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_READ_ALLATONCE, 0, 0);
01444             rt_copy_from_user(&args, (void *)arg, sizeof(args));
01445             args.count -= mbx_receive(&(fifop->mbx), args.buf, args.count, 1);
01446             if (args.count) {
01447                 inode->i_atime = CURRENT_TIME;
01448                 if ((handler_ret = (fifo[minor].handler)(minor,
01449 'r')) < 0) {
01450                     return handler_ret;
01451                 }
01452                 return args.count;
01453             }
01454             return 0;
01455         }
01456         case EAVESDROP: {
01457             struct { char *buf; int count; } args;
01458             rt_copy_from_user(&args, (void *)arg, sizeof(args));
01459             return args.count - mbx_evdrp(&(fifop->mbx), (char **)&args.buf, args.count, 1);
01460         }
01461         case READ_TIMED: {
01462             struct { char *buf; int count, delay; } args;
01463             int handler_ret;
01464             rt_copy_from_user(&args, (void *)arg, sizeof(args));
01465             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_READ_TIMED, args.count, DELAY(args.delay));
01466             if (!args.delay) {
01467                 args.count -= mbx_receive_wp(&(fifop->mbx), args.buf, args.count, 1);
01468                 if (!args.count) {
01469                     return -EAGAIN;
01470                 }
01471             } else {
01472                 args.count -= mbx_receive_timed(&(fifop->mbx), args.buf, args.count, DELAY(args.delay), 1);
01473             }
01474             if (args.count) {
01475                 inode->i_atime = CURRENT_TIME;
01476 //              if ((handler_ret = (fifop->handler)(minor)) < 0) {
01477                 if ((handler_ret = (fifop->handler)(minor, 'r')) < 0) {
01478                     return handler_ret;
01479                 }
01480                 return args.count;
01481             }
01482             return 0;
01483         }
01484         case READ_IF: {
01485             struct { char *buf; int count; } args;
01486             int handler_ret;
01487             rt_copy_from_user(&args, (void *)arg, sizeof(args));
01488             args.count -= mbx_receive_if(&(fifop->mbx), args.buf, args.count, 1);
01489             if (args.count) {
01490                 inode->i_atime = CURRENT_TIME;
01491                 if ((handler_ret = (fifo[minor].handler)(minor, 'r')) < 0) {
01492                     return handler_ret;
01493                 }
01494                 return args.count;
01495             }
01496             return 0;
01497         }
01498         case WRITE_TIMED: {
01499             struct { char *buf; int count, delay; } args;
01500             int handler_ret;
01501             rt_copy_from_user(&args, (void *)arg, sizeof(args));
01502             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_WRITE_TIMED, args.count, DELAY(args.delay));
01503             if (!args.delay) {
01504                 args.count -= mbx_send_wp(&(fifop->mbx), args.buf, args.count, 1);
01505                 if (!args.count) {
01506                     return -EAGAIN;
01507                 }
01508             } else {
01509                 args.count -= mbx_send_timed(&(fifop->mbx), args.buf, args.count, DELAY(args.delay), 1);
01510             }
01511             inode->i_ctime = inode->i_mtime = CURRENT_TIME;
01512 //          if ((handler_ret = (fifop->handler)(minor)) < 0) {
01513             if ((handler_ret = (fifop->handler)(minor, 'w')) < 0) {
01514                 return handler_ret;
01515             }
01516             return args.count;
01517         }
01518         case WRITE_IF: {
01519             struct { char *buf; int count, delay; } args;
01520             int handler_ret;
01521             rt_copy_from_user(&args, (void *)arg, sizeof(args));
01522             if (args.count) {
01523                 args.count -= mbx_send_wp(&(fifop->mbx), args.buf, args.count, 1);
01524                 if (!args.count) {
01525                     return -EAGAIN;
01526                 }
01527             }
01528             inode->i_ctime = inode->i_mtime = CURRENT_TIME;
01529             if ((handler_ret = (fifo[minor].handler)(minor, 'w')) <
01530 0) {
01531                 return handler_ret;
01532             }
01533             return args.count;
01534         }
01535         case OVRWRITE: {
01536             struct { char *buf; int count; } args;
01537             rt_copy_from_user(&args, (void *)arg, sizeof(args));
01538             return mbx_ovrwr_send(&(fifop->mbx), (char **)&args.buf, args.count, 1);
01539         }
01540         case RTF_SEM_INIT: {
01541             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_INIT, minor, arg);
01542             mbx_sem_init(&(fifop->sem), arg);
01543             return 0;
01544         }
01545         case RTF_SEM_WAIT: {
01546             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_WAIT, minor, 0);
01547             return mbx_sem_wait(&(fifop->sem));
01548         }
01549         case RTF_SEM_TRYWAIT: {
01550             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_TRY_WAIT, minor, 0);
01551             return mbx_sem_wait_if(&(fifop->sem));
01552         }
01553         case RTF_SEM_TIMED_WAIT: {
01554             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_TIMED_WAIT, minor, DELAY(arg));
01555             return mbx_sem_wait_timed(&(fifop->sem), DELAY(arg));
01556         }
01557         case RTF_SEM_POST: {
01558             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_POST, minor, 0);
01559             mbx_sem_signal(&(fifop->sem), 0);
01560             return 0;
01561         }
01562         case RTF_SEM_DESTROY: {
01563             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SEM_DESTROY, minor, 0);
01564             mbx_sem_delete(&(fifop->sem));
01565             return 0;
01566         }
01567         case SET_ASYNC_SIG: {
01568             TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_SET_ASYNC_SIG, arg, 0);
01569             async_sig = arg;
01570             return 0;
01571         }
01572         case FIONREAD: {
01573             return put_user(fifo[minor].mbx.avbs, (int *)arg);
01574             }
01575         /* 
01576          * Support for named FIFOS : Ian Soanes (ians@zentropix.com)
01577          * Based on ideas from Stuart Hughes and David Schleef
01578          */
01579         case RTF_GET_N_FIFOS: {
01580             return MAX_FIFOS;
01581         }
01582         case RTF_GET_FIFO_INFO: {
01583             struct rt_fifo_get_info_struct req;
01584             int i, n;
01585 
01586             rt_copy_from_user(&req, (void *)arg, sizeof(req));
01587             for ( i = req.fifo, n = 0; 
01588                   i < MAX_FIFOS && n < req.n; 
01589                   i++, n++
01590                   ) {
01591                 struct rt_fifo_info_struct info;
01592 
01593                 info.fifo_number = i;
01594                 info.size        = fifo[i].mbx.size;
01595                 info.opncnt      = fifo[i].opncnt;
01596                 info.avbs        = fifo[i].mbx.avbs;
01597                 info.frbs        = fifo[i].mbx.frbs;
01598                 strncpy(info.name, fifo[i].name, RTF_NAMELEN+1);
01599                 rt_copy_to_user(req.ptr + n, &info, sizeof(info));
01600             }
01601             return n;
01602         }
01603         case RTF_NAMED_CREATE: {
01604             struct { char name[RTF_NAMELEN+1]; int size; } args;
01605 
01606             rt_copy_from_user(&args, (void *)arg, sizeof(args));
01607             return rtf_named_create(args.name, args.size);
01608             }
01609         case RTF_CREATE_NAMED: {
01610             char name[RTF_NAMELEN+1];
01611 
01612             rt_copy_from_user(name, (void *)arg, RTF_NAMELEN+1);
01613             return rtf_create_named(name);
01614             }
01615         case RTF_NAME_LOOKUP: {
01616             char name[RTF_NAMELEN+1];
01617 
01618             rt_copy_from_user(name, (void *)arg, RTF_NAMELEN+1);
01619             return rtf_getfifobyname(name);
01620         }
01621             case TCGETS:
01622                 /* Keep isatty() probing silent */
01623                 return -ENOTTY;
01624 
01625         default : {
01626             printk("RTAI-FIFO: cmd %d is not implemented\n", cmd);
01627             return -EINVAL;
01628     }
01629     }
01630     return 0;
01631 }
01632 
01633 static unsigned int rtf_poll(struct file *filp, poll_table *wait)
01634 {
01635     unsigned int retval, minor;
01636 
01637     retval = 0;
01638     minor = MINOR((filp->f_dentry->d_inode)->i_rdev);
01639     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_POLL, minor, 0);
01640     poll_wait(filp, &(fifo[minor].pollq), wait);
01641     if (fifo[minor].mbx.avbs) {
01642         retval |= POLLIN | POLLRDNORM;
01643     }
01644     if (fifo[minor].mbx.frbs) {
01645         retval |= POLLOUT | POLLWRNORM;
01646     }
01647     return retval;
01648 }
01649 
01650 static loff_t rtf_llseek(struct file *filp, loff_t offset, int origin)
01651 {
01652     TRACE_RTAI_FIFO(TRACE_RTAI_EV_FIFO_LLSEEK, MINOR((filp->f_dentry->d_inode)->i_rdev), offset);
01653 
01654     return rtf_reset(MINOR((filp->f_dentry->d_inode)->i_rdev));
01655 }
01656 
01657 static struct file_operations rtf_fops =
01658 {
01659     owner:      THIS_MODULE,
01660     llseek:     rtf_llseek,
01661     read:       rtf_read,
01662     write:      rtf_write,
01663     poll:       rtf_poll,
01664     ioctl:      rtf_ioctl,
01665     open:       rtf_open,
01666     release:    rtf_release,
01667     fasync:     rtf_fasync,
01668 };
01669 
01670 #ifdef CONFIG_DEVFS_FS
01671 #include <linux/devfs_fs_kernel.h>
01672 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
01673 static devfs_handle_t devfs_handle;
01674 #endif
01675 #endif
01676 
01677 static int MaxFifos = MAX_FIFOS;
01678 RTAI_MODULE_PARM(MaxFifos, int);
01679 
01680 #define LXRTEXT  /* undef it to allow using fifos without any RTAI scheduler */
01681 
01682 #ifdef LXRTEXT
01683 
01684 static struct rt_fun_entry rtai_fifos_fun[] = {
01685     [_CREATE]       = { 0, rtf_create },
01686     [_DESTROY]      = { 0, rtf_destroy },
01687     [_PUT]          = { 0, rtf_put },
01688     [_GET]          = { 0, rtf_get },
01689     [_RESET]        = { 0, rtf_reset },
01690     [_RESIZE]       = { 0, rtf_resize },
01691     [_SEM_INIT]     = { 0, rtf_sem_init },
01692     [_SEM_DESTRY]   = { 0, rtf_sem_destroy },
01693     [_SEM_POST]     = { 0, rtf_sem_post },
01694     [_SEM_TRY]      = { 0, rtf_sem_trywait },
01695     [_CREATE_NAMED] = { 0, rtf_create_named },
01696     [_GETBY_NAME]   = { 0, rtf_getfifobyname },
01697     [_OVERWRITE]    = { 0, rtf_ovrwr_put },
01698     [_PUT_IF]       = { 0, rtf_put_if },
01699     [_GET_IF]       = { 0, rtf_get_if },
01700     [_AVBS]         = { 0, rtf_get_avbs },
01701     [_FRBS]         = { 0, rtf_get_frbs }
01702 };
01703 
01704 static int register_lxrt_fifos_support(void)
01705 {
01706     if (set_rt_fun_ext_index(rtai_fifos_fun, FUN_FIFOS_LXRT_INDX)) {
01707         printk("LXRT EXTENSION SLOT FOR FIFOS (%d) ALREADY USED\n", FUN_FIFOS_LXRT_INDX);
01708         return -EACCES;
01709     }
01710     return 0;
01711 }
01712 
01713 static void unregister_lxrt_fifos_support(void)
01714 {
01715     reset_rt_fun_ext_index(rtai_fifos_fun, FUN_FIFOS_LXRT_INDX);
01716 }
01717 
01718 #else
01719 
01720 static int register_lxrt_fifos_support(void) { return 0; }
01721 #define unregister_lxrt_fifos_support()
01722 
01723 #endif
01724 
01725 #define USE_UDEV_CLASS 1
01726 
01727 #if USE_UDEV_CLASS
01728 static class_t *fifo_class = NULL;
01729 #endif
01730 
01731 int __rtai_fifos_init(void)
01732 {
01733     int minor;
01734 
01735     if (!(fifo = (FIFO *)kmalloc(MaxFifos*sizeof(FIFO), GFP_KERNEL))) {
01736         printk("RTAI-FIFO: cannot allocate memory for FIFOS structure.\n");
01737         return -ENOSPC;
01738     }
01739     memset(fifo, 0, MaxFifos*sizeof(FIFO));
01740 
01741 #if USE_UDEV_CLASS
01742     if ((fifo_class = class_create(THIS_MODULE, "rtai_fifos")) == NULL) {
01743         printk("RTAI-FIFO: cannot create class.\n");
01744         return -EBUSY;
01745     }
01746     for (minor = 0; minor < MAX_FIFOS; minor++) {
01747         if (CLASS_DEVICE_CREATE(fifo_class, MKDEV(RTAI_FIFOS_MAJOR, minor), NULL, "rtf%d", minor) == NULL) {
01748             printk("RTAI-FIFO: cannot attach class.\n");
01749             class_destroy(fifo_class);
01750                         return -EBUSY;
01751         }
01752     }
01753 #endif
01754 
01755     if (register_chrdev(RTAI_FIFOS_MAJOR, "rtai_fifo", &rtf_fops)) {
01756         printk("RTAI-FIFO: cannot register major %d.\n", RTAI_FIFOS_MAJOR);
01757         return -EIO;
01758     }
01759 
01760     if ((fifo_srq = rtf_request_srq(rtf_sysrq_handler)) < 0) {
01761         printk("RTAI-FIFO: no srq available in rtai.\n");
01762         return fifo_srq;
01763     }
01764     taskq.in = taskq.out = pol_asyn_q.in = pol_asyn_q.out = 0;
01765     async_sig = SIGIO;
01766 
01767     for (minor = 0; minor < MAX_FIFOS; minor++) {
01768         fifo[minor].opncnt = fifo[minor].pol_asyn_pended = 0;
01769         init_waitqueue_head(&fifo[minor].pollq);
01770         fifo[minor].asynq = 0;;
01771         mbx_sem_init(&(fifo[minor].sem), 0);
01772     }
01773 #ifdef CONFIG_PROC_FS
01774     rtai_proc_fifo_register();
01775 #endif
01776     return register_lxrt_fifos_support();
01777 }
01778 
01779 void __rtai_fifos_exit(void)
01780 {
01781     unregister_lxrt_fifos_support();
01782     unregister_chrdev(RTAI_FIFOS_MAJOR, "rtai_fifo");
01783 
01784 #if USE_UDEV_CLASS
01785 {
01786     int minor;
01787     for (minor = 0; minor < MAX_FIFOS; minor++) {
01788         class_device_destroy(fifo_class, MKDEV(RTAI_FIFOS_MAJOR, minor));
01789     }
01790     class_destroy(fifo_class);
01791 }
01792 #endif
01793 
01794     if (rtf_free_srq(fifo_srq) < 0) {
01795         printk("RTAI-FIFO: rtai srq %d illegal or already free.\n", fifo_srq);
01796     }
01797 #ifdef CONFIG_PROC_FS
01798         rtai_proc_fifo_unregister();
01799 #endif
01800     kfree(fifo);
01801 }
01802 
01803 #ifndef CONFIG_RTAI_FIFOS_BUILTIN
01804 module_init(__rtai_fifos_init);
01805 module_exit(__rtai_fifos_exit);
01806 #endif /* !CONFIG_RTAI_FIFOS_BUILTIN */
01807 
01808 #ifdef CONFIG_PROC_FS
01809 /* ----------------------< proc filesystem section >----------------------*/
01810 
01811 static int rtai_read_fifos(char* buf, char** start, off_t offset,
01812     int len, int *eof, void *data)
01813 {
01814     int i;
01815 
01816     len = sprintf(buf, "RTAI Real Time fifos status.\n\n" );
01817     if (len > LIMIT) {
01818         return(len);
01819     }
01820     len += sprintf(buf + len, "Maximum number of FIFOS %d.\n\n", MaxFifos);
01821     if (len > LIMIT) {
01822         return(len);
01823     }
01824     len += sprintf(buf+len, "fifo No  Open Cnt  Buff Size  handler  malloc type");
01825     if (len > LIMIT) {
01826         return(len);
01827     }
01828     len += sprintf(buf+len, " Name\n----------------");
01829     if (len > LIMIT) {
01830         return(len);
01831     }
01832     len += sprintf(buf+len, "-----------------------------------------\n");
01833     if (len > LIMIT) {
01834         return(len);
01835     }
01836 /*
01837  * Display the status of all open RT fifos.
01838  */
01839     for (i = 0; i < MAX_FIFOS; i++) {
01840         if (fifo[i].opncnt > 0) {
01841             len += sprintf( buf+len, "%-8d %-9d %-10d %-10p %-12s", i,
01842                                     fifo[i].opncnt, fifo[i].mbx.size,
01843                     fifo[i].handler,
01844                     fifo[i].malloc_type == 'v'
01845                         ? "vmalloc" : "kmalloc" 
01846                     );
01847             if (len > LIMIT) {
01848                 return(len);
01849             }
01850             len += sprintf(buf+len, "%s\n", fifo[i].name);
01851             if (len > LIMIT) {
01852                 return(len);
01853             }
01854         } /* End if - fifo is open. */
01855     } /* End for loop - loop for all fifos. */
01856     return len;
01857 
01858 }  /* End function - rtai_read_fifos */
01859 
01860 static int rtai_proc_fifo_register(void) 
01861 {
01862         struct proc_dir_entry *proc_fifo_ent;
01863         proc_fifo_ent = create_proc_entry("fifos", S_IFREG|S_IRUGO|S_IWUSR, 
01864                                 rtai_proc_root);
01865         if (!proc_fifo_ent) {
01866                 printk("Unable to initialize /proc/rtai/fifos\n");
01867                 return(-1);
01868         }
01869         proc_fifo_ent->read_proc = rtai_read_fifos;
01870     return 0;
01871 }
01872 
01873 static void rtai_proc_fifo_unregister(void) 
01874 {
01875     remove_proc_entry("fifos", rtai_proc_root);
01876 }
01877 
01878 /* ------------------< end of proc filesystem section >------------------*/
01879 #endif /* CONFIG_PROC_FS */
01880 
01881 /* 
01882  * Support for named FIFOS : Ian Soanes (ians@zentropix.com)
01883  * Based on ideas from Stuart Hughes and David Schleef
01884  */
01885 int rtf_named_create(const char *name, int size)
01886 {
01887     int minor, err;
01888     unsigned long flags;
01889 
01890     if (strlen(name) > RTF_NAMELEN) {
01891             return -EINVAL;
01892     }
01893     rtf_spin_lock_irqsave(flags, rtf_name_lock);
01894     for (minor = 0; minor < MAX_FIFOS; minor++) {
01895             if (!strncmp(name, fifo[minor].name, RTF_NAMELEN)) {
01896             break;
01897         } else if (!fifo[minor].opncnt && !fifo[minor].name[0]) {
01898                 strncpy(fifo[minor].name, name, RTF_NAMELEN + 1);
01899             rtf_spin_unlock_irqrestore(flags, rtf_name_lock);
01900                 if ((err = rtf_create(minor, size)) < 0) {
01901                     fifo[minor].name[0] = 0;
01902                     return err;
01903             }
01904             return minor;
01905         }
01906     }
01907     rtf_spin_unlock_irqrestore(flags, rtf_name_lock);
01908     return -EBUSY;
01909 }
01910 
01911 RTAI_SYSCALL_MODE int rtf_create_named(const char *name)
01912 {
01913     return rtf_named_create(name, DEFAULT_SIZE);
01914 }
01915 
01916 RTAI_SYSCALL_MODE int rtf_getfifobyname(const char *name)
01917 {
01918         int minor;
01919 
01920     if (strlen(name) > RTF_NAMELEN) {
01921             return -EINVAL;
01922     }
01923     for (minor = 0; minor < MAX_FIFOS; minor++) {
01924             if ( fifo[minor].opncnt && 
01925              !strncmp(name, fifo[minor].name, RTF_NAMELEN)
01926              ) {
01927                 return minor;
01928         }
01929     }
01930     return -ENODEV;
01931 }
01932 
01933 #ifdef CONFIG_KBUILD
01934 EXPORT_SYMBOL(rtf_create);
01935 EXPORT_SYMBOL(rtf_create_handler);
01936 EXPORT_SYMBOL(rtf_create_named);
01937 EXPORT_SYMBOL(rtf_destroy);
01938 EXPORT_SYMBOL(rtf_evdrp);
01939 EXPORT_SYMBOL(rtf_get);
01940 EXPORT_SYMBOL(rtf_get_if);
01941 EXPORT_SYMBOL(rtf_getfifobyname);
01942 EXPORT_SYMBOL(rtf_ovrwr_put);
01943 EXPORT_SYMBOL(rtf_put);
01944 EXPORT_SYMBOL(rtf_put_if);
01945 EXPORT_SYMBOL(rtf_get_avbs);
01946 EXPORT_SYMBOL(rtf_get_frbs);
01947 EXPORT_SYMBOL(rtf_reset);
01948 EXPORT_SYMBOL(rtf_resize);
01949 EXPORT_SYMBOL(rtf_sem_destroy);
01950 EXPORT_SYMBOL(rtf_sem_init);
01951 EXPORT_SYMBOL(rtf_sem_post);
01952 EXPORT_SYMBOL(rtf_sem_trywait);
01953 EXPORT_SYMBOL(rtf_named_create);
01954 #endif /* CONFIG_KBUILD */

Generated on Tue Feb 2 17:46:05 2010 for RTAI API by  doxygen 1.4.7