//=========================================================================== // Callback for received events //=========================================================================== static void can_rcv_event(can_channel *chan, void *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. 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) { cbuf->data_cnt++; } else { // // the buffer is full but a new message arrived. We store this new // message and overwrite the oldest one, but at least we tell the user // that there is an overrun in RX queue // 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) { 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(); }
//=========================================================================== // Callback function for transmit events //=========================================================================== 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_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 // while (cbuf->data_cnt > 0) { pbuf_txmsg = &ptxbuf[cbuf->get]; if (funs->putmsg(chan, pbuf_txmsg, pdata)) { cbuf->get = (cbuf->get + 1) % cbuf->len; cbuf->data_cnt--; } else { // // we are here because the hardware is busy at the moment and // we can't send another message - now we check if there is already // some space in buffer so we can wakeup the writer // if ((cbuf->len - cbuf->data_cnt) > 0) { if (cbuf->waiting) { cbuf->waiting = false; cyg_drv_cond_broadcast(&cbuf->wait); } } return; } } // while (cbuf->data_cnt > 0) funs->stop_xmit(chan); // Done with transmit if (cbuf->waiting) { cbuf->waiting = false; cyg_drv_cond_broadcast(&cbuf->wait); } }
static void serial_data_xmt_done(serial_channel *chan, int chars_sent) { cbuf_t *cbuf = &chan->out_cbuf; serial_funs *funs = chan->funs; int space; cbuf->get += chars_sent; cbuf->nb -= chars_sent; if (cbuf->get == cbuf->len) cbuf->get = 0; CYG_ASSERT(cbuf->nb <= cbuf->len, "Buffer overflow"); CYG_ASSERT(cbuf->nb >= 0, "Buffer underflow"); CYG_ASSERT(cbuf->put < cbuf->len, "Invalid put ptr"); CYG_ASSERT(cbuf->get < cbuf->len, "Invalid get ptr"); if (0 == cbuf->nb) { (funs->stop_xmit)(chan); // Done with transmit cbuf->get = cbuf->put = 0; // reset ptrs if empty } // See if there is now enough room to restart writer space = cbuf->len - cbuf->nb; if (space >= cbuf->low_water) { if (cbuf->waiting) { cbuf->waiting = false; cyg_drv_cond_broadcast(&cbuf->wait); } #ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT cyg_selwakeup( &cbuf->selinfo ); #endif } #ifdef CYGDBG_USE_ASSERTS cbuf->block_mode_xfer_running = false; #endif }
static void serial_xmt_char(serial_channel *chan) { cbuf_t *cbuf = &chan->out_cbuf; serial_funs *funs = chan->funs; unsigned char c; int space; #if CYGINT_IO_SERIAL_BLOCK_TRANSFER CYG_ASSERT(false == cbuf->block_mode_xfer_running, "Attempting char xmt while block transfer is running"); #endif #ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE // if we are required to send an XON/XOFF char, send it before // anything else // FIXME: what if XON gets corrupted in transit to the other end? // Should we resend XON even though the other end may not be wanting // to send us stuff at this point? if ( chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX ) { if ( chan->flow_desc.xchar ) { if ( (funs->putc)(chan, chan->flow_desc.xchar) ) { chan->flow_desc.xchar = '\0'; } else { // otherwise there's no space and we have to wait return; } } } #endif #ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL // if we're meant to be throttled, just stop and leave if ( chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED ) { (funs->stop_xmit)(chan); // Stop transmitting for now return; } #endif while (cbuf->nb > 0) { c = cbuf->data[cbuf->get]; if ((funs->putc)(chan, c)) { cbuf->get++; if (cbuf->get == cbuf->len) cbuf->get = 0; cbuf->nb--; } else { // See if there is now enough room to restart writer space = cbuf->len - cbuf->nb; if (space >= cbuf->low_water) { if (cbuf->waiting) { cbuf->waiting = false; cyg_drv_cond_broadcast(&cbuf->wait); } #ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT cyg_selwakeup( &cbuf->selinfo ); #endif } return; // Need to wait for more space } } (funs->stop_xmit)(chan); // Done with transmit #ifdef CYGPKG_NET_BLUEZ_STACK if(chan->tty_ldisc)//clyu { struct tty_ldisc *ldisc = chan->tty_ldisc; //diag_printf("chan->tty_ldisc != NULL\n"); if(ldisc && ldisc->write_wakeup) ldisc->write_wakeup(serial_driver); } #endif // must signal waiters, and wake up selecters for the case when // this was the last char to be sent and they hadn't been signalled // before (e.g. because of flow control) if (cbuf->waiting) { cbuf->waiting = false; //diag_printf("cyg_drv_cond_broadcast signal\n"); //cyg_drv_cond_signal(&cbuf->wait);//clyu ? cyg_drv_cond_broadcast(&cbuf->wait); } #ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT cyg_selwakeup( &cbuf->selinfo ); #endif }
//=========================================================================== // Set CAN channel configuration //=========================================================================== static Cyg_ErrNo can_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *xbuf, cyg_uint32 *len) { cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle; can_channel *chan = (can_channel *)t->priv; Cyg_ErrNo res = ENOERR; can_lowlevel_funs *funs = chan->funs; can_cbuf_t *out_cbuf = &chan->out_cbuf; can_cbuf_t *in_cbuf = &chan->in_cbuf; 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) { return -EINVAL; } 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) { return -EINVAL; } out_cbuf->blocking = (1 == *(cyg_uint32*)xbuf) ? true : false; } break; #endif // CYGOPT_IO_CAN_SUPPORT_NONBLOCKING #ifdef CYGOPT_IO_CAN_SUPPORT_TIMEOUTS // // return current timeouts // case CYG_IO_SET_CONFIG_CAN_TIMEOUT : { cyg_can_timeout_info_t *ptimeout_info; if (*len < sizeof(cyg_can_timeout_info_t)) { return -EINVAL; } *len = sizeof(cyg_can_timeout_info_t); ptimeout_info = (cyg_can_timeout_info_t *)xbuf; in_cbuf->timeout = ptimeout_info->rx_timeout; out_cbuf->timeout = ptimeout_info->tx_timeout; } 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 // res = (funs->set_config)(chan, key, xbuf, len); } // switch (key) return res; }