OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [io/] [can/] [current/] [src/] [can.c] - Blame information for rev 825

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//==========================================================================
2
//
3
//      io/can/common/can.c
4
//
5
//      High level CAN 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, 2003 Free Software Foundation, 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      
16
// version.                                                                 
17
//
18
// eCos is distributed in the hope that it will be useful, but WITHOUT      
19
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or    
20
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License    
21
// for more details.                                                        
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with eCos; if not, write to the Free Software Foundation, Inc.,    
25
// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.            
26
//
27
// As a special exception, if other files instantiate templates or use      
28
// macros or inline functions from this file, or you compile this file      
29
// and link it with other works to produce a work based on this file,       
30
// this file does not by itself cause the resulting work to be covered by   
31
// the GNU General Public License. However the source code for this file    
32
// must still be made available in accordance with section (3) of the GNU   
33
// General Public License v2.                                               
34
//
35
// This exception does not invalidate any other reasons why a work based    
36
// on this file might be covered by the GNU General Public License.         
37
// -------------------------------------------                              
38
// ####ECOSGPLCOPYRIGHTEND####                                              
39
//==========================================================================
40
//#####DESCRIPTIONBEGIN####
41
//
42
// Author(s):    Uwe Kindler
43
// Contributors: Uwe Kindler
44
// Date:         2005-05-12
45
// Purpose:      Top level CAN driver
46
// Description: 
47
//
48
//####DESCRIPTIONEND####
49
//
50
//==========================================================================
51
 
52
 
53
//==========================================================================
54
//                              INCLUDES
55
//==========================================================================
56
#include <pkgconf/io.h>
57
#include <pkgconf/io_can.h>
58
 
59
#include <cyg/io/io.h>
60
#include <cyg/io/devtab.h>
61
#include <cyg/io/can.h>
62
#include <cyg/infra/cyg_ass.h>      // assertion support
63
#include <cyg/infra/diag.h>         // diagnostic output
64
 
65
 
66
//==========================================================================
67
//                                MACROS
68
//==========================================================================
69
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
70
#define CYG_DRV_COND_WAIT(_cond, _time) cyg_cond_timed_wait(_cond, cyg_current_time() + (_time))
71
#else
72
#define CYG_DRV_COND_WAIT(_cond, _time) cyg_drv_cond_wait(_cond)
73
#endif
74
 
75
 
76
//==========================================================================
77
//                            LOCAL FUNCTIONS
78
//==========================================================================
79
//
80
// Device I/O functions
81
//
82
static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len);
83
static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len);
84
static cyg_bool  can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info);
85
static Cyg_ErrNo can_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *xbuf, cyg_uint32 *len);
86
static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf, cyg_uint32 *len);
87
 
88
//
89
// Callback functions into upper layer driver
90
//
91
static void can_init(can_channel *chan);
92
static cyg_bool can_rcv_event(can_channel *chan, void *pdata);
93
static cyg_bool can_xmt_msg(can_channel *chan, void *pdata);
94
 
95
//
96
// Device I/O table
97
//
98
DEVIO_TABLE(cyg_io_can_devio,
99
            can_write,
100
            can_read,
101
            can_select,
102
            can_get_config,
103
            can_set_config
104
    );
105
 
106
 
107
//
108
// Callbacks into upper layer driver
109
//
110
CAN_CALLBACKS(cyg_io_can_callbacks,
111
              can_init,
112
              can_xmt_msg,
113
              can_rcv_event);
114
 
115
 
116
//===========================================================================
117
// Initialize CAN driver
118
//===========================================================================
119
static void can_init(can_channel *chan)
120
{
121
    can_cbuf_t *cbuf;
122
 
123
    if (chan->init)
124
    {
125
        return;
126
    }
127
 
128
    cbuf = &chan->in_cbuf;
129
    cbuf->waiting  = false;
130
    cbuf->abort    = false;
131
#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
132
    cbuf->blocking = true;
133
#endif
134
    cyg_drv_mutex_init(&cbuf->lock);
135
    cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
136
 
137
    cbuf = &chan->out_cbuf;
138
    cbuf->waiting  = false;
139
    cbuf->abort    = false;
140
#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
141
    cbuf->blocking = true;
142
#endif
143
    cyg_drv_mutex_init(&cbuf->lock);
144
    cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);
145
 
146
    chan->init = true;
147
}
148
 
149
 
150
//===========================================================================
151
// Write exactly one CAN message to CAN bus
152
//===========================================================================
153
static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len)
154
{
155
    cyg_devtab_entry_t *t      = (cyg_devtab_entry_t *)handle;
156
    can_channel        *chan   = (can_channel *)t->priv;
157
    can_lowlevel_funs  *funs   = chan->funs;
158
    Cyg_ErrNo           res    = ENOERR;
159
    can_cbuf_t         *cbuf   = &chan->out_cbuf;
160
    cyg_uint32          size   = *len;
161
 
162
    //
163
    // the user need to provide a can message buffer
164
    //
165
    if (*len != sizeof(cyg_can_message))
166
    {
167
        return -EINVAL;
168
    }
169
 
170
    cyg_drv_mutex_lock(&cbuf->lock);
171
    cbuf->abort = false;
172
    cyg_drv_dsr_lock(); // avoid race condition while testing pointers
173
 
174
    while (size > 0)
175
    {
176
        if (cbuf->data_cnt == cbuf->len)
177
        {
178
            cbuf->waiting = true;      // Buffer full - wait for space
179
            funs->start_xmit(chan);    // Make sure xmit is running
180
            //
181
            // Check flag: 'start_xmit' may have obviated the need
182
            // to wait
183
            //
184
            if (cbuf->waiting)
185
            {
186
                cbuf->pending += size;  // Have this much more to send [eventually]
187
#if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
188
#if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
189
                //
190
                // If timeouts are enabled and we use nonblocking calls then we
191
                // can use the timeout values
192
                //
193
                if (!cbuf->blocking)
194
                {
195
                    if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
196
                    {
197
                        cbuf->abort = true;
198
                    }
199
                } // if (!cbuf->blocking)#
200
                else
201
#else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
202
                //
203
                // if this is a nonblocking call then we return immediatelly
204
                //
205
                if (!cbuf->blocking)
206
                {
207
                    *len = 0;
208
                    res = -EAGAIN;
209
                    break;
210
                }
211
                else
212
#endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
213
#endif //defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
214
                {
215
                    if(!cyg_drv_cond_wait(&cbuf->wait))
216
                    {
217
                        cbuf->abort = true;
218
                    }
219
                }
220
                cbuf->pending -= size;
221
                if (cbuf->abort)
222
                {
223
                    // Give up!
224
                    *len -= size;   // number of characters actually sent
225
                     cbuf->abort = false;
226
                     cbuf->waiting = false;
227
                     res = -EINTR;
228
                     break;
229
                } // if (cbuf->abort) 
230
            } // if (cbuf->waiting)
231
        } // if (cbuf->data_cnt == cbuf->len) 
232
        else
233
        {
234
            //
235
            // there is enougth space left so we can store additional data
236
            //
237
            CYG_CAN_MSG_T   *ptxbuf       = (CYG_CAN_MSG_T *)cbuf->pdata;
238
            CYG_CAN_MSG_T   *pbuf_message = &ptxbuf[cbuf->put];
239
            cyg_can_message *pmessage     = (cyg_can_message *)_buf;
240
 
241
            CYG_CAN_WRITE_MSG(pbuf_message, pmessage); // copy message
242
 
243
            cbuf->put = (cbuf->put + 1) % cbuf->len;
244
            cbuf->data_cnt++;
245
            size -= sizeof(cyg_can_message);
246
        }
247
    } // while (size > 0)
248
 
249
    (funs->start_xmit)(chan);  // Start output as necessary
250
    cyg_drv_dsr_unlock();
251
    cyg_drv_mutex_unlock(&cbuf->lock);
252
    return res;
253
}
254
 
255
 
256
//===========================================================================
257
// Read one single CAN event from hw
258
//===========================================================================
259
static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
260
{
261
    cyg_devtab_entry_t *t      = (cyg_devtab_entry_t *)handle;
262
    can_channel        *chan   = (can_channel *)t->priv;
263
    can_cbuf_t         *cbuf   = &chan->in_cbuf;
264
    cyg_uint32          size   = 0;
265
    Cyg_ErrNo           res    = ENOERR;
266
 
267
    //
268
    // the user need to provide a can event buffer
269
    //
270
    if (*len != sizeof(cyg_can_event))
271
    {
272
        return -EINVAL;
273
    }
274
 
275
    cyg_drv_mutex_lock(&cbuf->lock);
276
    cbuf->abort = false;
277
 
278
    cyg_drv_dsr_lock();  // avoid race conditions
279
    while (size < *len)
280
    {
281
        //
282
        // if message buffer contains at least one message then read the
283
        // oldest message from buffer and return
284
        //
285
        if (cbuf->data_cnt > 0)
286
        {
287
            CYG_CAN_EVENT_T *prxbuf     = (CYG_CAN_EVENT_T *)cbuf->pdata;
288
            CYG_CAN_EVENT_T *pbuf_event = &prxbuf[cbuf->get];
289
            cyg_can_event *pevent       = (cyg_can_event *)_buf;
290
 
291
            CYG_CAN_READ_EVENT(pevent, pbuf_event); // copy event
292
 
293
            cbuf->get = (cbuf->get + 1) % cbuf->len;
294
            cbuf->data_cnt--;
295
            size += sizeof(cyg_can_event);
296
        }
297
        else
298
        {
299
            //
300
            // if messaeg buffer does not contain any message, then wait until
301
            // a message arrives or return immediatelly if nonblocking calls are
302
            // supported
303
            //
304
            cbuf->waiting = true;
305
#if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
306
#if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
307
            //
308
            // If timeouts are enabled and we use nonblocking calls then we
309
            // can use the timeout values
310
            //
311
            if (!cbuf->blocking)
312
            {
313
                if(!CYG_DRV_COND_WAIT(&cbuf->wait, cbuf->timeout))
314
                {
315
                    cbuf->abort = true;
316
                }
317
            } // if (!cbuf->blocking)#
318
            else
319
#else // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
320
            //
321
            // if this is a nonblocking call then we return immediatelly
322
            //
323
            if (!cbuf->blocking)
324
            {
325
                *len = 0;
326
                res = -EAGAIN;
327
                break;
328
            }
329
            else
330
#endif // #if defined(CYGOPT_IO_CAN_SUPPORT_TIMEOUTS)
331
#endif // #if defined(CYGOPT_IO_CAN_SUPPORT_NONBLOCKING)
332
            {
333
                if(!cyg_drv_cond_wait(&cbuf->wait))
334
                {
335
                    cbuf->abort = true;
336
                }
337
            }
338
 
339
            if (cbuf->abort)
340
            {
341
                *len = size;
342
                cbuf->abort = false;
343
                cbuf->waiting = false;
344
                res = -EINTR;
345
                break;
346
            }
347
        }
348
    } // while (size < *len)
349
    cyg_drv_dsr_unlock();
350
 
351
    cyg_drv_mutex_unlock(&cbuf->lock);
352
 
353
    return res;
354
}
355
 
356
 
357
//===========================================================================
358
// Query CAN channel configuration data
359
//===========================================================================
360
static Cyg_ErrNo can_get_config(cyg_io_handle_t handle,
361
               cyg_uint32      key,
362
               void           *xbuf,
363
               cyg_uint32     *len)
364
{
365
    cyg_devtab_entry_t *t         = (cyg_devtab_entry_t *)handle;
366
    can_channel        *chan      = (can_channel *)t->priv;
367
    Cyg_ErrNo           res       = ENOERR;
368
    cyg_can_info_t     *pcan_info = (cyg_can_info_t *)xbuf;
369
    can_cbuf_t         *out_cbuf  = &chan->out_cbuf;
370
    can_cbuf_t         *in_cbuf   = &chan->in_cbuf;
371
    can_lowlevel_funs  *funs      = chan->funs;
372
 
373
    switch (key)
374
    {
375
        //
376
        // query about CAN configuration like baud rate
377
        //
378
        case CYG_IO_GET_CONFIG_CAN_INFO :
379
             if (*len < sizeof(cyg_can_info_t))
380
             {
381
                 return -EINVAL;
382
             }
383
             *pcan_info = chan->config;
384
             *len       = sizeof(chan->config);
385
             break;
386
        //
387
        // return rx/tx buffer sizes and counts 
388
        //    
389
        case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO :
390
             {
391
                 cyg_can_buf_info_t *pbuf_info;
392
                 if (*len < sizeof(cyg_can_buf_info_t))
393
                 {
394
                     return -EINVAL;
395
                 }
396
 
397
                *len = sizeof(cyg_can_buf_info_t);
398
                pbuf_info = (cyg_can_buf_info_t *)xbuf;
399
                pbuf_info->rx_bufsize = in_cbuf->len;
400
                if (pbuf_info->rx_bufsize)
401
                {
402
                    pbuf_info->rx_count = in_cbuf->data_cnt ;
403
                }
404
                else
405
                {
406
                    pbuf_info->rx_count = 0;
407
                }
408
                pbuf_info->tx_bufsize = out_cbuf->len;
409
                if (pbuf_info->tx_bufsize)
410
                {
411
                    pbuf_info->tx_count = out_cbuf->data_cnt;
412
                }
413
                else
414
                {
415
                    pbuf_info->tx_count = 0;
416
                }
417
            }
418
            break; // case CYG_IO_GET_CONFIG_CAN_BUFFER_INFO
419
 
420
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS            
421
            //
422
            // return current timeouts
423
            //
424
            case CYG_IO_GET_CONFIG_CAN_TIMEOUT :
425
                 {
426
                     cyg_can_timeout_info_t *ptimeout_info;
427
                     if (*len < sizeof(cyg_can_timeout_info_t))
428
                     {
429
                         return -EINVAL;
430
                     }
431
 
432
                     *len = sizeof(cyg_can_timeout_info_t);
433
                      ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
434
 
435
                      ptimeout_info->rx_timeout = in_cbuf->timeout;
436
                      ptimeout_info->tx_timeout = out_cbuf->timeout;
437
                 }
438
                 break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
439
#endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
440
 
441
#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
442
            //
443
            // check if blocking calls are enabled
444
            //
445
            case CYG_IO_GET_CONFIG_READ_BLOCKING:
446
                 {
447
                     if (*len < sizeof(cyg_uint32))
448
                     {
449
                         return -EINVAL;
450
                     }
451
                     *(cyg_uint32*)xbuf = (in_cbuf->blocking) ? 1 : 0;
452
                 }
453
                 break;
454
 
455
            //
456
            // check if nonblocking calls are enabled
457
            // 
458
            case CYG_IO_GET_CONFIG_WRITE_BLOCKING:
459
                 {
460
                     if (*len < sizeof(cyg_uint32))
461
                     {
462
                         return -EINVAL;
463
                     }
464
                     *(cyg_uint32*)xbuf = (out_cbuf->blocking) ? 1 : 0;
465
                 }
466
                 break;
467
#endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
468
 
469
        //
470
        // return hardware description interface
471
        //
472
        case CYG_IO_GET_CONFIG_CAN_HDI :
473
             {
474
                 cyg_can_hdi *hdi = (cyg_can_hdi *)xbuf;
475
                 if (*len != sizeof(cyg_can_hdi))
476
                 {
477
                     return -EINVAL;
478
                 }
479
                 hdi = hdi; // avoid compiler warnings
480
                 *len = sizeof(cyg_can_hdi);
481
                 //
482
                 // pass down to low level to gather more information about
483
                 // CAN hardware
484
                 //
485
                 res = (funs->get_config)(chan, key, xbuf, len);
486
             }
487
             break;
488
 
489
        default:
490
            res = (funs->get_config)(chan, key, xbuf, len);
491
    } // switch (key)
492
 
493
    return res;
494
}
495
 
496
 
497
//===========================================================================
498
// Set CAN channel configuration
499
//===========================================================================
500
static Cyg_ErrNo can_set_config(cyg_io_handle_t handle,
501
               cyg_uint32      key,
502
               const void     *xbuf,
503
               cyg_uint32     *len)
504
{
505
    cyg_devtab_entry_t *t         = (cyg_devtab_entry_t *)handle;
506
    can_channel        *chan      = (can_channel *)t->priv;
507
    Cyg_ErrNo           res       = ENOERR;
508
    can_lowlevel_funs  *funs      = chan->funs;
509
    can_cbuf_t         *out_cbuf  = &chan->out_cbuf;
510
    can_cbuf_t         *in_cbuf   = &chan->in_cbuf;
511
 
512
    switch (key)
513
    {
514
#ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
515
        //
516
        // Set calls to read function to blocking / nonblocking mode
517
        //
518
        case CYG_IO_SET_CONFIG_READ_BLOCKING:
519
             {
520
                 if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len)
521
                 {
522
                     return -EINVAL;
523
                 }
524
                 in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
525
             }
526
             break;
527
 
528
        //
529
        // set calls to write functions to blocking / nonblocking mode
530
        //     
531
        case CYG_IO_SET_CONFIG_WRITE_BLOCKING:
532
             {
533
                 if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len)
534
                 {
535
                     return -EINVAL;
536
                 }
537
                 out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
538
             }
539
             break;
540
#endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
541
 
542
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS            
543
        //
544
        // return current timeouts
545
        //
546
        case CYG_IO_SET_CONFIG_CAN_TIMEOUT :
547
             {
548
                 cyg_can_timeout_info_t *ptimeout_info;
549
                 if (*len < sizeof(cyg_can_timeout_info_t))
550
                 {
551
                     return -EINVAL;
552
                 }
553
 
554
                 *len = sizeof(cyg_can_timeout_info_t);
555
                  ptimeout_info = (cyg_can_timeout_info_t *)xbuf;
556
 
557
                  in_cbuf->timeout = ptimeout_info->rx_timeout;
558
                  out_cbuf->timeout = ptimeout_info->tx_timeout;
559
             }
560
             break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
561
#endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
562
 
563
        case CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH:
564
             {
565
                 //
566
                 // Flush any buffered input
567
                 //
568
                 if (in_cbuf->len == 0)
569
                 {
570
                     break;  // Nothing to do if not buffered
571
                 }
572
                 cyg_drv_mutex_lock(&in_cbuf->lock);  // Stop any further input processing
573
                 cyg_drv_dsr_lock();
574
                 if (in_cbuf->waiting)
575
                 {
576
                     in_cbuf->abort = true;
577
                     cyg_drv_cond_broadcast(&in_cbuf->wait);
578
                     in_cbuf->waiting = false;
579
                 }
580
                 in_cbuf->get = in_cbuf->put = in_cbuf->data_cnt = 0; // Flush buffered input
581
 
582
                 //
583
                 // Pass to the hardware driver in case it wants to flush FIFOs etc.
584
                 //
585
                 (funs->set_config)(chan,
586
                                    CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH,
587
                                    NULL, NULL);
588
                 cyg_drv_dsr_unlock();
589
                 cyg_drv_mutex_unlock(&in_cbuf->lock);
590
            } // CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH:
591
 
592
        //
593
        // flush any buffered output
594
        //    
595
        case CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH:
596
             {
597
                  // Throw away any pending output
598
                  if (out_cbuf->len == 0)
599
                  {
600
                      break;  // Nothing to do if not buffered
601
                  }
602
                  cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
603
                  cyg_drv_dsr_lock();
604
                  if (out_cbuf->data_cnt > 0)
605
                  {
606
                      out_cbuf->get = out_cbuf->put = out_cbuf->data_cnt = 0;  // Empties queue!
607
                     (funs->stop_xmit)(chan);  // Done with transmit
608
                  }
609
 
610
                  //
611
                  // Pass to the hardware driver in case it wants to flush FIFOs etc.
612
                  //
613
                  (funs->set_config)(chan,
614
                                     CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH,
615
                                     NULL, NULL);
616
                  if (out_cbuf->waiting)
617
                  {
618
                      out_cbuf->abort = true;
619
                      cyg_drv_cond_broadcast(&out_cbuf->wait);
620
                      out_cbuf->waiting = false;
621
                  }// if (out_cbuf->waiting) 
622
                  cyg_drv_dsr_unlock();
623
                  cyg_drv_mutex_unlock(&out_cbuf->lock);
624
              }
625
              break; // CYG_IO_GET_CONFIG_CAN_OUTPUT_FLUSH:
626
 
627
        //
628
        // wait until all messages in outbut buffer are sent
629
        //      
630
        case CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN:
631
             {
632
                 // Wait for any pending output to complete
633
                 if (out_cbuf->len == 0)
634
                 {
635
                     break;  // Nothing to do if not buffered
636
                 }
637
                 cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
638
                 cyg_drv_dsr_lock();
639
                 while (out_cbuf->pending || (out_cbuf->data_cnt > 0))
640
                 {
641
                     out_cbuf->waiting = true;
642
                     if(!cyg_drv_cond_wait(&out_cbuf->wait))
643
                     {
644
                         res = -EINTR;
645
                     }
646
                 }
647
                 cyg_drv_dsr_unlock();
648
                 cyg_drv_mutex_unlock(&out_cbuf->lock);
649
             }
650
             break;// CYG_IO_SET_CONFIG_CAN_OUTPUT_DRAIN:
651
 
652
        //     
653
        // Abort any outstanding I/O, including blocked reads
654
        // Caution - assumed to be called from 'timeout' (i.e. DSR) code  
655
        //   
656
        case CYG_IO_SET_CONFIG_CAN_ABORT :
657
             {
658
                 in_cbuf->abort = true;
659
                 cyg_drv_cond_broadcast(&in_cbuf->wait);
660
 
661
                 out_cbuf->abort = true;
662
                 cyg_drv_cond_broadcast(&out_cbuf->wait);
663
             }
664
             break;
665
 
666
 
667
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
668
        //
669
        // Set callback configuration
670
        // To disable callback set flag_mask = 0
671
        //
672
        case CYG_IO_SET_CONFIG_CAN_CALLBACK:
673
             {
674
                 if (*len != sizeof(cyg_can_callback_cfg))
675
                 {
676
                         return -EINVAL;
677
                 }
678
 
679
                 // Copy data under DSR locking
680
                 cyg_drv_dsr_lock();
681
                 chan->callback_cfg = *((cyg_can_callback_cfg*) xbuf);
682
                 cyg_drv_dsr_unlock();
683
             }
684
             break;
685
#endif //CYGOPT_IO_CAN_SUPPORT_CALLBACK
686
 
687
        default:
688
            //
689
            // pass down to lower layers
690
            //
691
            res = (funs->set_config)(chan, key, xbuf, len);
692
    } // switch (key)
693
 
694
    return res;
695
}
696
 
697
 
698
//===========================================================================
699
// Select support for CAN channel
700
//===========================================================================
701
static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info)
702
{
703
    //
704
    // do nothing here because we currently do not support select
705
    //
706
    return true;
707
}
708
 
709
 
710
//===========================================================================
711
// Callback for received events
712
//===========================================================================
713
static cyg_bool can_rcv_event(can_channel *chan, void *pdata)
714
{
715
    can_cbuf_t       *cbuf   = &chan->in_cbuf;
716
    CYG_CAN_EVENT_T  *prxbuf = (CYG_CAN_EVENT_T *)cbuf->pdata;
717
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
718
    cyg_can_event_flags_t flags;
719
#endif
720
    cyg_bool          res    = false;
721
 
722
    //
723
    // cbuf is a ring buffer - if the buffer is full, then we overwrite the
724
    // oldest message in buffer so the user will always get the actual and
725
    // last state of the external hardware that is connected to the
726
    // CAN bus. We need to call cyg_drv_dsr_lock() here because this function
727
    // may be called from different message box interrupts and so we have to
728
    // protect data access here
729
    //
730
    cyg_drv_dsr_lock();
731
    prxbuf[cbuf->put].flags = 0; // clear flags because it is a new event
732
    if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata))
733
    {
734
        res = true;
735
        if (cbuf->data_cnt < cbuf->len)
736
        {
737
            cbuf->data_cnt++;
738
        }
739
        else
740
        {
741
            //
742
            // the buffer is full but a new message arrived. We store this new
743
            // message and overwrite the oldest one, but at least we tell the user
744
            // that there is an overrun in RX queue
745
            //
746
            prxbuf[cbuf->put].flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
747
            cbuf->get = (cbuf->get + 1) % cbuf->len;
748
        }
749
 
750
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
751
        flags = prxbuf[cbuf->put].flags;
752
#endif
753
 
754
        cbuf->put = (cbuf->put + 1) % cbuf->len;
755
 
756
        if (cbuf->waiting)
757
        {
758
            cbuf->waiting = false;
759
            cyg_drv_cond_broadcast(&cbuf->wait);
760
        }
761
#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
762
        // Call application callback function, if any of the flag events 
763
        // are unmasked.
764
        if((flags & chan->callback_cfg.flag_mask) &&
765
           (chan->callback_cfg.callback_func))
766
        {
767
            chan->callback_cfg.callback_func(flags,
768
                                             chan->callback_cfg.data);
769
        }
770
#endif
771
    }
772
 
773
    cyg_drv_dsr_unlock();
774
 
775
    return res;
776
}
777
 
778
 
779
//===========================================================================
780
// Callback function for transmit events
781
//===========================================================================
782
static cyg_bool can_xmt_msg(can_channel *chan, void *pdata)
783
{
784
    can_cbuf_t        *cbuf    = &chan->out_cbuf;
785
    can_lowlevel_funs *funs    = chan->funs;
786
    CYG_CAN_MSG_T     *ptxbuf  = (CYG_CAN_MSG_T *)cbuf->pdata;
787
    CYG_CAN_MSG_T     *pbuf_txmsg;
788
    cyg_bool           res     = false;
789
 
790
    //
791
    // transmit messages as long as there are messages in the buffer 
792
    //
793
    while (cbuf->data_cnt > 0)
794
    {
795
        pbuf_txmsg = &ptxbuf[cbuf->get];
796
 
797
        if (funs->putmsg(chan, pbuf_txmsg, pdata))
798
        {
799
            cbuf->get = (cbuf->get + 1) % cbuf->len;
800
            cbuf->data_cnt--;
801
            res = true;
802
        }
803
        else
804
        {
805
            //
806
            // we are here because the hardware is busy at the moment and
807
            // we can't send another message - now we check if there is already
808
            // some space in buffer so we can wakeup the writer
809
            //
810
            if ((cbuf->len - cbuf->data_cnt) > 0)
811
            {
812
                if (cbuf->waiting)
813
                {
814
                    cbuf->waiting = false;
815
                    cyg_drv_cond_broadcast(&cbuf->wait);
816
                }
817
            }
818
            return res;
819
        }
820
    } // while (cbuf->data_cnt > 0)
821
    funs->stop_xmit(chan);  // Done with transmit
822
 
823
    if (cbuf->waiting)
824
    {
825
        cbuf->waiting = false;
826
        cyg_drv_cond_broadcast(&cbuf->wait);
827
    }
828
 
829
    return res;
830
}
831
 
832
 
833
//---------------------------------------------------------------------------
834
// end of can.c

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.