⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial.c

📁 eCos操作系统源码
💻 C
📖 第 1 页 / 共 3 页
字号:
//==========================================================================////      io/serial/common/serial.c////      High level serial driver////==========================================================================//####ECOSGPLCOPYRIGHTBEGIN####// -------------------------------------------// This file is part of eCos, the Embedded Configurable Operating System.// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.// Copyright (C) 2003 Gary Thomas//// eCos is free software; you can redistribute it and/or modify it under// the terms of the GNU General Public License as published by the Free// Software Foundation; either version 2 or (at your option) any later version.//// eCos is distributed in the hope that it will be useful, but WITHOUT ANY// WARRANTY; without even the implied warranty of MERCHANTABILITY or// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License// for more details.//// You should have received a copy of the GNU General Public License along// with eCos; if not, write to the Free Software Foundation, Inc.,// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.//// As a special exception, if other files instantiate templates or use macros// or inline functions from this file, or you compile this file and link it// with other works to produce a work based on this file, this file does not// by itself cause the resulting work to be covered by the GNU General Public// License. However the source code for this file must still be made available// in accordance with section (3) of the GNU General Public License.//// This exception does not invalidate any other reasons why a work based on// this file might be covered by the GNU General Public License.//// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.// at http://sources.redhat.com/ecos/ecos-license/// -------------------------------------------//####ECOSGPLCOPYRIGHTEND####//==========================================================================//#####DESCRIPTIONBEGIN####//// Author(s):    gthomas// Contributors: gthomas, grante, jlarmour, jskov// Date:         1999-02-04// Purpose:      Top level serial driver// Description: ////####DESCRIPTIONEND####////==========================================================================#include <pkgconf/io.h>#include <pkgconf/io_serial.h>#include <cyg/io/io.h>#include <cyg/io/devtab.h>#include <cyg/io/serial.h>#include <cyg/infra/cyg_ass.h>      // assertion support#include <cyg/infra/diag.h>         // diagnostic outputstatic Cyg_ErrNo serial_write(cyg_io_handle_t handle, const void *buf, cyg_uint32 *len);static Cyg_ErrNo serial_read(cyg_io_handle_t handle, void *buf, cyg_uint32 *len);static cyg_bool serial_select(cyg_io_handle_t handle, cyg_uint32 which, CYG_ADDRWORD info);static Cyg_ErrNo serial_get_config(cyg_io_handle_t handle, cyg_uint32 key, void *buf, cyg_uint32 *len);static Cyg_ErrNo serial_set_config(cyg_io_handle_t handle, cyg_uint32 key, const void *buf, cyg_uint32 *len);DEVIO_TABLE(cyg_io_serial_devio,            serial_write,            serial_read,            serial_select,            serial_get_config,            serial_set_config    );static void serial_init(serial_channel *chan);static void serial_xmt_char(serial_channel *chan);static void serial_rcv_char(serial_channel *chan, unsigned char c);#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUSstatic void serial_indicate_status(serial_channel *chan,                                   cyg_serial_line_status_t *s);#endif#if CYGINT_IO_SERIAL_BLOCK_TRANSFERstatic rcv_req_reply_t serial_data_rcv_req(serial_channel *chan, int avail,                                            int* space_avail,                                            unsigned char** space);static void serial_data_rcv_done(serial_channel *chan, int chars_rcvd);static xmt_req_reply_t serial_data_xmt_req(serial_channel *chan, int space,                                           int* chars_avail,                                            unsigned char** chars);static void serial_data_xmt_done(serial_channel *chan, int chars_sent);# ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUSSERIAL_CALLBACKS(cyg_io_serial_callbacks,                  serial_init,                  serial_xmt_char,                  serial_rcv_char,                 serial_data_rcv_req,                 serial_data_rcv_done,                 serial_data_xmt_req,                 serial_data_xmt_done,                 serial_indicate_status);# elseSERIAL_CALLBACKS(cyg_io_serial_callbacks,                  serial_init,                  serial_xmt_char,                  serial_rcv_char,                 serial_data_rcv_req,                 serial_data_rcv_done,                 serial_data_xmt_req,                 serial_data_xmt_done);# endif#else# ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUSSERIAL_CALLBACKS(cyg_io_serial_callbacks,                  serial_init,                  serial_xmt_char,                  serial_rcv_char,                 serial_indicate_status);# elseSERIAL_CALLBACKS(cyg_io_serial_callbacks,                  serial_init,                  serial_xmt_char,                  serial_rcv_char);# endif#endif// ---------------------------------------------------------------------------#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROLstatic __inline__ voidthrottle_tx( serial_channel *chan ){    chan->flow_desc.flags |= CYG_SERIAL_FLOW_OUT_THROTTLED;    // the throttling itself occurs in the serial_xmt_char() callback}static __inline__ voidrestart_tx( serial_channel *chan ){    serial_funs *funs = chan->funs;    chan->flow_desc.flags &= ~CYG_SERIAL_FLOW_OUT_THROTTLED;#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT    // See if there is now enough room to say it is available    // for writing    {        cbuf_t *cbuf = &chan->out_cbuf;        int space;                space = cbuf->len - cbuf->nb;        if (space >= cbuf->low_water)            cyg_selwakeup( &cbuf->selinfo );    }#endif    if ( chan->out_cbuf.nb > 0 )        (funs->start_xmit)(chan);}static __inline__ voidthrottle_rx( serial_channel *chan, cyg_bool force ){    serial_funs *funs = chan->funs;#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE    cyg_uint32 prev_flags = chan->flow_desc.flags;#endif    chan->flow_desc.flags |= CYG_SERIAL_FLOW_IN_THROTTLED;#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE    // send an xoff if not already done (throttled)    if ( force ||        ((chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX) &&         (0==(prev_flags & CYG_SERIAL_FLOW_IN_THROTTLED))) ) {        CYG_ASSERT(force||(chan->flow_desc.xchar=='\0')||(chan->flow_desc.xchar==CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR), "xchar already set (XOFF)");        chan->flow_desc.xchar = CYGDAT_IO_SERIAL_FLOW_CONTROL_XOFF_CHAR;        // Make sure xmit is running so we can send it        (funs->start_xmit)(chan);     }#endif#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW    {        cyg_uint32 i=1;        cyg_uint32 len = sizeof(i);                // set hardware flow control - don't care if it fails        if ( force || (chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX) ||             (chan->config.flags & CYGNUM_SERIAL_FLOW_DSRDTR_RX) )            (funs->set_config)(chan,                               CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE,                               &i, &len);    }#endif}static __inline__ voidrestart_rx( serial_channel *chan, cyg_bool force ){    serial_funs *funs = chan->funs;#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE    cyg_uint32 prev_flags = chan->flow_desc.flags;#endif    chan->flow_desc.flags &= ~CYG_SERIAL_FLOW_IN_THROTTLED;#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE    // send an xon, if we haven't already    if ( force ||        ((chan->config.flags & CYGNUM_SERIAL_FLOW_XONXOFF_RX) &&         (prev_flags & CYG_SERIAL_FLOW_IN_THROTTLED)) ) {        CYG_ASSERT(force||(chan->flow_desc.xchar=='\0')||(chan->flow_desc.xchar==CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR), "xchar already set (XON)");        chan->flow_desc.xchar = CYGDAT_IO_SERIAL_FLOW_CONTROL_XON_CHAR;        (funs->start_xmit)(chan);  // Make sure xmit is running so we can send it    }#endif#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW    {        cyg_uint32 i=0;        cyg_uint32 len = sizeof(i);                // set hardware flow control - don't care if it fails        if ( force || (chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX) ||             (chan->config.flags & CYGNUM_SERIAL_FLOW_DSRDTR_RX) )            (funs->set_config)(chan,                               CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE,                               &i, &len);    }#endif}#endif// ---------------------------------------------------------------------------static voidserial_init(serial_channel *chan){    if (chan->init) return;    if (chan->out_cbuf.len != 0) {#ifdef CYGDBG_IO_INIT        diag_printf("Set output buffer - buf: %x len: %d\n", chan->out_cbuf.data, chan->out_cbuf.len);#endif        chan->out_cbuf.waiting = false;        chan->out_cbuf.abort = false;#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING        chan->out_cbuf.blocking = true;#endif        chan->out_cbuf.pending = 0;        cyg_drv_mutex_init(&chan->out_cbuf.lock);        cyg_drv_cond_init(&chan->out_cbuf.wait, &chan->out_cbuf.lock);        chan->out_cbuf.low_water = chan->out_cbuf.len / 4;#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT        cyg_selinit( &chan->out_cbuf.selinfo );#endif            }    if (chan->in_cbuf.len != 0) {        cbuf_t *cbuf = &chan->in_cbuf;#ifdef CYGDBG_IO_INIT        diag_printf("Set input buffer - buf: %x len: %d\n", cbuf->data, cbuf->len);#endif        cbuf->waiting = false;        cbuf->abort = false;#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING        cbuf->blocking = true;#endif#ifdef CYGPKG_IO_SERIAL_SELECT_SUPPORT        cyg_selinit( &cbuf->selinfo );#endif#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL        cbuf->low_water =            (CYGNUM_IO_SERIAL_FLOW_CONTROL_LOW_WATER_PERCENT * cbuf->len) / 100;        cbuf->high_water =            (CYGNUM_IO_SERIAL_FLOW_CONTROL_HIGH_WATER_PERCENT * cbuf->len) / 100;# ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_SOFTWARE        // But make sure it is at least 35 below buffer size, to allow        // for 16 byte fifos, twice, plus some latency before s/w flow        // control can kick in. This doesn't apply to h/w flow control        // as it is near-instantaneous        if ( (cbuf->len - cbuf->high_water) < 35 )            cbuf->high_water = cbuf->len - 35;        // and just in case...        if ( cbuf->high_water <= 0 )            cbuf->high_water = 1;        if ( cbuf->low_water > cbuf->high_water )            cbuf->low_water = cbuf->high_water;# endif#endif        cyg_drv_mutex_init(&cbuf->lock);        cyg_drv_cond_init(&cbuf->wait, &cbuf->lock);    }#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS    chan->status_callback = NULL;#endif#ifdef CYGDBG_USE_ASSERTS#if CYGINT_IO_SERIAL_BLOCK_TRANSFER    chan->in_cbuf.block_mode_xfer_running = false;    chan->out_cbuf.block_mode_xfer_running = false;#endif // CYGINT_IO_SERIAL_BLOCK_TRANSFER#endif // CYGDBG_USE_ASSERTS    chan->init = true;}// ---------------------------------------------------------------------------static Cyg_ErrNo serial_write(cyg_io_handle_t handle, const void *_buf, cyg_uint32 *len){    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;    serial_channel *chan = (serial_channel *)t->priv;    serial_funs *funs = chan->funs;    cyg_int32 size = *len;    cyg_uint8 *buf = (cyg_uint8 *)_buf;    int next;    cbuf_t *cbuf = &chan->out_cbuf;    Cyg_ErrNo res = ENOERR;    cyg_drv_mutex_lock(&cbuf->lock);    cbuf->abort = false;    if (cbuf->len == 0) {        // Non interrupt driven (i.e. polled) operation        while (size-- > 0) {#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL            while ( ( 0 != (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) ) ||                    ((funs->putc)(chan, *buf) == false) )                 ;  // Ignore full, keep trying#else            while ((funs->putc)(chan, *buf) == false)                 ;  // Ignore full, keep trying#endif            buf++;        }    } else {        cyg_drv_dsr_lock();  // Avoid race condition testing pointers        while (size > 0) {                   next = cbuf->put + 1;            if (next == cbuf->len) next = 0;            if (cbuf->nb == cbuf->len) {                cbuf->waiting = true;                // Buffer full - wait for space#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL                if ( 0 == (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) )#endif                    (funs->start_xmit)(chan);  // Make sure xmit is running                // Check flag: 'start_xmit' may have obviated the need                // to wait :-)                if (cbuf->waiting) {#ifdef CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING                    // Optionally return if configured for non-blocking mode.                    if (!cbuf->blocking) {                        *len -= size;   // number of characters actually sent                        cbuf->waiting = false;                        res = (*len == 0) ? -EAGAIN : ENOERR;                        break;                    }#endif // CYGOPT_IO_SERIAL_SUPPORT_NONBLOCKING                    cbuf->pending += size;  // Have this much more to send [eventually]                    if( !cyg_drv_cond_wait(&cbuf->wait) )                        cbuf->abort = true;                    cbuf->pending -= size;                }                if (cbuf->abort) {                    // Give up!                    *len -= size;   // number of characters actually sent                    cbuf->abort = false;                    cbuf->waiting = false;                    res = -EINTR;                    break;                }            } else {                cbuf->data[cbuf->put++] = *buf++;                cbuf->put = next;                cbuf->nb++;                size--;  // Only count if actually sent!            }        }#ifdef CYGPKG_IO_SERIAL_FLOW_CONTROL        if ( 0 == (chan->flow_desc.flags & CYG_SERIAL_FLOW_OUT_THROTTLED) )#endif            (funs->start_xmit)(chan);  // Start output as necessary        cyg_drv_dsr_unlock();    }    cyg_drv_mutex_unlock(&cbuf->lock);    return res;}// ---------------------------------------------------------------------------static Cyg_ErrNo serial_read(cyg_io_handle_t handle, void *_buf, cyg_uint32 *len){    cyg_devtab_entry_t *t = (cyg_devtab_entry_t *)handle;    serial_channel *chan = (serial_channel *)t->priv;    serial_funs *funs = chan->funs;    cyg_uint8 *buf = (cyg_uint8 *)_buf;    cyg_int32 size = 0;    cbuf_t *cbuf = &chan->in_cbuf;    Cyg_ErrNo res = ENOERR;#ifdef XX_CYGDBG_DIAG_BUF

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -