Subversion Repositories shark

Compare Revisions

Ignore whitespace Rev 538 → Rev 714

/shark/trunk/drivers/serial/scom.c
18,25 → 18,6
* http://shark.sssup.it
*/
 
/**
------------
CVS : $Id: scom.c,v 1.1 2004-03-29 18:31:42 mauro Exp $
 
File: $File$
Revision: $Revision: 1.1 $
Last update: $Date: 2004-03-29 18:31:42 $
------------
 
Author: Massimiliano Giorgi
 
Author: Gerardo Lamastra
Date: 9/5/96
 
File: SCOM.C
Revision: 1.0g
 
**/
 
/*
* Copyright (C) 2000 Paolo Gai
*
70,42 → 51,15
* mouse better (see below)
*/
 
//#include <string.h>
//#include <stdlib.h>
//#include <cons.h>
 
#include <kernel/kern.h>
//#include "exc.h"
 
#include <modules/sem.h>
#include <drivers/scom.h>
 
 
/* #define __DEBUG_SERIAL__ */
/* #define __STUB__ */
 
/* Base address for each standard COM link */
static unsigned com_base[] = {0x03F8,0x02F8,0x03E8,0x02E8};
/* Irq linked to each serial channel */
static unsigned com_irq[] = {COM1_IRQ,COM2_IRQ,COM3_IRQ,COM4_IRQ};
/* COM port which shares interrupt with indexed one */
/* I assume standard AT assignement where each irq line can */
/* hold up to 2 different COM port */
static const int com_share[] = {COM3,COM4,COM1,COM2};
 
/* Used for decoding the IIR status */
const int IIRbits[] = {MS_CHANGED,TX_EMPTY,RX_FULL,LS_CHANGED};
 
/* The descriptor of a serial link */
/* Each array entry is associated to a COM port */
/* The control field is used to specify which kind of interrupts */
/* are going to be served; the status field tracks if the entry */
/* is curretly used & if the shared fast handler is linked */
/* The semaphores are opened if you use an asyncronous server */
/* with the link */
 
struct COM_LINK com_link[COM_LINKS];
 
/* Register level access functions */
 
unsigned com_read(unsigned port,unsigned reg)
136,96 → 90,15
return(com_read(port,RBR));
}
 
/* Fast routines for cascaded irq */
 
/* By massy */
/* com_fast must be called if there isn't a server
* and an interrupt is detected (so sermouse.c module can
* activate mouse task only if a packet not a byte is received).
*/
static void dummy(int x) {}
void (*com_fast)(int)=dummy;
 
#ifdef __DEBUG_SERIAL__
int fast_times1 = 0,fast_times3 = 0;
#endif
 
static void com_1_3_fast(int n)
{
unsigned iir1,iir3;
iir1 = DECODE(com_read(COM1,IIR));
iir3 = DECODE(com_read(COM3,IIR));
if ((iir1 & com_link[COM1].control)) {
#ifdef __DEBUG_SERIAL__
fast_times1++;
#endif
com_write(COM1,IER,0);
com_link[COM1].request = iir1;
if (com_link[COM1].server==NIL)
com_fast(COM1);
else
task_activate(com_link[COM1].server);
}
else if ((iir3 & com_link[COM3].control)) {
#ifdef __DEBUG_SERIAL__
fast_times3++;
#endif
com_write(COM3,IER,0);
com_link[COM3].request = iir3;
if (com_link[COM3].server==NIL)
com_fast(COM3);
else
task_activate(com_link[COM3].server);
}
}
 
#ifdef __DEBUG_SERIAL__
int fast_times2 = 0,fast_times4 = 0;
#endif
 
static void com_2_4_fast(int n)
{
unsigned iir2,iir4;
iir2 = DECODE(com_read(COM2,IIR));
iir4 = DECODE(com_read(COM4,IIR));
if ((iir2 & com_link[COM2].control)) {
#ifdef __DEBUG_SERIAL__
fast_times2++;
#endif
com_write(COM2,IER,0);
com_link[COM2].request = iir2;
if (com_link[COM2].server==NIL)
com_fast(COM2);
else
task_activate(com_link[COM2].server);
}
else if ((iir4 & com_link[COM4].control)) {
#ifdef __DEBUG_SERIAL__
fast_times4++;
#endif
com_write(COM4,IER,0);
com_link[COM4].request = iir4;
if (com_link[COM4].server==NIL)
com_fast(COM4);
else
task_activate(com_link[COM4].server);
}
}
 
/* Initialize a serial channel */
 
int com_open(unsigned port,DWORD speed,BYTE parity,BYTE len,BYTE stop)
{
unsigned long div,b_mask;
/* Check if link is already open */
cli();
if (com_link[port].status & LINK_BUSY) {
sti();
return(-1);
} else com_link[port].status |= LINK_BUSY;
sti();
SYS_FLAGS f;
 
f = kern_fsave();
 
/* Now set up the serial link */
b_mask = (parity & 3) * 8 + (stop & 1) * 4 + ((len - 5) & 3);
div = 115200L / speed;
243,42 → 116,11
com_write(port,LCR,b_mask);
/* Attiva OUT1 & OUT2 */
com_write(port,MCR,0x0C);
return(1);
}
 
/* Link a particular server to a serial channel */
/* The semaphores are opened to syncronize the server and the */
/* application task which use serial communication */
kern_frestore(f);
 
int com_server(unsigned port,unsigned control,PID server)
{
unsigned hndl = com_irq[port];
unsigned shared = com_share[port];
void (*com_fast)(int n);
/* Select appropriate fast routine */
if (port == COM1 || port == COM3) com_fast = com_1_3_fast;
else if (port == COM2 || port == COM4) com_fast = com_2_4_fast;
else return(-1);
if ((control & (RX_FULL|TX_EMPTY)) == 0) return(-1);
/* If the fast routine is not already installed, install it! */
cli();
if (!(com_link[port].status & FAST_INSTALLED)) {
bit_on(com_link[port].status,FAST_INSTALLED);
bit_on(com_link[shared].status,FAST_INSTALLED);
handler_set(hndl,com_fast,NIL, TRUE);
#ifdef __DEBUG_SERIAL__
cputs("Handler OK\n");
#endif
}
sti();
/* Set com link tasks & flags */
com_link[port].control = control;
com_link[port].server = server;
com_link[port].msk = 0;
if (control & RX_FULL) sem_init(&com_link[port].rx_sem,0,0);
if (control & TX_EMPTY) sem_init(&com_link[port].tx_sem,0,0);
sem_init(&com_link[port].mutex,0,1);
return(1);
return(0);
 
}
 
/* Close port channel & release the server */
285,208 → 127,16
 
int com_close(unsigned port)
{
unsigned hndl = com_irq[port];
unsigned shared = com_share[port];
SYS_FLAGS f;
 
/* Check if fast is already installed */
cli();
if (!(com_link[port].status & LINK_BUSY)) {
sti();
return(-1);
} else {
if (com_link[port].control & RX_FULL) sem_destroy(&com_link[port].rx_sem);
if (com_link[port].control & TX_EMPTY) sem_destroy(&com_link[port].tx_sem);
com_write(port,IER,0);
com_read(port,IIR);
com_read(port,RBR);
com_link[port].status = 0;
com_link[port].control = 0;
com_link[port].msk = 0;
sti();
sem_destroy(&com_link[port].mutex);
if (com_link[port].server != NIL) {
task_kill(com_link[port].server);
com_link[port].server = NIL;
}
}
/* If the fast routine is no more necessary, remove it */
if (!(com_link[shared].status & FAST_INSTALLED))
handler_remove(hndl);
/* If the other link still uses it, we must remember this */
else com_link[port].status = FAST_INSTALLED;
return(1);
}
f = kern_fsave();
 
#ifdef __DEBUG_SERIAL__
int rx_time = 0;
int tx_time = 0;
#endif
 
/* This is the full duplex server; used for bidirectional data */
/* transmission. */
/* As intr is masked, the server can only be activated once */
/* and operates in mutex with the fast handler */
/* This server operates in conjunction with the com_Async... */
/* procedures! */
 
TASK duplexServer(int port)
{
char data;
for(;;) {
if (com_link[port].request & RX_FULL) {
#ifdef __DEBUG_SERIAL__
putc_xy(78,0,RED,'R');
rx_time++;
#endif
data = com_read(port,RBR);
*(com_link[port].rx_buf + com_link[port].rx_cnt) = data;
com_link[port].rx_cnt++;
if (com_link[port].rx_cnt == com_link[port].rx_len) {
bit_off(com_link[port].msk,RX_FULL);
sem_post(&com_link[port].rx_sem);
}
}
if (com_link[port].request & TX_EMPTY) {
#ifdef __DEBUG_SERIAL__
putc_xy(79,0,GREEN,'T');
tx_time++;
#endif
data = *(com_link[port].tx_buf + com_link[port].tx_cnt);
com_link[port].tx_cnt++;
com_write(port,THR,data);
if (com_link[port].tx_cnt == com_link[port].tx_len) {
bit_off(com_link[port].msk,TX_EMPTY);
sem_post(&com_link[port].tx_sem);
}
}
cli();
com_write(port,IER,com_link[port].msk);
task_endcycle();
sti();
}
}
 
/* This routines provides asyncronous decoupling between the server */
/* and the tasks which produce/consume serial data */
 
void com_AsyncSend(int port,void *buf,unsigned len)
{
sem_wait(&com_link[port].mutex);
com_link[port].tx_buf = buf;
com_link[port].tx_cnt = 0;
com_link[port].tx_len = len;
bit_on(com_link[port].msk,TX_EMPTY);
sem_post(&com_link[port].mutex);
com_write(port,IER,com_link[port].msk);
sem_wait(&com_link[port].tx_sem);
}
 
void com_AsyncReceive(int port,void *buf,unsigned len)
{
sem_wait(&com_link[port].mutex);
com_link[port].rx_buf = buf;
com_link[port].rx_cnt = 0;
com_link[port].rx_len = len;
bit_on(com_link[port].msk,RX_FULL);
sem_post(&com_link[port].mutex);
com_write(port,IER,com_link[port].msk);
sem_wait(&com_link[port].rx_sem);
}
 
/* Receive Only Server */
/* This server is used for passive devices which cannot receive */
/* data, but only transmit. I assume that only one byte is pro- */
/* cessed each time and the byte is got to the control process */
 
TASK rxServer(int port)
{
static char data;
com_link[port].rx_buf = &data;
for(;;) {
#ifdef __DEBUG_SERIAL__
putc_xy(76,0,YELLOW,'R');
#endif
data = com_read(port,RBR);
sem_post(&com_link[port].rx_sem);
cli();
com_write(port,IER,com_link[port].msk);
task_endcycle();
sti();
}
}
 
/* Debug Stub */
 
#ifdef __STUB__
 
#include "keyb.h"
 
TASK Visualize(void)
{
char str[40];
char buf[80];
unsigned long times = 0;
 
for (;;) {
com_AsyncReceive(COM2,str,10);
sprintf(buf,"Str : %s (Times : %lu)",str,times++);
puts_xy(0,1,WHITE,buf);
}
}
 
TASK Sender(void)
{
char buf[80];
unsigned long times = 0;
cputs("Sender has started...\n");
for (;;) {
buf[0] = keyb_getchar();
if (buf[0] == 'x') task_activate(MAIN_INDEX);
if ((times % 10) == 9) buf[0] = 0;
com_AsyncSend(COM2,buf,1);
sprintf(buf,"Sender (Times : %lu)",times++);
puts_xy(0,3,WHITE,buf);
}
} 0
 
void main()
{
PID p1,p2,p3;
BYTE m1 = TX_EMPTY|RX_FULL;
BYTE m2 = RX_FULL;
BYTE m3 = TX_EMPTY;
MODEL m = BASE_MODEL;
MODEL mm = BASE_MODEL;
com_write(port,IER,0);
com_read(port,IIR);
com_read(port,RBR);
sys_init(1000,uSec,0);
keyb_init(HARD,50);
clear();
/* This is the sequence of operations needed to setup */
/* a serial asyncronous bidirectional link */
task_def_arg(m,COM2);
task_def_wcet(m,500);
p1 = task_create("ComDuplex",duplexServer,HARD,APERIODIC,100,&m);
if (p1 == -1) {
ll_printf("Error creating comduplex task\n");
sys_end();
exit(-1);
}
com_open(COM2,9600,NONE,8,1);
com_server(COM2,m1,p1);
kern_frestore(f);
 
/* Well, that is some other stuff ... */
task_def_wcet(mm,500);
p2 = task_create("Visor",Visualize,NRT,APERIODIC,11,&mm);
p3 = task_create("Sender",Sender,NRT,APERIODIC,11,&mm);
task_activate(p2);
task_activate(p3);
task_endcycle();
sys_end();
#ifdef __DEBUG_SERIAL__
cprintf("RxServer was activated %d times\n",rx_time);
cprintf("TxServer was activated %d times\n",tx_time);
cprintf("Fast : %d\n",fast_times1);
#endif
return(0);
}
 
#endif
/shark/trunk/drivers/serial/include/drivers/scomirq.h
0,0 → 1,91
/*
* Project: S.Ha.R.K.
*
* Coordinators:
* Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@gandalf.sssup.it>
*
* Authors :
* Paolo Gai <pj@gandalf.sssup.it>
* (see the web pages for full authors list)
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
 
/*
* Copyright (C) 2000 Michele Cirinei
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
 
/*
CVS : $Id: scomirq.h,v 1.1 2004-06-01 14:08:28 giacomo Exp $
 
scomirq.h:
 
Layer for IRQ Serial Communication.
 
*/
#ifndef __SCOMIRQ_H__
#define __SCOMIRQ_H__
 
#include <drivers/scom.h>
 
#define bit0 (1 << 0)
#define bit1 (1 << 1)
#define bit2 (1 << 2)
#define bit3 (1 << 3)
#define bit4 (1 << 4)
#define bit5 (1 << 5)
#define bit6 (1 << 6)
#define bit7 (1 << 7)
 
#define RBRF_IRQ bit0
#define THRE_IRQ bit1
#define LSR_IRQ bit2
#define ALL_IRQ (RBRF_IRQ | THRE_IRQ | LSR_IRQ)
 
#define COM_OK 0
#define COM_ERROR 1
 
/****************************
Variables
****************************/
struct SCom_Access_Type{
void (*request)(unsigned port, BYTE len, BYTE *data);
void (*confirm)(unsigned port, BYTE msg_id);
void (*indication)(unsigned port, BYTE data);
};
 
extern struct SCom_Access_Type SCom_Access;
 
/*****************************
* Functions
*****************************/
void com_end(unsigned port);
 
void com_irq_enable(unsigned port, unsigned irq);
 
void com_irq_disable(unsigned port, unsigned irq);
 
void com_init(unsigned port, DWORD speed, BYTE parity, BYTE len, BYTE stop);
 
void com_set_functions(void (*confirm)(unsigned port, BYTE msg_status),void (*indication)(unsigned port, BYTE data));
 
#endif
/shark/trunk/drivers/serial/include/drivers/scom.h
18,17 → 18,6
* http://shark.sssup.it
*/
 
/**
------------
CVS : $Id: scom.h,v 1.1 2004-03-29 18:31:42 mauro Exp $
 
File: $File$
Revision: $Revision: 1.1 $
Last update: $Date: 2004-03-29 18:31:42 $
------------
 
**/
 
/*
* Copyright (C) 2000 Gerardo Lamastra
*
48,23 → 37,9
*
*/
 
/* Project: HARTIK 3.0 */
/* Description: Hard Real TIme Kernel for 386 & higher machines */
/* Author: Gerardo Lamastra */
/* Date: 9/5/96 */
 
/* File: SCOM.H */
/* Revision: 2.0 */
 
#ifndef __SCOM_H__
#define __SCOM_H__
 
#ifdef __cplusplus
extern "C" {
#endif
 
#include <modules/sem.h>
 
/* Number of available COM links */
#define COM_LINKS 4
 
110,46 → 85,11
#define bit_on(v,b) v |= (b)
#define bit_off(v,b) v &= (~(b))
 
/* The descriptor of a serial link */
/* Each array entry is associated to a COM port */
/* The control field is used to specify which kind of interrupts */
/* are going to be served; the status field tracks if the entry */
/* is curretly used & if the shared fast handler is linked */
/* The semaphores are opened if you use an asyncronous server */
/* with the link */
 
extern struct COM_LINK {
/* These fields are for general use */
BYTE status;
BYTE control;
BYTE request;
BYTE msk;
PID server;
sem_t mutex;
sem_t tx_sem;
sem_t rx_sem;
BYTE *tx_buf;
BYTE *rx_buf;
unsigned tx_len,rx_len;
unsigned tx_cnt,rx_cnt;
} com_link[COM_LINKS];
 
/* Available servers */
TASK duplexServer(int port);
TASK rxServer(int port);
 
int com_open(unsigned int port,DWORD speed,BYTE parity,BYTE len,BYTE stop);
int com_server(unsigned int port,unsigned int control,PID server);
int com_close(unsigned int port);
unsigned com_read(unsigned int port,unsigned int reg);
unsigned com_receive(unsigned int port);
void com_write(unsigned int port,unsigned int reg,unsigned int value);
void com_send(unsigned int port,BYTE b);
void com_AsyncSend(int port,void *buf,unsigned int len);
void com_AsyncReceive(int port,void *buf,unsigned int len);
 
#ifdef __cplusplus
};
#endif
 
#endif
/shark/trunk/drivers/serial/makefile
10,7 → 10,7
 
OBJS_PATH = $(BASE)/drivers/serial
 
OBJS = scom.o
OBJS = scom.o scomirq.o
 
OTHERINCL += -I$(BASE)/drivers/serial/include
 
/shark/trunk/drivers/serial/scomirq.c
0,0 → 1,212
/*
* Project: S.Ha.R.K.
*
* Coordinators:
* Giorgio Buttazzo <giorgio@sssup.it>
* Paolo Gai <pj@gandalf.sssup.it>
*
* Authors :
* Paolo Gai <pj@gandalf.sssup.it>
* (see the web pages for full authors list)
*
* ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
*
* http://www.sssup.it
* http://retis.sssup.it
* http://shark.sssup.it
*/
 
/*
* Copyright (C) 2000 Michele Cirinei
*
* This program 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 of the License, or
* (at your option) any later version.
*
* This program 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 this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
 
#include <kernel/kern.h>
#include <drivers/scomirq.h>
 
/****************************
Variables
****************************/
static unsigned com_irq[] = {COM1_IRQ, COM2_IRQ, COM3_IRQ, COM4_IRQ};
 
struct SCom_Access_Type SCom_Access;
 
unsigned SCom_Error;
 
struct TX_data_t{
int ptr;
int len;
BYTE buf[100];
};
 
static struct TX_data_t SCom_TX_data;
 
/*****************************
* Functions
*****************************/
 
void RBRF_handler(unsigned port);
 
void THRE_handler(unsigned port);
 
void LSR_handler(unsigned port);
 
void com_send_msg(unsigned port, BYTE len, BYTE *m);
 
void com_irq_sel(int no)
{
BYTE b;
unsigned i;
for(i=0;i<4;i++)
if (com_irq[i] == no) break;
 
b = DECODE(com_read(i, IIR));
 
switch (b)
{
case LS_CHANGED:
LSR_handler(i);
break;
case RX_FULL:
RBRF_handler(i);
break;
case TX_EMPTY:
THRE_handler(i);
break;
}
}
 
void com_irq_enable(unsigned port, unsigned irq)
{
SYS_FLAGS f;
f = kern_fsave();
 
com_read(port, LSR);
com_read(port, IIR);
com_write(port, IER, com_read(port, IER) | irq); /* Enable irq */
 
kern_frestore(f);
 
}
 
void com_irq_disable(unsigned port, unsigned irq)
{
 
SYS_FLAGS f;
f = kern_fsave();
 
com_read(port, LSR);
com_read(port, IIR);
com_write(port, IER, com_read(port, IER) & ~irq); /* Disable irq */
 
kern_frestore(f);
 
}
 
void com_end(unsigned port)
{
SYS_FLAGS f;
f = kern_fsave();
 
com_write(port, IER, 0);
com_read(port, LSR);
com_read(port, IIR);
com_close(port);
 
kern_frestore(f);
 
}
 
void com_init(unsigned port, DWORD speed, BYTE parity, BYTE len, BYTE stop)
{
SYS_FLAGS f;
 
f = kern_fsave();
 
com_open(port, speed, parity, len, stop);
SCom_Error = 0;
handler_set(com_irq[port], com_irq_sel, NIL, TRUE);
com_irq_disable(port, ALL_IRQ); /* Disable interrupts */
 
kern_frestore(f);
 
}
 
void com_set_functions(void (*confirm)(unsigned port, BYTE msg_status),void (*indication)(unsigned port, BYTE data))
{
SYS_FLAGS f;
 
f = kern_fsave();
 
SCom_Access.confirm = confirm;
SCom_Access.request = com_send_msg;
SCom_Access.indication = indication;
 
kern_frestore(f);
 
}
 
void com_send_msg(unsigned port, BYTE len, BYTE *m)
{
SYS_FLAGS f;
 
f = kern_fsave();
 
com_irq_disable(port, ALL_IRQ); /* Disable interrupts */
 
/* Transmit first byte of message */
SCom_TX_data.ptr = 0;
SCom_TX_data.len = len;
if (len < 100) {
memcpy(SCom_TX_data.buf, m, len);
com_write(port, THR, SCom_TX_data.buf[SCom_TX_data.ptr++]);
com_irq_enable(port, THRE_IRQ); /* Enable THRE */
}
 
kern_frestore(f);
 
}
 
void THRE_handler (unsigned port) /* Transmit Data Register Ready for next byte */
{
if (SCom_TX_data.ptr < SCom_TX_data.len)
com_write(port, THR, SCom_TX_data.buf[SCom_TX_data.ptr++]);
else
{
com_irq_disable(port, THRE_IRQ);
while((com_read(port,LSR) & bit6) == 0); /* Wait until last byte sent */
SCom_Access.confirm(port, COM_OK);
}
}
 
void RBRF_handler (unsigned port) /* Receive Data Register Full */
{
SCom_Access.indication(port, com_read(port, RBR));
}
 
void LSR_handler (unsigned port) /* break = 8, frame = 4, parity = 2, RBR overrun = 1*/
{
SCom_Error = (com_read(port, LSR) & (bit4|bit3|bit2|bit1) ) >> 1;
com_irq_disable(port, ALL_IRQ); /* Disable all interrupts */
SCom_Access.confirm(port, COM_ERROR);
}