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