-/* can_quekern.c - CAN message queues functions for the Linux kernel
- * Linux CAN-bus device driver.
- * New CAN queues by Pavel Pisa - OCERA team member
- * email:pisa@cmp.felk.cvut.cz
- * This software is released under the GPL-License.
- * Version lincan-0.2 9 Jul 2003
- */
+/**************************************************************************/
+/* File: can_quekern.c - CAN message queues functions for the Linux kernel*/
+/* */
+/* LinCAN - (Not only) Linux CAN bus driver */
+/* Copyright (C) 2002-2009 DCE FEE CTU Prague <http://dce.felk.cvut.cz> */
+/* Copyright (C) 2002-2009 Pavel Pisa <pisa@cmp.felk.cvut.cz> */
+/* Funded by OCERA and FRESCOR IST projects */
+/* */
+/* LinCAN is free software; you can redistribute it and/or modify it */
+/* under terms of the GNU General Public License as published by the */
+/* Free Software Foundation; either version 2, or (at your option) any */
+/* later version. LinCAN is distributed in the hope that it will be */
+/* useful, but WITHOUT ANY WARRANTY; without even the implied warranty */
+/* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
+/* General Public License for more details. You should have received a */
+/* copy of the GNU General Public License along with LinCAN; see file */
+/* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, */
+/* Cambridge, MA 02139, USA. */
+/* */
+/* To allow use of LinCAN in the compact embedded systems firmware */
+/* and RT-executives (RTEMS for example), main authors agree with next */
+/* special exception: */
+/* */
+/* Including LinCAN header files in a file, instantiating LinCAN generics */
+/* or templates, or linking other files with LinCAN objects to produce */
+/* an application image/executable, does not by itself cause the */
+/* resulting application image/executable to be covered by */
+/* the GNU General Public License. */
+/* This exception does not however invalidate any other reasons */
+/* why the executable file might be covered by the GNU Public License. */
+/* Publication of enhanced or derived LinCAN files is required although. */
+/**************************************************************************/
#include "../include/can.h"
#include "../include/can_sysdep.h"
extern atomic_t edge_num_cnt;
#ifdef CAN_DEBUG
- #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_queue (debug): " fmt,\
+ #define DEBUGQUE(fmt,args...) can_printk(KERN_ERR "can_quekern (debug): " fmt,\
##args)
#else
#define DEBUGQUE(fmt,args...)
#endif
-#define ERRMSGQUE(fmt,args...) can_printk(KERN_ERR "can_queue: " fmt,\
+#define ERRMSGQUE(fmt,args...) can_printk(KERN_ERR "can_quekern: " fmt,\
##args)
-/*
- * Modifies Tx message processing
+/*
+ * Modifies Tx message processing
* 0 .. local message processing disabled
* 1 .. local messages disabled by default but can be enabled by canque_set_filt
* 2 .. local messages enabled by default, can be disabled by canque_set_filt
canque_fifo_done_kern(&qedge->fifo);
kfree(qedge);
}
-
+
can_spin_lock_irqsave(&canque_dead_func_lock, flags);
entry=canque_dead_ends.next;
can_spin_unlock_irqrestore(&canque_dead_func_lock,flags);
}
-void canque_edge_do_dead(struct canque_edge_t *edge, int dead_fl)
+void canque_edge_do_dead(struct canque_edge_t *edge)
{
can_spin_irqflags_t flags;
-
- if(dead_fl) return;
-
+
+ canque_notify_bothends(edge,CANQUEUE_NOTIFY_NOUSR);
+ #ifdef CAN_WITH_RTL
+ /* The problem of the above call is, that in RT-Linux to Linux notify
+ case is edge scheduled for delayed notify delivery, this needs
+ to be reflected there */
+ if(atomic_read(&edge->edge_used)>0){
+ can_spin_lock_irqsave(&edge->inends->ends_lock, flags);
+ can_spin_lock(&edge->outends->ends_lock);
+ if(atomic_read(&edge->edge_used)>0){
+ /* left edge to live for a while, banshee comes again in a while */
+ canque_fifo_clear_fl(&edge->fifo,DEAD);
+ can_spin_unlock(&edge->outends->ends_lock);
+ can_spin_unlock_irqrestore(&edge->inends->ends_lock, flags);
+ can_printk(KERN_ERR "can_quertl (debug): canque_edge_do_dead postponed\n");
+ return;
+ }
+ can_spin_unlock(&edge->outends->ends_lock);
+ can_spin_unlock_irqrestore(&edge->inends->ends_lock, flags);
+ }
+ #endif /*CAN_WITH_RTL*/
+
if(canqueue_disconnect_edge(edge)<0){
ERRMSGQUE("canque_edge_do_dead: canqueue_disconnect_edge failed !!!\n");
return;
/**
* canqueue_notify_kern - notification callback handler for Linux userspace clients
* @qends: pointer to the callback side ends structure
- * @qedge: edge which invoked notification
+ * @qedge: edge which invoked notification
* @what: notification type
+ *
+ * The notification event is handled directly by call of this function except case,
+ * when called from RT-Linux context in mixed mode Linux/RT-Linux compilation.
+ * It is not possible to directly call Linux kernel synchronization primitives
+ * in such case. The notification request is postponed and signaled by @pending_inops flags
+ * by call canqueue_rtl2lin_check_and_pend() function.
+ * The edge reference count is increased until until all pending notifications are processed.
*/
void canqueue_notify_kern(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
{
DEBUGQUE("canqueue_notify_kern postponed\n");
return;
}
-
+
switch(what){
case CANQUEUE_NOTIFY_EMPTY:
wake_up(&qends->endinfo.fileinfo.emptyq);
wake_up(&qends->endinfo.fileinfo.writeq);
#ifdef CAN_ENABLE_KERN_FASYNC
/* Asynchronous I/O processing */
- kill_fasync(&qends->endinfo.fileinfo.fasync, SIGIO, POLL_OUT);
+ kill_fasync(&qends->endinfo.fileinfo.fasync, SIGIO, POLL_OUT);
#endif /*CAN_ENABLE_KERN_FASYNC*/
break;
case CANQUEUE_NOTIFY_PROC:
wake_up(&qends->endinfo.fileinfo.readq);
#ifdef CAN_ENABLE_KERN_FASYNC
/* Asynchronous I/O processing */
- kill_fasync(&qends->endinfo.fileinfo.fasync, SIGIO, POLL_IN);
+ kill_fasync(&qends->endinfo.fileinfo.fasync, SIGIO, POLL_IN);
#endif /*CAN_ENABLE_KERN_FASYNC*/
break;
case CANQUEUE_NOTIFY_NOUSR:
#ifdef CAN_ENABLE_KERN_FASYNC
qends->endinfo.fileinfo.fasync=NULL;
#endif /*CAN_ENABLE_KERN_FASYNC*/
-
+
qends->notify=canqueue_notify_kern;
DEBUGQUE("canqueue_ends_init_kern\n");
return 0;
{
int ret=-1;
DEBUGQUE("canque_get_inslot4id_wait_kern for cmd %d, id %ld, prio %d\n",cmd,id,prio);
- wait_event_interruptible((qends->endinfo.fileinfo.writeq),
+ wait_event_interruptible((qends->endinfo.fileinfo.writeq),
(ret=canque_get_inslot4id(qends,qedgep,slotp,cmd,id,prio))!=-1);
return ret;
}
{
int ret=-1;
DEBUGQUE("canque_get_outslot_wait_kern\n");
- wait_event_interruptible((qends->endinfo.fileinfo.readq),
+ wait_event_interruptible((qends->endinfo.fileinfo.readq),
(ret=canque_test_outslot(qends,qedgep,slotp))!=-1);
return ret;
}
{
int ret=-1;
DEBUGQUE("canque_sync_wait_kern\n");
- wait_event_interruptible((qends->endinfo.fileinfo.emptyq),
+ wait_event_interruptible((qends->endinfo.fileinfo.emptyq),
(ret=canque_fifo_test_fl(&qedge->fifo,EMPTY)?1:0));
return ret;
}
#ifdef USE_SYNC_DISCONNECT_EDGE_KERN
-/**
+/*not included in doc
* canqueue_disconnect_edge_kern - disconnect edge from communicating entities with wait
* @qends: ends structure belonging to calling communication object
* @qedge: pointer to edge
DEBUGQUE("canqueue_disconnect_edge_kern %d called\n",qedge->edge_num);
if(!canque_fifo_test_and_set_fl(&qedge->fifo,DEAD)){
canque_notify_bothends(qedge, CANQUEUE_NOTIFY_DEAD);
-
+
if(atomic_read(&qedge->edge_used)>0)
atomic_dec(&qedge->edge_used);
DEBUGQUE("canqueue_disconnect_edge_kern %d waiting\n",qedge->edge_num);
- wait_event((qends->endinfo.fileinfo.emptyq),
+ wait_event((qends->endinfo.fileinfo.emptyq),
(canqueue_disconnect_edge(qedge)>=0));
/*set_current_state(TASK_UNINTERRUPTIBLE);*/
int canqueue_ends_sync_all_kern(struct canque_ends_t *qends)
{
struct canque_edge_t *qedge;
-
+
canque_for_each_inedge(qends, qedge){
DEBUGQUE("canque_sync_wait_kern called for edge %d\n",qedge->edge_num);
canque_sync_wait_kern(qends, qedge);
/*Wait for sending of all pending messages in the output FIFOs*/
if(sync)
canqueue_ends_sync_all_kern(qends);
-
+
/* Finish or kill all outgoing edges listed in inends */
delayed=canqueue_ends_kill_inlist(qends, 1);
/* Kill all incoming edges listed in outends */