]> git.karo-electronics.de Git - karo-tx-redboot.git/blobdiff - packages/io/can/v2_0/src/can.c
unified MX27, MX25, MX37 trees
[karo-tx-redboot.git] / packages / io / can / v2_0 / src / can.c
index d638a234f3ef54467fbdd8b0e7fdee2f88cce6e5..f264d611aaca0fd271694ef1c44674f1f6119006 100644 (file)
@@ -236,12 +236,12 @@ static Cyg_ErrNo can_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32
             //
             // there is enougth space left so we can store additional data
             //
-            cyg_can_message *ptxbuf       = (cyg_can_message *)cbuf->pdata;
-            cyg_can_message *pbuf_message = &ptxbuf[cbuf->put];
+            CYG_CAN_MSG_T   *ptxbuf       = (CYG_CAN_MSG_T *)cbuf->pdata;
+            CYG_CAN_MSG_T   *pbuf_message = &ptxbuf[cbuf->put];
             cyg_can_message *pmessage     = (cyg_can_message *)_buf;
             
-            *pbuf_message = *pmessage; // copy message
-   
+            CYG_CAN_WRITE_MSG(pbuf_message, pmessage); // copy message
+              
             cbuf->put = (cbuf->put + 1) % cbuf->len;
             cbuf->data_cnt++;   
             size -= sizeof(cyg_can_message);   
@@ -286,11 +286,11 @@ static Cyg_ErrNo can_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len)
         //
         if (cbuf->data_cnt > 0)
         {
-            cyg_can_event *prxbuf     = (cyg_can_event *)cbuf->pdata;   
-            cyg_can_event *pbuf_event = &prxbuf[cbuf->get];
-            cyg_can_event *pevent     = (cyg_can_event *)_buf;
-
-            *pevent = *pbuf_event; // copy event
+            CYG_CAN_EVENT_T *prxbuf     = (CYG_CAN_EVENT_T *)cbuf->pdata;   
+            CYG_CAN_EVENT_T *pbuf_event = &prxbuf[cbuf->get];
+            cyg_can_event *pevent       = (cyg_can_event *)_buf;
+           
+            CYG_CAN_READ_EVENT(pevent, pbuf_event); // copy event
             
             cbuf->get = (cbuf->get + 1) % cbuf->len;
             cbuf->data_cnt--; 
@@ -370,9 +370,13 @@ static Cyg_ErrNo can_get_config(cyg_io_handle_t handle,
     cyg_can_info_t     *pcan_info = (cyg_can_info_t *)xbuf;
     can_cbuf_t         *out_cbuf  = &chan->out_cbuf;
     can_cbuf_t         *in_cbuf   = &chan->in_cbuf;
+    can_lowlevel_funs  *funs      = chan->funs;
     
     switch (key)
     {
+        //
+        // query about CAN configuration like baud rate
+        //
         case CYG_IO_GET_CONFIG_CAN_INFO :
              if (*len < sizeof(cyg_can_info_t)) 
              {
@@ -437,6 +441,9 @@ static Cyg_ErrNo can_get_config(cyg_io_handle_t handle,
 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
 
 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
+            //
+            // check if blocking calls are enabled
+            //
             case CYG_IO_GET_CONFIG_READ_BLOCKING:
                  {
                      if (*len < sizeof(cyg_uint32)) 
@@ -447,6 +454,9 @@ static Cyg_ErrNo can_get_config(cyg_io_handle_t handle,
                  }
                  break;
 
+            //
+            // check if nonblocking calls are enabled
+            // 
             case CYG_IO_GET_CONFIG_WRITE_BLOCKING:
                  {
                      if (*len < sizeof(cyg_uint32))
@@ -458,8 +468,28 @@ static Cyg_ErrNo can_get_config(cyg_io_handle_t handle,
                  break;
 #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
         
+        //
+        // return hardware description interface
+        //
+        case CYG_IO_GET_CONFIG_CAN_HDI :
+             {
+                 cyg_can_hdi *hdi = (cyg_can_hdi *)xbuf;
+                 if (*len != sizeof(cyg_can_hdi)) 
+                 {
+                     return -EINVAL;
+                 }
+                 hdi = hdi; // avoid compiler warnings
+                 *len = sizeof(cyg_can_hdi);  
+                 //
+                 // pass down to low level to gather more information about
+                 // CAN hardware
+                 //
+                 res = (funs->get_config)(chan, key, xbuf, len); 
+             }
+             break;
+        
         default:
-            res = -EINVAL;   
+            res = (funs->get_config)(chan, key, xbuf, len);
     } // switch (key)
     
     return res;
@@ -484,6 +514,9 @@ static Cyg_ErrNo can_set_config(cyg_io_handle_t handle,
     switch (key)
     {
 #ifdef CYGOPT_IO_CAN_SUPPORT_NONBLOCKING
+        //
+        // Set calls to read function to blocking / nonblocking mode
+        //
         case CYG_IO_SET_CONFIG_READ_BLOCKING:
              {
                  if (*len < sizeof(cyg_uint32) || 0 == in_cbuf->len) 
@@ -493,7 +526,10 @@ static Cyg_ErrNo can_set_config(cyg_io_handle_t handle,
                  in_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false;
              }
              break;
-             
+        
+        //
+        // set calls to write functions to blocking / nonblocking mode
+        //     
         case CYG_IO_SET_CONFIG_WRITE_BLOCKING:
              {
                  if (*len < sizeof(cyg_uint32) || 0 == out_cbuf->len) 
@@ -525,7 +561,131 @@ static Cyg_ErrNo can_set_config(cyg_io_handle_t handle,
              }
              break; // case CYG_IO_GET_CONFIG_CAN_TIMEOUT_INFO
 #endif // CYGOPT_IO_CAN_SUPPORT_TIMEOUTS
+
+        case CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH:
+             {
+                 //
+                 // Flush any buffered input
+                 //
+                 if (in_cbuf->len == 0)
+                 {
+                     break;  // Nothing to do if not buffered
+                 }
+                 cyg_drv_mutex_lock(&in_cbuf->lock);  // Stop any further input processing
+                 cyg_drv_dsr_lock();
+                 if (in_cbuf->waiting) 
+                 {
+                     in_cbuf->abort = true;
+                     cyg_drv_cond_broadcast(&in_cbuf->wait);
+                     in_cbuf->waiting = false;
+                 }
+                 in_cbuf->get = in_cbuf->put = in_cbuf->data_cnt = 0; // Flush buffered input
+                 
+                 //
+                 // Pass to the hardware driver in case it wants to flush FIFOs etc.
+                 //
+                 (funs->set_config)(chan,
+                                    CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH,
+                                    NULL, NULL);
+                 cyg_drv_dsr_unlock();
+                 cyg_drv_mutex_unlock(&in_cbuf->lock);
+            } // CYG_IO_SET_CONFIG_CAN_INPUT_FLUSH:
+        
+        //
+        // flush any buffered output
+        //    
+        case CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH:
+             {
+                  // Throw away any pending output
+                  if (out_cbuf->len == 0) 
+                  {
+                      break;  // Nothing to do if not buffered
+                  }
+                  cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
+                  cyg_drv_dsr_lock();
+                  if (out_cbuf->data_cnt > 0) 
+                  {
+                      out_cbuf->get = out_cbuf->put = out_cbuf->data_cnt = 0;  // Empties queue!
+                     (funs->stop_xmit)(chan);  // Done with transmit
+                  }
+                  
+                  //
+                  // Pass to the hardware driver in case it wants to flush FIFOs etc.
+                  //
+                  (funs->set_config)(chan,
+                                     CYG_IO_SET_CONFIG_CAN_OUTPUT_FLUSH,
+                                     NULL, NULL);
+                  if (out_cbuf->waiting) 
+                  {
+                      out_cbuf->abort = true;
+                      cyg_drv_cond_broadcast(&out_cbuf->wait);
+                      out_cbuf->waiting = false;
+                  }// if (out_cbuf->waiting) 
+                  cyg_drv_dsr_unlock();
+                  cyg_drv_mutex_unlock(&out_cbuf->lock);
+              }
+              break; // CYG_IO_GET_CONFIG_CAN_OUTPUT_FLUSH:
+        
+        //
+        // wait until all messages in outbut buffer are sent
+        //      
+        case CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN:
+             {
+                 // Wait for any pending output to complete
+                 if (out_cbuf->len == 0) 
+                 {
+                     break;  // Nothing to do if not buffered
+                 }
+                 cyg_drv_mutex_lock(&out_cbuf->lock);  // Stop any further output processing
+                 cyg_drv_dsr_lock();
+                 while (out_cbuf->pending || (out_cbuf->data_cnt > 0)) 
+                 {
+                     out_cbuf->waiting = true;
+                     if(!cyg_drv_cond_wait(&out_cbuf->wait))
+                     {
+                         res = -EINTR;
+                     }
+                 }
+                 cyg_drv_dsr_unlock();
+                 cyg_drv_mutex_unlock(&out_cbuf->lock);
+             }
+             break;// CYG_IO_GET_CONFIG_SERIAL_OUTPUT_DRAIN:
+             
+        //     
+        // Abort any outstanding I/O, including blocked reads
+        // Caution - assumed to be called from 'timeout' (i.e. DSR) code  
+        //   
+        case CYG_IO_SET_CONFIG_CAN_ABORT :
+             {
+                 in_cbuf->abort = true;
+                 cyg_drv_cond_broadcast(&in_cbuf->wait);
+                 
+                 out_cbuf->abort = true;
+                 cyg_drv_cond_broadcast(&out_cbuf->wait);
+             }
+             break;
         
+
+#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
+        //
+        // Set callback configuration
+        // To disable callback set flag_mask = 0
+        //
+        case CYG_IO_SET_CONFIG_CAN_CALLBACK:
+             {
+                 if (*len != sizeof(cyg_can_callback_cfg))
+                 {
+                         return -EINVAL;
+                 }
+            
+                 // Copy data under DSR locking
+                 cyg_drv_dsr_lock();
+                 chan->callback_cfg = *((cyg_can_callback_cfg*) xbuf);
+                 cyg_drv_dsr_unlock();
+             }
+             break;
+#endif //CYGOPT_IO_CAN_SUPPORT_CALLBACK
+
         default:
             //
             // pass down to lower layers
@@ -554,15 +714,22 @@ static cyg_bool can_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWOR
 //===========================================================================
 static void can_rcv_event(can_channel *chan, void *pdata)
 {
-    can_cbuf_t     *cbuf   = &chan->in_cbuf;
-    cyg_can_event  *prxbuf = (cyg_can_event *)cbuf->pdata;
+    can_cbuf_t       *cbuf   = &chan->in_cbuf;
+    CYG_CAN_EVENT_T  *prxbuf = (CYG_CAN_EVENT_T *)cbuf->pdata;
+#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
+    cyg_uint16        flags;
+#endif
     
     //
     // cbuf is a ring buffer - if the buffer is full, then we overwrite the
     // oldest message in buffer so the user will always get the actual and
     // last state of the external hardware that is connected to the
-    // CAN bus. 
+    // CAN bus. We need to call cyg_drv_dsr_lock() here because this function
+    // may be called from different message box interrupts and so we have to
+    // protect data access here
     //
+    cyg_drv_dsr_lock();
+    prxbuf[cbuf->put].flags = 0; // clear flags because it is a new event
     if (chan->funs->getevent(chan, &prxbuf[cbuf->put], pdata))
     {
         if (cbuf->data_cnt < cbuf->len)
@@ -579,7 +746,11 @@ static void can_rcv_event(can_channel *chan, void *pdata)
             prxbuf[cbuf->put].flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
             cbuf->get = (cbuf->get + 1) % cbuf->len;
         }
-        
+
+#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
+        flags = prxbuf[cbuf->put].flags;
+#endif
+
         cbuf->put = (cbuf->put + 1) % cbuf->len;
         
         if (cbuf->waiting) 
@@ -587,7 +758,19 @@ static void can_rcv_event(can_channel *chan, void *pdata)
             cbuf->waiting = false;
             cyg_drv_cond_broadcast(&cbuf->wait);
         }
+#ifdef CYGOPT_IO_CAN_SUPPORT_CALLBACK
+        // Call application callback function, if any of the flag events 
+        // are unmasked.
+        if((flags & chan->callback_cfg.flag_mask) &&
+           (chan->callback_cfg.callback_func))
+        {
+            chan->callback_cfg.callback_func(flags,
+                                             chan->callback_cfg.data);
+        }
+#endif
     }
+    
+    cyg_drv_dsr_unlock();
 }
 
 
@@ -598,8 +781,8 @@ static void can_xmt_msg(can_channel *chan, void *pdata)
 {
     can_cbuf_t        *cbuf    = &chan->out_cbuf;
     can_lowlevel_funs *funs    = chan->funs;  
-    cyg_can_message   *ptxbuf  = (cyg_can_message *)cbuf->pdata;
-    cyg_can_message   *pbuf_txmsg;
+    CYG_CAN_MSG_T     *ptxbuf  = (CYG_CAN_MSG_T *)cbuf->pdata;
+    CYG_CAN_MSG_T     *pbuf_txmsg;
 
     //
     // transmit messages as long as there are messages in the buffer