1 /* can_devrtl.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"
14 #include "../include/main.h"
15 #include "../include/setup.h"
17 #include <rtl_malloc.h>
19 unsigned int can_rtl_isr( unsigned int irq_num, struct pt_regs *r )
22 struct candevice_t *candev;
25 pthread_t thread=NULL;
27 DEBUGMSG("can_rtl_isr invoked for irq %d\n",irq_num);
29 /* I hate next loop, but RT-Linux does not provide context to ISR */
30 for (board_nr=hardware_p->nr_boards; board_nr--; ) {
31 if((candev=hardware_p->candevice[board_nr])==NULL)
33 for(chip_nr=candev->nr_all_chips; chip_nr--; ) {
34 if((chip=candev->chip[chip_nr])==NULL)
36 if(chip->chip_irq!=irq_num) continue;
38 set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
39 set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags);
41 if(!chip->worker_thread) continue;
42 thread=chip->worker_thread;
43 pthread_kill(thread,RTL_SIGNAL_WAKEUP);
47 /*rtl_global_pend_irq(irq_num);*/
49 /*if(thread) rtl_reschedule_thread(thread);*/
59 RTL_MARK_READY(pthread_self())
60 RTL_MARK_SUSPENDED(pthread_self());
61 return rtl_schedule();
65 rtl_end_critical( state )
66 rtl_request_global_irq( irq, isr );
67 rtl_free_global_irq( irq )
70 void * can_chip_worker_thread(void *arg)
72 struct chip_t *chip = (struct chip_t *) arg;
80 if (!(chip->flags & CHIP_CONFIGURED)){
81 if (chip->chipspecops->chip_config(chip))
82 CANMSG("Error configuring chip.\n");
84 chip->flags |= CHIP_CONFIGURED;
86 if((chip->msgobj[0])!=NULL)
87 if (chip->chipspecops->pre_read_config(chip,chip->msgobj[0])<0)
88 CANMSG("Error initializing chip for receiving\n");
90 } /* End of chip configuration */
91 set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
95 DEBUGMSG("Worker thread for chip %d active\n",chip->chip_idx);
96 if(test_and_clear_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags)){
97 DEBUGMSG("IRQ_REQUEST processing ...\n");
99 if(chip->chipspecops->irq_handler) do{
100 ret=chip->chipspecops->irq_handler(chip->chip_irq,chip,NULL);
101 }while(ret && --loop_cnt);
104 if(test_and_clear_bit(MSGOBJ_TX_REQUEST_b,&chip->pend_flags)){
105 DEBUGMSG("TX_REQUEST processing ...\n");
106 for(i=0;i<chip->max_objects;i++){
107 if((obj=chip->msgobj[i])==NULL)
109 if(!can_msgobj_test_and_clear_fl(obj,TX_REQUEST))
111 DEBUGMSG("Calling wakeup_tx\n");
112 chip->chipspecops->wakeup_tx(chip, obj);
117 /*re-enable chip IRQ, I am not sure, if this is required,
118 but it seems to not work without that */
119 if(chip->chip_irq>=0)
120 can_enable_irq(chip->chip_irq);
122 RTL_MARK_SUSPENDED(pthread_self());
123 if(test_and_clear_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags)){
124 RTL_MARK_READY(pthread_self());
134 int can_chip_setup_irq(struct chip_t *chip)
140 if(chip->chipspecops->irq_handler){
141 if (rtl_request_irq(chip->chip_irq,can_rtl_isr))
144 DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
145 chip->flags |= CHIP_IRQ_SETUP;
148 ret=pthread_create(&chip->worker_thread, NULL, can_chip_worker_thread, chip);
149 if(ret<0) chip->worker_thread=NULL;
155 void can_chip_free_irq(struct chip_t *chip)
157 if(chip->worker_thread)
158 pthread_delete_np(chip->worker_thread);
159 if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
160 rtl_free_irq(chip->chip_irq);
161 chip->flags &= ~CHIP_IRQ_SETUP;
166 #endif /*CAN_WITH_RTL*/