Added glue required for RTL hardware filters updates.
[lincan.git] / lincan / src / can_devrtl.c
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
7  */
8
9 #ifdef CAN_WITH_RTL
10
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"
16
17 #include <rtl_malloc.h>
18
19 can_spinlock_t can_irq_manipulation_lock;
20
21 unsigned int can_rtl_isr( unsigned int irq_num, struct pt_regs *r )
22 {
23         struct chip_t *chip;
24         struct candevice_t *candev;
25         int board_nr;
26         int chip_nr;
27         int irq2linux=0;
28         pthread_t thread=NULL;
29
30         DEBUGMSG("can_rtl_isr invoked for irq %d\n",irq_num);
31         
32         /* I hate next loop, but RT-Linux does not provide context to ISR */
33         for (board_nr=hardware_p->nr_boards; board_nr--; ) {
34                 if((candev=hardware_p->candevice[board_nr])==NULL)
35                         continue;
36                 for(chip_nr=candev->nr_all_chips; chip_nr--; ) {
37                         if((chip=candev->chip[chip_nr])==NULL)
38                                 continue;
39                         if(chip->chip_irq!=irq_num) continue;
40
41                         set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
42                         set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags);
43                         if(chip->flags & CHIP_IRQ_PCI)
44                                 irq2linux=1;
45                         if(!chip->worker_thread) continue;
46                         thread=chip->worker_thread;
47                         pthread_kill(thread,RTL_SIGNAL_WAKEUP);
48                 }
49         }
50
51         if(irq2linux)
52                 rtl_global_pend_irq(irq_num);
53
54         /*if(thread) rtl_reschedule_thread(thread);*/
55
56         rtl_schedule();
57
58         return 0;
59 }
60
61
62
63 /*
64 RTL_MARK_READY(pthread_self())
65 RTL_MARK_SUSPENDED(pthread_self());
66 return rtl_schedule();
67 can_enable_irq
68 can_disable_irq 
69 rtl_critical( state )
70 rtl_end_critical( state )
71 rtl_request_global_irq( irq, isr ); 
72 rtl_free_global_irq( irq )
73 */
74
75 void * can_chip_worker_thread(void *arg)
76 {
77         struct chip_t *chip = (struct chip_t *) arg;
78         struct msgobj_t *obj;
79         int ret, i;
80         int loop_cnt;
81         
82         if(!chip) return 0;
83         
84         
85         if (!(chip->flags & CHIP_CONFIGURED)){
86                 if (chip->chipspecops->chip_config(chip))
87                         CANMSG("Error configuring chip.\n");
88                 else
89                         chip->flags |= CHIP_CONFIGURED; 
90
91                 if((chip->msgobj[0])!=NULL)
92                         if (chip->chipspecops->pre_read_config(chip,chip->msgobj[0])<0)
93                                 CANMSG("Error initializing chip for receiving\n");
94                                 
95         } /* End of chip configuration */
96         set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
97         
98
99         while (1) {
100                 DEBUGMSG("Worker thread for chip %d active\n",chip->chip_idx);
101                 if(test_and_clear_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags)){
102                         DEBUGMSG("IRQ_REQUEST processing ...\n");
103                         loop_cnt = 100;
104                         if(chip->chipspecops->irq_handler) do{
105                                 ret=chip->chipspecops->irq_handler(chip->chip_irq,chip,NULL);
106                         }while(ret && --loop_cnt);
107                         continue;
108                 }
109                 if(test_and_clear_bit(MSGOBJ_TX_REQUEST_b,&chip->pend_flags)){
110                         DEBUGMSG("TX_REQUEST processing ...\n");
111                         for(i=0;i<chip->max_objects;i++){
112                                 if((obj=chip->msgobj[i])==NULL)
113                                         continue;
114                                 if(can_msgobj_test_fl(obj,TX_REQUEST)) {
115                                         DEBUGMSG("Calling wakeup_tx\n");
116                                         chip->chipspecops->wakeup_tx(chip, obj);
117                                 }
118                                 if(can_msgobj_test_fl(obj,FILTCH_REQUEST)) {
119                                         DEBUGMSG("Calling filtch_rq\n");
120                                         if(chip->chipspecops->filtch_rq)
121                                                 chip->chipspecops->filtch_rq(chip, obj);
122                                 }
123                         }
124                         continue;
125                 }
126
127                 /*re-enable chip IRQ, I am not sure, if this is required,
128                   but it seems to not work without that */
129                 if(chip->chip_irq>=0)
130                         can_enable_irq(chip->chip_irq);
131
132                 RTL_MARK_SUSPENDED(pthread_self());
133                 if(test_and_clear_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags)){
134                         RTL_MARK_READY(pthread_self());
135                         continue;
136                 }
137                 rtl_schedule();
138
139         }
140         return 0;
141 }
142
143
144 int can_chip_setup_irq(struct chip_t *chip)
145 {
146         int ret;
147         struct sched_param sched_param;
148         pthread_attr_t attrib;
149         pthread_attr_t *attrib_p=NULL;
150         
151         if(chip==NULL)
152                 return -1;
153         
154         if(can_rtl_priority>=0){
155                 pthread_attr_init(&attrib);
156                 sched_param.sched_priority = can_rtl_priority;
157                 pthread_attr_setschedparam(&attrib, &sched_param);
158                 /* pthread_attr_setschedpolicy(&attrib, SCHED_FIFO); */
159                 attrib_p=&attrib;
160         }
161         
162         if(chip->chipspecops->irq_handler){
163                 if (rtl_request_irq(chip->chip_irq,can_rtl_isr))
164                         return -1;
165                 else {
166                         DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
167                         chip->flags |= CHIP_IRQ_SETUP;
168                 }
169         }
170         ret=pthread_create(&chip->worker_thread, attrib_p, can_chip_worker_thread, chip);
171         if(ret<0) chip->worker_thread=NULL;
172         
173         return ret;
174 }
175
176
177 void can_chip_free_irq(struct chip_t *chip)
178 {
179         if(chip->worker_thread)
180                 pthread_delete_np(chip->worker_thread);
181         if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)) {
182                 rtl_free_irq(chip->chip_irq);
183                 chip->flags &= ~CHIP_IRQ_SETUP;
184         }
185 }
186
187
188 #endif /*CAN_WITH_RTL*/