/[gxemul]/upstream/0.3.1/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.1/devices/dev_dc7085.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Mon Oct 8 16:17:52 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 9005 byte(s)
0.3.1
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.49 2005/02/22 20:18:30 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 idata = memory_readmax64(cpu, data, len);
176
177 /* Always clear: */
178 d->regs.dc_csr &= ~CSR_CLR;
179
180 switch (relative_addr) {
181 case 0x00: /* CSR: Control and Status */
182 if (writeflag == MEM_WRITE) {
183 debug("[ dc7085 write to CSR: 0x%04x ]\n", idata);
184 idata &= (CSR_TIE | CSR_RIE | CSR_MSE | CSR_CLR
185 | CSR_MAINT);
186 d->regs.dc_csr &= ~(CSR_TIE | CSR_RIE | CSR_MSE
187 | CSR_CLR | CSR_MAINT);
188 d->regs.dc_csr |= idata;
189 if (!(d->regs.dc_csr & CSR_MSE))
190 d->regs.dc_csr &= ~(CSR_TRDY | CSR_RDONE);
191 goto do_return;
192 } else {
193 /* read: */
194
195 /* fatal("[ dc7085 read from CSR: (csr = 0x%04x) ]\n",
196 d->regs.dc_csr); */
197 odata = d->regs.dc_csr;
198 }
199 break;
200 case 0x08: /* LPR: */
201 if (writeflag == MEM_WRITE) {
202 debug("[ dc7085 write to LPR: 0x%04x ]\n", idata);
203 d->regs.dc_rbuf_lpr = idata;
204 goto do_return;
205 } else {
206 /* read: */
207 int avail = d->cur_rx_queue_pos_write !=
208 d->cur_rx_queue_pos_read;
209 int ch = 0, lineno = 0;
210 /* debug("[ dc7085 read from RBUF: "); */
211 if (avail) {
212 ch = d->rx_queue_char[d->cur_rx_queue_pos_read];
213 lineno = d->rx_queue_lineno[
214 d->cur_rx_queue_pos_read];
215 d->cur_rx_queue_pos_read++;
216 if (d->cur_rx_queue_pos_read == MAX_QUEUE_LEN)
217 d->cur_rx_queue_pos_read = 0;
218 /* if (ch >= ' ' && ch < 127)
219 debug("'%c'", ch);
220 else
221 debug("0x%x", ch);
222 debug(" for lineno %i ", lineno); */
223 } /* else
224 debug("empty ");
225 debug("]\n"); */
226 odata = (avail? RBUF_DVAL:0) |
227 (lineno << RBUF_LINE_NUM_SHIFT) | ch;
228
229 d->regs.dc_csr &= ~CSR_RDONE;
230 cpu_interrupt_ack(cpu, d->irqnr);
231
232 d->just_transmitted_something = 4;
233 }
234 break;
235 case 0x10: /* TCR: */
236 if (writeflag == MEM_WRITE) {
237 /* fatal("[ dc7085 write to TCR: 0x%04x) ]\n",
238 (int)idata); */
239 d->regs.dc_tcr = idata;
240 d->regs.dc_csr &= ~CSR_TRDY;
241 cpu_interrupt_ack(cpu, d->irqnr);
242 goto do_return;
243 } else {
244 /* read: */
245 /* debug("[ dc7085 read from TCR: (tcr = 0x%04x) ]\n",
246 d->regs.dc_tcr); */
247 odata = d->regs.dc_tcr;
248 }
249 break;
250 case 0x18: /* Modem status (R), transmit data (W) */
251 if (writeflag == MEM_WRITE) {
252 int line_no = (d->regs.dc_csr >>
253 RBUF_LINE_NUM_SHIFT) & 0x3;
254 idata &= 0xff;
255
256 lk201_tx_data(&d->lk201, line_no, idata);
257
258 d->regs.dc_csr &= ~CSR_TRDY;
259 cpu_interrupt_ack(cpu, d->irqnr);
260
261 d->just_transmitted_something = 4;
262 } else {
263 /* read: */
264 d->regs.dc_msr_tdr |= MSR_DSR2 | MSR_CD2 |
265 MSR_DSR3 | MSR_CD3;
266 debug("[ dc7085 read from MSR: (msr_tdr = 0x%04x) ]\n",
267 d->regs.dc_msr_tdr);
268 odata = d->regs.dc_msr_tdr;
269 }
270 break;
271 default:
272 if (writeflag==MEM_READ) {
273 debug("[ dc7085 read from 0x%08lx ]\n",
274 (long)relative_addr);
275 } else {
276 debug("[ dc7085 write to 0x%08lx:",
277 (long)relative_addr);
278 for (i=0; i<len; i++)
279 debug(" %02x", data[i]);
280 debug(" ]\n");
281 }
282 }
283
284 if (writeflag == MEM_READ)
285 memory_writemax64(cpu, data, len, odata);
286
287 do_return:
288 dev_dc7085_tick(cpu, extra);
289
290 return 1;
291 }
292
293
294 /*
295 * dev_dc7085_init():
296 *
297 * Initialize a dc7085 serial controller device. use_fb should be non-zero
298 * if a framebuffer device is used. Channel 0 will then be treated as a
299 * DECstation keyboard, instead of a plain serial console.
300 */
301 int dev_dc7085_init(struct machine *machine, struct memory *mem,
302 uint64_t baseaddr, int irq_nr, int use_fb)
303 {
304 struct dc_data *d;
305
306 d = malloc(sizeof(struct dc_data));
307 if (d == NULL) {
308 fprintf(stderr, "out of memory\n");
309 exit(1);
310 }
311 memset(d, 0, sizeof(struct dc_data));
312 d->irqnr = irq_nr;
313 d->use_fb = use_fb;
314
315 d->regs.dc_csr = CSR_TRDY | CSR_MSE;
316 d->regs.dc_tcr = 0x00;
317
318 d->console_handle = console_start_slave(machine, "DC7085");
319
320 lk201_init(&d->lk201, use_fb, add_to_rx_queue, d->console_handle, d);
321
322 memory_device_register(mem, "dc7085", baseaddr, DEV_DC7085_LENGTH,
323 dev_dc7085_access, d, MEM_DEFAULT, NULL);
324 machine_add_tickfunction(machine, dev_dc7085_tick, d, DC_TICK_SHIFT);
325
326 return d->console_handle;
327 }
328

  ViewVC Help
Powered by ViewVC 1.1.26