/[gxemul]/upstream/0.3.6.2/src/devices/dev_dc7085.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /upstream/0.3.6.2/src/devices/dev_dc7085.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 19 - (show annotations)
Mon Oct 8 16:19:16 2007 UTC (16 years, 8 months ago) by dpavlin
File MIME type: text/plain
File size: 9035 byte(s)
0.3.6.2
1 /*
2 * Copyright (C) 2003-2005 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 * $Id: dev_dc7085.c,v 1.50 2005/10/26 14:37:03 debug Exp $
29 *
30 * DC7085 serial controller, used in some DECstation models.
31 */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "console.h"
38 #include "cpu.h"
39 #include "devices.h"
40 #include "machine.h"
41 #include "memory.h"
42 #include "misc.h"
43
44 #include "dc7085.h"
45
46
47 #define DC_TICK_SHIFT 14
48
49 #define MAX_QUEUE_LEN 4096
50
51 struct dc_data {
52 struct dc7085regs regs;
53
54 int console_handle;
55
56 /* For slow_serial_interrupts_hack_for_linux: */
57 int just_transmitted_something;
58
59 unsigned char rx_queue_char[MAX_QUEUE_LEN];
60 char rx_queue_lineno[MAX_QUEUE_LEN];
61 int cur_rx_queue_pos_write;
62 int cur_rx_queue_pos_read;
63
64 int tx_scanner;
65
66 int irqnr;
67 int use_fb;
68
69 struct lk201_data lk201;
70 };
71
72
73 /*
74 * Add a character to the receive queue.
75 */
76 void add_to_rx_queue(void *e, int ch, int line_no)
77 {
78 struct dc_data *d = (struct dc_data *) e;
79 int entries_in_use = d->cur_rx_queue_pos_write -
80 d->cur_rx_queue_pos_read;
81 while (entries_in_use < 0)
82 entries_in_use += MAX_QUEUE_LEN;
83
84 /* Ignore mouse updates, if they come too often: */
85 if (entries_in_use > MAX_QUEUE_LEN/2 && line_no == DCMOUSE_PORT)
86 return;
87
88 d->rx_queue_char[d->cur_rx_queue_pos_write] = ch;
89 d->rx_queue_lineno[d->cur_rx_queue_pos_write] = line_no;
90 d->cur_rx_queue_pos_write ++;
91 if (d->cur_rx_queue_pos_write == MAX_QUEUE_LEN)
92 d->cur_rx_queue_pos_write = 0;
93
94 if (d->cur_rx_queue_pos_write == d->cur_rx_queue_pos_read)
95 fatal("warning: add_to_rx_queue(): rx_queue overrun!\n");
96 }
97
98
99 /*
100 * dev_dc7085_tick():
101 *
102 * This function is called "every now and then".
103 * If a key is available from the keyboard, add it to the rx queue.
104 * If other bits are set, an interrupt might need to be caused.
105 */
106 void dev_dc7085_tick(struct cpu *cpu, void *extra)
107 {
108 struct dc_data *d = extra;
109 int avail;
110
111 if (cpu->machine->slow_serial_interrupts_hack_for_linux) {
112 /*
113 * Special hack to prevent Linux from Oopsing. (This makes
114 * interrupts not come as fast as possible.)
115 */
116 if (d->just_transmitted_something) {
117 d->just_transmitted_something --;
118 return;
119 }
120 }
121
122 d->regs.dc_csr &= ~CSR_RDONE;
123
124 if ((d->regs.dc_csr & CSR_MSE) && !(d->regs.dc_csr & CSR_TRDY)) {
125 int scanner_start = d->tx_scanner;
126
127 /* Loop until we've checked all 4 channels, or some
128 channel was ready to transmit: */
129
130 do {
131 d->tx_scanner = (d->tx_scanner + 1) % 4;
132
133 if (d->regs.dc_tcr & (1 << d->tx_scanner)) {
134 d->regs.dc_csr |= CSR_TRDY;
135 if (d->regs.dc_csr & CSR_TIE)
136 cpu_interrupt(cpu, d->irqnr);
137
138 d->regs.dc_csr &= ~CSR_TX_LINE_NUM;
139 d->regs.dc_csr |= (d->tx_scanner << 8);
140 }
141 } while (!(d->regs.dc_csr & CSR_TRDY) &&
142 d->tx_scanner != scanner_start);
143
144 /* We have to return here. NetBSD can handle both
145 rx and tx interrupts simultaneously, but Ultrix
146 doesn't like that? */
147
148 if (d->regs.dc_csr & CSR_TRDY)
149 return;
150 }
151
152 lk201_tick(&d->lk201);
153
154 avail = d->cur_rx_queue_pos_write != d->cur_rx_queue_pos_read;
155
156 if (avail && (d->regs.dc_csr & CSR_MSE))
157 d->regs.dc_csr |= CSR_RDONE;
158
159 if ((d->regs.dc_csr & CSR_RDONE) && (d->regs.dc_csr & CSR_RIE))
160 cpu_interrupt(cpu, d->irqnr);
161 }
162
163
164 /*
165 * dev_dc7085_access():
166 */
167 int dev_dc7085_access(struct cpu *cpu, struct memory *mem,
168 uint64_t relative_addr, unsigned char *data, size_t len,
169 int writeflag, void *extra)
170 {
171 uint64_t idata = 0, odata = 0;
172 int i;
173 struct dc_data *d = extra;
174
175 if (writeflag == MEM_WRITE)
176 idata = memory_readmax64(cpu, data, len);
177
178 /* Always clear: */
179 d->regs.dc_csr &= ~CSR_CLR;
180
181 switch (relative_addr) {
182 case 0x00: /* CSR: Control and Status */
183 if (writeflag == MEM_WRITE) {
184 debug("[ dc7085 write to CSR: 0x%04x ]\n", idata);
185 idata &= (CSR_TIE | CSR_RIE | CSR_MSE | CSR_CLR
186 | CSR_MAINT);
187 d->regs.dc_csr &= ~(CSR_TIE | CSR_RIE | CSR_MSE
188 | CSR_CLR | CSR_MAINT);
189 d->regs.dc_csr |= idata;
190 if (!(d->regs.dc_csr & CSR_MSE))
191 d->regs.dc_csr &= ~(CSR_TRDY | CSR_RDONE);
192 goto do_return;
193 } else {
194 /* read: */
195
196 /* fatal("[ dc7085 read from CSR: (csr = 0x%04x) ]\n",
197 d->regs.dc_csr); */
198 odata = d->regs.dc_csr;
199 }
200 break;
201 case 0x08: /* LPR: */
202 if (writeflag == MEM_WRITE) {
203 debug("[ dc7085 write to LPR: 0x%04x ]\n", idata);
204 d->regs.dc_rbuf_lpr = idata;
205 goto do_return;
206 } else {
207 /* read: */
208 int avail = d->cur_rx_queue_pos_write !=
209 d->cur_rx_queue_pos_read;
210 int ch = 0, lineno = 0;
211 /* debug("[ dc7085 read from RBUF: "); */
212 if (avail) {
213 ch = d->rx_queue_char[d->cur_rx_queue_pos_read];
214 lineno = d->rx_queue_lineno[
215 d->cur_rx_queue_pos_read];
216 d->cur_rx_queue_pos_read++;
217 if (d->cur_rx_queue_pos_read == MAX_QUEUE_LEN)
218 d->cur_rx_queue_pos_read = 0;
219 /* if (ch >= ' ' && ch < 127)
220 debug("'%c'", ch);
221 else
222 debug("0x%x", ch);
223 debug(" for lineno %i ", lineno); */
224 } /* else
225 debug("empty ");
226 debug("]\n"); */
227 odata = (avail? RBUF_DVAL:0) |
228 (lineno << RBUF_LINE_NUM_SHIFT) | ch;
229
230 d->regs.dc_csr &= ~CSR_RDONE;
231 cpu_interrupt_ack(cpu, d->irqnr);
232
233 d->just_transmitted_something = 4;
234 }
235 break;
236 case 0x10: /* TCR: */
237 if (writeflag == MEM_WRITE) {
238 /* fatal("[ dc7085 write to TCR: 0x%04x) ]\n",
239 (int)idata); */
240 d->regs.dc_tcr = idata;
241 d->regs.dc_csr &= ~CSR_TRDY;
242 cpu_interrupt_ack(cpu, d->irqnr);
243 goto do_return;
244 } else {
245 /* read: */
246 /* debug("[ dc7085 read from TCR: (tcr = 0x%04x) ]\n",
247 d->regs.dc_tcr); */
248 odata = d->regs.dc_tcr;
249 }
250 break;
251 case 0x18: /* Modem status (R), transmit data (W) */
252 if (writeflag == MEM_WRITE) {
253 int line_no = (d->regs.dc_csr >>
254 RBUF_LINE_NUM_SHIFT) & 0x3;
255 idata &= 0xff;
256
257 lk201_tx_data(&d->lk201, line_no, idata);
258
259 d->regs.dc_csr &= ~CSR_TRDY;
260 cpu_interrupt_ack(cpu, d->irqnr);
261
262 d->just_transmitted_something = 4;
263 } else {
264 /* read: */
265 d->regs.dc_msr_tdr |= MSR_DSR2 | MSR_CD2 |
266 MSR_DSR3 | MSR_CD3;
267 debug("[ dc7085 read from MSR: (msr_tdr = 0x%04x) ]\n",
268 d->regs.dc_msr_tdr);
269 odata = d->regs.dc_msr_tdr;
270 }
271 break;
272 default:
273 if (writeflag==MEM_READ) {
274 debug("[ dc7085 read from 0x%08lx ]\n",
275 (long)relative_addr);
276 } else {
277 debug("[ dc7085 write to 0x%08lx:",
278 (long)relative_addr);
279 for (i=0; i<len; i++)
280 debug(" %02x", data[i]);
281 debug(" ]\n");
282 }
283 }
284
285 if (writeflag == MEM_READ)
286 memory_writemax64(cpu, data, len, odata);
287
288 do_return:
289 dev_dc7085_tick(cpu, extra);
290
291 return 1;
292 }
293
294
295 /*
296 * dev_dc7085_init():
297 *
298 * Initialize a dc7085 serial controller device. use_fb should be non-zero
299 * if a framebuffer device is used. Channel 0 will then be treated as a
300 * DECstation keyboard, instead of a plain serial console.
301 */
302 int dev_dc7085_init(struct machine *machine, struct memory *mem,
303 uint64_t baseaddr, int irq_nr, int use_fb)
304 {
305 struct dc_data *d;
306
307 d = malloc(sizeof(struct dc_data));
308 if (d == NULL) {
309 fprintf(stderr, "out of memory\n");
310 exit(1);
311 }
312 memset(d, 0, sizeof(struct dc_data));
313 d->irqnr = irq_nr;
314 d->use_fb = use_fb;
315
316 d->regs.dc_csr = CSR_TRDY | CSR_MSE;
317 d->regs.dc_tcr = 0x00;
318
319 d->console_handle = console_start_slave(machine, "DC7085");
320
321 lk201_init(&d->lk201, use_fb, add_to_rx_queue, d->console_handle, d);
322
323 memory_device_register(mem, "dc7085", baseaddr, DEV_DC7085_LENGTH,
324 dev_dc7085_access, d, MEM_DEFAULT, NULL);
325 machine_add_tickfunction(machine, dev_dc7085_tick, d, DC_TICK_SHIFT);
326
327 return d->console_handle;
328 }
329

  ViewVC Help
Powered by ViewVC 1.1.26