1 |
/* |
2 |
* PearPC |
3 |
* serial.cc |
4 |
* |
5 |
* Copyright (C) 2005 Daniel Foesch (dfoesch@cs.nmsu.edu) |
6 |
* |
7 |
* Reverse Engineered from how OpenBIOS access the serial device |
8 |
* |
9 |
* This program is free software; you can redistribute it and/or modify |
10 |
* it under the terms of the GNU General Public License version 2 as |
11 |
* published by the Free Software Foundation. |
12 |
* |
13 |
* This program is distributed in the hope that it will be useful, |
14 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 |
* GNU General Public License for more details. |
17 |
* |
18 |
* You should have received a copy of the GNU General Public License |
19 |
* along with this program; if not, write to the Free Software |
20 |
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
21 |
*/ |
22 |
|
23 |
#include "debug/tracers.h" |
24 |
#include "system/arch/sysendian.h" |
25 |
#include "io/pci/pci.h" |
26 |
#include "serial.h" |
27 |
|
28 |
#include <cstring> |
29 |
|
30 |
#define SERIAL_DATA 0x00 |
31 |
#define SERIAL_INTR 0x01 |
32 |
#define SERIAL_INTR_ID 0x02 |
33 |
#define SERIAL_FORMAT 0x03 |
34 |
#define SERIAL_CONTROL_OUT 0x04 |
35 |
#define SERIAL_STATE 0x05 |
36 |
#define SERIAL_CONTROL_IN 0x06 |
37 |
#define SERIAL_SCRATCH 0x07 |
38 |
|
39 |
/* activate with FORMAT_DLAB: */ |
40 |
#define SERIAL_LATCH_LSB 0x00 |
41 |
#define SERIAL_LATCH_MSB 0x01 |
42 |
|
43 |
/* SERIAL_INTR flags */ |
44 |
#define INTR_RxRD 0x01 |
45 |
#define INTR_TBE 0x02 |
46 |
#define INTR_ERBK 0x04 |
47 |
#define INTR_SINP 0x08 |
48 |
|
49 |
/* SERIAL_INTR_ID flags */ |
50 |
#define INTR_PND 0x01 |
51 |
#define INTR_ID0 0x02 |
52 |
#define INTR_ID1 0x04 |
53 |
|
54 |
#define INTR_ID (ID0|ID1) |
55 |
#define INTR_INPUT_CHANGE (0) |
56 |
#define INTR_BUFFER_EMPTY (ID0) |
57 |
#define INTR_RECEIVED (ID1) |
58 |
#define INTR_ERR (ID0|ID1) |
59 |
|
60 |
/* SERIAL_FORMAT flags */ |
61 |
#define FORMAT_DATA 0x03 |
62 |
#define FORMAT_STOP 0x04 |
63 |
#define FORMAT_PARITY 0x38 |
64 |
#define FORMAT_BRK 0x40 |
65 |
#define FORMAT_DLAB 0x80 |
66 |
|
67 |
/* SERIAL_CONTROL_OUT */ |
68 |
#define OUT_DTR 0x01 |
69 |
#define OUT_RTS 0x02 |
70 |
#define OUT_1 0x04 |
71 |
#define OUT_2 0x08 |
72 |
#define OUT_LOOP 0x10 |
73 |
|
74 |
/* SERIAL_STATE */ |
75 |
#define STATE_RxRD 0x01 |
76 |
#define STATE_OVFL 0x02 |
77 |
#define STATE_PAR 0x04 |
78 |
#define STATE_FRM 0x08 |
79 |
#define STATE_BRK 0x10 |
80 |
#define STATE_TBE 0x20 |
81 |
#define STATE_TXE 0x40 |
82 |
|
83 |
/* SERIAL_CONTROL_IN */ |
84 |
#define IN_DCTS 0x01 |
85 |
#define IN_DDSR 0x02 |
86 |
#define IN_DRI 0x04 |
87 |
#define IN_DDCD 0x08 |
88 |
#define IN_CTS 0x10 |
89 |
#define IN_DSR 0x20 |
90 |
#define IN_RI 0x40 |
91 |
#define IN_DCD 0x80 |
92 |
|
93 |
extern bool gSinglestep; |
94 |
|
95 |
struct SerialState { |
96 |
uint8 intr; |
97 |
uint8 intr_id; |
98 |
uint8 format; |
99 |
uint8 scratch; |
100 |
}; |
101 |
|
102 |
/* |
103 |
* |
104 |
*/ |
105 |
class PCI_Serial: public PCI_Device { |
106 |
SerialState state; |
107 |
public: |
108 |
|
109 |
PCI_Serial() |
110 |
:PCI_Device("pci-serial", 0x01, 0x42) |
111 |
{ |
112 |
mIORegSize[0] = 0x0010; |
113 |
mIORegType[0] = PCI_ADDRESS_SPACE_IO; |
114 |
|
115 |
mConfig[0x00] = 0x00; // vendor ID |
116 |
mConfig[0x01] = 0x00; |
117 |
mConfig[0x02] = 0x00; // unit ID |
118 |
mConfig[0x03] = 0x00; |
119 |
|
120 |
mConfig[0x08] = 0x00; // revision |
121 |
mConfig[0x09] = 0x00; // |
122 |
mConfig[0x0a] = 0x00; // |
123 |
mConfig[0x0b] = 0x00; // |
124 |
|
125 |
mConfig[0x0e] = 0x00; // header-type |
126 |
|
127 |
assignIOPort(0, 0x000003f8); |
128 |
|
129 |
mConfig[0x3c] = 0x03; |
130 |
mConfig[0x3d] = 0x03; |
131 |
mConfig[0x3e] = 0x03; |
132 |
mConfig[0x3f] = 0x03; |
133 |
|
134 |
reset(); |
135 |
} |
136 |
|
137 |
void reset() |
138 |
{ |
139 |
memset(&state, 0, sizeof state); |
140 |
} |
141 |
|
142 |
static const char *a2n(int a) |
143 |
{ |
144 |
if (a <= 0x7) { |
145 |
static const char *n[] = {"data", "intr", "intr_id", "format", "ctrlout", "state", "ctrlin", "scratch"}; |
146 |
return n[a]; |
147 |
} else { |
148 |
static char bl[10]; |
149 |
sprintf(bl, "%08x", a); |
150 |
} |
151 |
} |
152 |
|
153 |
virtual bool readDeviceIO(uint r, uint32 address, uint32 &data, uint size) |
154 |
{ |
155 |
IO_SERIAL_TRACE("read(r=%d, a=%s, %d)\n", r, a2n(address), size); |
156 |
if (r != 0) return false; |
157 |
if (size != 1) return false; |
158 |
|
159 |
if ((state.format & FORMAT_DLAB) && !(address & 0xe)) { |
160 |
switch (address) { |
161 |
case SERIAL_LATCH_LSB: |
162 |
case SERIAL_LATCH_MSB:; |
163 |
} |
164 |
return false; |
165 |
} |
166 |
|
167 |
switch (address) { |
168 |
case SERIAL_DATA: |
169 |
data = 0; |
170 |
return true; |
171 |
case SERIAL_INTR: |
172 |
data = state.intr & 0x0f; |
173 |
return true; |
174 |
case SERIAL_INTR_ID: |
175 |
data = state.intr_id & 0x07; |
176 |
return true; |
177 |
case SERIAL_FORMAT: |
178 |
data = state.format; |
179 |
return true; |
180 |
case SERIAL_CONTROL_OUT: |
181 |
return true; |
182 |
case SERIAL_STATE: |
183 |
return true; |
184 |
case SERIAL_CONTROL_IN: |
185 |
return true; |
186 |
case SERIAL_SCRATCH: |
187 |
data = state.scratch; |
188 |
return true; |
189 |
default: |
190 |
return false; |
191 |
} |
192 |
|
193 |
// gSinglestep = true; |
194 |
return true; |
195 |
} |
196 |
|
197 |
virtual bool writeDeviceIO(uint r, uint32 address, uint32 data, uint size) |
198 |
{ |
199 |
IO_SERIAL_TRACE("write(r=%d, a=%s, data=%08x, %d)\n", r, a2n(address), data, size); |
200 |
if (r != 0) return false; |
201 |
if (size != 1) return false; |
202 |
|
203 |
if ((state.format & FORMAT_DLAB) && !(address & 0xe)) { |
204 |
switch (address) { |
205 |
case SERIAL_LATCH_LSB: |
206 |
case SERIAL_LATCH_MSB:; |
207 |
} |
208 |
return false; |
209 |
} |
210 |
|
211 |
switch (address) { |
212 |
case SERIAL_DATA: |
213 |
ht_printf("%c\n", data); |
214 |
// gDisplay->printf("%c", data); |
215 |
break; |
216 |
case SERIAL_INTR: |
217 |
state.intr = data; |
218 |
return true; |
219 |
case SERIAL_INTR_ID: |
220 |
state.intr_id = data; |
221 |
return true; |
222 |
case SERIAL_FORMAT: |
223 |
return true; |
224 |
case SERIAL_CONTROL_OUT: |
225 |
return true; |
226 |
case SERIAL_STATE: |
227 |
return true; |
228 |
case SERIAL_CONTROL_IN: |
229 |
return true; |
230 |
case SERIAL_SCRATCH: |
231 |
state.scratch = data; |
232 |
return true; |
233 |
default: |
234 |
return false; |
235 |
} |
236 |
|
237 |
// gSinglestep = true; |
238 |
return true; |
239 |
} |
240 |
|
241 |
}; |
242 |
|
243 |
|
244 |
#include "configparser.h" |
245 |
|
246 |
#define SERIAL_KEY_INSTALLED "pci_serial_installed" |
247 |
|
248 |
void serial_init() |
249 |
{ |
250 |
if (gConfig->getConfigInt(SERIAL_KEY_INSTALLED)) { |
251 |
gPCI_Devices->insert(new PCI_Serial()); |
252 |
} |
253 |
} |
254 |
|
255 |
void serial_done() |
256 |
{ |
257 |
} |
258 |
|
259 |
void serial_init_config() |
260 |
{ |
261 |
gConfig->acceptConfigEntryIntDef(SERIAL_KEY_INSTALLED, 0); |
262 |
} |