Import drv/ modules.
authorbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Sun, 23 May 2004 18:10:11 +0000 (18:10 +0000)
committerbernie <bernie@38d2e660-2303-0410-9eaa-f027e97ec537>
Sun, 23 May 2004 18:10:11 +0000 (18:10 +0000)
git-svn-id: https://src.develer.com/svnoss/bertos/trunk@4 38d2e660-2303-0410-9eaa-f027e97ec537

drv/buzzer.c [new file with mode: 0755]
drv/buzzer.h [new file with mode: 0755]
drv/kdebug.c [new file with mode: 0755]
drv/kdebug.h [new file with mode: 0755]
drv/ser.c [new file with mode: 0755]
drv/ser.h [new file with mode: 0755]
drv/ser_avr.c [new file with mode: 0755]
drv/ser_dsp56k.c [new file with mode: 0755]
drv/ser_i196.c [new file with mode: 0755]
drv/ser_p.h [new file with mode: 0755]

diff --git a/drv/buzzer.c b/drv/buzzer.c
new file mode 100755 (executable)
index 0000000..cb72239
--- /dev/null
@@ -0,0 +1,207 @@
+/*!
+ * \file
+ * <!--
+ * Copyright (C) 1999,2003 Bernardo Innocenti <bernie@develer.com>
+ * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \brief Buzzer driver
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 18:10:11  bernie
+ * Import drv/ modules.
+ *
+ * Revision 1.5  2004/04/04 17:44:51  aleph
+ * Move event.h from mware to kern dir
+ *
+ * Revision 1.4  2004/03/24 15:03:45  bernie
+ * Use explicit include paths; clean Doxygen comments
+ *
+ * Revision 1.3  2004/03/03 18:27:44  bernie
+ * Fixed race conds with IRQ when fiddling with I/O ports
+ *
+ * Revision 1.2  2003/12/18 18:15:24  aleph
+ * Use new IRQ disable/enable reentrant macros
+ *
+ * Revision 1.1  2003/12/13 23:53:37  aleph
+ * Add buzzer driver
+ *
+ */
+
+#include "hw.h"
+#include "kdebug.h"
+#include "timer.h"
+#include "buzzer.h"
+#include <kern/event.h>
+
+
+#if (ARCH & ARCH_EMUL)
+
+       int Emul_IsBuzzerOn(void);
+       void Emul_BuzzerOn(void);
+       void Emul_BuzzerOff(void);
+       void Emul_BuzzerInit(void);
+
+#      define IS_BUZZER_ON  (Emul_IsBuzzerOn())
+#      define BUZZER_ON     (Emul_BuzzerOn())
+#      define BUZZER_OFF    (Emul_BuzzerOff())
+#      define BUZZER_INIT   (Emul_BuzzerInit())
+
+#elif defined(__AVR__)
+
+#      define IS_BUZZER_ON  (PORTG & BV(PORTG0))
+
+       /**
+        * Buzzer manipulation macros
+        *
+        * \note Some PORTG functions are being used from
+        *       interrupt code, so we must be careful to
+        *       avoid race conditions.
+        */
+#      define BUZZER_ON \
+       do { \
+               cpuflags_t _flags; \
+               DISABLE_IRQSAVE(_flags); \
+               PORTG |= BV(PORTG0); \
+               ENABLE_IRQRESTORE(_flags); \
+       } while (0)
+
+#      define BUZZER_OFF \
+       do { \
+               cpuflags_t _flags; \
+               DISABLE_IRQSAVE(_flags); \
+               PORTG &= ~BV(PORTG0); \
+               ENABLE_IRQRESTORE(_flags); \
+       } while (0)
+
+#      define BUZZER_INIT \
+       do { \
+               cpuflags_t _flags; \
+               DISABLE_IRQSAVE(_flags); \
+               PORTG &= ~BV(PORTG0); \
+               DDRG |= BV(PORTG0); \
+               ENABLE_IRQRESTORE(_flags); \
+       } while (0)
+
+#elif defined(__IAR_SYSTEMS_ICC) || defined(__IAR_SYSTEMS_ICC__) /* 80C196 */
+
+#      define IS_BUZZER_ON  (cpld->Buzzer & 1)
+#      define BUZZER_ON     (cpld->Buzzer = 1)
+#      define BUZZER_OFF    (cpld->Buzzer = 0)
+#      define BUZZER_INIT   (cpld->Buzzer = 0)
+
+#endif /* ARCH, __AVR__, __IAR_SYSTEM_ICC */
+
+
+/* Local vars */
+static Timer *buz_timer;
+static bool buz_timer_running;
+static time_t buz_repeat_interval;
+static time_t buz_repeat_duration;
+
+
+/*!
+ * Turn off buzzer, called by software timer
+ */
+static void buz_softint(void)
+{
+       if (IS_BUZZER_ON)
+       {
+               BUZZER_OFF;
+               if (buz_repeat_interval)
+               {
+                       /* Wait for interval time */
+                       buz_timer->delay = buz_repeat_interval;
+                       timer_add(buz_timer);
+               }
+               else
+                       buz_timer_running = false;
+       }
+       else if (buz_repeat_interval)
+       {
+               /* Wait for beep time */
+               BUZZER_ON;
+               buz_timer->delay = buz_repeat_duration;
+               timer_add(buz_timer);
+       }
+       else
+               buz_timer_running = false;
+}
+
+
+/*!
+ * Beep for the specified ms time
+ */
+void buz_beep(time_t time)
+{
+       cpuflags_t flags;
+
+       /* Remove the software interrupt if it was already queued */
+       DISABLE_IRQSAVE(flags);
+       if (buz_timer_running)
+               timer_abort(buz_timer);
+
+       /* Turn on buzzer */
+       BUZZER_ON;
+
+       /* Add software interrupt to turn the buzzer off later */
+       buz_timer_running = true;
+       buz_timer->delay = time;
+       timer_add(buz_timer);
+
+       ENABLE_IRQRESTORE(flags);
+}
+
+
+/*!
+ * Start buzzer repetition
+ */
+void buz_repeat_start(time_t duration, time_t interval)
+{
+       buz_repeat_interval = interval;
+       buz_repeat_duration = duration;
+       buz_beep(duration);
+}
+
+
+/*!
+ * Stop buzzer repetition
+ */
+void buz_repeat_stop(void)
+{
+       cpuflags_t flags;
+       DISABLE_IRQSAVE(flags);
+
+       /* Remove the software interrupt if it was already queued */
+       if (buz_timer_running)
+       {
+               timer_abort(buz_timer);
+               buz_timer_running = false;
+       }
+
+       buz_repeat_interval = 0;
+       BUZZER_OFF;
+
+       ENABLE_IRQRESTORE(flags);
+}
+
+
+/*!
+ * Initialize buzzer
+ */
+void buz_init(void)
+{
+       BUZZER_INIT;
+
+       /* Inizializza software interrupt */
+       buz_timer = timer_new();
+       ASSERT(buz_timer != NULL);
+       INITEVENT_INT(&buz_timer->expire, (Hook)buz_softint, 0);
+}
diff --git a/drv/buzzer.h b/drv/buzzer.h
new file mode 100755 (executable)
index 0000000..646c467
--- /dev/null
@@ -0,0 +1,31 @@
+/*!
+ * \file
+ * Copyright (C) 1999,2003 Bernardo Innocenti <bernie@develer.com>
+ * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \brief Buzzer driver
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 18:10:11  bernie
+ * Import drv/ modules.
+ *
+ * Revision 1.1  2003/12/13 23:53:37  aleph
+ * Add buzzer driver
+ *
+ */
+#ifndef BUZZER_H
+#define BUZZER_H
+
+extern void buz_init(void);
+extern void buz_beep(time_t time);
+extern void buz_repeat_start(time_t duration, time_t interval);
+extern void buz_repeat_stop(void);
+
+#endif /* BUZZER_H */
diff --git a/drv/kdebug.c b/drv/kdebug.c
new file mode 100755 (executable)
index 0000000..44d211f
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * \file
+ * <!--
+ * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2000,2001,2002 Bernardo Innocenti <bernie@codewiz.org>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief General pourpose debug functions.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ * \author Stefano Fedrigo <aleph@develer.com>
+ */
+
+/*
+ */
+
+#include "kdebug.h"
+#include "hw.h"
+#include "config.h"
+
+#include <mware/formatwr.h> /* for _formatted_write() */
+
+#ifdef _DEBUG
+
+#if defined(_EMUL)
+       #include <stdio.h>
+       #define KDBG_WAIT_READY()      do {/*nop*/} while(0)
+       #define KDBG_WRITE_CHAR(c)     putchar((c))
+       #define KDBG_MASK_IRQ(old)     do {/*nop*/} while(0)
+       #define KDBG_RESTORE_IRQ()     do {/*nop*/} while(0)
+#elif defined(__I196__)
+       #include "Util196.h"
+       #define KDBG_WAIT_READY()      do {} while (!(SP_STAT & (SPSF_TX_EMPTY | SPSF_TX_INT)))
+       #define KDBG_WRITE_CHAR(c)     do { SBUF = (c); } while(0)
+       #define KDBG_MASK_IRQ(old) \
+               do { \
+                       (old) = INT_MASK1 & INT1F_TI; \
+                       INT_MASK1 &= ~INT1F_TI; \
+               } while(0)
+       #define KDBG_RESTORE_IRQ(old)  do { INT_MASK1 |= (old); }
+#elif defined(__AVR__)
+       #include <avr/io.h>
+       #if CONFIG_KDEBUG_PORT == 0
+               #ifndef __AVR_ATmega103__
+                       #define UCR UCSR0B
+                       #define UDR UDR0
+                       #define USR UCSR0A
+               #endif
+               #define KDBG_WAIT_READY()     do { loop_until_bit_is_set(USR, UDRE); } while(0)
+               #define KDBG_WRITE_CHAR(c)    do { UCR |= BV(TXEN); UDR = (c); } while(0)
+               #define KDBG_MASK_IRQ(old)    do { (old) = UCR & BV(TXCIE); cbi(UCR, TXCIE); } while(0)
+               #define KDBG_RESTORE_IRQ(old) do { UCR |= (old); } while(0)
+       #elif CONFIG_KDEBUG_PORT == 1
+               #define KDBG_WAIT_READY()     do { loop_until_bit_is_set(UCSR1A, UDRE); } while(0)
+               #define KDBG_WRITE_CHAR(c)    do { UCSR1B |= BV(TXEN); UDR1 = (c); } while(0)
+               #define KDBG_MASK_IRQ(old)    do { (old) = UCSR1B & BV(TXCIE); cbi(UCSR1B, TXCIE); } while(0)
+               #define KDBG_RESTORE_IRQ(old) do { UCSR1B |= (old); } while(0)
+       #else
+               #error CONFIG_KDEBUG_PORT should be either 0 or 1
+       #endif
+#else
+       #error Unknown architecture
+#endif
+
+
+void kdbg_init(void)
+{
+#if defined(__I196__)
+
+       /* Set serial port for 19200bps 8N1 */
+       INT_MASK1 &= ~(INT1F_TI | INT1F_RI);
+       SP_CON = SPCF_RECEIVE_ENABLE | SPCF_MODE1;
+       ioc1_img |= IOC1F_TXD_SEL | IOC1F_EXTINT_SRC;
+       IOC1 = ioc1_img;
+       BAUD_RATE = 0x33;
+       BAUD_RATE = 0x80;
+
+#elif defined(__AVR__)
+
+       /* Compute the baud rate */
+       uint16_t period = (((CLOCK_FREQ / 16UL) + (CONFIG_KDEBUG_BAUDRATE / 2)) / CONFIG_KDEBUG_BAUDRATE) - 1;
+
+       #ifdef __AVR_ATmega64__
+               #if CONFIG_KDEBUG_PORT == 0
+
+                       /* Set the baud rate */
+                       UBRR0H = (uint8_t)(period>>8);
+                       UBRR0L = (uint8_t)period;
+
+               #elif CONFIG_KDEBUG_PORT == 1
+
+                       UBRR1H = (uint8_t)(period>>8);
+                       UBRR1L = (uint8_t)period;
+
+               #else
+                       #error CONFIG_KDEBUG_PORT should be either 0 or 1
+               #endif
+       #elif defined (__AVR_ATmega103__)
+
+               /* Set the baud rate */
+               UBRR = (uint8_t)period;
+
+       #else
+               #error Unknown arch
+       #endif
+
+#endif /* !__I196__ && !__AVR__ */
+
+       kputs("\n\n*** DBG START ***\n");
+}
+
+
+/*!
+ * Output one character to the debug console
+ */
+static void kputchar(char c, UNUSED(void *unused))
+{
+       /* Poll while serial buffer is still busy */
+       KDBG_WAIT_READY();
+
+       /* Send '\n' as '\r\n' for dumb terminals */
+       if (c == '\n')
+       {
+               KDBG_WRITE_CHAR('\r');
+               KDBG_WAIT_READY();
+       }
+
+       KDBG_WRITE_CHAR(c);
+}
+
+
+void PGM_FUNC(kprintf)(const char * PGM_ATTR fmt, ...)
+{
+       va_list ap;
+
+       /* Mask serial TX intr */
+       unsigned char irqsave;
+       KDBG_MASK_IRQ(irqsave);
+
+       va_start(ap, fmt);
+       PGM_FUNC(_formatted_write)(fmt, kputchar, 0, ap);
+       va_end(ap);
+
+       /* Restore serial TX intr */
+       KDBG_RESTORE_IRQ(irqsave);
+}
+
+
+void PGM_FUNC(kputs)(const char * PGM_ATTR str)
+{
+       char c;
+
+       /* Mask serial TX intr */
+       unsigned char irqsave;
+       KDBG_MASK_IRQ(irqsave);
+
+       while ((c = PGM_READ_CHAR(str++)))
+               kputchar(c, 0);
+
+       KDBG_RESTORE_IRQ(irqsave);
+}
+
+
+int PGM_FUNC(__assert)(const char * PGM_ATTR cond, const char *file, int line)
+{
+       PGM_FUNC(kputs)(file);
+       PGM_FUNC(kprintf)(PSTR(":%d: Assertion failed: \""), line);
+       PGM_FUNC(kputs)(cond);
+       PGM_FUNC(kputs)(PSTR("\"\n"));
+       return 1;
+}
+
+
+int PGM_FUNC(__invalid_ptr)(void *value, const char * PGM_ATTR name, const char * PGM_ATTR file, int line)
+{
+       PGM_FUNC(kputs)(file);
+       PGM_FUNC(kprintf)(PSTR(":%d: Invalid pointer: "), line);
+       PGM_FUNC(kputs)(name);
+       PGM_FUNC(kprintf)(PSTR(" = 0x%x\n"), value);
+       return 1;
+}
+
+
+void __init_wall(long *wall, int size)
+{
+       while(size--)
+               *wall++ = WALL_VALUE;
+}
+
+
+int __check_wall(long *wall, int size, const char *name, const char *file, int line)
+{
+       int i, fail = 0;
+
+       for (i = 0; i < size; i++)
+       {
+               if (wall[i] != WALL_VALUE)
+               {
+                       kprintf("%s:%d: Wall broken: %s[%d] (0x%p) = %ld\n",
+                               file, line, name, i, wall + i, wall[i]);
+                       fail = 1;
+               }
+       }
+
+       return fail;
+}
+
+
+/*!
+ * Dump binary data in hex
+ */
+void kdump(const void *_buf, size_t len)
+{
+       const unsigned char *buf = (const unsigned char *)_buf;
+
+       while (len--)
+               kprintf("%02X", *buf++);
+       kputs("\n");
+}
+
+#endif /* _DEBUG */
diff --git a/drv/kdebug.h b/drv/kdebug.h
new file mode 100755 (executable)
index 0000000..3777d3e
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * \file
+ * <!--
+ * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * Copyright 2000,2001,2002 Bernardo Innocenti <bernie@codewiz.org>
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Definition of handy debug macros.  These macros are no-ops
+ *        when the preprocessor symbol _DEBUG isn't defined.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 18:10:11  bernie
+ * Import drv/ modules.
+ *
+ */
+#ifndef KDEBUG_H
+#define KDEBUG_H
+
+#include "compiler.h"
+
+/* Avoid name clashes with Win32 headers */
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#if defined(_DEBUG)
+       void kdbg_init(void);
+       void kdump(const void *buf, size_t len);
+
+       #ifdef __AVR__
+
+               #include <avr/pgmspace.h>
+               void kputs_P(const char *PROGMEM str);
+               void kprintf_P(const char *PROGMEM fmt, ...) FORMAT(__printf__, 1, 2);
+               int __assert_P(const char *PROGMEM cond, const char *PROGMEM file, int line);
+               int __invalid_ptr_P(void *p, const char *PROGMEM name, const char *PROGMEM file, int line);
+               #define kputs(str)  kputs_P(PSTR(str))
+               #define kprintf(fmt, ...)  kprintf_P(PSTR(fmt) ,## __VA_ARGS__)
+               #define __assert(cond, file, line)  __assert_P(PSTR(cond), PSTR(file), (line))
+               #define __invalid_ptr(p, name, file, line)  __invalid_ptr_P((p), PSTR(name), PSTR(file), (line))
+
+       #else
+               void kputs(const char *str);
+               void kprintf(const char * fmt, ...) FORMAT(__printf__, 1, 2);
+               int __assert(const char *cond, const char *file, int line);
+               int __invalid_ptr(void *p, const char *name, const char *file, int line);
+       #endif
+
+       void __init_wall(long *wall, int size);
+       int __check_wall(long *wall, int size, const char *name, const char *file, int line);
+
+       #define THIS_FILE                       __FILE__
+       #define ASSERT(x)                       ((x) ? 0 : __assert(#x, THIS_FILE, __LINE__))
+       #define ASSERT_VALID_PTR(p)             ((p >= 0x200) ? 0 : __invalid_ptr(p, #p, THIS_FILE, __LINE__))
+       #define ASSERT_VALID_PTR_OR_NULL(p)     (((p == NULL) || (p >= 0x200)) ? 0 : __invalid_ptr(p, #p, THIS_FILE, __LINE__))
+       #define TRACE                           kprintf("%s()\n", __FUNCTION__)
+       #define TRACEMSG(msg,...)               kprintf("%s(): " msg "\n", __FUNCTION__, ## __VA_ARGS__)
+       #define DB(x)                           x
+
+       /* Walls to detect data corruption */
+       #define WALL_SIZE                       8
+       #define WALL_VALUE                      (long)0xABADCAFEL
+       #define DECLARE_WALL(name,size)         static long name[(size) / sizeof(long)];
+       #define INIT_WALL(name)                 __init_wall((name), countof(name))
+       #define CHECK_WALL(name)                __check_wall((name), countof(name), #name, THIS_FILE, __LINE__)
+
+#else /* !_DEBUG */
+
+       #define ASSERT(x)
+       #define ASSERT_VALID_PTR(p)
+       #define ASSERT_VALID_PTR_OR_NULL(p)
+       #define TRACE                           do {} while(0)
+       #define TRACEMSG(x,...)                 do {} while(0)
+       #define DB(x)
+
+       #define DECLARE_WALL(name, size)
+       #define INIT_WALL(name)
+       #define CHECK_WALL(name)
+
+#endif /* !_DEBUG */
+
+#endif /* KDEBUG_H */
diff --git a/drv/ser.c b/drv/ser.c
new file mode 100755 (executable)
index 0000000..96c93df
--- /dev/null
+++ b/drv/ser.c
@@ -0,0 +1,370 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
+ * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief Buffered serial I/O driver
+ *
+ * The serial rx interrupt buffers incoming data in a software FIFO
+ * to decouple the higher level protocols from the line speed.
+ * Outgoing data is buffered as well for better performance.
+ * This driver is not optimized for best performance, but it
+ * has proved to be fast enough to handle transfer rates up to
+ * 38400bps on a 16MHz 80196.
+ *
+ * MODULE CONFIGURATION
+ *     \li \c CONFIG_SER_HWHANDSHAKE define this preprocessor symbol to enable
+ *     support for RTS/CTS handshake. Support is incomplete/untested
+ *     for 80196.
+ *  \li \c CONFIG_SER_TXTIMEOUT - Enable software serial transmission timeouts
+ *
+ *
+ * \version $Id$
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 18:10:11  bernie
+ * Import drv/ modules.
+ *
+ * Revision 1.5  2004/05/14 12:47:26  rasky
+ * Importato nuovo supporto seriale per AVR da Stefano
+ *
+ * Revision 1.4  2004/04/29 16:40:23  rasky
+ * Durante i busy loop della seriale, chiama la proc_switch() per cambiare processo
+ *
+ * Revision 1.3  2004/04/21 17:38:24  rasky
+ * New application
+ *
+ * Revision 1.16  2004/04/03 18:30:49  aleph
+ * Move timeout defines in config, private define in .c
+ *
+ * Revision 1.15  2004/03/29 17:01:02  aleph
+ * Add function to set serial parity, fix it when ser_open is used
+ *
+ * Revision 1.14  2004/03/29 16:19:33  aleph
+ * Add ser_cleanup function; Various code improvements
+ *
+ * Revision 1.13  2004/03/24 15:48:53  bernie
+ * Remove Copyright messages from Doxygen output
+ */
+
+#include <mware/formatwr.h>
+#include <drv/kdebug.h>
+#include "ser.h"
+#include "ser_p.h"
+#include "hw.h"
+
+#ifdef CONFIG_KERNEL
+       #include <kern/proc.h>
+#endif
+#if defined(CONFIG_SER_TXTIMEOUT) || defined(CONFIG_SER_RXTIMEOUT)
+       #include <drv/timer.h>
+#endif
+
+
+/* Serial configuration parameters */
+#define SER_CTSDELAY       70  /*!< CTS line retry interval (ms) */
+#define SER_TXPOLLDELAY             2  /*!< Transmit buffer full retry interval (ms) */
+#define SER_RXPOLLDELAY             2  /*!< Receive buffer empty retry interval (ms) */
+
+
+struct Serial ser_handles[SER_CNT];
+
+
+/*!
+ * Inserisce il carattere c nel buffer di trasmissione.
+ * Questa funzione mette il processo chiamante in attesa
+ * quando il buffer e' pieno.
+ *
+ * \return EOF in caso di errore o timeout, altrimenti
+ *         il carattere inviato.
+ */
+int ser_putchar(int c, struct Serial *port)
+{
+       if (fifo_isfull_locked(&port->txfifo))
+       {
+#ifdef CONFIG_SER_TXTIMEOUT
+               time_t start_time = timer_gettick();
+#endif
+
+               /* Attende finche' il buffer e' pieno... */
+               do
+               {
+#ifdef CONFIG_KERN_SCHED
+                       /* Give up timeslice to other processes. */
+                       proc_switch();
+#endif
+#ifdef CONFIG_SER_TXTIMEOUT
+                       if (timer_gettick() - start_time >= port->txtimeout)
+                       {
+                               port->status |= SERRF_TXTIMEOUT;
+                               return EOF;
+                       }
+#endif /* CONFIG_SER_TXTIMEOUT */
+               }
+               while (fifo_isfull_locked(&port->txfifo));
+       }
+
+       fifo_push(&port->txfifo, (unsigned char)c);
+
+       /* (re)trigger tx interrupt */
+       port->hw->table->enabletxirq(port->hw);
+
+       /* Avoid returning signed estended char */
+       return (int)((unsigned char)c);
+}
+
+
+/*!
+ * Preleva un carattere dal buffer di ricezione.
+ * Questa funzione mette il processo chiamante in attesa
+ * quando il buffer e' vuoto. L'attesa ha un timeout
+ * di ser_rxtimeout millisecondi.
+ *
+ * \return EOF in caso di errore o timeout, altrimenti
+ *         il carattere ricevuto.
+ */
+int ser_getchar(struct Serial *port)
+{
+       int result;
+
+       if (fifo_isempty_locked(&port->rxfifo))
+       {
+#ifdef CONFIG_SER_RXTIMEOUT
+               time_t start_time = timer_gettick();
+#endif
+               /* Wait while buffer is empty */
+               do
+               {
+#ifdef CONFIG_KERN_SCHED
+                       /* Give up timeslice to other processes. */
+                       proc_switch();
+#endif
+#ifdef CONFIG_SER_RXTIMEOUT
+                       if (timer_gettick() - start_time >= port->rxtimeout)
+                       {
+                               port->status |= SERRF_RXTIMEOUT;
+                               return EOF;
+                       }
+#endif /* CONFIG_SER_RXTIMEOUT */
+               }
+               while (fifo_isempty_locked(&port->rxfifo));
+       }
+
+       /*
+        * Get a byte from the FIFO (avoiding sign-extension),
+        * re-enable RTS, then return result.
+        */
+       result = (int)(unsigned char)fifo_pop(&port->rxfifo);
+       return port->status ? EOF : result;
+}
+
+
+/*!
+ * Preleva un carattere dal buffer di ricezione.
+ * Se il buffer e' vuoto, ser_getchar_nowait() ritorna
+ * immediatamente EOF.
+ */
+int ser_getchar_nowait(struct Serial *port)
+{
+       if (fifo_isempty_locked(&port->rxfifo))
+               return EOF;
+
+       /* NOTE: the double cast prevents unwanted sign extension */
+       return (int)(unsigned char)fifo_pop(&port->rxfifo);
+}
+
+
+/*!
+ * Read a line long at most as size and puts it
+ * in buf.
+ * \return number of chars read or EOF in case
+ *         of error.
+ */
+int ser_gets(struct Serial *port, char *buf, int size)
+{
+       return ser_gets_echo(port, buf, size, false);
+}
+
+
+/*!
+ * Read a line long at most as size and puts it
+ * in buf, with optional echo.
+ * \return number of chars read or EOF in case
+ *         of error.
+ */
+int ser_gets_echo(struct Serial *port, char *buf, int size, bool echo)
+{
+       int i = 0;
+       int c;
+
+       for (;;)
+       {
+               if ((c = ser_getchar(port)) == EOF)
+                       return -1;
+               /* FIXME */
+               if (c == '\r' || c == '\n' || i >= size-1)
+               {
+                       buf[i] = '\0';
+                       if (echo)
+                               ser_print(port, "\r\n");
+                       break;
+               }
+               buf[i++] = c;
+               if (echo)
+                       ser_putchar(c, port);
+       }
+
+       return i;
+}
+
+
+/*!
+ * Read at most size bytes and puts them
+ * in buf.
+ * \return number of bytes read or EOF in case
+ *         of error.
+ */
+int ser_read(struct Serial *port, char *buf, size_t size)
+{
+       size_t i = 0;
+       int c;
+
+       while (i < size)
+       {
+               if ((c = ser_getchar(port)) == EOF)
+                       return EOF;
+               buf[i++] = c;
+       }
+
+       return i;
+}
+
+
+/*!
+ * Write a string to serial.
+ * \return 0 if OK, EOF in case of error.
+ */
+int ser_print(struct Serial *port, const char *s)
+{
+       while (*s)
+       {
+               if (ser_putchar(*s++, port) == EOF)
+                       return EOF;
+       }
+       return 0;
+}
+
+
+/*!
+ * \brief Write a buffer to serial.
+ *
+ * \return 0 if OK, EOF in case of error.
+ */
+int ser_write(struct Serial *port, const void *buf, size_t len)
+{
+       while (len--)
+       {
+               if (ser_putchar(*((const char *)buf)++, port) == EOF)
+                       return EOF;
+       }
+       return 0;
+}
+
+
+/*!
+ * Formatted write
+ */
+int ser_printf(struct Serial *port, const char *format, ...)
+{
+       va_list ap;
+       int len;
+
+       ser_setstatus(port, 0);
+       va_start(ap, format);
+       len = _formatted_write(format, (void (*)(char, void *))ser_putchar, port, ap);
+       va_end(ap);
+
+       return len;
+}
+
+#if defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT)
+void ser_settimeouts(struct Serial *port, time_t rxtimeout, time_t txtimeout)
+{
+       port->rxtimeout = rxtimeout;
+       port->txtimeout = txtimeout;
+}
+#endif /* defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT) */
+
+
+void ser_setbaudrate(struct Serial *port, unsigned long rate)
+{
+       port->hw->table->setbaudrate(port->hw, rate);
+}
+
+
+void ser_setparity(struct Serial *port, int parity)
+{
+       port->hw->table->setparity(port->hw, parity);
+}
+
+
+/*!
+ * Flush both the RX and TX buffers.
+ */
+void ser_purge(struct Serial *ser)
+{
+       fifo_flush(&ser->rxfifo);
+       fifo_flush(&ser->txfifo);
+}
+
+
+/*!
+ * Initialize serial
+ */
+struct Serial *ser_open(unsigned int unit)
+{
+       struct Serial *port;
+
+       ASSERT(unit < countof(ser_handles));
+
+       port = &ser_handles[unit];
+
+       ASSERT(!port->is_open);
+
+       port->unit = unit;
+       port->is_open = true;
+
+       /* Initialize circular buffer */
+       fifo_init(&port->rxfifo, port->rxbuffer, sizeof(port->rxbuffer));
+       fifo_init(&port->txfifo, port->txbuffer, sizeof(port->txbuffer));
+
+       port->hw = ser_hw_getdesc(unit);
+       port->hw->table->init(port->hw, port);
+
+       /* Set default values */
+#if defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT)
+       ser_settimeouts(port, CONFIG_SER_RXTIMEOUT, CONFIG_SER_TXTIMEOUT);
+#endif
+       ser_setbaudrate(port, CONFIG_SER_DEFBAUDRATE);
+
+       return port;
+}
+
+
+/*!
+ * Clean up serial port, disabling the associated hardware.
+ */
+void ser_close(struct Serial *port)
+{
+       ASSERT(port->is_open);
+
+       port->is_open = false;
+       port->hw->table->cleanup(port->hw);
+       port->hw = NULL;        
+}
diff --git a/drv/ser.h b/drv/ser.h
new file mode 100755 (executable)
index 0000000..ad643e3
--- /dev/null
+++ b/drv/ser.h
@@ -0,0 +1,196 @@
+/*!
+ * \file
+ * <!--
+ * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
+ * Copyright 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \brief High level serial I/O API
+ *
+ * \version $Id$
+ * \author Bernardo Innocenti <bernie@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 18:10:11  bernie
+ * Import drv/ modules.
+ *
+ * Revision 1.2  2004/04/21 17:38:24  rasky
+ * New application
+ *
+ * Revision 1.16  2004/04/03 18:30:49  aleph
+ * Move timeout defines in config, private define in .c
+ *
+ * Revision 1.15  2004/03/29 17:01:02  aleph
+ * Add function to set serial parity, fix it when ser_open is used
+ *
+ * Revision 1.14  2004/03/29 16:19:33  aleph
+ * Add ser_cleanup function; Various code improvements
+ *
+ * Revision 1.13  2004/03/24 15:22:27  aleph
+ * Removed subdirs -I, fix header inclusion, move config.h in board_kf, kctrl
+ *
+ * Revision 1.12  2004/03/17 17:30:30  bernie
+ * Add GCC format checks to printf()-like functions.
+ *
+ * Revision 1.11  2004/03/16 23:06:42  aleph
+ * Doc fix
+ *
+ * Revision 1.10  2004/03/12 18:46:53  bernie
+ * ser_read(): New function.
+ *
+ * Revision 1.9  2004/03/11 18:11:51  bernie
+ * Cosmetic fixes
+ */
+#ifndef SER_H
+#define SER_H
+
+#include "compiler.h"
+#include <mware/fifobuf.h>
+#include "config.h"
+
+/*!
+ * \name Serial Error/status flags
+ *
+ * Some of these flags map directly to the flags
+ * in AVR UART Status Register(USR).
+ * \todo  flags of DSP56k aren't mapped to these flags. Luckily
+ *        these flags doesn't collide with the DSP56k ones,
+ *        which are from 0x0100 to 0x8000
+ */
+/*\{*/
+#if defined(__AVR__)
+       /* Software errors */
+       #define SERRF_RXFIFOOVERRUN  BV(0)  /*!< Rx FIFO buffer overrun */
+       #define SERRF_RXTIMEOUT      BV(5)  /*!< Receive timeout */
+       #define SERRF_TXTIMEOUT      BV(6)  /*!< Transmit timeout */
+
+       /* Hardware errors */
+       #define SERRF_RXSROVERRUN    BV(3)  /*!< Rx shift register overrun */
+       #define SERRF_FRAMEERROR     BV(4)  /*!< Stop bit missing */
+       #define SERRF_PARITYERROR    BV(7)  /*!< Parity error */
+#elif defined(__m56800__)
+       /* Software errors */
+       #define SERRF_RXFIFOOVERRUN  BV(0)  /*!< Rx FIFO buffer overrun */
+       #define SERRF_RXTIMEOUT      BV(1)  /*!< Receive timeout */
+       #define SERRF_TXTIMEOUT      BV(2)  /*!< Transmit timeout */
+
+       /* Hardware errors */
+       #define SERRF_PARITYERROR    BV(8)  /*!< Parity error */
+       #define SERRF_FRAMEERROR     BV(9)  /*!< Stop bit missing */
+       #define SERRF_NOISEERROR     BV(10) /*!< Noise error */
+       #define SERRF_RXSROVERRUN    BV(11) /*!< Rx shift register overrun */
+#else
+       #error unknown architecture
+#endif
+/*\}*/
+
+/*! \name Parity settings for ser_setparity() */
+/*\{*/
+#define SER_PARITY_NONE  0
+#define SER_PARITY_EVEN  2
+#define SER_PARITY_ODD   3
+/*\}*/
+
+/*!
+ * \name Serial hw numbers
+ *
+ * \{
+ */
+enum
+{
+       #if defined(__AVR_ATmega64__)
+       SER_UART0,
+       SER_UART1,
+       SER_SPI,
+
+       #elif defined(__AVR_ATmega103__)
+       SER_UART0,
+       SER_SPI,
+       
+       #elif defined (__m56800__)
+       SER_UART0,
+       SER_UART1,      
+       
+       #else
+               #error unknown architecture
+       #endif
+
+       SER_CNT       /**< Number of serial ports */
+};
+/* @} */
+
+
+struct SerialHardware;
+
+/*! Human-readable serial error descriptions */
+extern const char * const serial_errors[8];
+
+/*! Serial handle structure */
+struct Serial
+{
+       /*! Physical port number */
+       unsigned int unit;
+
+       bool is_open;
+
+       /*!
+        * \name FIFO transmit and receive buffers.
+        *
+        * Declared volatile because handled asinchronously by interrupts.
+        *
+        * \{
+        */
+       volatile FIFOBuffer txfifo;
+       volatile FIFOBuffer     rxfifo;
+       unsigned char txbuffer[CONFIG_SER_TXBUFSIZE];
+       unsigned char rxbuffer[CONFIG_SER_RXBUFSIZE];
+       /* \} */
+
+#ifdef CONFIG_SER_RXTIMEOUT
+       time_t rxtimeout;
+#endif
+#ifdef CONFIG_SER_TXTIMEOUT
+       time_t txtimeout;
+#endif
+
+       /*! Holds the flags defined above.  Will be 0 when no errors have occurred. */
+       REGISTER uint16_t status;
+       
+       /*! Low-level interface to hardware. */
+       struct SerialHardware* hw;
+       
+};
+
+
+/* Function prototypes */
+extern int ser_putchar(int c, struct Serial *port);
+extern int ser_getchar(struct Serial *port);
+extern int ser_getchar_nowait(struct Serial *port);
+extern int ser_write(struct Serial *port, const void *buf, size_t len);
+extern int ser_read(struct Serial *port, char *buf, size_t size);
+extern int ser_print(struct Serial *port, const char *s);
+extern int ser_gets(struct Serial *port, char *buf, int size);
+extern int ser_gets_echo(struct Serial *port, char *buf, int size, bool echo);
+extern int ser_printf(struct Serial *port, const char *format, ...) FORMAT(__printf__, 2, 3);
+extern void ser_setbaudrate(struct Serial *port, unsigned long rate);
+extern void ser_setparity(struct Serial *port, int parity);
+extern void ser_purge(struct Serial *port);
+extern struct Serial *ser_open(unsigned int unit);
+extern void ser_close(struct Serial *port);
+#if defined(CONFIG_SER_RXTIMEOUT) || defined(CONFIG_SER_TXTIMEOUT)
+       extern void ser_settimeouts(struct Serial *port, time_t rxtimeout, time_t txtimeout);
+#endif
+
+/**
+ * @name Additional functions implemented as macros
+ *
+ * @{
+ */
+#define ser_getstatus(h)    ((h)->status)
+#define ser_setstatus(h, x) ((h)->status = (x))
+/* @} */
+
+#endif /* SER_H */
diff --git a/drv/ser_avr.c b/drv/ser_avr.c
new file mode 100755 (executable)
index 0000000..c3bab67
--- /dev/null
@@ -0,0 +1,472 @@
+/**
+ * \file
+ * <!--
+ * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
+ * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ * -->
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \brief AVR UART and SPI I/O driver
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 18:10:11  bernie
+ * Import drv/ modules.
+ *
+ * Revision 1.30  2004/05/19 17:06:11  bernie
+ * Serial TX fill mode
+ *
+ * Revision 1.29  2004/05/16 19:16:46  aleph
+ * Serial always transmitting, first try
+ *
+ * Revision 1.28  2004/05/14 12:09:00  aleph
+ * Fix TX port pull-ups
+ *
+ * Revision 1.27  2004/05/08 13:56:02  aleph
+ * Adapt avr serial driver to new design
+ *
+ * Revision 1.25  2004/04/28 13:42:16  aleph
+ * Serial port fixes
+ *
+ * Revision 1.24  2004/04/08 14:17:27  bernie
+ * Change serial to disable TX when not sending data
+ *
+ * Revision 1.23  2004/04/03 20:39:41  aleph
+ * Remove strobe
+ *
+ * Revision 1.22  2004/03/29 17:01:02  aleph
+ * Add function to set serial parity, fix it when ser_open is used
+ */
+
+#include "ser.h"
+#include "ser_p.h"
+#include "kdebug.h"
+#include "config.h"
+#include "hw.h"
+#include <mware/fifobuf.h>
+
+extern struct Serial ser_handles[SER_CNT];
+
+struct AvrSerial
+{
+       struct SerialHardware hw;
+       struct Serial* serial;
+};
+
+
+/* Hardware handshake */
+#define RTS_ON
+#define RTS_OFF
+#define IS_CTS_ON   true
+#define IS_CTS_OFF  false
+
+
+/* SPI port and pin configuration */
+#define SPI_PORT      PORTB
+#define SPI_DDR       DDRB
+#define SPI_SCK_BIT   PORTB1
+#define SPI_MOSI_BIT  PORTB2
+#define SPI_MISO_BIT  PORTB3
+
+
+#ifdef __AVR_ATmega103__
+       /* Macro for ATmega103 compatibility */
+       #define UCSR0B UCR 
+       #define UDR0   UDR 
+       #define UCSR0A USR 
+       #define UBRR0L UBRR
+#else
+       #define UCR  UCSR0B 
+       #define UDR  UDR0  
+       #define USR  UCSR0A 
+#endif
+
+
+/* Transmission fill byte */
+#define SER_FILL_BYTE 0xAA
+
+
+static void uart0_enabletxirq(UNUSED(struct SerialHardware *ctx))
+{
+#ifdef CONFIG_SER_TXFILL
+       UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN) | BV(UCSZ2);
+#else
+       UCSR0B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
+#endif
+}
+
+static void uart0_init(struct SerialHardware *_hw, struct Serial *ser)
+{
+       struct AvrSerial *hw = (struct AvrSerial *)_hw;
+       hw->serial = ser;
+
+       /* Set TX port as input with pull-up enabled to avoid
+        * noise on the remote RX when TX is disabled */
+       cpuflags_t flags;
+       DISABLE_IRQSAVE(flags);
+       DDRE &= ~BV(PORTE1);
+       PORTE |= BV(PORTE1);
+       ENABLE_IRQRESTORE(flags);
+
+       /* TODO: explain why TX is disabled whenever possible */
+#ifdef CONFIG_SER_TXFILL
+       /*!
+        * Set multiprocessor mode and 9 bit data frame.
+        * The receiver keep MPCM bit always on. When useful data
+        * is trasmitted the ninth bit is set. Receiver consider the
+        * frame as address info and receive it.
+        * When useless fill bytes are sent the ninth bit is cleared
+        * and the receiver will ignore them, avoiding useless triggering
+        * of RXC interrupt.
+        */
+       UCSR0A = BV(MPCM);
+       UCSR0B = BV(RXCIE) | BV(RXEN) | BV(UCSZ2);
+#else
+       UCSR0B = BV(RXCIE) | BV(RXEN);
+#endif
+
+       RTS_ON;
+}
+
+static void uart0_cleanup(UNUSED(struct SerialHardware *ctx))
+{
+       UCSR0B = 0;
+}
+
+static void uart0_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
+{
+       // Compute baud-rate period
+       uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
+
+#ifndef __AVR_ATmega103__
+       UBRR0H = (period) >> 8;
+#endif
+       UBRR0L = (period);
+}
+
+
+#ifndef __AVR_ATmega103__
+
+static void uart1_enabletxirq(UNUSED(struct SerialHardware *ctx))
+{
+       UCSR1B = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
+}
+
+static void uart1_init(struct SerialHardware *_hw, struct Serial *ser)
+{
+       struct AvrSerial *hw = (struct AvrSerial *)_hw;
+       hw->serial = ser;
+
+       /* Set TX port as input with pull-up enabled to avoid
+        * noise on the remote RX when TX is disabled */
+       cpuflags_t flags;
+       DISABLE_IRQSAVE(flags);
+       DDRD &= ~BV(PORTD3);
+       PORTD |= BV(PORTD3);
+       ENABLE_IRQRESTORE(flags);
+
+       /* TODO: explain why TX is disabled whenever possible */
+       UCSR1B = BV(RXCIE) | BV(RXEN);
+
+       RTS_ON;
+}
+
+static void uart1_cleanup(UNUSED(struct SerialHardware *ctx))
+{
+       UCSR1B = 0;
+}
+
+static void uart1_setbaudrate(UNUSED(struct SerialHardware *ctx), unsigned long rate)
+{
+       // Compute baud-rate period
+       uint16_t period = (((CLOCK_FREQ / 16UL) + (rate / 2)) / rate) - 1;
+
+       UBRR1H = (period) >> 8;
+       UBRR1L = (period);
+}
+
+static void uart0_setparity(UNUSED(struct SerialHardware *ctx), int parity)
+{
+       UCSR0C |= (parity) << UPM0;
+}
+
+static void uart1_setparity(UNUSED(struct SerialHardware *ctx), int parity)
+{
+       UCSR1C |= (parity) << UPM0;
+}
+
+#endif /* !__AVR_ATmega103__ */
+
+
+static void spi_init(struct SerialHardware *_hw, struct Serial *ser)
+{
+       struct AvrSerial *hw = (struct AvrSerial *)_hw;
+       hw->serial = ser;
+
+       /* MOSI and SCK out, MISO in */
+       SPI_DDR |= BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT);
+       SPI_DDR &= ~BV(SPI_MISO_BIT);
+       /* Enable SPI, IRQ on, Master, CPU_CLOCK/16 */
+       SPCR = BV(SPE) | BV(SPIE) | BV(MSTR) | BV(SPR0);
+}
+
+static void spi_cleanup(UNUSED(struct SerialHardware *ctx))
+{
+       SPCR = 0;
+       /* Set all pins as inputs */
+       SPI_DDR &= ~(BV(SPI_MISO_BIT) | BV(SPI_MOSI_BIT) | BV(SPI_SCK_BIT));
+}
+
+
+
+#if defined(CONFIG_SER_HW_HANDSHAKE)
+
+//! This interrupt is triggered when the CTS line goes high
+SIGNAL(SIG_CTS)
+{
+       // Re-enable UDR empty interrupt and TX, then disable CTS interrupt
+       UCR = BV(RXCIE) | BV(UDRIE) | BV(RXEN) | BV(TXEN);
+       cbi(EIMSK, EIMSKB_CTS);
+}
+
+#endif // CONFIG_SER_HW_HANDSHAKE
+
+
+/*!
+ * Serial 0 TX interrupt handler
+ */
+#ifdef __AVR_ATmega103__
+SIGNAL(SIG_UART_DATA)
+#else
+SIGNAL(SIG_UART0_DATA)
+#endif
+{
+       if (fifo_isempty(&ser_handles[SER_UART0].txfifo))
+       {
+#ifdef CONFIG_SER_TXFILL
+               /*
+                * To avoid audio interference: always transmit useless char.
+                * Send the byte with the ninth bit cleared, the receiver in MCPM mode
+                * will ignore it.
+                */
+               UCSR0B &= ~BV(TXB8);
+               UDR0 = SER_FILL_BYTE;
+#else
+               /* Disable UDR empty interrupt and transmitter */
+               UCR = BV(RXCIE) | BV(RXEN);
+#endif
+       }
+#if defined(CONFIG_SER_HWHANDSHAKE)
+       else if (IS_CTS_OFF)
+       {
+               // disable rx interrupt and tx, enable CTS interrupt
+               UCR = BV(RXCIE) | BV(RXEN);
+               sbi(EIFR, EIMSKB_CTS);
+               sbi(EIMSK, EIMSKB_CTS);
+       }
+#endif // CONFIG_SER_HWHANDSHAKE
+       else
+       {
+#ifdef CONFIG_SER_TXFILL
+               /* Send with ninth bit set. Receiver in MCPM mode will receive it */
+               UCSR0B |= BV(TXB8);
+#endif
+               UDR = fifo_pop(&ser_handles[SER_UART0].txfifo);
+       }
+}
+
+/*!
+ * Serial 1 TX interrupt handler
+ */
+#ifndef __AVR_ATmega103__
+SIGNAL(SIG_UART1_DATA)
+{
+       if (fifo_isempty(&ser_handles[SER_UART1].txfifo))
+       {
+               /* Disable UDR empty interrupt and transmitter */
+               UCSR1B = BV(RXCIE) | BV(RXEN);
+       }
+#if defined(CONFIG_SER_HWHANDSHAKE)
+       else if (IS_CTS_OFF)
+       {
+               // disable rx interrupt and tx, enable CTS interrupt
+               UCSR1B = BV(RXCIE) | BV(RXEN);
+               sbi(EIFR, EIMSKB_CTS);
+               sbi(EIMSK, EIMSKB_CTS);
+       }
+#endif // CONFIG_SER_HWHANDSHAKE
+       else
+               UDR1 = fifo_pop(&ser_handles[SER_UART1].txfifo);
+}
+#endif /* !__AVR_ATmega103__ */
+
+
+/*!
+ * Serial 0 RX complete interrupt handler
+ */
+#ifdef __AVR_ATmega103__
+SIGNAL(SIG_UART_RECV)
+#else
+SIGNAL(SIG_UART0_RECV)
+#endif
+{
+       /* Should be read before UDR */
+       ser_handles[SER_UART0].status |= USR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
+
+       /* To clear the RXC flag we must _always_ read the UDR even when we're
+        * not going to accept the incoming data, otherwise a new interrupt
+        * will occur once the handler terminates.
+        */
+       char c = UDR;
+
+       if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
+               ser_handles[SER_UART0].status |= SERRF_RXFIFOOVERRUN;
+       else
+       {
+               fifo_push(&ser_handles[SER_UART0].rxfifo, c);
+#if defined(CONFIG_SER_HW_HANDSHAKE)
+               if (fifo_isfull(&ser_handles[SER_UART0].rxfifo))
+                       RTS_OFF;
+#endif
+       }
+}
+
+/*!
+ * Serial 1 RX complete interrupt handler
+ */
+#ifndef __AVR_ATmega103__
+SIGNAL(SIG_UART1_RECV)
+{
+       /* Should be read before UDR */
+       ser_handles[SER_UART1].status |= UCSR1A & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
+
+       /* To avoid an IRQ storm, we must _always_ read the UDR even when we're
+        * not going to accept the incoming data
+        */
+       char c = UDR1;
+
+       if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
+               ser_handles[SER_UART1].status |= SERRF_RXFIFOOVERRUN;
+       else
+       {
+               fifo_push(&ser_handles[SER_UART1].rxfifo, c);
+#if defined(CONFIG_SER_HW_HANDSHAKE)
+               if (fifo_isfull(&ser_handles[SER_UART1].rxfifo))
+                       RTS_OFF;
+#endif
+       }
+}
+#endif /* !__AVR_ATmega103__ */
+
+
+/*
+ * SPI Flag: true if we are transmitting/receiving with the SPI.
+ *
+ * This kludge is necessary because the SPI sends and receives bytes
+ * at the same time and the SPI IRQ is unique for send/receive.
+ * The only way to start transmission is to write data in SPDR (this
+ * is done by ser_spi_starttx()). We do this *only* if a transfer is
+ * not already started.
+ */
+static volatile bool spi_sending = false;
+
+static void spi_starttx(UNUSED(struct SerialHardware *ctx))
+{
+       cpuflags_t flags;
+
+       DISABLE_IRQSAVE(flags);
+
+       /* Send data only if the SPI is not already transmitting */
+       if (!spi_sending && !fifo_isempty(&ser_handles[SER_SPI].txfifo))
+       {
+               SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo); 
+               spi_sending = true;
+       }
+
+       ENABLE_IRQRESTORE(flags);
+}
+
+/*!
+ * SPI interrupt handler
+ */
+SIGNAL(SIG_SPI)
+{
+       /* Read incoming byte. */
+       if (!fifo_isfull(&ser_handles[SER_SPI].rxfifo))
+               fifo_push(&ser_handles[SER_SPI].rxfifo, SPDR);
+       /*
+        * FIXME
+       else
+               ser_handles[SER_SPI].status |= SERRF_RXFIFOOVERRUN;
+       */
+
+       /* Send */
+       if (!fifo_isempty(&ser_handles[SER_SPI].txfifo))
+               SPDR = fifo_pop(&ser_handles[SER_SPI].txfifo);
+       else
+               spi_sending = false;
+}
+
+
+/*
+
+#pragma vector = UART_TXC_vect
+__interrupt void UART_TXC_interrupt(void)
+{
+  UCSRB &= ~TXCIE;
+  ReceiveMode();
+  UCSRB = RXCIE | RXEN | TXEN;  //Abilito l'Interrupt in ricezione e RX e TX  
+}
+*/
+
+
+static const struct SerialHardwareVT UART0_VT = 
+{
+       .init = uart0_init,
+       .cleanup = uart0_cleanup,
+       .setbaudrate = uart0_setbaudrate,
+       .setparity = uart0_setparity,
+       .enabletxirq = uart0_enabletxirq,
+};
+
+static const struct SerialHardwareVT UART1_VT = 
+{
+       .init = uart1_init,
+       .cleanup = uart1_cleanup,
+       .setbaudrate = uart1_setbaudrate,
+       .setparity = uart1_setparity,
+       .enabletxirq = uart1_enabletxirq,
+};
+
+static const struct SerialHardwareVT SPI_VT = 
+{
+       .init = spi_init,
+       .cleanup = spi_cleanup,
+       .enabletxirq = spi_starttx,
+};
+
+static struct AvrSerial UARTDescs[SER_CNT] =
+{
+       { 
+               .hw = { .table = &UART0_VT }, 
+       },
+       
+       { 
+               .hw = { .table = &UART1_VT }, 
+       },  
+
+       { 
+               .hw = { .table = &SPI_VT }, 
+       },  
+};
+
+struct SerialHardware* ser_hw_getdesc(int unit)
+{
+       ASSERT(unit < SER_CNT);
+       return &UARTDescs[unit].hw;
+}
diff --git a/drv/ser_dsp56k.c b/drv/ser_dsp56k.c
new file mode 100755 (executable)
index 0000000..d2f1362
--- /dev/null
@@ -0,0 +1,228 @@
+/**
+ * \file
+ * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ *
+ * \version $Id$
+ *
+ * \author Stefano Fedrigo <aleph@develer.com>
+ *
+ * \brief DSP5680x CPU specific serial I/O driver
+ */
+
+#include <DSP56F807.H>
+#include <drv/kdebug.h>
+#include <hw.h>
+#include "ser.h"
+#include "ser_p.h"
+
+// GPIO E is shared with SPI (in DSP56807). Pins 0&1 are TXD0 and RXD0. To use
+//  the serial, we need to disable the GPIO functions on them.
+#define REG_GPIO_SERIAL         REG_GPIO_E
+#define REG_GPIO_SERIAL_MASK    0x3
+
+// Check flag consistency
+#if (SERRF_PARITYERROR != REG_SCI_SR_PF) || \
+       (SERRF_RXSROVERRUN != REG_SCI_SR_OR) || \
+       (SERRF_FRAMEERROR  != REG_SCI_SR_FE) || \
+       (SERRF_NOISEERROR  != REG_SCI_SR_NF)
+       #error error flags do not match with register bits
+#endif
+
+struct SCI
+{
+       struct SerialHardware hw;
+       struct Serial* serial;
+       volatile struct REG_SCI_STRUCT* regs;
+       uint16_t irq_tx;
+       uint16_t irq_rx;
+};
+
+
+static inline void enable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
+{
+       regs->CR |= REG_SCI_CR_TEIE | REG_SCI_CR_TIIE;
+}
+
+static inline void enable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
+{
+       regs->CR |= REG_SCI_CR_RIE | REG_SCI_CR_REIE;
+}
+
+static inline void disable_tx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
+{
+       regs->CR &= ~(REG_SCI_CR_TEIE | REG_SCI_CR_TIIE);
+}
+
+static inline void disable_rx_irq_bare(volatile struct REG_SCI_STRUCT* regs)
+{
+       regs->CR &= ~(REG_SCI_CR_RIE | REG_SCI_CR_REIE);
+}
+
+static inline void disable_tx_irq(struct SerialHardware* _hw)
+{
+       struct SCI* hw = (struct SCI*)_hw;
+       volatile struct REG_SCI_STRUCT* regs = hw->regs;
+
+       disable_tx_irq_bare(regs);
+}
+
+static inline void enable_tx_irq(struct SerialHardware* _hw)
+{
+       struct SCI* hw = (struct SCI*)_hw;
+       volatile struct REG_SCI_STRUCT* regs = hw->regs;
+
+       enable_tx_irq_bare(regs);
+}
+
+static inline void enable_rx_irq(struct SerialHardware* _hw)
+{
+       struct SCI* hw = (struct SCI*)_hw;
+       volatile struct REG_SCI_STRUCT* regs = hw->regs;
+
+       enable_rx_irq_bare(regs);
+}
+
+INLINE void tx_isr(struct SCI *hw)
+{
+       volatile struct REG_SCI_STRUCT* regs = hw->regs;
+
+       if (fifo_isempty(&hw->serial->txfifo))
+               disable_tx_irq_bare(regs);
+       else
+       {
+               // Clear transmitter flags before sending data
+               (void)regs->SR;
+               regs->DR = fifo_pop(&hw->serial->txfifo);
+       }
+}
+
+INLINE void rx_isr(struct SCI *hw)
+{
+       volatile struct REG_SCI_STRUCT* regs = hw->regs;
+
+       hw->serial->status |= regs->SR & (SERRF_PARITYERROR | 
+                                         SERRF_RXSROVERRUN | 
+                                         SERRF_FRAMEERROR | 
+                                         SERRF_NOISEERROR);
+       
+       if (fifo_isfull(&hw->serial->rxfifo))
+               hw->serial->status |= SERRF_RXFIFOOVERRUN;
+       else
+               fifo_push(&hw->serial->rxfifo, regs->DR);
+               
+       // Writing anything to the status register clear the
+       //  error bits.
+       regs->SR = 0;
+}
+
+static void init(struct SerialHardware* _hw, struct Serial* ser)
+{
+       struct SCI* hw = (struct SCI*)_hw;
+       volatile struct REG_SCI_STRUCT* regs = hw->regs;
+
+       // Clear status register (IRQ/status flags)
+       (void)regs->SR;
+       regs->SR = 0;
+       
+       // Clear data register
+       (void)regs->DR;
+       
+       // Set priorities for both IRQs
+       irq_setpriority(hw->irq_tx, IRQ_PRIORITY_SCI_TX);
+       irq_setpriority(hw->irq_rx, IRQ_PRIORITY_SCI_RX);
+
+       // Activate the RX error interrupts, and RX/TX transmissions
+       regs->CR = REG_SCI_CR_TE | REG_SCI_CR_RE;
+       enable_rx_irq_bare(regs);
+       
+       // Disable GPIO pins for TX and RX lines
+       REG_GPIO_SERIAL->PER |= REG_GPIO_SERIAL_MASK;
+
+       hw->serial = ser;
+}
+
+static void cleanup(struct SerialHardware* _hw)
+{
+       // TODO!
+       ASSERT(0);
+}
+
+static void setbaudrate(struct SerialHardware* _hw, unsigned long rate)
+{
+       struct SCI* hw = (struct SCI*)_hw;
+
+       // SCI has an internal 16x divider on the input clock, which comes
+       //  from the IPbus (see the scheme in user manual, 12.7.3). We apply
+       //  it to calculate the period to store in the register.
+       hw->regs->BR = (IPBUS_FREQ + rate * 8ul) / (rate * 16ul);
+}
+
+static void setparity(struct SerialHardware* _hw, int parity)
+{
+       // ???
+       ASSERT(0);
+}
+
+
+static const struct SerialHardwareVT SCI_VT = 
+{
+       .init = init,
+       .cleanup = cleanup,
+       .setbaudrate = setbaudrate,
+       .setparity = setparity,
+       .enabletxirq = enable_tx_irq,
+};
+
+static struct SCI SCIDescs[2] =
+{
+       { 
+               .hw = { .table = &SCI_VT }, 
+               .regs = &REG_SCI[0],
+               .irq_rx = IRQ_SCI0_RECEIVER_FULL,
+               .irq_tx = IRQ_SCI0_TRANSMITTER_READY,
+       },
+       
+       { 
+               .hw = { .table = &SCI_VT }, 
+               .regs = &REG_SCI[1],
+               .irq_rx = IRQ_SCI1_RECEIVER_FULL,
+               .irq_tx = IRQ_SCI1_TRANSMITTER_READY,
+       },  
+};
+
+
+
+void ser_hw_tx_isr_0(void);
+void ser_hw_tx_isr_0(void)
+{
+#pragma interrupt warn
+       tx_isr(&SCIDescs[0]);
+}
+
+void ser_hw_rx_isr_0(void);
+void ser_hw_rx_isr_0(void)
+{
+#pragma interrupt warn
+       rx_isr(&SCIDescs[0]);
+}
+
+void ser_hw_tx_isr_1(void);
+void ser_hw_tx_isr_1(void)
+{
+#pragma interrupt warn
+       tx_isr(&SCIDescs[1]);
+}
+
+void ser_hw_rx_isr_1(void);
+void ser_hw_rx_isr_1(void)
+{
+#pragma interrupt warn
+       rx_isr(&SCIDescs[1]);
+}
+
+struct SerialHardware* ser_hw_getdesc(int unit)
+{
+       ASSERT(unit < 2);
+       return &SCIDescs[unit].hw;
+}
diff --git a/drv/ser_i196.c b/drv/ser_i196.c
new file mode 100755 (executable)
index 0000000..7225e86
--- /dev/null
@@ -0,0 +1,95 @@
+/**
+ * \file
+ * Copyright (C) 2000 Bernardo Innocenti <bernie@codewiz.org>
+ * Copyright (C) 2003 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ *
+ * \version $Id$
+ *
+ * \author Bernardo Innocenti <bernie@develer.com>
+ *
+ * \brief CPU specific serial I/O driver
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 18:10:11  bernie
+ * Import drv/ modules.
+ *
+ * Revision 1.1  2003/11/20 22:30:21  aleph
+ * Add serial driver
+ *
+ */
+
+#include "hw.h"
+#include "serhw.h"
+
+#define SER_HW_ENABLE_TX \
+       DISABLE_INTS; \
+       if (!ser_sending) \
+       { \
+               ser_sending = true; \
+               (INT_PEND1 |= INT1F_TI) \
+       } \
+       ENABLE_INTS;
+
+static volatile bool ser_sending;
+
+// Serial TX intr
+INTERRUPT(0x30) void TI_interrupt(void)
+{
+       if (CANT_SEND)
+       {
+               ser_sending = false;
+               return;
+       }
+
+       /* Can we send two bytes at the same time? */
+       if (SP_STAT & SPSF_TX_EMPTY)
+       {
+               SBUF = fifo_pop(&ser_txfifo);
+
+               if (CANT_SEND)
+               {
+                       ser_sending = false;
+                       return;
+               }
+       }
+
+       SBUF = fifo_pop(&ser_txfifo);
+}
+
+INTERRUPT(0x32) void RI_interrupt(void)
+{
+       ser_status |= SP_STAT &
+               (SPSF_OVERRUN_ERROR | SPSF_PARITY_ERROR | SPSF_FRAMING_ERROR);
+       if (fifo_isfull(&ser_rxfifo))
+               ser_status |= SERRF_RXFIFOOVERRUN;
+       else
+               fifo_push(&ser_rxfifo, SBUF);
+}
+
+static void ser_setbaudrate(unsigned long rate)
+{
+       // Calcola il periodo per la generazione del baud rate richiesto
+       uint16_t baud = (uint16_t)(((CLOCK_FREQ / 16) / rate) - 1) | 0x8000;
+       BAUD_RATE = (uint8_t)baud;
+       BAUD_RATE = (uint8_t)(baud >> 8);
+}
+
+static void ser_hw_init(void)
+{
+       // Inizializza la porta seriale
+       SP_CON = SPCF_RECEIVE_ENABLE | SPCF_MODE1;
+       ioc1_img |= IOC1F_TXD_SEL | IOC1F_EXTINT_SRC;
+       IOC1 = ioc1_img;
+
+       // Svuota il buffer di ricezione
+       {
+               uint8_t dummy = SBUF;
+       }
+
+       // Abilita gli interrupt
+       INT_MASK1 |= INT1F_TI | INT1F_RI;
+}
+
diff --git a/drv/ser_p.h b/drv/ser_p.h
new file mode 100755 (executable)
index 0000000..14d2171
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * \file
+ * Copyright (C) 2003,2004 Develer S.r.l. (http://www.develer.com/)
+ * All Rights Reserved.
+ *
+ * \brief Hardware dependent serial driver (interface)
+ *
+ * \version $Id$
+ *
+ * \author Stefano Fedrigo <aleph@develer.com>
+ * \author Giovanni Bajo <rasky@develer.com>
+ */
+
+/*
+ * $Log$
+ * Revision 1.1  2004/05/23 18:10:11  bernie
+ * Import drv/ modules.
+ *
+ * Revision 1.1  2004/05/14 12:47:26  rasky
+ * Importato nuovo supporto seriale per AVR da Stefano
+ *
+ * Revision 1.3  2004/05/08 13:59:08  aleph
+ * Fix header guard
+ *
+ * Revision 1.2  2004/05/08 13:58:36  aleph
+ * Add log comment
+ *
+ */
+
+#ifndef _DRV_SER_P_H
+#define _DRV_SER_P_H
+
+struct SerialHardware;
+struct Serial;
+
+struct SerialHardwareVT
+{
+       void (*init)(struct SerialHardware* ctx, struct Serial* ser);
+       void (*cleanup)(struct SerialHardware* ctx);
+       void (*setbaudrate)(struct SerialHardware* ctx, unsigned long rate);
+       void (*setparity)(struct SerialHardware* ctx, int parity);
+       void (*enabletxirq)(struct SerialHardware* ctx);
+};
+
+struct SerialHardware
+{
+       const struct SerialHardwareVT* table;
+};
+
+struct SerialHardware* ser_hw_getdesc(int unit);
+
+#endif // _DRV_SER_P_H