synthetic serial driver
Savin Zlobec
savin@torina.fe.uni-lj.si
Tue Aug 5 13:44:00 GMT 2003
On Tue, 5 Aug 2003, Andrew Lunn wrote:
> On Tue, Aug 05, 2003 at 12:10:27AM +0200, Savin Zlobec wrote:
> > Hi!
> >
> > I've already mailed my assignment a week ago. But I guess
> > that mail needs about two weeks from here to US.
>
> Thats great. Thanks
>
> >
> > The code wich uses a buffer to fetch charachters
> > from auxiliary is based on code send to me from
> > Philippe Moutarlier - but I rewrote and modified
> > it so there is little of original code left.
> >
> > I can post here the diffs of Philippe's changes if it
> > is of any help.
>
> Yes please.
>
> Andrew
>
I've attached my old sources and diffs of Philippe's changes.
savin
-------------- next part --------------
A non-text attachment was scrubbed...
Name: serial.tcl
Type: application/x-tcl
Size: 5437 bytes
Desc:
URL: <http://sourceware.org/pipermail/ecos-devel/attachments/20030805/0737abd8/attachment.tcl>
-------------- next part --------------
//==========================================================================
//
// synthserial.c
//
// Serial device driver for the synthetic target
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 2003 Savin Zlobec.
//
// 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): savin
// Contributors:
// Date: 2003-03-27
//
//####DESCRIPTIONEND####
//
//==========================================================================
#include <pkgconf/devs_serial_ecosynth.h>
#include <cyg/infra/cyg_type.h>
#include <cyg/infra/cyg_ass.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_arch.h>
#include <cyg/hal/hal_io.h>
#include <cyg/hal/drv_api.h>
#include <cyg/io/io.h>
#include <cyg/io/devtab.h>
#include <cyg/io/serial.h>
// Protocol between this driver and the auxiliary
#define SYNTH_SERIAL_TX 0x01 // send char
#define SYNTH_SERIAL_RX 0x02 // receive char
#define SYNTH_SERIAL_GETPARAMS 0x03 // get init parameters
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
} 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,
struct cyg_devtab_entry *sub_tab,
const char *name);
static unsigned char synth_serial_getc(serial_channel *chan);
static Cyg_ErrNo synth_serial_set_config(serial_channel *chan,
cyg_uint32 key,
const void *xbuf,
cyg_uint32 *len);
static void synth_serial_start_xmit(serial_channel *chan);
static void synth_serial_stop_xmit(serial_channel *chan);
static cyg_uint32 synth_serial_ISR(cyg_vector_t vector,
cyg_addrword_t data);
static void synth_serial_DSR(cyg_vector_t vector,
cyg_ucount32 count,
cyg_addrword_t data);
static SERIAL_FUNS(synth_serial_funs,
synth_serial_putc,
synth_serial_getc,
synth_serial_set_config,
synth_serial_start_xmit,
synth_serial_stop_xmit
);
#define SYNTH_SERIAL_INSTANCE(_number_) \
static synth_serial_info synth_serial_info##_number_ = { \
synth_id: -1, \
interrupt: 0, \
interrupt_handle: 0 \
}; \
static unsigned char synth_serial_out_buf##_number_[CYGNUM_IO_SERIAL_ECOSYNTH_SERIAL##_number_##_BUFSIZE]; \
static unsigned char synth_serial_in_buf##_number_[CYGNUM_IO_SERIAL_ECOSYNTH_SERIAL##_number_##_BUFSIZE]; \
static SERIAL_CHANNEL_USING_INTERRUPTS(synth_serial_channel##_number_, \
synth_serial_funs, \
synth_serial_info##_number_, \
CYGNUM_SERIAL_BAUD_MIN, \
CYG_SERIAL_STOP_DEFAULT, \
CYG_SERIAL_PARITY_DEFAULT, \
CYG_SERIAL_WORD_LENGTH_DEFAULT, \
CYG_SERIAL_FLAGS_DEFAULT, \
&synth_serial_out_buf##_number_[0], sizeof(synth_serial_out_buf##_number_), \
&synth_serial_in_buf##_number_[0], sizeof(synth_serial_in_buf##_number_) \
); \
DEVTAB_ENTRY(synth_serial_io##_number_, \
CYGDAT_IO_SERIAL_ECOSYNTH_SERIAL##_number_##_NAME, \
0, \
&cyg_io_serial_devio, \
synth_serial_init, \
synth_serial_lookup, \
&synth_serial_channel##_number_ \
);
#ifdef CYGVAR_DEVS_SERIAL_ECOSYNTH_SERIAL0
SYNTH_SERIAL_INSTANCE(0);
#endif
static bool
synth_serial_init(struct cyg_devtab_entry *tab)
{
bool result = false;
serial_channel *chan = (serial_channel *)tab->priv;
synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv;
if (synth_auxiliary_running) {
synth_info->synth_id =
synth_auxiliary_instantiate("devs/serial/synth/ecosynth",
SYNTH_MAKESTRING(CYGPKG_DEVS_SERIAL_ECOSYNTH),
"serial", tab->name, (const char*) 0);
if (-1 != synth_info->synth_id) {
result = true;
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,
0,
(CYG_ADDRWORD)chan,
&synth_serial_ISR,
&synth_serial_DSR,
&(synth_info->interrupt_handle),
&(synth_info->interrupt_data));
cyg_drv_interrupt_attach(synth_info->interrupt_handle);
cyg_drv_interrupt_unmask(synth_info->interrupt);
}
}
(chan->callbacks->serial_init)(chan);
return result;
}
static Cyg_ErrNo
synth_serial_lookup(struct cyg_devtab_entry **tab,
struct cyg_devtab_entry *sub_tab,
const char *name)
{
serial_channel *chan = (serial_channel *)(*tab)->priv;
(chan->callbacks->serial_init)(chan);
return ENOERR;
}
static bool
synth_serial_putc(serial_channel *chan, unsigned char c)
{
synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv;
if (-1 != synth_info->synth_id) {
synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_TX, 0, 0,
&c, 1, 0, 0, 0, 0);
return true;
}
return false;
}
static unsigned char
synth_serial_getc(serial_channel *chan)
{
synth_serial_info *synth_info = (synth_serial_info *)chan->dev_priv;
if (-1 != synth_info->synth_id) {
char c;
int l;
do {
synth_auxiliary_xchgmsg(synth_info->synth_id, SYNTH_SERIAL_RX, 0, 0,
0, 0, &l, &c, 0, 1);
} while (l < 0);
return c;
}
return 0;
}
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;
}
break;
default:
return -EINVAL;
}
return ENOERR;
}
static void
synth_serial_start_xmit(serial_channel *chan)
{
(chan->callbacks->xmt_char)(chan);
}
static void
synth_serial_stop_xmit(serial_channel *chan)
{
}
static cyg_uint32
synth_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
{
cyg_drv_interrupt_mask(vector);
cyg_drv_interrupt_acknowledge(vector);
return CYG_ISR_CALL_DSR;
}
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);
}
cyg_drv_interrupt_unmask(vector);
}
// ----------------------------------------------------------------------------
// EOF synthserial.c
-------------- next part --------------
--- serial.tcl.orig Wed May 7 18:26:24 2003
+++ serial.tcl Sat Aug 2 14:20:41 2003
@@ -52,25 +52,34 @@
# The protocol between eCos and this script.
variable SYNTH_SERIAL_TX 0x01
variable SYNTH_SERIAL_RX 0x02
variable SYNTH_SERIAL_GETPARAMS 0x03
+
# This array holds all the interesting data for all the
# interfaces, indexed by the instance id. It is also useful
# to keep track of the instance id's associated with serial
# devices.
array set data [list]
set ids [list]
-
+ set baudRate 115200
# -------------------------------------------------------------------------
proc instantiate { id name data } {
# open pty and init input handler
- # FIXME: hardcoded file name
- set fid [open "loop1" "r+"]
- fconfigure $fid -translation binary -encoding binary -buffering none
+ puts "serial name : $name"
+ if { [string equal -length -1 $name "/dev/ser0"] } {
+ set serial_dev "/dev/ttyS0"
+ set fid [open "/dev/ttyS0" "r+"]
+ } else {
+ return ""
+ }
+ fconfigure $fid -blocking 0 -translation binary -encoding binary -buffering none \
+ -mode $serial::baudRate,n,8,1
+ exec -- stty -F $serial_dev crtscts
+
fileevent $fid readable [list serial::handle_input $id]
# allocate an interrupt vector
set vector [synth::interrupt_allocate $name]
if { -1 == $vector } {
@@ -96,17 +105,28 @@
# puts "Put char '$reqdata'"
puts -nonewline $serial::data($id,fid) $reqdata
} elseif { $reqcode == $serial::SYNTH_SERIAL_RX } {
set len [llength $serial::data($id,in_buff)]
if { $len == 0 } {
- synth::send_reply -1 1 0
+ synth::send_reply -1 1 0
} else {
- set replay [binary format "a" \
- [lindex $serial::data($id,in_buff) 0]]
- set serial::data($id,in_buff) \
- [lrange $serial::data($id,in_buff) 1 $len]
- synth::send_reply [expr $len - 1] 1 $replay
+ if { $len >= $reply_len } {
+ set slen $reply_len
+ } else {
+ set slen $len
+ }
+ #puts "len $slen"
+
+ for { set i 0 } { $i < $slen } { incr i } {
+ append replay [lindex $serial::data($id,in_buff) $i]
+ }
+
+ #set replay [lrange $serial::data($id,in_buff) 0 [expr $len - 1]]
+ set serial::data($id,in_buff) \
+ [lrange $serial::data($id,in_buff) $slen [expr $len - 1]]
+ synth::send_reply [expr $len - $slen] $slen $replay
+ #puts "replay $slen $replay"
}
} elseif { $reqcode == $serial::SYNTH_SERIAL_GETPARAMS } {
synth::send_reply $serial::data($id,int_vector) 0 ""
} else {
synth::report_error "Received unexpected request $reqcode for serial device"
@@ -114,14 +134,25 @@
}
# -------------------------------------------------------------------------
proc handle_input { id } {
- set ch [read $serial::data($id,fid) 1]
-# puts "Got char '$ch'"
- lappend serial::data($id,in_buff) $ch
- synth::interrupt_raise $serial::data($id,int_vector)
+ set len [llength $serial::data($id,in_buff)]
+ if { $len < 80 } {
+ set ch [read $serial::data($id,fid) 1]
+ # puts "Got char '$ch'"
+ set blocked [fblocked $serial::data($id,fid)]
+ if { $blocked == 0 } {
+ lappend serial::data($id,in_buff) $ch
+
+ }
+ }
+#elseif { $len == 80 } {
+ # puts "getting full !"
+ # flush stdout
+# }
+ synth::interrupt_raise $serial::data($id,int_vector)
}
# -------------------------------------------------------------------------
proc ecos_exited { arg_list } {
-------------- next part --------------
--- 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);
}
// ----------------------------------------------------------------------------
More information about the Ecos-devel
mailing list