/[gxemul]/upstream/0.4.6/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.4.6/src/devices/dev_dc7085.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 43 - (show annotations)
Mon Oct 8 16:22:43 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 8768 byte(s)
0.4.6
1 /*
2 * Copyright (C) 2003-2007 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.62 2007/06/15 18:44:19 debug Exp $
29 *
30 * COMMENT: 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 32768
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 struct interrupt irq;
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
82 while (entries_in_use < 0)
83 entries_in_use += MAX_QUEUE_LEN;
84
85 /* Ignore mouse updates, if they come too often: */
86 if (entries_in_use > MAX_QUEUE_LEN/2 && line_no == DCMOUSE_PORT)
87 return;
88
89 d->rx_queue_char[d->cur_rx_queue_pos_write] = ch;
90 d->rx_queue_lineno[d->cur_rx_queue_pos_write] = line_no;
91 d->cur_rx_queue_pos_write ++;
92 if (d->cur_rx_queue_pos_write == MAX_QUEUE_LEN)
93 d->cur_rx_queue_pos_write = 0;
94
95 if (d->cur_rx_queue_pos_write == d->cur_rx_queue_pos_read)
96 fatal("warning: add_to_rx_queue(): rx_queue overrun!\n");
97 }
98
99
100 DEVICE_TICK(dc7085)
101 {
102 /*
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 struct dc_data *d = extra;
107 int avail;
108
109 if (cpu->machine->slow_serial_interrupts_hack_for_linux) {
110 /*
111 * Special hack to prevent Linux from Oopsing. (This makes
112 * interrupts not come as fast as possible.)
113 */
114 if (d->just_transmitted_something) {
115 d->just_transmitted_something --;
116 return;
117 }
118 }
119
120 d->regs.dc_csr &= ~CSR_RDONE;
121
122 if ((d->regs.dc_csr & CSR_MSE) && !(d->regs.dc_csr & CSR_TRDY)) {
123 int scanner_start = d->tx_scanner;
124
125 /* Loop until we've checked all 4 channels, or some
126 channel was ready to transmit: */
127
128 do {
129 d->tx_scanner = (d->tx_scanner + 1) % 4;
130
131 if (d->regs.dc_tcr & (1 << d->tx_scanner)) {
132 d->regs.dc_csr |= CSR_TRDY;
133 if (d->regs.dc_csr & CSR_TIE)
134 INTERRUPT_ASSERT(d->irq);
135
136 d->regs.dc_csr &= ~CSR_TX_LINE_NUM;
137 d->regs.dc_csr |= (d->tx_scanner << 8);
138 }
139 } while (!(d->regs.dc_csr & CSR_TRDY) &&
140 d->tx_scanner != scanner_start);
141
142 /* We have to return here. NetBSD can handle both
143 rx and tx interrupts simultaneously, but Ultrix
144 doesn't like that? */
145
146 if (d->regs.dc_csr & CSR_TRDY)
147 return;
148 }
149
150 lk201_tick(cpu->machine, &d->lk201);
151
152 avail = d->cur_rx_queue_pos_write != d->cur_rx_queue_pos_read;
153
154 if (avail && (d->regs.dc_csr & CSR_MSE))
155 d->regs.dc_csr |= CSR_RDONE;
156
157 if ((d->regs.dc_csr & CSR_RDONE) && (d->regs.dc_csr & CSR_RIE))
158 INTERRUPT_ASSERT(d->irq);
159 }
160
161
162 DEVICE_ACCESS(dc7085)
163 {
164 struct dc_data *d = extra;
165 uint64_t idata = 0, odata = 0;
166 size_t i;
167
168 if (writeflag == MEM_WRITE)
169 idata = memory_readmax64(cpu, data, len);
170
171 /* Always clear: */
172 d->regs.dc_csr &= ~CSR_CLR;
173
174 switch (relative_addr) {
175
176 case 0x00: /* CSR: Control and Status */
177 if (writeflag == MEM_WRITE) {
178 debug("[ dc7085 write to CSR: 0x%04x ]\n", idata);
179 idata &= (CSR_TIE | CSR_RIE | CSR_MSE | CSR_CLR
180 | CSR_MAINT);
181 d->regs.dc_csr &= ~(CSR_TIE | CSR_RIE | CSR_MSE
182 | CSR_CLR | CSR_MAINT);
183 d->regs.dc_csr |= idata;
184 if (!(d->regs.dc_csr & CSR_MSE))
185 d->regs.dc_csr &= ~(CSR_TRDY | CSR_RDONE);
186 goto do_return;
187 } else {
188 /* read: */
189
190 /* fatal("[ dc7085 read from CSR: (csr = 0x%04x) ]\n",
191 d->regs.dc_csr); */
192 odata = d->regs.dc_csr;
193 }
194 break;
195
196 case 0x08: /* LPR: */
197 if (writeflag == MEM_WRITE) {
198 debug("[ dc7085 write to LPR: 0x%04x ]\n", idata);
199 d->regs.dc_rbuf_lpr = idata;
200 goto do_return;
201 } else {
202 /* read: */
203 int avail = d->cur_rx_queue_pos_write !=
204 d->cur_rx_queue_pos_read;
205 int ch = 0, lineno = 0;
206 /* debug("[ dc7085 read from RBUF: "); */
207 if (avail) {
208 ch = d->rx_queue_char[d->cur_rx_queue_pos_read];
209 lineno = d->rx_queue_lineno[
210 d->cur_rx_queue_pos_read];
211 d->cur_rx_queue_pos_read++;
212 if (d->cur_rx_queue_pos_read == MAX_QUEUE_LEN)
213 d->cur_rx_queue_pos_read = 0;
214 /* if (ch >= ' ' && ch < 127)
215 debug("'%c'", ch);
216 else
217 debug("0x%x", ch);
218 debug(" for lineno %i ", lineno); */
219 } /* else
220 debug("empty ");
221 debug("]\n"); */
222 odata = (avail? RBUF_DVAL:0) |
223 (lineno << RBUF_LINE_NUM_SHIFT) | ch;
224
225 d->regs.dc_csr &= ~CSR_RDONE;
226 INTERRUPT_DEASSERT(d->irq);
227
228 d->just_transmitted_something = 4;
229 }
230 break;
231
232 case 0x10: /* TCR: */
233 if (writeflag == MEM_WRITE) {
234 /* fatal("[ dc7085 write to TCR: 0x%04x) ]\n",
235 (int)idata); */
236 d->regs.dc_tcr = idata;
237 d->regs.dc_csr &= ~CSR_TRDY;
238 INTERRUPT_DEASSERT(d->irq);
239 goto do_return;
240 } else {
241 /* read: */
242 /* debug("[ dc7085 read from TCR: (tcr = 0x%04x) ]\n",
243 d->regs.dc_tcr); */
244 odata = d->regs.dc_tcr;
245 }
246 break;
247
248 case 0x18: /* Modem status (R), transmit data (W) */
249 if (writeflag == MEM_WRITE) {
250 int line_no = (d->regs.dc_csr >>
251 RBUF_LINE_NUM_SHIFT) & 0x3;
252 idata &= 0xff;
253
254 lk201_tx_data(&d->lk201, line_no, idata);
255
256 d->regs.dc_csr &= ~CSR_TRDY;
257 INTERRUPT_DEASSERT(d->irq);
258
259 d->just_transmitted_something = 4;
260 } else {
261 /* read: */
262 d->regs.dc_msr_tdr |= MSR_DSR2 | MSR_CD2 |
263 MSR_DSR3 | MSR_CD3;
264 debug("[ dc7085 read from MSR: (msr_tdr = 0x%04x) ]\n",
265 d->regs.dc_msr_tdr);
266 odata = d->regs.dc_msr_tdr;
267 }
268 break;
269
270 default:
271 if (writeflag==MEM_READ) {
272 debug("[ dc7085 read from 0x%08lx ]\n",
273 (long)relative_addr);
274 } else {
275 debug("[ dc7085 write to 0x%08lx:",
276 (long)relative_addr);
277 for (i=0; i<len; i++)
278 debug(" %02x", data[i]);
279 debug(" ]\n");
280 }
281 }
282
283 if (writeflag == MEM_READ)
284 memory_writemax64(cpu, data, len, odata);
285
286 do_return:
287 dev_dc7085_tick(cpu, extra);
288
289 return 1;
290 }
291
292
293 /*
294 * dev_dc7085_init():
295 *
296 * Initialize a dc7085 serial controller device. use_fb should be non-zero
297 * if a framebuffer device is used. Channel 0 will then be treated as a
298 * DECstation keyboard, instead of a plain serial console.
299 */
300 int dev_dc7085_init(struct machine *machine, struct memory *mem,
301 uint64_t baseaddr, char *irq_path, int use_fb)
302 {
303 struct dc_data *d;
304
305 CHECK_ALLOCATION(d = malloc(sizeof(struct dc_data)));
306 memset(d, 0, sizeof(struct dc_data));
307
308 INTERRUPT_CONNECT(irq_path, d->irq);
309 d->use_fb = use_fb;
310
311 d->regs.dc_csr = CSR_TRDY | CSR_MSE;
312 d->regs.dc_tcr = 0x00;
313
314 d->console_handle = console_start_slave(machine, "DC7085", 1);
315
316 lk201_init(&d->lk201, use_fb, add_to_rx_queue, d->console_handle, d);
317
318 memory_device_register(mem, "dc7085", baseaddr, DEV_DC7085_LENGTH,
319 dev_dc7085_access, d, DM_DEFAULT, NULL);
320 machine_add_tickfunction(machine, dev_dc7085_tick, d,
321 DC_TICK_SHIFT);
322
323 return d->console_handle;
324 }
325

  ViewVC Help
Powered by ViewVC 1.1.26