1 /* can_quertl.c - CAN message queues functions for the RT-Linux
2 * Linux CAN-bus device driver.
3 * New CAN queues by Pavel Pisa - OCERA team member
4 * email:pisa@cmp.felk.cvut.cz
5 * This software is released under the GPL-License.
6 * Version lincan-0.2 9 Jul 2003
11 #include "../include/can.h"
12 #include "../include/can_sysdep.h"
13 #include "../include/can_queue.h"
15 #include <rtl_malloc.h>
18 * Modifies Tx message processing
19 * 0 .. local message processing disabled
20 * 1 .. local messages disabled by default but can be enabled by canque_set_filt
21 * 2 .. local messages enabled by default, can be disabled by canque_set_filt
23 extern int processlocal;
26 #define CANQUE_PENDOPS_LIMIT 15
27 #define CANQUE_PENDOPS_MASK ((1<<CANQUE_PENDOPS_LIMIT)-1)
29 struct list_head canque_pending_edges_list;
30 can_spinlock_t canque_pending_edges_lock;
32 static int canqueue_rtl_irq = 0;
35 canqueue_rtl2lin_handler(int irq, void *ignore, struct pt_regs *ignoreregs)
37 can_spin_irqflags_t flags;
38 struct canque_edge_t *qedge;
39 unsigned pending_inops;
40 unsigned pending_outops;
43 can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
45 while(!list_empty(&canque_pending_edges_list)){
46 qedge=list_entry(canque_pending_edges_list.next,struct canque_edge_t,pending_peers);
47 list_del(&qedge->pending_peers);
48 canque_fifo_clear_fl(&qedge->fifo, NOTIFYPEND);
49 pending_inops=qedge->pending_inops;
50 qedge->pending_inops=0;
51 pending_outops=qedge->pending_outops;
52 qedge->pending_outops=0;
53 can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
55 if(pending_outops & ~CANQUE_PENDOPS_MASK){
56 pending_outops &= CANQUE_PENDOPS_MASK;
57 canque_notify_outends(qedge,CANQUEUE_NOTIFY_ERROR | qedge->fifo.error_code);
59 for(i=0;pending_outops;i++,pending_outops>>=1){
61 canque_notify_outends(qedge,i);
63 if(pending_inops & ~CANQUE_PENDOPS_MASK){
64 pending_inops &= CANQUE_PENDOPS_MASK;
65 canque_notify_inends(qedge,CANQUEUE_NOTIFY_ERROR | qedge->fifo.error_code);
67 for(i=0;pending_inops;i++,pending_inops>>=1){
69 canque_notify_inends(qedge,i);
72 canque_edge_decref(qedge);
73 can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
76 can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
83 * canqueue_rtl2lin_check_and_pend - postpones edge notification if called from RT-Linux
84 * @qends: notification target ends
85 * @qedge: edge delivering notification
86 * @what: notification type
88 * Return Value: if called from Linux context, returns 0 and lefts notification processing
89 * on caller responsibility. If called from RT-Linux contexts, schedules postponed
90 * event delivery and returns 1
92 int canqueue_rtl2lin_check_and_pend(struct canque_ends_t *qends,
93 struct canque_edge_t *qedge, int what)
95 can_spin_irqflags_t flags;
97 if(rtl_rt_system_is_idle()) return 0;
99 can_spin_lock_irqsave (&canque_pending_edges_lock, flags);
101 if(what>CANQUE_PENDOPS_LIMIT) what=CANQUE_PENDOPS_LIMIT;
103 if(qends == qedge->inends) {
104 set_bit(what,&qedge->pending_inops);
105 } else if(qends == qedge->outends) {
106 set_bit(what,&qedge->pending_outops);
109 if(!canque_fifo_test_and_set_fl(&qedge->fifo, NOTIFYPEND)){
110 canque_edge_incref(qedge);
111 list_add_tail(&qedge->pending_peers,&canque_pending_edges_list);
112 rtl_global_pend_irq (canqueue_rtl_irq);
115 can_spin_unlock_irqrestore (&canque_pending_edges_lock, flags);
123 * canque_fifo_init_rtl - initialize one CAN FIFO
124 * @fifo: pointer to the FIFO structure
125 * @slotsnr: number of requested slots
127 * Return Value: The negative value indicates, that there is no memory
128 * to allocate space for the requested number of the slots.
130 int canque_fifo_init_rtl(struct canque_fifo_t *fifo, int slotsnr)
133 if(!slotsnr) slotsnr=MAX_BUF_LENGTH;
134 size=sizeof(struct canque_slot_t)*slotsnr;
135 fifo->entry=rt_malloc(size);
136 if(!fifo->entry) return -1;
137 fifo->slotsnr=slotsnr;
138 return canque_fifo_init_slots(fifo);
142 * canque_fifo_done_rtl - frees slots allocated for CAN FIFO
143 * @fifo: pointer to the FIFO structure
145 int canque_fifo_done_rtl(struct canque_fifo_t *fifo)
148 rt_free(fifo->entry);
153 void canque_dispose_edge_rtl(struct canque_edge_t *qedge)
155 canque_fifo_done_rtl(&qedge->fifo);
160 * canque_new_edge_rtl - allocate new edge structure in the RT-Linux context
161 * @slotsnr: required number of slots in the newly allocated edge structure
163 * Return Value: Returns pointer to allocated slot structure or %NULL if
164 * there is not enough memory to process operation.
166 struct canque_edge_t *canque_new_edge_rtl(int slotsnr)
168 struct canque_edge_t *qedge;
169 qedge = (struct canque_edge_t *)rt_malloc(sizeof(struct canque_edge_t));
170 if(qedge == NULL) return NULL;
172 memset(qedge,0,sizeof(struct canque_edge_t));
173 can_spin_lock_init(&qedge->fifo.fifo_lock);
174 canque_fifo_set_fl(&qedge->fifo,RTL_MEM);
175 if(canque_fifo_init_rtl(&qedge->fifo, slotsnr)<0){
179 atomic_set(&qedge->edge_used,1);
181 qedge->filtmask = canque_filtid2internal(0l, (processlocal<2)? MSG_LOCAL:0);
182 qedge->edge_prio = 0;
183 #if defined(CAN_DEBUG) && 0
184 /* not exactly clean, but enough for debugging */
185 atomic_inc(&edge_num_cnt);
186 qedge->edge_num=atomic_read(&edge_num_cnt);
187 #endif /* CAN_DEBUG */
191 void canque_ends_free_rtl(struct canque_ends_t *qends)
198 * canqueue_notify_rtl - notification callback handler for Linux userspace clients
199 * @qends: pointer to the callback side ends structure
200 * @qedge: edge which invoked notification
201 * @what: notification type
203 void canqueue_notify_rtl(struct canque_ends_t *qends, struct canque_edge_t *qedge, int what)
205 rtl_irqstate_t flags;
208 case CANQUEUE_NOTIFY_EMPTY:
209 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
210 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
211 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
212 if(canque_fifo_test_and_clear_fl(&qedge->fifo, FREEONEMPTY))
213 canque_edge_decref(qedge);
215 case CANQUEUE_NOTIFY_SPACE:
216 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
217 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
218 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
220 case CANQUEUE_NOTIFY_PROC:
221 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
222 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
223 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
225 case CANQUEUE_NOTIFY_NOUSR:
226 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
227 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
228 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
229 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
230 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
232 case CANQUEUE_NOTIFY_DEAD_WANTED:
233 case CANQUEUE_NOTIFY_DEAD:
234 if(canque_fifo_test_and_clear_fl(&qedge->fifo, READY))
235 canque_edge_decref(qedge);
237 case CANQUEUE_NOTIFY_ATTACH:
244 * canqueue_ends_init_rtl - RT-Linux clients specific ends initialization
245 * @qends: pointer to the callback side ends structure
247 int canqueue_ends_init_rtl(struct canque_ends_t *qends)
249 canqueue_ends_init_gen(qends);
251 rtl_spin_lock_init(&(qends->endinfo.rtlinfo.rtl_lock));
252 rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_readq));
253 rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_writeq));
254 rtl_wait_init(&(qends->endinfo.rtlinfo.rtl_emptyq));
256 qends->notify=canqueue_notify_rtl;
261 * canqueue_ends_dispose_rtl - finalizing of the ends structure for Linux kernel clients
262 * @qends: pointer to ends structure
263 * @sync: flag indicating, that user wants to wait for processing of all remaining
266 * Return Value: Function should be designed such way to not fail.
268 int canqueue_ends_dispose_rtl(struct canque_ends_t *qends, int sync)
270 rtl_irqstate_t flags;
273 canqueue_block_inlist(qends);
274 canqueue_block_outlist(qends);
276 /*Wait for sending of all pending messages in the output FIFOs*/
278 canqueue_ends_sync_all_rtl(qends);*/
280 /* Finish or kill all outgoing edges listed in inends */
281 delayed=canqueue_ends_kill_inlist(qends, 1);
282 /* Kill all incoming edges listed in outends */
283 delayed|=canqueue_ends_kill_outlist(qends);
285 rtl_spin_lock_irqsave(&qends->endinfo.rtlinfo.rtl_lock, flags);
286 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_readq);
287 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_writeq);
288 rtl_wait_wakeup(&qends->endinfo.rtlinfo.rtl_emptyq);
289 rtl_spin_unlock_irqrestore(&qends->endinfo.rtlinfo.rtl_lock, flags);
291 if(delayed || !(qends->ends_flags&CAN_ENDSF_MEM_RTL)){
292 canqueue_ends_dispose_postpone(qends);
297 canque_ends_free_rtl(qends);
303 void canqueue_rtl_initialize(void)
305 INIT_LIST_HEAD(&canque_pending_edges_list);
306 can_spin_lock_init(&canque_pending_edges_lock);
308 canqueue_rtl_irq = rtl_get_soft_irq (canqueue_rtl2lin_handler, "rtl_canqueue_irq");
312 void canqueue_rtl_done(void)
314 rtl_free_soft_irq (canqueue_rtl_irq);
319 #endif /*CAN_WITH_RTL*/