]> rtime.felk.cvut.cz Git - lincan.git/blobdiff - lincan/src/can_devrtl.c
LinCAN can be compiled in mode with RT-Linux chip worker threads now.
[lincan.git] / lincan / src / can_devrtl.c
diff --git a/lincan/src/can_devrtl.c b/lincan/src/can_devrtl.c
new file mode 100644 (file)
index 0000000..182eb42
--- /dev/null
@@ -0,0 +1,166 @@
+/* can_devrtl.c - CAN message queues functions for the RT-Linux
+ * 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
+ */
+
+#ifdef CAN_WITH_RTL
+
+#include "../include/can.h"
+#include "../include/can_sysdep.h"
+#include "../include/can_queue.h"
+#include "../include/main.h"
+#include "../include/setup.h"
+
+#include <rtl_malloc.h>
+
+unsigned int can_rtl_isr( unsigned int irq_num, struct pt_regs *r )
+{
+       struct chip_t *chip;
+       struct candevice_t *candev;
+       int board_nr;
+       int chip_nr;
+       pthread_t thread=NULL;
+
+       DEBUGMSG("can_rtl_isr invoked for irq %d\n",irq_num);
+       
+       /* I hate next loop, but RT-Linux does not provide context to ISR */
+       for (board_nr=hardware_p->nr_boards; board_nr--; ) {
+               if((candev=hardware_p->candevice[board_nr])==NULL)
+                       continue;
+               for(chip_nr=candev->nr_all_chips; chip_nr--; ) {
+                       if((chip=candev->chip[chip_nr])==NULL)
+                               continue;
+                       if(chip->chip_irq!=irq_num) continue;
+
+                       set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
+                       set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags);
+                       
+                       if(!chip->worker_thread) continue;
+                       thread=chip->worker_thread;
+                       pthread_kill(thread,RTL_SIGNAL_WAKEUP);
+               }
+       }
+
+       /*rtl_global_pend_irq(irq_num);*/
+
+       /*if(thread) rtl_reschedule_thread(thread);*/
+
+       rtl_schedule();
+
+       return 0;
+}
+
+
+
+/*
+RTL_MARK_READY(pthread_self())
+RTL_MARK_SUSPENDED(pthread_self());
+return rtl_schedule();
+can_enable_irq
+can_disable_irq 
+rtl_critical( state )
+rtl_end_critical( state )
+rtl_request_global_irq( irq, isr ); 
+rtl_free_global_irq( irq )
+*/
+
+void * can_chip_worker_thread(void *arg)
+{
+       struct chip_t *chip = (struct chip_t *) arg;
+       struct msgobj_t *obj;
+       int ret, i;
+       int loop_cnt;
+       
+       if(!chip) return 0;
+       
+       
+       if (!(chip->flags & CHIP_CONFIGURED)){
+               if (chip->chipspecops->chip_config(chip))
+                       CANMSG("Error configuring chip.\n");
+               else
+                       chip->flags |= CHIP_CONFIGURED; 
+
+               if((chip->msgobj[0])!=NULL)
+                       if (chip->chipspecops->pre_read_config(chip,chip->msgobj[0])<0)
+                               CANMSG("Error initializing chip for receiving\n");
+                               
+       } /* End of chip configuration */
+       set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
+       
+
+       while (1) {
+               DEBUGMSG("Worker thread for chip %d active\n",chip->chip_idx);
+               if(test_and_clear_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags)){
+                       DEBUGMSG("IRQ_REQUEST processing ...\n");
+                       loop_cnt = 100;
+                       if(chip->chipspecops->irq_handler) do{
+                               ret=chip->chipspecops->irq_handler(chip->chip_irq,chip,NULL);
+                       }while(ret && --loop_cnt);
+                       continue;
+               }
+               if(test_and_clear_bit(MSGOBJ_TX_REQUEST_b,&chip->pend_flags)){
+                       DEBUGMSG("TX_REQUEST processing ...\n");
+                       for(i=0;i<chip->max_objects;i++){
+                               if((obj=chip->msgobj[i])==NULL)
+                                       continue;
+                               if(!can_msgobj_test_and_clear_fl(obj,TX_REQUEST))
+                                       continue;
+                               DEBUGMSG("Calling wakeup_tx\n");
+                               chip->chipspecops->wakeup_tx(chip, obj);
+                       }
+                       continue;
+               }
+
+               /*re-enable chip IRQ, I am not sure, if this is required,
+                 but it seems to not work without that */
+               if(chip->chip_irq>=0)
+                       can_enable_irq(chip->chip_irq);
+
+               RTL_MARK_SUSPENDED(pthread_self());
+               if(test_and_clear_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags)){
+                       RTL_MARK_READY(pthread_self());
+                       continue;
+               }
+               rtl_schedule();
+
+       }
+       return 0;
+}
+
+
+int can_chip_setup_irq(struct chip_t *chip)
+{
+       int ret;
+       
+       if(chip==NULL)
+               return -1;
+       if(chip->chipspecops->irq_handler){
+               if (rtl_request_irq(chip->chip_irq,can_rtl_isr))
+                       return -1;
+               else {
+                       DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
+                       chip->flags |= CHIP_IRQ_SETUP;
+               }
+       }
+        ret=pthread_create(&chip->worker_thread, NULL, can_chip_worker_thread, chip);
+       if(ret<0) chip->worker_thread=NULL;
+       
+       return ret;
+}
+
+
+void can_chip_free_irq(struct chip_t *chip)
+{
+       if(chip->worker_thread)
+               pthread_delete_np(chip->worker_thread);
+       if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
+               rtl_free_irq(chip->chip_irq);
+               chip->flags &= ~CHIP_IRQ_SETUP;
+       }
+}
+
+
+#endif /*CAN_WITH_RTL*/