]> rtime.felk.cvut.cz Git - lincan.git/blob - lincan/src/irq.c
The original version of Arnaud Westenberg Linux CAN-bus driver
[lincan.git] / lincan / src / irq.c
1 /* irq.c
2  * Linux CAN-bus device driver.
3  * Written by Arnaud Westenberg email:arnaud@wanadoo.nl
4  * This software is released under the GPL-License.
5  * Version 0.7  6 Aug 2001
6  */
7
8 #include <linux/autoconf.h>
9 #if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
10 #define MODVERSIONS
11 #endif
12
13 #if defined (MODVERSIONS)
14 #include <linux/modversions.h>
15 #endif 
16
17 #include <linux/sched.h>
18 #include <linux/version.h>
19
20 #if (LINUX_VERSION_CODE <= KERNEL_VERSION(2,2,19))
21 #include <asm/spinlock.h>
22 #else
23 #include <linux/spinlock.h>
24 #endif
25
26 #include "../include/main.h"
27 #include "../include/irq.h"
28 #include "../include/i82527.h"
29 #include "../include/sja1000.h"
30
31 void i82527_irq_rtr_handler(void);
32 void sja1000_irq_read_handler(void);
33 void sja1000_irq_write_handler(void);
34
35 void (*put_reg)(unsigned char data, unsigned long address);
36 unsigned (*get_reg)(unsigned long address);
37
38 struct chip_t *chip=NULL;
39 struct candevice_t *device=NULL;
40 unsigned object=0,irq_register=0;
41 unsigned long msgbase=0;
42 struct canfifo_t *fifo=NULL;
43 unsigned long message_id=0;
44 struct rtr_id *rtr_search;
45
46 inline void i82527_irq_write_handler(void)
47 {
48         put_reg((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase+iMSGCTL0);
49
50         fifo->tx_readp++;
51         if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH)
52                 fifo->tx_readp = fifo->buf_tx_entry;
53         if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty
54                 fifo->tx_in_progress = 0;
55                 if (waitqueue_active(&fifo->writeq)) {
56                         chip->msgobj[object]->ret = 0;
57                         wake_up_interruptible(&fifo->writeq);
58                 }
59                 return;
60         }
61         if (chip->chipspecops->pre_write_config(chip, chip->msgobj[object],
62                                                         fifo->tx_readp)) {
63                 if (waitqueue_active(&fifo->writeq)) {
64                         chip->msgobj[object]->ret = -1;
65                         wake_up_interruptible(&fifo->writeq);
66                         return;
67                 }
68         }
69         if (chip->chipspecops->send_msg(chip, chip->msgobj[object],
70                                                         fifo->tx_readp)) {
71                 if (waitqueue_active(&fifo->writeq)) {
72                         chip->msgobj[object]->ret = -1;
73                         wake_up_interruptible(&fifo->writeq);
74                         return;
75                 }
76         } 
77 }
78
79 inline void i82527_irq_read_handler(void)
80 {
81         int i=0, tmp=1 ;
82
83         while (tmp) {
84                 put_reg((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES), msgbase +
85                                                                 iMSGCTL1);
86                 put_reg((MVAL_SET|TXIE_RES|RXIE_SET|INTPD_RES), msgbase +
87                                                                 iMSGCTL0);
88
89                 fifo->rx_writep->length =(get_reg(msgbase+iMSGCFG) & 0xf0) >> 4;
90                 fifo->rx_writep->id = message_id;
91                 for (i=0; i < fifo->rx_writep->length; i++)
92                         fifo->rx_writep->data[i] = get_reg(msgbase+iMSGDAT0+i);
93
94 //FIXME: Add buffer overflow check, currently it's silently over written!
95
96                 fifo->rx_writep++;
97                 if (fifo->rx_writep >= fifo->buf_rx_entry + MAX_BUF_LENGTH)
98                         fifo->rx_writep = fifo->buf_rx_entry;
99
100                 if (!((tmp=get_reg(msgbase + iMSGCTL1)) & NEWD_SET)) {
101                         break;
102                 }
103
104                 if (tmp & MLST_SET)
105                         CANMSG("Message lost!\n");
106
107         }
108         if (waitqueue_active(&fifo->readq)) {
109                 wake_up_interruptible(&fifo->readq);
110         }
111 }
112
113 void i82527_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
114 {
115         int id0=0, id1=0, id2=0, id3=0;
116
117         chip=(struct chip_t *)dev_id;
118         device=(struct candevice_t *)chip->hostdevice;
119
120         put_reg=device->hwspecops->write_register;
121         get_reg=device->hwspecops->read_register;
122
123         if ( (chip->flags & SEGMENTED) != 0)
124                 irq_register = get_reg(chip->chip_base_addr+iIRQ+SPACING);
125         else 
126                 irq_register = get_reg(chip->chip_base_addr+iIRQ);
127
128         while (irq_register) {
129
130                 if (irq_register == 0x01) {
131                         DEBUGMSG("Status register: 0x%x\n",get_reg(chip->chip_base_addr+iSTAT));
132                         return;
133                 }
134                 
135                 if (irq_register == 0x02)
136                         object = 14;
137                 else
138                         object = irq_register-3;
139
140                 fifo=chip->msgobj[object]->fifo;
141                 msgbase=chip->msgobj[object]->obj_base_addr;
142
143                 if (get_reg(msgbase+iMSGCFG) & MCFG_DIR) {
144                         i82527_irq_write_handler(); 
145                 }
146                 else { 
147
148                         if (extended) {
149                                 id0=get_reg(msgbase+iMSGID3);
150                                 id1=get_reg(msgbase+iMSGID2)<<8;
151                                 id2=get_reg(msgbase+iMSGID1)<<16;
152                                 id3=get_reg(msgbase+iMSGID0)<<24;
153                                 message_id=(id0|id1|id2|id3)>>3;
154                         }
155                         else {
156                                 id0=get_reg(msgbase+iMSGID1);
157                                 id1=get_reg(msgbase+iMSGID0)<<8;
158                                 message_id=(id0|id1)>>5;
159                         }
160
161                         spin_lock(&hardware_p->rtr_lock);
162                         rtr_search=hardware_p->rtr_queue;
163                         while (rtr_search != NULL) {
164                                 if (rtr_search->id == message_id)
165                                         break;
166                                 rtr_search=rtr_search->next;
167                         }
168                         spin_unlock(&hardware_p->rtr_lock);
169                         if ((rtr_search!=NULL) && (rtr_search->id==message_id))
170                                 i82527_irq_rtr_handler();
171                         else
172                                 i82527_irq_read_handler(); 
173                 }
174
175                 if ( (chip->flags & SEGMENTED) != 0)
176                         irq_register=get_reg(chip->chip_base_addr+iIRQ+SPACING);
177                 else
178                         irq_register=get_reg(chip->chip_base_addr+iIRQ);
179         }
180         
181 }
182
183 void i82527_irq_rtr_handler(void)
184 {
185         short int i=0;
186
187         put_reg((MVAL_RES|TXIE_RES|RXIE_RES|INTPD_RES),msgbase + iMSGCTL0);
188         put_reg((RMPD_RES|TXRQ_RES|MLST_RES|NEWD_RES),msgbase + iMSGCTL1);
189         
190         spin_lock(&hardware_p->rtr_lock);
191
192         rtr_search->rtr_message->id=message_id;
193         rtr_search->rtr_message->length=(get_reg(msgbase + iMSGCFG) & 0xf0)>>4;
194         for (i=0; i<rtr_search->rtr_message->length; i++)
195                 rtr_search->rtr_message->data[i]=get_reg(msgbase+iMSGDAT0+i);
196         
197         spin_unlock(&hardware_p->rtr_lock);
198
199         if (waitqueue_active(&rtr_search->rtr_wq))
200                 wake_up_interruptible(&rtr_search->rtr_wq);
201 }
202
203 void sja1000_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
204 {
205         chip=(struct chip_t *)dev_id;
206         device=(struct candevice_t *)chip->hostdevice;
207
208         put_reg=device->hwspecops->write_register;
209         get_reg=device->hwspecops->read_register;
210
211         irq_register=get_reg(chip->chip_base_addr+SJAIR);
212 //      DEBUGMSG("sja1000_irq_handler: SJAIR:%02x\n",irq_register);
213 //      DEBUGMSG("sja1000_irq_handler: SJASR:%02x\n",
214 //                                      get_reg(chip->chip_base_addr+SJASR));
215
216         if ((irq_register & (IR_WUI|IR_DOI|IR_EI|IR_TI|IR_RI)) == 0)
217                 return;
218
219         fifo=chip->msgobj[0]->fifo;
220         msgbase=chip->msgobj[0]->obj_base_addr;
221
222         if ((irq_register & IR_RI) != 0) 
223                 sja1000_irq_read_handler();
224         if ((irq_register & IR_TI) != 0) 
225                 sja1000_irq_write_handler();
226         if ((irq_register & (IR_EI|IR_DOI)) != 0) { 
227                 // Some error happened
228 // FIXME: chip should be brought to usable state. Transmission cancelled if in progress.
229 // Reset flag set to 0 if chip is already off the bus. Full state report
230                 CANMSG("Error: status register: 0x%x irq_register: 0x%02x\n",
231                         get_reg(chip->chip_base_addr+SJASR), irq_register);
232                 chip->msgobj[0]->ret=-1;
233                 if (waitqueue_active(&fifo->writeq))
234                         wake_up_interruptible(&fifo->writeq);
235                 if (waitqueue_active(&fifo->readq))
236                         wake_up_interruptible(&fifo->readq);
237         }
238
239         return;
240 }
241 void sja1000_irq_read_handler(void)
242 {
243         int i=0, id=0, tmp=1;
244
245         while (tmp) {
246                 id = get_reg(msgbase+SJARXID0) | (get_reg(msgbase+SJARXID1)<<8);
247                 fifo->buf_rx_entry[fifo->head].length = id & 0x0f;
248                 fifo->buf_rx_entry[fifo->head].flags = id&ID0_RTR ? MSG_RTR : 0;
249                 fifo->buf_rx_entry[fifo->head].timestamp = 0;
250                 fifo->buf_rx_entry[fifo->head].cob = 0;
251                 fifo->buf_rx_entry[fifo->head].id = id>>5;
252
253                 for (i=0; i<fifo->buf_rx_entry[fifo->head].length; i++)
254                         fifo->buf_rx_entry[fifo->head].data[i]=get_reg(msgbase +
255                                                                 SJARXDAT0 + i);
256
257                 put_reg(CMR_RRB,msgbase+SJACMR);
258
259                 fifo->head++;
260                 if (fifo->head >= MAX_BUF_LENGTH-1)
261                         fifo->head=0;
262
263                 tmp=(get_reg(msgbase+SJASR) & SR_RBS);
264         }
265         if (waitqueue_active(&fifo->readq))
266                 wake_up_interruptible(&fifo->readq);
267 }
268
269 void sja1000_irq_write_handler(void)
270 {
271         fifo->tx_readp++;
272         if (fifo->tx_readp >= fifo->buf_tx_entry + MAX_BUF_LENGTH)
273                 fifo->tx_readp = fifo->buf_tx_entry;
274         if (fifo->tx_readp == fifo->tx_writep) { // Output buffer is empty
275                 fifo->tx_in_progress = 0;
276                 if (waitqueue_active(&fifo->writeq)) {
277                         chip->msgobj[object]->ret = 0;
278                         wake_up_interruptible(&fifo->writeq);
279                 }
280                 return;
281         }
282         if (chip->chipspecops->pre_write_config(chip, chip->msgobj[object],
283                                                         fifo->tx_readp)) {
284                 if (waitqueue_active(&fifo->writeq)) {
285                         chip->msgobj[object]->ret = -1;
286                         wake_up_interruptible(&fifo->writeq);
287                         return;
288                 }
289         }
290         if (chip->chipspecops->send_msg(chip, chip->msgobj[object],
291                                                         fifo->tx_readp)) {
292                 if (waitqueue_active(&fifo->writeq)) {
293                         chip->msgobj[object]->ret = -1;
294                         wake_up_interruptible(&fifo->writeq);
295                         return;
296                 }
297         }
298 }