1 /*
2 * Copyright (C) 2003-2009 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * COMMENT: DC7085 serial controller, used in some DECstation models
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "console.h"
36 #include "cpu.h"
37 #include "devices.h"
38 #include "machine.h"
39 #include "memory.h"
40 #include "misc.h"
41
42 #include "thirdparty/dc7085.h"
43
44
45 #define DC_TICK_SHIFT 14
46
47 #define MAX_QUEUE_LEN 32768
48
49 struct dc_data {
50 struct dc7085regs regs;
51
52 int console_handle;
53
54 /* For slow_serial_interrupts_hack_for_linux: */
55 int just_transmitted_something;
56
57 unsigned char rx_queue_char[MAX_QUEUE_LEN];
58 char rx_queue_lineno[MAX_QUEUE_LEN];
59 int cur_rx_queue_pos_write;
60 int cur_rx_queue_pos_read;
61
62 int tx_scanner;
63
64 struct interrupt irq;
65 int use_fb;
66
67 struct lk201_data lk201;
68 };
69
70
71 /*
72 * Add a character to the receive queue.
73 */
add_to_rx_queue(void * e,int ch,int line_no)74 void add_to_rx_queue(void *e, int ch, int line_no)
75 {
76 struct dc_data *d = (struct dc_data *) e;
77 int entries_in_use = d->cur_rx_queue_pos_write -
78 d->cur_rx_queue_pos_read;
79
80 while (entries_in_use < 0)
81 entries_in_use += MAX_QUEUE_LEN;
82
83 /* Ignore mouse updates, if they come too often: */
84 if (entries_in_use > MAX_QUEUE_LEN/2 && line_no == DCMOUSE_PORT)
85 return;
86
87 d->rx_queue_char[d->cur_rx_queue_pos_write] = ch;
88 d->rx_queue_lineno[d->cur_rx_queue_pos_write] = line_no;
89 d->cur_rx_queue_pos_write ++;
90 if (d->cur_rx_queue_pos_write == MAX_QUEUE_LEN)
91 d->cur_rx_queue_pos_write = 0;
92
93 if (d->cur_rx_queue_pos_write == d->cur_rx_queue_pos_read)
94 fatal("warning: add_to_rx_queue(): rx_queue overrun!\n");
95 }
96
97
DEVICE_TICK(dc7085)98 DEVICE_TICK(dc7085)
99 {
100 /*
101 * If a key is available from the keyboard, add it to the rx queue.
102 * If other bits are set, an interrupt might need to be caused.
103 */
104 struct dc_data *d = (struct dc_data *) extra;
105 int avail;
106
107 if (cpu->machine->slow_serial_interrupts_hack_for_linux) {
108 /*
109 * Special hack to prevent Linux from Oopsing. (This makes
110 * interrupts not come as fast as possible.)
111 */
112 if (d->just_transmitted_something) {
113 d->just_transmitted_something --;
114 return;
115 }
116 }
117
118 d->regs.dc_csr &= ~CSR_RDONE;
119
120 if ((d->regs.dc_csr & CSR_MSE) && !(d->regs.dc_csr & CSR_TRDY)) {
121 int scanner_start = d->tx_scanner;
122
123 /* Loop until we've checked all 4 channels, or some
124 channel was ready to transmit: */
125
126 do {
127 d->tx_scanner = (d->tx_scanner + 1) % 4;
128
129 if (d->regs.dc_tcr & (1 << d->tx_scanner)) {
130 d->regs.dc_csr |= CSR_TRDY;
131 if (d->regs.dc_csr & CSR_TIE)
132 INTERRUPT_ASSERT(d->irq);
133
134 d->regs.dc_csr &= ~CSR_TX_LINE_NUM;
135 d->regs.dc_csr |= (d->tx_scanner << 8);
136 }
137 } while (!(d->regs.dc_csr & CSR_TRDY) &&
138 d->tx_scanner != scanner_start);
139
140 /* We have to return here. NetBSD can handle both
141 rx and tx interrupts simultaneously, but Ultrix
142 doesn't like that? */
143
144 if (d->regs.dc_csr & CSR_TRDY)
145 return;
146 }
147
148 lk201_tick(cpu->machine, &d->lk201);
149
150 avail = d->cur_rx_queue_pos_write != d->cur_rx_queue_pos_read;
151
152 if (avail && (d->regs.dc_csr & CSR_MSE))
153 d->regs.dc_csr |= CSR_RDONE;
154
155 if ((d->regs.dc_csr & CSR_RDONE) && (d->regs.dc_csr & CSR_RIE))
156 INTERRUPT_ASSERT(d->irq);
157 }
158
159
DEVICE_ACCESS(dc7085)160 DEVICE_ACCESS(dc7085)
161 {
162 struct dc_data *d = (struct dc_data *) extra;
163 uint64_t idata = 0, odata = 0;
164 size_t i;
165
166 if (writeflag == MEM_WRITE)
167 idata = memory_readmax64(cpu, data, len);
168
169 /* Always clear: */
170 d->regs.dc_csr &= ~CSR_CLR;
171
172 switch (relative_addr) {
173
174 case 0x00: /* CSR: Control and Status */
175 if (writeflag == MEM_WRITE) {
176 debug("[ dc7085 write to CSR: 0x%04x ]\n", idata);
177 idata &= (CSR_TIE | CSR_RIE | CSR_MSE | CSR_CLR
178 | CSR_MAINT);
179 d->regs.dc_csr &= ~(CSR_TIE | CSR_RIE | CSR_MSE
180 | CSR_CLR | CSR_MAINT);
181 d->regs.dc_csr |= idata;
182 if (!(d->regs.dc_csr & CSR_MSE))
183 d->regs.dc_csr &= ~(CSR_TRDY | CSR_RDONE);
184 goto do_return;
185 } else {
186 /* read: */
187
188 /* fatal("[ dc7085 read from CSR: (csr = 0x%04x) ]\n",
189 d->regs.dc_csr); */
190 odata = d->regs.dc_csr;
191 }
192 break;
193
194 case 0x08: /* LPR: */
195 if (writeflag == MEM_WRITE) {
196 debug("[ dc7085 write to LPR: 0x%04x ]\n", idata);
197 d->regs.dc_rbuf_lpr = idata;
198 goto do_return;
199 } else {
200 /* read: */
201 int avail = d->cur_rx_queue_pos_write !=
202 d->cur_rx_queue_pos_read;
203 int ch = 0, lineno = 0;
204 /* debug("[ dc7085 read from RBUF: "); */
205 if (avail) {
206 ch = d->rx_queue_char[d->cur_rx_queue_pos_read];
207 lineno = d->rx_queue_lineno[
208 d->cur_rx_queue_pos_read];
209 d->cur_rx_queue_pos_read++;
210 if (d->cur_rx_queue_pos_read == MAX_QUEUE_LEN)
211 d->cur_rx_queue_pos_read = 0;
212 /* if (ch >= ' ' && ch < 127)
213 debug("'%c'", ch);
214 else
215 debug("0x%x", ch);
216 debug(" for lineno %i ", lineno); */
217 } /* else
218 debug("empty ");
219 debug("]\n"); */
220 odata = (avail? RBUF_DVAL:0) |
221 (lineno << RBUF_LINE_NUM_SHIFT) | ch;
222
223 d->regs.dc_csr &= ~CSR_RDONE;
224 INTERRUPT_DEASSERT(d->irq);
225
226 d->just_transmitted_something = 4;
227 }
228 break;
229
230 case 0x10: /* TCR: */
231 if (writeflag == MEM_WRITE) {
232 /* fatal("[ dc7085 write to TCR: 0x%04x) ]\n",
233 (int)idata); */
234 d->regs.dc_tcr = idata;
235 d->regs.dc_csr &= ~CSR_TRDY;
236 INTERRUPT_DEASSERT(d->irq);
237 goto do_return;
238 } else {
239 /* read: */
240 /* debug("[ dc7085 read from TCR: (tcr = 0x%04x) ]\n",
241 d->regs.dc_tcr); */
242 odata = d->regs.dc_tcr;
243 }
244 break;
245
246 case 0x18: /* Modem status (R), transmit data (W) */
247 if (writeflag == MEM_WRITE) {
248 int line_no = (d->regs.dc_csr >>
249 RBUF_LINE_NUM_SHIFT) & 0x3;
250 idata &= 0xff;
251
252 lk201_tx_data(&d->lk201, line_no, idata);
253
254 d->regs.dc_csr &= ~CSR_TRDY;
255 INTERRUPT_DEASSERT(d->irq);
256
257 d->just_transmitted_something = 4;
258 } else {
259 /* read: */
260 d->regs.dc_msr_tdr |= MSR_DSR2 | MSR_CD2 |
261 MSR_DSR3 | MSR_CD3;
262 debug("[ dc7085 read from MSR: (msr_tdr = 0x%04x) ]\n",
263 d->regs.dc_msr_tdr);
264 odata = d->regs.dc_msr_tdr;
265 }
266 break;
267
268 default:
269 if (writeflag==MEM_READ) {
270 debug("[ dc7085 read from 0x%08lx ]\n",
271 (long)relative_addr);
272 } else {
273 debug("[ dc7085 write to 0x%08lx:",
274 (long)relative_addr);
275 for (i=0; i<len; i++)
276 debug(" %02x", data[i]);
277 debug(" ]\n");
278 }
279 }
280
281 if (writeflag == MEM_READ)
282 memory_writemax64(cpu, data, len, odata);
283
284 do_return:
285 dev_dc7085_tick(cpu, extra);
286
287 return 1;
288 }
289
290
291 /*
292 * dev_dc7085_init():
293 *
294 * Initialize a dc7085 serial controller device. use_fb should be non-zero
295 * if a framebuffer device is used. Channel 0 will then be treated as a
296 * DECstation keyboard, instead of a plain serial console.
297 */
dev_dc7085_init(struct machine * machine,struct memory * mem,uint64_t baseaddr,char * irq_path,int use_fb)298 int dev_dc7085_init(struct machine *machine, struct memory *mem,
299 uint64_t baseaddr, char *irq_path, int use_fb)
300 {
301 struct dc_data *d;
302
303 CHECK_ALLOCATION(d = (struct dc_data *) malloc(sizeof(struct dc_data)));
304 memset(d, 0, sizeof(struct dc_data));
305
306 INTERRUPT_CONNECT(irq_path, d->irq);
307 d->use_fb = use_fb;
308
309 d->regs.dc_csr = CSR_TRDY | CSR_MSE;
310 d->regs.dc_tcr = 0x00;
311
312 d->console_handle = console_start_slave(machine, "DC7085", 1);
313
314 lk201_init(&d->lk201, use_fb, add_to_rx_queue, d->console_handle, d);
315
316 memory_device_register(mem, "dc7085", baseaddr, DEV_DC7085_LENGTH,
317 dev_dc7085_access, d, DM_DEFAULT, NULL);
318 machine_add_tickfunction(machine, dev_dc7085_tick, d,
319 DC_TICK_SHIFT);
320
321 return d->console_handle;
322 }
323
324