|
2059
|
1 //========================================================================== |
|
|
2 // |
|
|
3 // loop_can.c |
|
|
4 // |
|
|
5 // Loopback CAN device driver |
|
|
6 // |
|
|
7 //========================================================================== |
|
|
8 //####ECOSGPLCOPYRIGHTBEGIN#### |
|
|
9 // ------------------------------------------- |
|
|
10 // This file is part of eCos, the Embedded Configurable Operating System. |
|
|
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. |
|
|
12 // |
|
|
13 // eCos is free software; you can redistribute it and/or modify it under |
|
|
14 // the terms of the GNU General Public License as published by the Free |
|
|
15 // Software Foundation; either version 2 or (at your option) any later version. |
|
|
16 // |
|
|
17 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY |
|
|
18 // WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
|
19 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
|
20 // for more details. |
|
|
21 // |
|
|
22 // You should have received a copy of the GNU General Public License along |
|
|
23 // with eCos; if not, write to the Free Software Foundation, Inc., |
|
|
24 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
|
|
25 // |
|
|
26 // As a special exception, if other files instantiate templates or use macros |
|
|
27 // or inline functions from this file, or you compile this file and link it |
|
|
28 // with other works to produce a work based on this file, this file does not |
|
|
29 // by itself cause the resulting work to be covered by the GNU General Public |
|
|
30 // License. However the source code for this file must still be made available |
|
|
31 // in accordance with section (3) of the GNU General Public License. |
|
|
32 // |
|
|
33 // This exception does not invalidate any other reasons why a work based on |
|
|
34 // this file might be covered by the GNU General Public License. |
|
|
35 // |
|
|
36 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. |
|
|
37 // at http://sources.redhat.com/ecos/ecos-license/ |
|
|
38 // ------------------------------------------- |
|
|
39 //####ECOSGPLCOPYRIGHTEND#### |
|
|
40 //========================================================================== |
|
|
41 //#####DESCRIPTIONBEGIN#### |
|
|
42 // |
|
|
43 // Author(s): Uwe Kindler |
|
|
44 // Contributors: Uwe Kindler |
|
|
45 // Date: 2005-07-10 |
|
|
46 // Purpose: Loopback CAN device driver |
|
|
47 // Description: This device driver implements a pair of CAN lines that are |
|
|
48 // connected back-to-back. Data output to one will appear as |
|
|
49 // input on the other. This process in part driven by an alarm |
|
|
50 // object which provides a degree of separation between the two |
|
|
51 // channels. |
|
|
52 // |
|
|
53 //####DESCRIPTIONEND#### |
|
|
54 // |
|
|
55 //========================================================================== |
|
|
56 |
|
|
57 #include <pkgconf/hal.h> |
|
|
58 #include <pkgconf/io_can.h> |
|
|
59 #include <pkgconf/io_can_loop.h> |
|
|
60 #include <cyg/hal/hal_io.h> |
|
|
61 |
|
|
62 #include <cyg/io/io.h> |
|
|
63 #include <cyg/io/devtab.h> |
|
|
64 #include <cyg/io/can.h> |
|
|
65 #include <cyg/hal/hal_intr.h> |
|
|
66 #include <cyg/kernel/kapi.h> |
|
|
67 |
|
|
68 #ifdef CYGPKG_IO_CAN_LOOP |
|
|
69 |
|
|
70 //------------------------------------------------------------------------- |
|
|
71 |
|
|
72 extern void diag_printf(const char *fmt, ...); |
|
|
73 |
|
|
74 //------------------------------------------------------------------------- |
|
|
75 // Forward definitions |
|
|
76 |
|
|
77 static bool loop_can_init(struct cyg_devtab_entry *devtab_entry); |
|
|
78 static bool loop_can_putmsg(can_channel *priv, cyg_can_message *pmsg, void *pdata); |
|
|
79 static Cyg_ErrNo loop_can_lookup(struct cyg_devtab_entry **tab, |
|
|
80 struct cyg_devtab_entry *sub_tab, |
|
|
81 const char *name); |
|
|
82 static bool loop_can_getevent(can_channel *priv, cyg_can_event *pevent, void *pdata); |
|
|
83 static Cyg_ErrNo loop_can_set_config(can_channel *chan, cyg_uint32 key, |
|
|
84 const void *xbuf, cyg_uint32 *len); |
|
|
85 static void loop_can_start_xmit(can_channel *chan); |
|
|
86 static void loop_can_stop_xmit(can_channel *chan); |
|
|
87 |
|
|
88 static void alarm_handler(cyg_handle_t alarm, cyg_addrword_t data); |
|
|
89 |
|
|
90 |
|
|
91 //------------------------------------------------------------------------- |
|
|
92 // Alarm object for feeding data back into CAN channels |
|
|
93 |
|
|
94 static cyg_alarm alarm_obj; |
|
|
95 |
|
|
96 static cyg_handle_t alarm_handle; |
|
|
97 |
|
|
98 //------------------------------------------------------------------------- |
|
|
99 // Transfer FIFOs |
|
|
100 |
|
|
101 #define FIFO_SIZE 16 |
|
|
102 |
|
|
103 struct fifo |
|
|
104 { |
|
|
105 cyg_bool tx_enable; |
|
|
106 volatile int head; |
|
|
107 volatile int tail; |
|
|
108 volatile int num; |
|
|
109 volatile cyg_can_event buf[FIFO_SIZE+1]; |
|
|
110 }; |
|
|
111 |
|
|
112 static struct fifo fifo0 = { false, 0, 0, 0 }; // from CAN0 to CAN1 |
|
|
113 static struct fifo fifo1 = { false, 0, 0, 0 }; // from CAN1 to CAN0 |
|
|
114 |
|
|
115 //------------------------------------------------------------------------- |
|
|
116 |
|
|
117 #define BUFSIZE 128 |
|
|
118 |
|
|
119 //------------------------------------------------------------------------- |
|
|
120 // Info for each serial device controlled |
|
|
121 |
|
|
122 typedef struct loop_can_info { |
|
|
123 struct fifo *write_fifo; |
|
|
124 struct fifo *read_fifo; |
|
|
125 } loop_can_info; |
|
|
126 |
|
|
127 //------------------------------------------------------------------------- |
|
|
128 // Callback functions exported by this driver |
|
|
129 CAN_LOWLEVEL_FUNS(loop_can_lowlevel_funs, |
|
|
130 loop_can_putmsg, |
|
|
131 loop_can_getevent, |
|
|
132 loop_can_set_config, |
|
|
133 loop_can_start_xmit, |
|
|
134 loop_can_stop_xmit |
|
|
135 ); |
|
|
136 |
|
|
137 //------------------------------------------------------------------------- |
|
|
138 // Hardware info for each serial line |
|
|
139 |
|
|
140 #ifdef CYGPKG_IO_CAN_LOOP_CAN0 |
|
|
141 static loop_can_info loop_can_info0 = { |
|
|
142 &fifo0, |
|
|
143 &fifo1 |
|
|
144 }; |
|
|
145 |
|
|
146 static cyg_can_message loop_can_txbuf0[CYGNUM_DEVS_CAN_LOOP_CAN0_QUEUESIZE_TX]; |
|
|
147 static cyg_can_event loop_can_rxbuf0[CYGNUM_DEVS_CAN_LOOP_CAN0_QUEUESIZE_RX]; |
|
|
148 #endif // CYGPKG_IO_SERIAL_LOOP_SERIAL0 |
|
|
149 |
|
|
150 #ifdef CYGPKG_IO_CAN_LOOP_CAN1 |
|
|
151 static loop_can_info loop_can_info1 = { |
|
|
152 &fifo1, |
|
|
153 &fifo0 |
|
|
154 }; |
|
|
155 |
|
|
156 static cyg_can_message loop_can_txbuf1[CYGNUM_DEVS_CAN_LOOP_CAN1_QUEUESIZE_TX]; |
|
|
157 static cyg_can_event loop_can_rxbuf1[CYGNUM_DEVS_CAN_LOOP_CAN1_QUEUESIZE_RX]; |
|
|
158 #endif // CYGPKG_IO_SERIAL_LOOP_SERIAL1 |
|
|
159 |
|
|
160 |
|
|
161 |
|
|
162 //------------------------------------------------------------------------- |
|
|
163 // Channel descriptions: |
|
|
164 // |
|
|
165 #ifdef CYGPKG_IO_CAN_LOOP_CAN0 |
|
|
166 CAN_CHANNEL_USING_INTERRUPTS(loop_can0_chan, |
|
|
167 loop_can_lowlevel_funs, |
|
|
168 loop_can_info0, |
|
|
169 CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LOOP_CAN0_KBAUD), |
|
|
170 loop_can_txbuf0, CYGNUM_DEVS_CAN_LOOP_CAN0_QUEUESIZE_TX, |
|
|
171 loop_can_rxbuf0, CYGNUM_DEVS_CAN_LOOP_CAN0_QUEUESIZE_RX |
|
|
172 ); |
|
|
173 #endif // CYGPKG_IO_CAN_LOOP_CAN1 |
|
|
174 |
|
|
175 #ifdef CYGPKG_IO_CAN_LOOP_CAN1 |
|
|
176 CAN_CHANNEL_USING_INTERRUPTS(loop_can1_chan, |
|
|
177 loop_can_lowlevel_funs, |
|
|
178 loop_can_info1, |
|
|
179 CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LOOP_CAN1_KBAUD), |
|
|
180 loop_can_txbuf1, CYGNUM_DEVS_CAN_LOOP_CAN1_QUEUESIZE_TX, |
|
|
181 loop_can_rxbuf1, CYGNUM_DEVS_CAN_LOOP_CAN1_QUEUESIZE_RX |
|
|
182 ); |
|
|
183 #endif // CYGPKG_IO_CAN_LOOP_CAN1 |
|
|
184 |
|
|
185 |
|
|
186 |
|
|
187 //------------------------------------------------------------------------- |
|
|
188 // And finally, the device table entries: |
|
|
189 // |
|
|
190 #ifdef CYGPKG_IO_CAN_LOOP_CAN0 |
|
|
191 DEVTAB_ENTRY(loop_can_io0, |
|
|
192 CYGDAT_DEVS_CAN_LOOP_CAN0_NAME, |
|
|
193 0, // Does not depend on a lower level interface |
|
|
194 &cyg_io_can_devio, |
|
|
195 loop_can_init, |
|
|
196 loop_can_lookup, // CAN driver may need initializing |
|
|
197 &loop_can0_chan |
|
|
198 ); |
|
|
199 #endif // CYGPKG_IO_CAN_LOOP_CAN0 |
|
|
200 |
|
|
201 #ifdef CYGPKG_IO_CAN_LOOP_CAN1 |
|
|
202 DEVTAB_ENTRY(loop_can_io1, |
|
|
203 CYGDAT_DEVS_CAN_LOOP_CAN1_NAME, |
|
|
204 0, // Does not depend on a lower level interface |
|
|
205 &cyg_io_can_devio, |
|
|
206 loop_can_init, |
|
|
207 loop_can_lookup, // CAN driver may need initializing |
|
|
208 &loop_can1_chan |
|
|
209 ); |
|
|
210 #endif // CYGPKG_IO_CAN_LOOP_CAN1 |
|
|
211 |
|
|
212 //------------------------------------------------------------------------- |
|
|
213 |
|
|
214 static bool |
|
|
215 loop_can_config_channel(can_channel *chan, cyg_can_info_t *new_config, bool init) |
|
|
216 { |
|
|
217 if (new_config != &chan->config) { |
|
|
218 chan->config = *new_config; |
|
|
219 } |
|
|
220 return true; |
|
|
221 } |
|
|
222 |
|
|
223 //------------------------------------------------------------------------- |
|
|
224 // Function to initialize the device. Called at bootstrap time. |
|
|
225 |
|
|
226 bool loop_can_init(struct cyg_devtab_entry *tab) |
|
|
227 { |
|
|
228 can_channel *chan = (can_channel *)tab->priv; |
|
|
229 |
|
|
230 (chan->callbacks->can_init)(chan); |
|
|
231 |
|
|
232 // Set up alarm for feeding data back into channels |
|
|
233 |
|
|
234 cyg_alarm_create( cyg_real_time_clock(), |
|
|
235 alarm_handler, |
|
|
236 0, |
|
|
237 &alarm_handle, |
|
|
238 &alarm_obj); |
|
|
239 |
|
|
240 cyg_alarm_initialize( alarm_handle, 1, 1 ); |
|
|
241 |
|
|
242 loop_can_config_channel(chan, &chan->config, true); |
|
|
243 |
|
|
244 return true; |
|
|
245 } |
|
|
246 |
|
|
247 //------------------------------------------------------------------------- |
|
|
248 // This routine is called when the device is "looked" up (i.e. attached) |
|
|
249 |
|
|
250 static Cyg_ErrNo |
|
|
251 loop_can_lookup(struct cyg_devtab_entry **tab, |
|
|
252 struct cyg_devtab_entry *sub_tab, |
|
|
253 const char *name) |
|
|
254 { |
|
|
255 can_channel *chan = (can_channel *)(*tab)->priv; |
|
|
256 (chan->callbacks->can_init)(chan); |
|
|
257 return ENOERR; |
|
|
258 } |
|
|
259 |
|
|
260 //------------------------------------------------------------------------- |
|
|
261 // Return 'true' if message is sent to device |
|
|
262 |
|
|
263 bool |
|
|
264 loop_can_putmsg(can_channel *chan, cyg_can_message *pmsg, void *pdata) |
|
|
265 { |
|
|
266 loop_can_info *loop_chan = (loop_can_info *)chan->dev_priv; |
|
|
267 |
|
|
268 struct fifo *fwr = loop_chan->write_fifo; |
|
|
269 struct fifo *frd = loop_chan->read_fifo; |
|
|
270 |
|
|
271 if( fwr->num == FIFO_SIZE ) |
|
|
272 { |
|
|
273 return false; |
|
|
274 } |
|
|
275 |
|
|
276 fwr->buf[fwr->tail].msg = *pmsg; |
|
|
277 fwr->buf[fwr->tail].flags = CYGNUM_CAN_EVENT_RX; |
|
|
278 fwr->num++; |
|
|
279 fwr->tail = (fwr->tail + 1) % FIFO_SIZE; |
|
|
280 |
|
|
281 #ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT |
|
|
282 // |
|
|
283 // if TX events are supported we insert a TX event into read fifo |
|
|
284 // |
|
|
285 if( frd->num < FIFO_SIZE ) |
|
|
286 { |
|
|
287 frd->buf[frd->tail].msg = *pmsg; |
|
|
288 frd->buf[frd->tail].flags = CYGNUM_CAN_EVENT_TX; |
|
|
289 frd->num++; |
|
|
290 frd->tail = (frd->tail + 1) % FIFO_SIZE; |
|
|
291 } |
|
|
292 #endif |
|
|
293 |
|
|
294 return true; |
|
|
295 } |
|
|
296 |
|
|
297 //------------------------------------------------------------------------- |
|
|
298 |
|
|
299 bool loop_can_getevent(can_channel *chan, cyg_can_event *pevent, void *pdata) |
|
|
300 { |
|
|
301 loop_can_info *loop_chan = (loop_can_info *)chan->dev_priv; |
|
|
302 |
|
|
303 struct fifo *frd = loop_chan->read_fifo; |
|
|
304 |
|
|
305 while( frd->num == 0 ) |
|
|
306 { |
|
|
307 continue; |
|
|
308 } |
|
|
309 |
|
|
310 *pevent = frd->buf[frd->head]; |
|
|
311 |
|
|
312 |
|
|
313 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMESTAMP |
|
|
314 // |
|
|
315 // if timestamps are supported then we store a actual timestamp into |
|
|
316 // CAN event |
|
|
317 // |
|
|
318 pevent->timestamp = cyg_current_time(); |
|
|
319 #endif // CYGOPT_IO_CAN_SUPPORT_TIMESTAMP |
|
|
320 |
|
|
321 frd->num--; |
|
|
322 frd->head = (frd->head + 1) % FIFO_SIZE; |
|
|
323 |
|
|
324 return true; |
|
|
325 } |
|
|
326 |
|
|
327 //------------------------------------------------------------------------- |
|
|
328 |
|
|
329 static Cyg_ErrNo |
|
|
330 loop_can_set_config(can_channel *chan, cyg_uint32 key, |
|
|
331 const void *xbuf, cyg_uint32 *len) |
|
|
332 { |
|
|
333 return ENOERR; |
|
|
334 } |
|
|
335 |
|
|
336 |
|
|
337 //------------------------------------------------------------------------- |
|
|
338 // Enable the transmitter on the device |
|
|
339 |
|
|
340 static void |
|
|
341 loop_can_start_xmit(can_channel *chan) |
|
|
342 { |
|
|
343 loop_can_info *loop_chan = (loop_can_info *)chan->dev_priv; |
|
|
344 |
|
|
345 loop_chan->write_fifo->tx_enable = true; |
|
|
346 |
|
|
347 (chan->callbacks->xmt_msg)(chan, 0); |
|
|
348 } |
|
|
349 |
|
|
350 //------------------------------------------------------------------------- |
|
|
351 // Disable the transmitter on the device |
|
|
352 |
|
|
353 static void |
|
|
354 loop_can_stop_xmit(can_channel *chan) |
|
|
355 { |
|
|
356 loop_can_info *loop_chan = (loop_can_info *)chan->dev_priv; |
|
|
357 |
|
|
358 loop_chan->write_fifo->tx_enable = false; |
|
|
359 } |
|
|
360 |
|
|
361 //------------------------------------------------------------------------- |
|
|
362 |
|
|
363 static void alarm_handler(cyg_handle_t alarm, cyg_addrword_t data) |
|
|
364 { |
|
|
365 can_channel *chan0 = &loop_can0_chan; |
|
|
366 can_channel *chan1 = &loop_can1_chan; |
|
|
367 |
|
|
368 |
|
|
369 while(fifo0.num ) |
|
|
370 { |
|
|
371 (chan1->callbacks->rcv_event)(chan1, 0); |
|
|
372 |
|
|
373 if(fifo0.tx_enable ) |
|
|
374 { |
|
|
375 (chan0->callbacks->xmt_msg)(chan0, 0); |
|
|
376 } |
|
|
377 } |
|
|
378 |
|
|
379 while(fifo1.num ) |
|
|
380 { |
|
|
381 (chan0->callbacks->rcv_event)(chan0, 0); |
|
|
382 |
|
|
383 if(fifo1.tx_enable ) |
|
|
384 { |
|
|
385 (chan1->callbacks->xmt_msg)(chan1, 0); |
|
|
386 } |
|
|
387 } // while( fifo1.num ) |
|
|
388 } |
|
|
389 |
|
|
390 |
|
|
391 #endif // CYGPKG_IO_CAN_LOOP |
|
|
392 |
|
|
393 //------------------------------------------------------------------------- |
|
|
394 // EOF loop_can.c |