📄 ser_16x5x.c
字号:
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
_ier |= (IER_LS|IER_MS);
#endif
HAL_WRITE_UINT8(base+REG_ier, _ier);
if (new_config != &chan->config) {
chan->config = *new_config;
}
return true;
}
// Function to initialize the device. Called at bootstrap time.
static bool
pc_serial_init(struct cyg_devtab_entry *tab)
{
serial_channel *chan = (serial_channel *)tab->priv;
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
#ifdef CYG_IO_SERIAL_GENERIC_16X5X_BAUD_GENERATOR
// Fill in baud rate table - used for platforms where this cannot
// be determined statically
int baud_idx, baud_val;
if (select_baud[0] == 9999) {
// Table not yet initialized
// Assumes that 'select_baud' looks like this:
// static int select_baud[] = {
// 9999, -- marker
// 50, -- first baud rate
// 110, -- second baud rate
// etc.
for (baud_idx = 1; baud_idx < sizeof(select_baud)/sizeof(select_baud[0]); baud_idx++) {
baud_val = CYG_IO_SERIAL_GENERIC_16X5X_BAUD_GENERATOR(select_baud[baud_idx]);
select_baud[baud_idx] = baud_val;
}
select_baud[0] = 0;
}
#endif
#ifdef CYGDBG_IO_INIT
diag_printf("16x5x SERIAL init - dev: %x.%d\n",
ser_chan->base, ser_chan->int_num);
#endif
// Really only required for interrupt driven devices
(chan->callbacks->serial_init)(chan);
if (chan->out_cbuf.len != 0) {
cyg_drv_interrupt_create(ser_chan->int_num,
CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY,
(cyg_addrword_t)chan,
pc_serial_ISR,
pc_serial_DSR,
&ser_chan->serial_interrupt_handle,
&ser_chan->serial_interrupt);
cyg_drv_interrupt_attach(ser_chan->serial_interrupt_handle);
cyg_drv_interrupt_unmask(ser_chan->int_num);
}
serial_config_port(chan, &chan->config, true);
return true;
}
// This routine is called when the device is "looked" up (i.e. attached)
static Cyg_ErrNo
pc_serial_lookup(struct cyg_devtab_entry **tab,
struct cyg_devtab_entry *sub_tab,
const char *name)
{
serial_channel *chan = (serial_channel *)(*tab)->priv;
// Really only required for interrupt driven devices
(chan->callbacks->serial_init)(chan);
return ENOERR;
}
// Send a character to the device output buffer.
// Return 'true' if character is sent to device
static bool
pc_serial_putc(serial_channel *chan, unsigned char c)
{
cyg_uint8 _lsr;
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
cyg_addrword_t base = ser_chan->base;
HAL_READ_UINT8(base+REG_lsr, _lsr);
if (_lsr & LSR_THE) {
// Transmit buffer is empty
HAL_WRITE_UINT8(base+REG_thr, c);
return true;
}
// No space
return false;
}
// Fetch a character from the device input buffer, waiting if necessary
static unsigned char
pc_serial_getc(serial_channel *chan)
{
unsigned char c;
cyg_uint8 _lsr;
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
cyg_addrword_t base = ser_chan->base;
// Wait for char
do {
HAL_READ_UINT8(base+REG_lsr, _lsr);
} while ((_lsr & LSR_RSR) == 0);
HAL_READ_UINT8(base+REG_rhr, c);
return c;
}
// Set up the device characteristics; baud rate, etc.
static Cyg_ErrNo
pc_serial_set_config(serial_channel *chan, cyg_uint32 key, const void *xbuf,
cyg_uint32 *len)
{
switch (key) {
case CYG_IO_SET_CONFIG_SERIAL_INFO:
{
cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
if ( *len < sizeof(cyg_serial_info_t) ) {
return -EINVAL;
}
*len = sizeof(cyg_serial_info_t);
if ( true != serial_config_port(chan, config, false) )
return -EINVAL;
}
break;
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
case CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE:
{
cyg_uint8 _mcr;
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
cyg_addrword_t base = ser_chan->base;
cyg_uint32 *f = (cyg_uint32 *)xbuf;
unsigned char mask=0;
if ( *len < sizeof(*f) )
return -EINVAL;
if ( chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_RX )
mask = MCR_RTS;
if ( chan->config.flags & CYGNUM_SERIAL_FLOW_DSRDTR_RX )
mask |= MCR_DTR;
HAL_READ_UINT8(base+REG_mcr, _mcr);
if (*f) // we should throttle
_mcr &= ~mask;
else // we should no longer throttle
_mcr |= mask;
HAL_WRITE_UINT8(base+REG_mcr, _mcr);
}
break;
case CYG_IO_SET_CONFIG_SERIAL_HW_FLOW_CONFIG:
// Nothing to do because we do support both RTSCTS and DSRDTR flow
// control.
// Other targets would clear any unsupported flags here and
// would then return -ENOSUPP - the higher layer can then query
// what flags are set and decide what to do. This is optimised for
// the most common case - i.e. that authors know what their hardware
// is capable of.
// We just return ENOERR.
break;
#endif
default:
return -EINVAL;
}
return ENOERR;
}
// Enable the transmitter on the device
static void
pc_serial_start_xmit(serial_channel *chan)
{
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
cyg_addrword_t base = ser_chan->base;
cyg_uint8 _ier;
HAL_READ_UINT8(base+REG_ier, _ier);
_ier |= IER_XMT; // Enable xmit interrupt
HAL_WRITE_UINT8(base+REG_ier, _ier);
}
// Disable the transmitter on the device
static void
pc_serial_stop_xmit(serial_channel *chan)
{
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
cyg_addrword_t base = ser_chan->base;
cyg_uint8 _ier;
HAL_READ_UINT8(base+REG_ier, _ier);
_ier &= ~IER_XMT; // Disable xmit interrupt
HAL_WRITE_UINT8(base+REG_ier, _ier);
}
// Serial I/O - low level interrupt handler (ISR)
static cyg_uint32
pc_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
cyg_drv_interrupt_mask(ser_chan->int_num);
cyg_drv_interrupt_acknowledge(ser_chan->int_num);
return CYG_ISR_CALL_DSR; // Cause DSR to be run
}
// Serial I/O - high level interrupt handler (DSR)
static void
pc_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
serial_channel *chan = (serial_channel *)data;
pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv;
cyg_addrword_t base = ser_chan->base;
cyg_uint8 _isr;
// Check if we have an interrupt pending - note that the interrupt
// is pending of the low bit of the isr is *0*, not 1.
HAL_READ_UINT8(base+REG_isr, _isr);
while ((_isr & ISR_nIP) == 0) {
switch (_isr&0xE) {
case ISR_Rx:
case ISR_RxTO:
{
cyg_uint8 _lsr;
unsigned char c;
HAL_READ_UINT8(base+REG_lsr, _lsr);
while(_lsr & LSR_RSR) {
HAL_READ_UINT8(base+REG_rhr, c);
(chan->callbacks->rcv_char)(chan, c);
HAL_READ_UINT8(base+REG_lsr, _lsr);
}
break;
}
case ISR_Tx:
(chan->callbacks->xmt_char)(chan);
break;
#ifdef CYGOPT_IO_SERIAL_SUPPORT_LINE_STATUS
case ISR_LS:
{
cyg_serial_line_status_t stat;
cyg_uint8 _lsr;
HAL_READ_UINT8(base+REG_lsr, _lsr);
// this might look expensive, but it is rarely the case that
// more than one of these is set
stat.value = 1;
if ( _lsr & LSR_OE ) {
stat.which = CYGNUM_SERIAL_STATUS_OVERRUNERR;
(chan->callbacks->indicate_status)(chan, &stat );
}
if ( _lsr & LSR_PE ) {
stat.which = CYGNUM_SERIAL_STATUS_PARITYERR;
(chan->callbacks->indicate_status)(chan, &stat );
}
if ( _lsr & LSR_FE ) {
stat.which = CYGNUM_SERIAL_STATUS_FRAMEERR;
(chan->callbacks->indicate_status)(chan, &stat );
}
if ( _lsr & LSR_BI ) {
stat.which = CYGNUM_SERIAL_STATUS_BREAK;
(chan->callbacks->indicate_status)(chan, &stat );
}
}
break;
case ISR_MS:
{
cyg_serial_line_status_t stat;
cyg_uint8 _msr;
HAL_READ_UINT8(base+REG_msr, _msr);
#ifdef CYGOPT_IO_SERIAL_FLOW_CONTROL_HW
if ( _msr & MSR_DDSR )
if ( chan->config.flags & CYGNUM_SERIAL_FLOW_DSRDTR_TX ) {
stat.which = CYGNUM_SERIAL_STATUS_FLOW;
stat.value = (0 != (_msr & MSR_DSR));
(chan->callbacks->indicate_status)(chan, &stat );
}
if ( _msr & MSR_DCTS )
if ( chan->config.flags & CYGNUM_SERIAL_FLOW_RTSCTS_TX ) {
stat.which = CYGNUM_SERIAL_STATUS_FLOW;
stat.value = (0 != (_msr & MSR_CTS));
(chan->callbacks->indicate_status)(chan, &stat );
}
#endif
if ( _msr & MSR_DDCD ) {
stat.which = CYGNUM_SERIAL_STATUS_CARRIERDETECT;
stat.value = (0 != (_msr & MSR_CD));
(chan->callbacks->indicate_status)(chan, &stat );
}
if ( _msr & MSR_RI ) {
stat.which = CYGNUM_SERIAL_STATUS_RINGINDICATOR;
stat.value = 1;
(chan->callbacks->indicate_status)(chan, &stat );
}
if ( _msr & MSR_TERI ) {
stat.which = CYGNUM_SERIAL_STATUS_RINGINDICATOR;
stat.value = 0;
(chan->callbacks->indicate_status)(chan, &stat );
}
}
break;
#endif
default:
// Yes, this assertion may well not be visible. *But*
// if debugging, we may still successfully hit a breakpoint
// on cyg_assert_fail, which _is_ useful
CYG_FAIL("unhandled serial interrupt state");
}
HAL_READ_UINT8(base+REG_isr, _isr);
} // while
cyg_drv_interrupt_unmask(ser_chan->int_num);
}
#endif
// EOF ser_16x5x.c
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -