-
Notifications
You must be signed in to change notification settings - Fork 16
/
serial.c
138 lines (123 loc) · 3.37 KB
/
serial.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
/*
* Copyright 2009 by Brian Dominy <brian@oddchange.com>
*
* This file is part of GCC6809.
*
* GCC6809 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.
*
* GCC6809 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 GCC6809; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include "machine.h"
/* Emulate a serial port. Basically this driver can be used for any byte-at-a-time
input/output interface. */
struct serial_port
{
unsigned int ctrl;
unsigned int status;
int fin;
int fout;
};
/* The I/O registers exposed by this driver */
#define SER_DATA 0 /* Data input/output */
#define SER_CTL_STATUS 1 /* Control (write) and status (read) */
#define SER_CTL_ASYNC 0x1 /* Enable async mode (more realistic) */
#define SER_CTL_RESET 0x2 /* Reset device */
#define SER_STAT_READOK 0x1
#define SER_STAT_WRITEOK 0x2
void serial_update (struct serial_port *port)
{
fd_set infds, outfds;
struct timeval timeout;
int rc;
FD_ZERO (&infds);
FD_SET (port->fin, &infds);
FD_ZERO (&outfds);
FD_SET (port->fout, &outfds);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
rc = select (2, &infds, &outfds, NULL, &timeout);
if (FD_ISSET (port->fin, &infds))
port->status |= SER_STAT_READOK;
else
port->status &= ~SER_STAT_READOK;
if (FD_ISSET (port->fout, &outfds))
port->status |= SER_STAT_WRITEOK;
else
port->status &= ~SER_STAT_WRITEOK;
}
U8 serial_read (struct hw_device *dev, unsigned long addr)
{
struct serial_port *port = (struct serial_port *)dev->priv;
serial_update (port);
switch (addr)
{
case SER_DATA:
{
U8 val;
if (!(port->status & SER_STAT_READOK))
return 0xFF;
read (port->fin, &val, 1);
return val;
}
case SER_CTL_STATUS:
return port->status;
}
}
void serial_write (struct hw_device *dev, unsigned long addr, U8 val)
{
struct serial_port *port = (struct serial_port *)dev->priv;
switch (addr)
{
case SER_DATA:
{
U8 v = val;
write (port->fout, &v, 1);
break;
}
case SER_CTL_STATUS:
port->ctrl = val;
break;
}
}
void serial_reset (struct hw_device *dev)
{
struct serial_port *port = (struct serial_port *)dev->priv;
port->ctrl = 0;
port->status = 0;
}
struct hw_class serial_class =
{
.readonly = 0,
.reset = serial_reset,
.read = serial_read,
.write = serial_write,
};
extern U8 null_read (struct hw_device *dev, unsigned long addr);
struct hw_device *serial_create (void)
{
struct serial_port *port = malloc (sizeof (struct serial_port));
port->fin = STDIN_FILENO;
port->fout = STDOUT_FILENO;
return device_attach (&serial_class, 4, port);
}
struct hw_device *hostfile_create (const char *filename, int flags)
{
struct serial_port *port = malloc (sizeof (struct serial_port));
port->fin = port->fout = open (filename, O_CREAT | flags);
return device_attach (&serial_class, 4, port);
}