--- synthserial.c.orig Wed May 7 18:29:37 2003 +++ synthserial.c Sat Aug 2 14:20:45 2003 @@ -35,10 +35,14 @@ // // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. // at http://sources.redhat.com/ecos/ecos-license/ // ------------------------------------------- //####ECOSGPLCOPYRIGHTEND#### + +//Updated by Philippe Moutarlier at Alliant Networks to cover +//interrupt misses. + //========================================================================== //#####DESCRIPTIONBEGIN#### // // Author(s): savin // Contributors: @@ -68,10 +72,11 @@ typedef struct synth_serial_info { int synth_id; // Device id within the auxiliary cyg_vector_t interrupt; // Interrupt number allocated by the auxiliary cyg_handle_t interrupt_handle; // Interrupt handle cyg_interrupt interrupt_data; // Interrupt data + char is_throttled; } synth_serial_info; static bool synth_serial_init(struct cyg_devtab_entry *tab); static bool synth_serial_putc(serial_channel *chan, unsigned char c); static Cyg_ErrNo synth_serial_lookup(struct cyg_devtab_entry **tab, @@ -143,10 +148,11 @@ SYNTH_MAKESTRING(CYGPKG_DEVS_SERIAL_ECOSYNTH), "serial", tab->name, (const char*) 0); if (-1 != synth_info->synth_id) { result = true; + synth_info->is_throttled = 0; synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_GETPARAMS, 0, 0, 0, 0, &(synth_info->interrupt), 0, 0, 0); cyg_drv_interrupt_create(synth_info->interrupt, @@ -206,24 +212,41 @@ static Cyg_ErrNo synth_serial_set_config(serial_channel *chan, cyg_uint32 key, const void *xbuf, cyg_uint32 *len) { - switch (key) { - case CYG_IO_SET_CONFIG_SERIAL_INFO: - { - if ( *len < sizeof(cyg_serial_info_t) ) { - return -EINVAL; - } - *len = sizeof(cyg_serial_info_t); - return ENOERR; + long f; + synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv; + switch (key) { + case CYG_IO_SET_CONFIG_SERIAL_INFO: + { + if ( *len < sizeof(cyg_serial_info_t) ) { + return -EINVAL; } - break; - default: - return -EINVAL; + *len = sizeof(cyg_serial_info_t); + return ENOERR; } - return ENOERR; + break; + case CYG_IO_SET_CONFIG_SERIAL_HW_RX_FLOW_THROTTLE: + { + f = *(long *)xbuf; + if(f){ + synth_info->is_throttled = 1; + //diag_printf("throttled\n"); + cyg_drv_interrupt_mask(synth_info->interrupt); + } + else{ + synth_info->is_throttled = 0; + //diag_printf("started\n"); + cyg_drv_interrupt_unmask(synth_info->interrupt); + } + } + break; + default: + return -EINVAL; + } + return ENOERR; } static void synth_serial_start_xmit(serial_channel *chan) { @@ -241,22 +264,73 @@ cyg_drv_interrupt_mask(vector); cyg_drv_interrupt_acknowledge(vector); return CYG_ISR_CALL_DSR; } + +//how many character max do we want from the peer for +//each call to synth_auxiliary_xchgmsg +#define MAX_CHAR_PER_READ 10 +static char buff[MAX_CHAR_PER_READ]; +//how many char in the current buffer; +static int nb_read; +//next to read +static int next_to_read; + static void synth_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) { serial_channel *chan = (serial_channel *)data; synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv; if (-1 != synth_info->synth_id) { char c; - int l; - synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_RX, 0, 0, - 0, 0, &l, &c, 0, 1); - (chan->callbacks->rcv_char)(chan, c); + int l= 0,len; + int i; + if(synth_info->is_throttled) + diag_printf("WHAT ARE WE DOING HERE !\n"); +#if 0 + //Do we still have something in out buffer (in case we were throttled) + if(nb_len) + { + len = nb_len; + for (i = next_to_read ; i < (next_to_read + len) && !synth_info->is_throttled; i++){ + (chan->callbacks->rcv_char)(chan, buff[i]); + nb_read--; + next_to_read++; + } + } + if(nb_len) + { + cyg_drv_interrupt_unmask(vector); + return; + } +#endif + //make sure we get everything out of the host. This help + //when we miss interrupts. + //this is potentially blocking the dsr for a little while, + //but this is in fact a good thing. The host side should be + //able to bufferize in the mean time. + + while(l >= 0){ + synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_RX, 0, 0, + 0, 0, &l,buff, &len, MAX_CHAR_PER_READ); + + if(l >= 0 && len){ + + //buff[len] = 0; + //printf("%s\n",buff); + for (i = 0 ; i < len ; i++){ + (chan->callbacks->rcv_char)(chan, buff[i]); + //diag_printf("i= %d\n",i); + } + + //we were throttled : stop reading from host. + if(synth_info->is_throttled) + return; + } + } } cyg_drv_interrupt_unmask(vector); } // ----------------------------------------------------------------------------