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
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 #ifdef CAN_ENABLE_VME_SUPPORT
21 /* Modified version of ca91c042 driver can be found in
22 * components/comm/contrib directory. */
25 can_spinlock_t can_irq_manipulation_lock;
27 unsigned int can_rtl_isr( unsigned int irq_num, struct pt_regs *r )
29 struct canchip_t *chip;
30 struct candevice_t *candev;
35 pthread_t thread=NULL;
37 DEBUGMSG("can_rtl_isr invoked for irq %d\n",irq_num);
39 /* I hate next loop, but RT-Linux does not provide context to ISR */
40 for (board_nr=hardware_p->nr_boards; board_nr--; ) {
41 if((candev=hardware_p->candevice[board_nr])==NULL)
43 for(chip_nr=candev->nr_all_chips; chip_nr--; ) {
44 if((chip=candev->chip[chip_nr])==NULL)
46 if(chip->chip_irq!=irq_num) continue;
48 if(chip->chipspecops->irq_accept)
49 ret=chip->chipspecops->irq_accept(chip->chip_irq,chip);
51 set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
52 set_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags);
53 if(chip->flags & CHIP_IRQ_PCI)
55 #ifdef CAN_ENABLE_VME_SUPPORT
56 if (chip->flags & CHIP_IRQ_VME)
57 tundra_rtl_ack_irq_vector(irq_num);
59 if(!chip->worker_thread) continue;
60 thread=chip->worker_thread;
61 pthread_kill(thread,RTL_SIGNAL_WAKEUP);
65 /* The following lines are commented out because of it is not
66 * possible to share level activated (PCI) IRQs between Linux
69 /* rtl_global_pend_irq(irq_num); */
71 /*if(thread) rtl_reschedule_thread(thread);*/
81 RTL_MARK_READY(pthread_self())
82 RTL_MARK_SUSPENDED(pthread_self());
83 return rtl_schedule();
87 rtl_end_critical( state )
88 rtl_request_global_irq( irq, isr );
89 rtl_free_global_irq( irq )
92 void * can_chip_worker_thread(void *arg)
94 struct canchip_t *chip = (struct canchip_t *) arg;
103 if (!(chip->flags & CHIP_CONFIGURED)){
104 if (chip->chipspecops->chip_config(chip))
105 CANMSG("Error configuring chip.\n");
107 chip->flags |= CHIP_CONFIGURED;
109 if((chip->msgobj[0])!=NULL)
110 if (chip->chipspecops->pre_read_config(chip,chip->msgobj[0])<0)
111 CANMSG("Error initializing chip for receiving\n");
113 } /* End of chip configuration */
114 set_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags);
118 DEBUGMSG("Worker thread for chip %d active\n",chip->chip_idx);
119 if(test_and_clear_bit(MSGOBJ_IRQ_REQUEST_b,&chip->pend_flags)){
120 DEBUGMSG("IRQ_REQUEST processing ...\n");
122 if(chip->chipspecops->irq_handler) do{
123 ret=chip->chipspecops->irq_handler(chip->chip_irq,chip);
124 }while(ret && --loop_cnt);
127 if(test_and_clear_bit(MSGOBJ_TX_REQUEST_b,&chip->pend_flags)){
128 DEBUGMSG("TX_REQUEST processing ...\n");
129 for(i=0;i<chip->max_objects;i++){
130 if((obj=chip->msgobj[i])==NULL)
132 if(can_msgobj_test_fl(obj,TX_REQUEST)) {
133 DEBUGMSG("Calling wakeup_tx\n");
134 chip->chipspecops->wakeup_tx(chip, obj);
136 if(can_msgobj_test_fl(obj,FILTCH_REQUEST)) {
137 DEBUGMSG("Calling filtch_rq\n");
138 if(chip->chipspecops->filtch_rq)
139 chip->chipspecops->filtch_rq(chip, obj);
145 /*re-enable chip IRQ, I am not sure, if this is required,
146 but it seems to not work without that */
147 if(chip->chip_irq>=0) {
148 if ((chip->flags & CHIP_IRQ_VME) == 0) can_enable_irq(chip->chip_irq);
149 #ifdef CAN_ENABLE_VME_SUPPORT
151 else tundra_rtl_enable_pci_irq();
153 /* FIXME: Bad practice. Doesn't work with more
156 * irq_accept added to the LinCAN driver now,
157 * and above workaround should not be required.
158 * Enable rtl_hard_enable_irq() at line
161 #endif /*CAN_ENABLE_VME_SUPPORT*/
165 rtl_no_interrupts (flags);
166 RTL_MARK_SUSPENDED(pthread_self());
167 if(test_and_clear_bit(MSGOBJ_WORKER_WAKE_b,&chip->pend_flags)){
168 RTL_MARK_READY(pthread_self());
169 rtl_restore_interrupts (flags);
172 rtl_restore_interrupts (flags);
180 int can_chip_setup_irq(struct canchip_t *chip)
183 struct sched_param sched_param;
184 pthread_attr_t attrib;
185 pthread_attr_t *attrib_p=NULL;
190 if(can_rtl_priority>=0){
191 pthread_attr_init(&attrib);
192 sched_param.sched_priority = can_rtl_priority;
193 pthread_attr_setschedparam(&attrib, &sched_param);
194 /* pthread_attr_setschedpolicy(&attrib, SCHED_FIFO); */
198 if(chip->chipspecops->irq_handler && !(chip->flags & CHIP_IRQ_CUSTOM)){
199 int (*my_request_irq)(unsigned int vector, unsigned int (*rtl_handler)(unsigned int irq, struct pt_regs *regs));
200 #ifdef CAN_ENABLE_VME_SUPPORT
201 if ((chip->flags & CHIP_IRQ_VME) != 0)
202 my_request_irq = rtl_request_vmeirq;
205 my_request_irq = rtl_request_irq;
207 if (my_request_irq(chip->chip_irq,can_rtl_isr))
210 DEBUGMSG("Registered interrupt %d\n",chip->chip_irq);
211 chip->flags |= CHIP_IRQ_SETUP;
214 ret=pthread_create(&chip->worker_thread, attrib_p, can_chip_worker_thread, chip);
215 if(ret<0) chip->worker_thread=NULL;
221 void can_chip_free_irq(struct canchip_t *chip)
223 if(chip->worker_thread)
224 pthread_delete_np(chip->worker_thread);
225 if((chip->flags & CHIP_IRQ_SETUP) && (chip->chip_irq>=0)
226 && !(chip->flags & CHIP_IRQ_CUSTOM)) {
227 int (*my_free_irq)(unsigned int vector);
228 #ifdef CAN_ENABLE_VME_SUPPORT
229 if ((chip->flags & CHIP_IRQ_VME) != 0)
230 my_free_irq = rtl_free_vmeirq;
233 my_free_irq = rtl_free_irq;
234 my_free_irq(chip->chip_irq);
235 chip->flags &= ~CHIP_IRQ_SETUP;
240 #endif /*CAN_WITH_RTL*/