📄 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 devicestatic boolpc_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 necessarystatic 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_ErrNopc_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 devicestatic voidpc_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 devicestatic 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 + -