diff -r -u5 -N -x CVS /cygdrive/z/Share/Resource/eCos/anoncvs/ecos/packages/devs/serial/generic/16x5x/current/src/ser_16x5x.c /cygdrive/d/work/dev/ecos/packages/devs/serial/generic/16x5x/current/src/ser_16x5x.c --- /cygdrive/z/Share/Resource/eCos/anoncvs/ecos/packages/devs/serial/generic/16x5x/current/src/ser_16x5x.c 2007-06-22 19:41:49.000000000 +0800 +++ /cygdrive/d/work/dev/ecos/packages/devs/serial/generic/16x5x/current/src/ser_16x5x.c 2008-01-25 11:47:46.232562700 +0800 @@ -62,15 +62,18 @@ #include // Only compile driver if an inline file with driver details was selected. #ifdef CYGDAT_IO_SERIAL_GENERIC_16X5X_INL -#ifndef CYGPRI_IO_SERIAL_GENERIC_16X5X_STEP -#define CYGPRI_IO_SERIAL_GENERIC_16X5X_STEP 1 -#endif - -#define SER_REG(_x_) ((_x_)*CYGPRI_IO_SERIAL_GENERIC_16X5X_STEP) +//here we use a 'step' variable to indicate the address delta between a 16X5X channel's registers +//user should new a variable named 'step' and set appropriate value before access 16X5X's register. +//For example: +//{ +// int step = ser_chan->step; +// HAL_WRITE_UINT8(base+REG_thr, c); +//} +#define SER_REG(_x_) ((_x_)*step) // Receive control Registers #define REG_rhr SER_REG(0) // Receive holding register #define REG_isr SER_REG(2) // Interrupt status register #define REG_lsr SER_REG(5) // Line status register @@ -180,10 +183,15 @@ // selec_baud[] must be define by the client typedef struct pc_serial_info { cyg_addrword_t base; int int_num; + int int_prio; + int step; + int baud_num; + int *select_baud; + int (*baud_generator)(unsigned int baud); cyg_interrupt serial_interrupt; cyg_handle_t serial_interrupt_handle; #ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO enum { sNone = 0, @@ -233,12 +241,17 @@ serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init) { pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv; cyg_addrword_t base = ser_chan->base; - unsigned short baud_divisor = select_baud[new_config->baud]; + int step = ser_chan->step; + unsigned short baud_divisor; unsigned char _lcr, _ier; + + if (new_config->baud >= ser_chan->baud_num) return false; // Invalid configuration + + baud_divisor = ser_chan->select_baud[new_config->baud]; if (baud_divisor == 0) return false; // Invalid configuration // Disable port interrupts while changing hardware HAL_READ_UINT8(base+REG_ier, _ier); HAL_WRITE_UINT8(base+REG_ier, 0); @@ -253,21 +266,22 @@ if (init) { #ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO unsigned char _fcr_thresh; cyg_uint8 b; - /* First, find out what kind of device it is. */ - ser_chan->deviceType = sNone; - HAL_WRITE_UINT8(base+REG_mcr, MCR_LOOP); // enable loopback mode - HAL_READ_UINT8(base+REG_msr, b); - if (0 == (b & 0xF0)) { // see if MSR had CD, RI, DSR or CTS set - HAL_WRITE_UINT8(base+REG_mcr, MCR_LOOP|MCR_DTR|MCR_RTS); - HAL_READ_UINT8(base+REG_msr, b); - if (0xF0 != (b & 0xF0)) // check that all of CD,RI,DSR and CTS set - ser_chan->deviceType = s8250; + if (ser_chan->deviceType == sNone) { + /* First, find out what kind of device it is. */ + HAL_WRITE_UINT8(base+REG_mcr, MCR_LOOP); // enable loopback mode + HAL_READ_UINT8(base+REG_msr, b); + if (0 == (b & 0xF0)) { // see if MSR had CD, RI, DSR or CTS set + HAL_WRITE_UINT8(base+REG_mcr, MCR_LOOP|MCR_DTR|MCR_RTS); + HAL_READ_UINT8(base+REG_msr, b); + if (0xF0 != (b & 0xF0)) // check that all of CD,RI,DSR and CTS set + ser_chan->deviceType = s8250; + } + HAL_WRITE_UINT8(base+REG_mcr, 0); // disable loopback mode } - HAL_WRITE_UINT8(base+REG_mcr, 0); // disable loopback mode if (ser_chan->deviceType == s8250) { // Check for a scratch register; scratch register // indicates 16450 or above. HAL_WRITE_UINT8(base+REG_scr, 0x55); @@ -308,10 +322,11 @@ CYGNUM_IO_SERIAL_GENERIC_16X5X_FIFO_TX_SIZE; // Enable and clear FIFO HAL_WRITE_UINT8(base+REG_fcr, _fcr_thresh); } else { + CYG_FAIL("Can't enable FIFO on this device."); ser_chan->tx_fifo_size = 1; HAL_WRITE_UINT8(base+REG_fcr, 0); // make sure it's disabled } ser_chan->tx_fifo_avail = ser_chan->tx_fifo_size; @@ -348,36 +363,39 @@ #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) { + + if (ser_chan->select_baud[0] == 9999) { + CYG_ASSERTC(ser_chan->baud_generator != NULL); + // 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; + for (baud_idx = 1; baud_idx < ser_chan->baud_num; baud_idx++) { + baud_val = ser_chan->baud_generator(ser_chan->select_baud[baud_idx]); + ser_chan->select_baud[baud_idx] = baud_val; } - select_baud[0] = 0; + ser_chan->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); + diag_printf("16x5x SERIAL init - dev: base=%x.step=%d.int_num=%d\n", + ser_chan->base, ser_chan->step, 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, + ser_chan->int_prio == -1 ? CYG_IO_SERIAL_GENERIC_16X5X_INT_PRIORITY : ser_chan->int_prio, (cyg_addrword_t)chan, pc_serial_ISR, pc_serial_DSR, &ser_chan->serial_interrupt_handle, &ser_chan->serial_interrupt); @@ -409,10 +427,11 @@ #ifndef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO cyg_uint8 _lsr; #endif pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv; cyg_addrword_t base = ser_chan->base; + int step = ser_chan->step; #ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_FIFO if (ser_chan->tx_fifo_avail > 0) { HAL_WRITE_UINT8(base+REG_thr, c); --ser_chan->tx_fifo_avail; @@ -436,10 +455,11 @@ { unsigned char c; cyg_uint8 _lsr; pc_serial_info *ser_chan = (pc_serial_info *)chan->dev_priv; cyg_addrword_t base = ser_chan->base; + int step = ser_chan->step; // Wait for char do { HAL_READ_UINT8(base+REG_lsr, _lsr); } while ((_lsr & LSR_RSR) == 0); @@ -469,10 +489,11 @@ 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; + int step = ser_chan->step; cyg_uint32 *f = (cyg_uint32 *)xbuf; unsigned char mask=0; if ( *len < sizeof(*f) ) return -EINVAL; @@ -509,26 +530,34 @@ 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; + int step = ser_chan->step; + cyg_uint8 _ier, _lsr; HAL_READ_UINT8(base+REG_ier, _ier); _ier |= IER_XMT; // Enable xmit interrupt HAL_WRITE_UINT8(base+REG_ier, _ier); #ifdef CYGPKG_IO_SERIAL_GENERIC_16X5X_XMIT_REQUIRE_PRIME - (chan->callbacks->xmt_char)(chan); + //some chip(at least LPC2XXX's embedded DUART) may not generate ISR_Tx interrupt after enable IER_XMT, + //so we try transmitting here to trigger the ISR_Tx intertupt. + HAL_READ_UINT8(base+REG_lsr, _lsr); + if ((_lsr & LSR_THE)) { + // transmitter holding register ready + (chan->callbacks->xmt_char)(chan); + } #endif } // 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; + int step = ser_chan->step; cyg_uint8 _ier; HAL_READ_UINT8(base+REG_ier, _ier); _ier &= ~IER_XMT; // Disable xmit interrupt HAL_WRITE_UINT8(base+REG_ier, _ier); @@ -550,10 +579,11 @@ 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; + int step = ser_chan->step; 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); @@ -645,14 +675,16 @@ } } 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"); + #if 0 + //some chip(at least Philips SC16C2550B) may generate a interrupt without valid source, + //so we print a error message rather than die here. + diag_printf("unhandled serial interrupt state""\r\n"); + #endif + break; } HAL_READ_UINT8(base+REG_isr, _isr); } // while